Angr_CTF总结

在这里插入图片描述


前言

根据大佬们的angr教程的学习,作个人总结
参考内容1:https://www.anquanke.com/post/id/212816#h2-16
参考内容2:https://www.bilibili.com/video/BV167411o7WK/?spm_id_from=333.788.videocard.0


一、基本模板

1.以地址的形式寻找

"""
步骤:
    1.加载文件
    2.初始化入口
    3.给入口 开始设置模拟执行
    4.告诉程序要执行到的地方
    5.出结果
    6.输出结果

"""
import angr
import sys
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)  # 加载文件
    initial_state = project.factory.entry_state()  # 初始化,二进制文件入口
    simulation = project.factory.simgr(initial_state) # 模拟执行,给参数:入口
	
    avoid_me_address =   0x080485A8
    maybe_good_address = 0x080485E0
	
    simulation.explore(find=maybe_good_address, avoid=avoid_me_address)
	#想要执行到及避免的地方,find=addr avoid
    if simulation.found:
        solution_state = simulation.found[0]
        solution = solution_state.posix.dumps(sys.stdin.fileno())
        # 等价于 dump(0)
        print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
    else:
        raise Exception('Could not find the solution')
if __name__ == "__main__":
    Go(sys.argv)

2.以字节对象的形式寻找

import angr
import sys
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Good Job.' in stdout_output:
            return True
        # 对象要使用的是b'string'不能缺b
        # 该对象是字节对象 而不是字符串
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Try again.' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        solution_state = simulation.found[0]
        solution = solution_state.posix.dumps(sys.stdin.fileno())
        # 可用dumps(0)
        print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

二、绕过scanf

1.寄存器符号化

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address = 0x08048980
    initial_state = project.factory.blank_state(addr=start_address)
    # 自定义入口 而不再是从二进制文件入口直接进入
    passwd_size_in_bits = 32
    # 生成符号位向量,BVS(ame,size)
    passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
    passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)
    passwd2 = claripy.BVS('passwd2', passwd_size_in_bits)

    initial_state.regs.eax = passwd0
    initial_state.regs.ebx = passwd1
    initial_state.regs.edx = passwd2
    # state.regs.xxx 取寄存器

    simulation = project.factory.simgr(initial_state) 

    def is_successful(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(sys.stdout.fileno())
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = format(solution_state.solver.eval(passwd0), 'x')
            # 约束求解 求值 而不是直接dump(0)
            solution1 = format(solution_state.solver.eval(passwd1), 'x')
            solution2 = format(solution_state.solver.eval(passwd2), 'x')
            solution = solution0 + " " + solution1 + " " + solution2
            print("[+] Success! Solution is: {}".format(solution))
            # print(simgr.found[0].posix.dumps(0))
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

2.栈符号化

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address = 0x8048697
    initial_state = project.factory.blank_state(addr=start_address)

    initial_state.regs.ebp = initial_state.regs.esp
	# mov ebp,esp
    passwd_size_in_bits = 32
    passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
    passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)
	
    padding_length_in_bytes = 0x8
    initial_state.regs.esp -= padding_length_in_bytes
	# esp_addr
    initial_state.stack_push(passwd0)  
    initial_state.stack_push(passwd1) 
	# push 两个变量
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = (solution_state.solver.eval(passwd0))
            solution1 = (solution_state.solver.eval(passwd1))
            print("[+] Success! Solution is: {0} {1}".format(solution0, solution1))
            #print(solution0, solution1)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

3.内存符号化

3.1 固定内存地址符号化

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address = 0x8048601
    initial_state = project.factory.blank_state(addr=start_address)

    passwd_size_in_bits = 64
    # 因为是4个8字节即64比特大小的字符串
    passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
    passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)
    passwd2 = claripy.BVS('passwd2', passwd_size_in_bits)
    passwd3 = claripy.BVS('passwd3', passwd_size_in_bits)

    passwd0_address = 0xA1BA1C0
    #passwd1_address = 0xA1BA1C8
    #passwd2_address = 0xA1BA1D0
    #passwd3_address = 0xA1BA1D8
    initial_state.memory.store(passwd0_address, passwd0)
    # state.memory.store(addr,value)
    # 数据存在了某一固定地址
    initial_state.memory.store(passwd0_address + 0x8,  passwd1)
    initial_state.memory.store(passwd0_address + 0x10, passwd2)
    initial_state.memory.store(passwd0_address + 0x18, passwd3)

    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = solution_state.solver.eval(passwd0,cast_to=bytes)
            solution1 = solution_state.solver.eval(passwd1,cast_to=bytes)
            solution2 = solution_state.solver.eval(passwd2,cast_to=bytes)
            solution3 = solution_state.solver.eval(passwd3,cast_to=bytes)
            solution = solution0 + b" " + solution1 + b" " + solution2 + b" " + solution3
            print("[+] Success! Solution is: {}".format(solution.decode("utf-8")))
            #print(solution0, solution1, solution2, solution3)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

