项目地址:
https://github.com/jakespringer/angr_ctf
https://github.com/Hustcw/Angr_Tutorial_For_CTF
00_angr_find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import angr
proj = angr.Project('./00_angr_find',auto_load_libs=False)
state = proj.factory.entry_state()
sm = proj.factory.simulation_manager(state)
good = 0x0804867D
sm.explore(find = good)
if sm.found: find_state = sm.found[0]
flag = find_state.posix.dumps(0)
print(str(flag,'utf-8'))
|
01_angr_avoid
有很多avoid_me
过程,为了避免浪费时间可以设置不执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import angr
proj = angr.Project('./01_angr_avoid',auto_load_libs=False)
state = proj.factory.entry_state()
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=0x080485E5,avoid=0x080485A8)
if simgr.found: found_state = simgr.found[0]
flag = found_state.posix.dumps(0) print(flag) print(str(flag,'utf-8'))
|
02_angr_find_condition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import angr
proj = angr.Project('./02_angr_find_condition',auto_load_libs=False)
state = proj.factory.entry_state()
simgr = proj.factory.simulation_manager(state)
good = lambda s:b'Good Job.' in s.posix.dumps(1)
simgr.explore(find=good)
if simgr.found: found_state = simgr.found[0]
flag = found_state.posix.dumps(0)
print(str(flag,'utf-8'))
|
03_angr_symbolic_registers
这个scanf
需要输入3个,并且是通过eax
,ebx
,edx
三个寄存器传参的。
所以需要对三个寄存器进行设置值,所以利用到了claripy
所以通过设置空状态来跳过这个scanf
输入,设置起始地址为0x08048937
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import angr import claripy
proj = angr.Project('./03_angr_symbolic_registers',auto_load_libs=False)
start_addr = 0x08048980 good = lambda s:b'Good Job.' in s.posix.dumps(1)
state = proj.factory.blank_state(addr = start_addr)
p1 = claripy.BVS('p1',32) p2 = claripy.BVS('p2',32) p3 = claripy.BVS('p3',32)
state.regs.eax = p1 state.regs.ebx = p2 state.regs.edx = p3
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=good)
if simgr.found: found_state = simgr.found[0]
flag1 = found_state.solver.eval(p1) flag2 = found_state.solver.eval(p2) flag3 = found_state.solver.eval(p3)
print("flag:{} {} {}".format(hex(flag1),hex(flag2),hex(flag3))) else: print("no find")
|
04_angr_symbolic_stack
输入两个参数,是通过栈传参的。
这一步是恢复scanf
函数的栈空间。所以要从0x8048697
处开始,并且复制栈中的数据。可以通过gdb
调出偏移。
可以模仿开辟这个栈,复制其中的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import angr import claripy
proj = angr.Project('./04_angr_symbolic_stack',auto_load_libs=False)
start_addr = 0x08048697
good = lambda s:b'Good Job.' in s.posix.dumps(1)
state = proj.factory.blank_state(addr = start_addr)
state.regs.ebp = state.regs.esp
state.regs.esp = state.regs.esp - 8
p1 = claripy.BVS('p1',32) p2 = claripy.BVS('p2',32)
state.stack_push(p1) state.stack_push(p2)
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=good)
if simgr.found: found_state = simgr.found[0]
flag1 = found_state.solver.eval(p1) flag2 = found_state.solver.eval(p2) print("flag:{} {}".format(flag1,flag2))
else: print("not found")
|
05_angr_symbolic_memory
数据存储在内存中。
所以就是利用claripy
生成四个符号向量,其中scanf
中的每个值为%8s
,就是8个字符,而char是一个字节(8 bit),所以BVS
设置设置为8*8
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import angr import claripy
proj = angr.Project('./05_angr_symbolic_memory',auto_load_libs=False)
start_addr = 0x080485FE
state = proj.factory.blank_state(addr=start_addr)
good = lambda s:b'Good Job.' in s.posix.dumps(1)
input1 = 0x0A1BA1C0 input2 = 0x0A1BA1C8 input3 = 0x0A1BA1D0 input4 = 0x0A1BA1D8
p1 = claripy.BVS('p1',8*8) p2 = claripy.BVS('p2',8*8) p3 = claripy.BVS('p3',8*8) p4 = claripy.BVS('p4',8*8)
state.memory.store(input1,p1) state.memory.store(input2,p2) state.memory.store(input3,p3) state.memory.store(input4,p4)
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=good)
if simgr.found: found_state = simgr.found[0] s1 = found_state.solver.eval(p1,cast_to=bytes).decode() s2 = found_state.solver.eval(p2,cast_to=bytes).decode() s3 = found_state.solver.eval(p3,cast_to=bytes).decode() s4 = found_state.solver.eval(p4,cast_to=bytes).decode() print("flag:{} {} {} {}".format(s1,s2,s3,s4)) else: print("not found")
|
因为最后读取的是字符串,但是eval
出来的是bytes
类型的,所以需要进行个类型转换。
06_angr_symbolic_dynamic_memory
首先malloc
分配两块动态内存。buffer0
和buffer1
用来存储这两块内存的地址。
所以可以先设置两个fake
地址,再设置符号变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import angr import claripy
proj = angr.Project('./06_angr_symbolic_dynamic_memory',auto_load_libs=False)
start_addr = 0x08048696
good = lambda s:b'Good Job.' in s.posix.dumps(1)
butter0 = 0x0ABCC8A4 butter1 = 0x0ABCC8AC
state = proj.factory.blank_state(addr = start_addr)
fake_addr1 = 0x11111111 fake_addr2 = 0x22222222
b0 = claripy.BVS('b0',8*8) b1 = claripy.BVS('b1',8*8) state.memory.store(butter0,fake_addr1,endness=proj.arch.memory_endness,size=4) state.memory.store(butter1,fake_addr2,endness=proj.arch.memory_endness,size=4) state.memory.store(fake_addr1,b0) state.memory.store(fake_addr2,b1)
simgr = proj.factory.simulation_manager(state) simgr.explore(find=good) if simgr.found: found_state = simgr.found[0] flag1 = found_state.solver.eval(b0,cast_to=bytes).decode() flag2 = found_state.solver.eval(b1,cast_to=bytes).decode() print("flag:{} {}".format(flag1,flag2))
else: print("not found")
|
07_angr_symbolic_file
这题需要符号化整个文件,然后再设置符号化文件中的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import angr import claripy
proj = angr.Project('./07_angr_symbolic_file',auto_load_libs=False)
good = lambda s:b'Good Job.' in s.posix.dumps(1)
start_addr = 0x080488D6 buffer = 0x0804A0A0
state = proj.factory.blank_state(addr = start_addr)
file_name = "OJKSQYDP.txt" size_file = 64 password = claripy.BVS('p1',size_file*8)
file_sym = angr.storage.SimFile(file_name,content=password) state.fs.insert(file_name,file_sym)
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=good) if simgr.found: found_state = simgr.found[0] flag1 = found_state.solver.eval(password,cast_to=bytes).decode() print("flag:{}".format(flag1)) else: print("not found")
|
08_angr_constraints
如果不设置其它约束直接跑的话,可能会导致路径爆炸。循环里的分支呈指数增长的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import angr import claripy
proj = angr.Project('./08_angr_constraints',auto_load_libs=False)
start_addr = 0x8048625 good = lambda s:b'Good Job.' in s.posix.dumps(1) state = proj.factory.blank_state(addr = start_addr)
b1 = claripy.BVS('b1',16*8)
password = 0x0804A050
state.memory.store(password,b1) simgr = proj.factory.simulation_manager(state)
check_addr = 0x08048673
simgr.explore(find=check_addr)
if simgr.found: found_state = simgr.found[0] constrain_addr = password byte_size = 16 load_symbols = found_state.memory.load(constrain_addr,byte_size) string = "AUPDNNPROEZRJWKB" found_state.add_constraints(load_symbols == string) flag = found_state.solver.eval(b1,cast_to=bytes).decode() print("flag:{}".format(flag)) else: print("not found")
|
09_angr_hooks
这个函数会引起路径爆炸,所以这里采用hook
技术,将这个函数改成自己写的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import angr import claripy
proj = angr.Project('./09_angr_hooks',auto_load_libs=False)
state = proj.factory.entry_state() good = lambda s:b'Good Job.' in s.posix.dumps(1) check_addr = 0x080486B3 skip_len = 5
@proj.hook(check_addr,length=skip_len)
def check_equal(state): buffer_addr = 0x0804A054 load_buffer_symbol = state.memory.load(buffer_addr,16) check_str = "XYMKBKUHNIQYNQXE" state.regs.eax = claripy.If(load_buffer_symbol == check_str,claripy.BVV(1,32),claripy.BVV(0,32))
simgr = proj.factory.simulation_manager(state)
simgr.explore(find = good) if simgr.found: found_state = simgr.found[0] flag = found_state.posix.dumps(0) print(str(flag,'utf-8')) else: print("not found")
|
10_angr_simprocedures
跟前面一个差不多,但是这个check
被调用的次数多。
所以不再是根据函数地址去hook
了,直接根据函数名称hook
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import angr import claripy
def exp(): proj = angr.Project('./10_angr_simprocedures',auto_load_libs=False) state = proj.factory.entry_state()
class my_symbol(angr.SimProcedure): def run(self,check_addr,length): angr_input = self.state.memory.load(check_addr,length) check_string = "ORSDDWXHZURJRBDH" return claripy.If(angr_input == check_string,claripy.BVV(1,32),claripy.BVV(0,32)) check_symbol = 'check_equals_ORSDDWXHZURJRBDH' proj.hook_symbol(check_symbol,my_symbol()) simgr = proj.factory.simulation_manager(state)
simgr.explore(find = is_good,avoid = is_bad) if simgr.found: found_state = simgr.found[0] flag = found_state.posix.dumps(0) print(str(flag,'utf-8')) else: print("not found")
def is_good(state): return b'Good Job.' in state.posix.dumps(1)
def is_bad(state): return b'Try again.' in state.posix.dumps(1)
if __name__ == '__main__': exp()
|
11_angr_sim_scanf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import angr import claripy
def exp(): proj = angr.Project('./11_angr_sim_scanf',auto_load_libs=False) start_addr = 0x08048714 state = proj.factory.entry_state() class my_symbol(angr.SimProcedure): def run(self,format_string,addr1,addr2): buffer0 = claripy.BVS('buffer0',32) buffer1 = claripy.BVS('buffer1',32) self.state.memory.store(addr1,buffer0,endness=proj.arch.memory_endness,size = 4) self.state.memory.store(addr2,buffer1,endness=proj.arch.memory_endness,size = 4) self.state.globals['solutions'] = (buffer0,buffer1) scanf_symbol = "__isoc99_scanf" proj.hook_symbol(scanf_symbol,my_symbol()) simgr = proj.factory.simulation_manager(state) simgr.explore(find=is_good,avoid=is_bad) if simgr.found: found_state = simgr.found[0] flag = found_state.globals['solutions'] flag1 = found_state.solver.eval(flag[0]) flag2 = found_state.solver.eval(flag[1]) print("flag:{} {}".format(flag1,flag2)) else: print("not found")
def is_good(state): return b'Good Job.' in state.posix.dumps(1) def is_bad(state) : return b'Try again.' in state.posix.dumps(1)
if __name__ == '__main__': exp()
|
12_angr_veritesting
简单说一下Veritesting
由于动态符号执行和静态符号执行的优缺点不同,Veritesting
结合了静态符号执行与动态符号执行,减少路径爆炸的影响。
红框处的循环内有着混淆和判断,所以如果继续循环下去的话,分支会呈指数式增长,会导致路径爆炸。所以需要增加条件约束和Hook
函数避免路径爆炸。也可以使用Veritesting
自动就会节约时间,避免路径爆炸。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import angr import claripy
def exp(): proj = angr.Project('./12_angr_veritesting',auto_load_libs=False) state = proj.factory.entry_state() simgr = proj.factory.simulation_manager(state,veritesting=True)
simgr.explore(find=is_good,avoid=is_bad)
if simgr.found: found_state = simgr.found[0] flag = found_state.posix.dumps(0) print(flag.decode()) else: print("not found")
def is_good(state): return b'Good Job.' in state.posix.dumps(1) def is_bad(state): return b'Try again.' in state.posix.dumps(1)
if __name__ == '__main__': exp()
|
13_angr_static_binary
这道题用的是静态编译。通常情况下,Angr
会自动地用工作速度快的多的simporcedure
代替标准库函数,但是这一题中由于用的是静态编译,所以都编译为静态函数,angr
没有自动替换。所以需要手动hook
所有使用标准库的C函数,angr
在simprocedure
中提供了这些静态函数。
1 2 3 4 5 6 7 8 9 10 11
| angr.SIM_PROCEDURES['libc']['malloc'] angr.SIM_PROCEDURES['libc']['fopen'] angr.SIM_PROCEDURES['libc']['fclose'] angr.SIM_PROCEDURES['libc']['fwrite'] angr.SIM_PROCEDURES['libc']['getchar'] angr.SIM_PROCEDURES['libc']['strncmp'] angr.SIM_PROCEDURES['libc']['strcmp'] angr.SIM_PROCEDURES['libc']['scanf'] angr.SIM_PROCEDURES['libc']['printf'] angr.SIM_PROCEDURES['libc']['puts'] angr.SIM_PROCEDURES['libc']['exit']
|
只需要找到静态函数的地址进行hook
替换即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import angr import claripy
def exp(): proj = angr.Project('./13_angr_static_binary',auto_load_libs=False) state = proj.factory.entry_state() proj.hook(0x0804ED40,angr.SIM_PROCEDURES['libc']['printf']()) proj.hook(0x0804ED80,angr.SIM_PROCEDURES['libc']['scanf']()) proj.hook(0x0804F350,angr.SIM_PROCEDURES['libc']['puts']()) proj.hook(0x08048D10,angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
simgr = proj.factory.simulation_manager(state,veritesting=True) simgr.explore(find=is_good,avoid=is_bad) if simgr.found: found_state = simgr.found[0] flag = found_state.posix.dumps(0) print(flag.decode()) else: print("not found")
def is_good(state): return b'Good Job.' in state.posix.dumps(1)
def is_bad(state): return b'Try again.' in state.posix.dumps(1)
if __name__ == '__main__': exp()
|
14_angr_shared_library
validate
是一个外部导入函数
在.so
文件中找到函数的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import angr import claripy
def exp(): base = 0x4000000 proj = angr.Project('./lib14_angr_shared_library.so',load_options={'main_opts':{'custom_base_addr':base}}) buffer_pointer = claripy.BVV(0x3000000,32) validate_addr = base + 0x6d7 state = proj.factory.call_state(validate_addr,buffer_pointer,claripy.BVV(8,32))
password = claripy.BVS('password',8*8) state.memory.store(buffer_pointer,password)
simgr = proj.factory.simulation_manager(state) success_addr = base + 0x783 simgr.explore(find=success_addr) if simgr.found: found_state = simgr.found[0] found_state.add_constraints(found_state.regs.eax != 0) flag = found_state.solver.eval(password,cast_to=bytes).decode() print("flag:{}".format(flag))
else: print("not found") def is_good(state): return b'Good Job.' in state.posix.dumps(1)
def is_bad(state): return b'Try again.' in state.posix.dumps(1)
if __name__ == '__main__': exp()
|