3.2 动态内存符号化


import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address = 0x8048699
    initial_state = project.factory.blank_state(addr=start_address)

    passwd_size_in_bits = 64
    # 缓冲区大小为 8字节,所以64bit
    passwd0 = claripy.BVS('passwd0', passwd_size_in_bits)
    passwd1 = claripy.BVS('passwd1', passwd_size_in_bits)

    fake_heap_address0 = 0xffffc93c
    pointer_to_malloc_memory_address0 = 0xabcc8a4
    fake_heap_address1 = 0xffffc94c
    pointer_to_malloc_memory_address1 = 0xabcc8ac
    initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address0, endness=project.arch.memory_endness)
    initial_state.memory.store(pointer_to_malloc_memory_address1, fake_heap_address1, endness=project.arch.memory_endness)

    initial_state.memory.store(fake_heap_address0, passwd0)  
    initial_state.memory.store(fake_heap_address1, passwd1)
	# fake_heap_address放入了pointer_to_malloc_memory_addresss(fake即伪装的动态地址faker),之后pass放入这伪装的动态地址中。
	# 实现:"pass->fake->pointer"
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = solution_state.solver.eval(passwd0, cast_to=bytes)
            solution1 = solution_state.solver.eval(passwd1, cast_to=bytes)
            print("[+] Success! Solution is: {0} {1}".format(solution0.decode('utf-8'), solution1.decode('utf-8')))
            #print(solution0, solution1)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

scanf绕过总结

state.regs.xxx
state.memory.store
BVV(value,size) 和 BVS( name, size)
要注意大小 是用bit的,所以要注意各种转换(1字节=8比特)
在后边有直接hook scanf,不选择绕过 而选择模拟的操作方式。哪种更好尚且不知。
针对不同情况下的不同符号化,并非只是绕过scanf时才会用到。要点在于 输入是否需要符号化,再根据输入的情境不同 使用不同的符号化。

hook

hook单一程序 使用地址hook

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
	# 因为使用了hook 所以 可直接从entry处进行操作
    check_equals_called_address = 0x80486B3
    instruction_to_skip_length = 5
	# project.hook(要hook的函数地址,该地址所占长度)
    @project.hook(check_equals_called_address, length=instruction_to_skip_length)
    def skip_check_equals_(state):
        user_input_buffer_address = 0x804A054 
        user_input_buffer_length = 16

        user_input_string = state.memory.load(
            user_input_buffer_address,
            user_input_buffer_length
        )
        # 固定内存地址 的 操作方式
        check_against_string = 'XKSPZSJKJYQCQXZV'

        register_size_bit = 32
        state.regs.eax = claripy.If(
            user_input_string == check_against_string, # 如果相等
            claripy.BVV(1, register_size_bit),  	   # 成功返回1
            claripy.BVV(0, register_size_bit)		   # 不成功返回0
        )
	    # 题目中,eax是作为函数计算后返回值存放的地方 成功则返回1,不成功则返回0
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution = solution_state.posix.dumps(0)
            print("[+] Success! Solution is: {0}".format(solution.decode('utf-8')))
            #print(solution0)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

hook函数名

import angr
import claripy
import sys

def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
	# 同上,可直接从entry进入
	# class 继承自angr.SimProcedure 
	# 作用:使得函数被我们写的函数代替 并在run(self),开始用self
    class ReplacementCheckEquals(angr.SimProcedure):
        def run(self, to_check, length):
            user_input_buffer_address = to_check
            user_input_buffer_length = length
            user_input_string = self.state.memory.load(
                user_input_buffer_address,
                user_input_buffer_length
            )
            check_against_string = 'ORSDDWXHZURJRBDH'
            return claripy.If(
                user_input_string == check_against_string, 
                claripy.BVV(1, 32), 
                claripy.BVV(0, 32)
            )
            # 同上 与之不同的是:hook函数名是对所有的该名函数作hook,所以需要定义一个模拟函数的类,在里边作模拟程序 def run; 

    check_equals_symbol = 'check_equals_ORSDDWXHZURJRBDH'
    project.hook_symbol(check_equals_symbol, ReplacementCheckEquals())
	# project.hook_symbol(要hook的函数名, 用于代替该函数的类)
    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution = solution_state.posix.dumps(0)
            print("[+] Success! Solution is: {0}".format(solution.decode('utf-8')))
            #print(solution0)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

hook scanf

import angr
import claripy
import sys

def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
	
	# 与hook 函数名一样 模拟scanf函数
    class ReplacementScanf(angr.SimProcedure):
        def run(self, format_string, param0, param1):
            scanf0 = claripy.BVS('scanf0', 32)
            scanf1 = claripy.BVS('scanf1', 32)
			# 两个scnaf的调用
            scanf0_address = param0
            self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
            scanf1_address = param1
            self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)

            self.state.globals['solutions'] = (scanf0, scanf1)
            #这里的关键我们都知道Python的变量生存周期,在这里scanf0和scanf1是函数ReplacementScanf的局		     部变量,为了让函数外部也能获得我们输入的符号位向量,从而调用求解器获得答案,需要将这两个符号位向量变为全局变量,这里我们需要调用带有全局状态的globals插件中“保存”对我们的符号值的引用。globals插件允许使用列表,元组或多个键的字典来存储多个位向量(作者原话)
			# 在局部函数里定义了scanf,但是scanf事实上是被很多地方所使用的,所以需要state.globals
    scanf_symbol = '__isoc99_scanf'  # scanf的函数名
    project.hook_symbol(scanf_symbol, ReplacementScanf())

    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            stored_solutions = solution_state.globals['solutions']
            # 两个值 以列表形式存储了
            scanf0_solution = solution_state.solver.eval(stored_solutions[0])
            scanf1_solution = solution_state.solver.eval(stored_solutions[1])
            print("[+] Success! Solution is: {0} {1}".format(scanf0_solution,scanf1_solution))
            #print(scanf0_solution, scanf1_solution)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

hook 静态库

hook 外部文件导入动态库

hook总结

hook针对不同内容,会有不同写法。说不出个所以然。。。

路径爆炸问题

路径爆炸:当程序进行逐位比较时,每次比较都会有对或错两种结果,假设有16个字符,那么会有2^16种路径,即路径爆炸。不利于angr分析

hook

上方已写 – hook单一程序 使用地址hook

约束条件:使用z3求解结果

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)

    start_address = 0x8048625
    buff_addr = 0x0804A050
    address_to_check_constraint = 0x08048565

    initial_state = project.factory.blank_state(addr=start_address)
	# 自定义地址 跳过scanf处
    char_size_in_bits = 8
    passwd_len = 16
    passwd0 = claripy.BVS('passwd0', char_size_in_bits*passwd_len)
    initial_state.memory.store(buff_addr, passwd0)

    simulation = project.factory.simgr(initial_state)
    simulation.explore(find=address_to_check_constraint)
	# 模拟执行到check函数处 在下方开始使用约束求解,来求解出值
    if simulation.found:
        solution_state = simulation.found[0]
        constrained_parameter_address = buff_addr
        constrained_parameter_size_bytes = 16
        constrained_parameter_bitvector = solution_state.memory.load(  # check函数的
        constrained_parameter_address,
        constrained_parameter_size_bytes
    )
        constrained_parameter_desired_value = 'AUPDNNPROEZRJWKB'
        solution_state.solver.add(constrained_parameter_bitvector == constrained_parameter_desired_value)
        # state.solver.add() -- 添加约束 就z3 之后求解出来
        solution0 = solution_state.solver.eval(passwd0,cast_to=bytes)       
        print("[+] Success! Solution is: {0}".format(solution0))
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

veritesting

import angr
import claripy
import sys

def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    initial_state = project.factory.entry_state()
    simulation = project.factory.simgr(initial_state, veritesting=True)
	# 简而言之,veritesting的开启使得angr同时使用"动态符号执行" 和 "静态分析" 减少路径爆炸的影响,直接跑angr
    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution = solution_state.posix.dumps(0)
            print("[+] Success! Solution is: {0}".format(solution))
            #print(scanf0_solution, scanf1_solution)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

文件模拟

import angr
import sys
import claripy
def Go(argv):
    path_to_binary = argv[1]   
    project = angr.Project(path_to_binary, auto_load_libs=False)
    start_address =  0x80488EA
    initial_state = project.factory.blank_state(addr=start_address)

    filename = 'OJKSQYDP.txt'
    symbolic_file_size_bytes = 64
    passwd0 = claripy.BVS('password', symbolic_file_size_bytes * 8)
    passwd_file = angr.storage.SimFile(filename, content=passwd0, size=symbolic_file_size_bytes)

    initial_state.fs.insert(filename, passwd_file)

    simulation = project.factory.simgr(initial_state)

    def is_successful(state):
        stdout_output = state.posix.dumps(1)
        if b'Good Job.\n' in stdout_output:
            return True
        else: 
            return False

    def should_abort(state):
        stdout_output = state.posix.dumps(1)
        if b'Try again.\n' in  stdout_output:
            return True
        else: 
            return False

    simulation.explore(find=is_successful, avoid=should_abort)

    if simulation.found:
        for i in simulation.found:
            solution_state = i
            solution0 = solution_state.solver.eval(passwd0, cast_to=bytes)
            print("[+] Success! Solution is: {0}".format(solution0.decode('utf-8')))
            #print(solution0)
    else:
        raise Exception('Could not find the solution')

if __name__ == "__main__":
    Go(sys.argv)

PWN

任意读

任意写

任意跳转

总结

人比较笨,总觉得没有理解得很好。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值