0%

angr

00_find_angr

从这道题逻辑看非常简单,就一个complex_function加密函数,我们可以选择爆破和逆向,但这里可以选择简单的方式

找到“Good Job”的地址,写代码

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
import sys
import angr

def main(argv):
# 目标文件的路径
path_to_binary = './00_angr_find'
# 创建angr项目
project = angr.Project(path_to_binary)

# 设置项目起点,entry_state代表程序的入口点,即main函数
initial_state = project.factory.entry_state()
# 设置模拟器
sm = project.factory.simgr(initial_state)

# 设置目标地址
is_good_addr = 0x08048678
sm.explore(find=is_good_addr)
#约束模拟器到达find指定的地址

# 如果到达目标地址,打印此时的符号向量
if sm.found:
solution_state = sm.found[0]
print(solution_state.posix.dumps(0))
# 否者抛出失败异常
else:
raise Exception('Could not find solution')

结果:

01_angr_avoid

当我们找到main函数想F5进去的时候,却反编译不了,然后我们就找到Good Job地址;

写代码:

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
import sys
import angr

def main(argv):
# 目标文件的路径
path_to_binary = './01_angr_avoid'
# 创建angr项目
project = angr.Project(path_to_binary)

# 设置项目起点,enter_state代表程序的入口点,即main函数
initial_state = project.factory.entry_state()
# 设置模拟器
sm = project.factory.simgr(initial_state)

# 设置目标地址
is_good_addr = 0x080485E0
fail_addr = 0x080485F2
sm.explore(find=is_good_addr, avoid=fail_addr)
#avoid避开avoid的地址

# 如果到达目标地址,打印此时的符号向量
if sm.found:
solution_state = sm.found[0]
print(solution_state.posix.dumps(0))
# 否者抛出失败异常
else:
raise Exception('Could not find solution')

if __name__ == '__main__':
main(sys.argv)

我们新增了一个avoid选项,但是在某些题目中,添加avoid可以有效地防止路径爆炸

02_angr_find_condition

和第一题类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
import angr
def main(argv):
bin_path = "./02_angr_find_condition"
p = angr.Project(bin_path)
init_state = p.factory.entry_state()
sm = p.factory.simulation_manager(init_state)
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)
sm.explore(find = is_good,avoid = is_bad)
if sm.found:
found_state = sm.found[0]
print("Solution:{}".format(found_state.posix.dumps(0)))
if __name__ == '__main__':
main(sys.argv)

find处也可以是函数,可以不写函数地址,写字符串。

03_angr_symbolic_registers

这里输入三个参数,angr没法解出来。

这里看到分别把三个参数给了eax,ebx和edx,我们就可以写如下代码:

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
import angr
import sys
import claripy
def main(argv):
bin_path = "./03_angr_symbolic_registers"
p = angr.Project(bin_path)
start_addr = 0x8048980
init_state = p.factory.blank_state(addr = start_addr)
#将eax,ebx,edx符号化为32位的位向量
pass1 = claripy.BVS("pass1",32)
pass2 = claripy.BVS("pass2",32)
pass3 = claripy.BVS("pass3",32)
init_state.regs.eax = pass1
init_state.regs.ebx = pass2
init_state.regs.edx = pass3

sm = p.factory.simulation_manager(init_state)
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)
sm.explore(find = is_good,avoid = is_bad)
if sm.found:
found_state = sm.found[0]
password1 = found_state.solver.eval(pass1)
password2 = found_state.solver.eval(pass2)
password3 = found_state.solver.eval(pass3)
print("Solution:{:x} {:x} {:x}".format(password1,password2,password3))
else:
raise Exception("No solution found")
if __name__ == '__main__':
main(sys.argv)

地址0x8048978处是恢复栈,所以我们从下一个地址开始。

结果:

04_angr_symbolic_stack

这里我们可以看到输入在栈上,我们需要 符号化栈上的内存

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
import angr
import sys
import claripy

def main(argv):
bin_path = "./04_angr_symbolic_stack"
p = angr.Project(bin_path)
start_addr = 0x08048697
init_state = p.factory.blank_state(addr = start_addr)

#符号化栈上的内存
padding_size = 8
init_state.stack_push(init_state.regs.ebp)
init_state.regs.ebp = init_state.regs.esp
init_state.regs.esp -= padding_size
pass1 = init_state.solver.BVS("pass1",32)
pass2 = init_state.solver.BVS("pass2",32)
init_state.stack_push(pass1)
init_state.stack_push(pass2)

sm = p.factory.simgr(init_state)
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)
sm.explore(find = is_good,avoid = is_bad)
if sm.found:
found_state = sm.found[0]
password1 = found_state.solver.eval(pass1)
password2 = found_state.solver.eval(pass2)
print("Solution:{} {}".format(password1,password2))
else:
raise Exception("Solution not found")

if __name__ == '__main__':
main(sys.argv)

结果:

05_angr_symbolic_memory

我们要将 将内存地址符号化 :

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
41
42
43
44
45
46
import angr
import sys
import claripy
def main(argv):
bin_path = "./05_angr_symbolic_memory"
p = angr.Project(bin_path)
start_addr = 0x08048601
init_state = p.factory.blank_state(addr = start_addr)

p1 = init_state.solver.BVS("p1",64)
p2 = init_state.solver.BVS("p2",64)
p3 = init_state.solver.BVS("p3",64)
p4 = init_state.solver.BVS("p4",64)

p1_addr = 0xA1BA1C0
p2_addr = 0xA1BA1C8
p3_addr = 0xA1BA1D0
p4_addr = 0xA1BA1D8
#内存地址符号化
init_state.memory.store(p1_addr,p1)
init_state.memory.store(p2_addr,p2)
init_state.memory.store(p3_addr,p3)
init_state.memory.store(p4_addr,p4)

sm = p.factory.simgr(init_state)

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)

sm.explore(find = is_good,avoid = is_bad)

if sm.found:
found_state = sm.found[0]
password1 = found_state.solver.eval(p1,cast_to = bytes).decode('utf-8')
password2 = found_state.solver.eval(p2,cast_to = bytes).decode('utf-8')
password3 = found_state.solver.eval(p3,cast_to = bytes).decode('utf-8')
password4 = found_state.solver.eval(p4,cast_to = bytes).decode('utf-8')
print("Solution:{} {} {} {}".format(password1,password2,password3,password4))
else:
raise Exception("solution not found")

if __name__ == '__main__':
main(sys.argv)

结果:

06_angr_symbolic_dynamic_memory

这一节关于堆区的内容,程序申请两块内存,把输入存进去

虽然malloc来的空间是动态的,但是存放malloc返回值的变量buffer位于bss段,是静态的,那么我们可以伪造指针,使其指向一片可写内存,将这块内存符号化

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
41
42
43
44
45
import angr
import sys
import claripy

def main(argv):
bin_path = "./06_angr_symbolic_dynamic_memory"
p = angr.Project(bin_path)
start_addr = 0x08048699
init_state = p.factory.blank_state(addr = start_addr)
print("ESP:",init_state.regs.esp)
#开辟内存
buffer0 = 0x7fff0000-0x100
buffer1 = 0x7fff0000-0x200

buffer0_addr = 0x0ABCC8A4
buffer1_addr = 0x0ABCC8AC
#buffer_addr保存着buffer0的地址
init_state.memory.store(buffer0_addr,buffer0,endness = p.arch.memory_endness)
init_state.memory.store(buffer1_addr,buffer1,endness = p.arch.memory_endness)

p1 = init_state.solver.BVS("p1",8*8)
p2 = init_state.solver.BVS("p2",8*8)
init_state.memory.store(buffer0,p1)
init_state.memory.store(buffer1,p2)

sm = p.factory.simgr(init_state)
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)

sm.explore(find = is_good,avoid = is_bad)

if sm.found:
found_state = sm.found[0]
pass1 = found_state.solver.eval(p1,cast_to = bytes).decode('utf-8')
pass2 = found_state.solver.eval(p2,cast_to = bytes).decode('utf-8')

print("Solution: {} {}".format(pass1,pass2))
else:
raise Exception("solution not found")

if __name__ == '__main__':
main(sys.argv)

endness = p.arch.memory_endness

默认情况angr以大端方式写入数据,该参数以小端写入

结果:

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
29
30
31
32
33
34
35
36
37
38
import angr
import sys
import claripy

def main(argv):
bin_path = "./07_angr_symbolic_file"
p = angr.Project(bin_path)

start_addr = 0x080488D6
init_state = p.factory.blank_state(addr = start_addr)

filename = "OJKSQYDP.txt"
file_size = 0x40

password = init_state.solver.BVS("password",file_size*8)
sim_file = angr.storage.SimFile(filename,content = password,size = file_size)
#符号化文件插入
init_state.fs.insert(filename,sim_file)
sm = p.factory.simgr(init_state)

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)
sm.explore(find = is_good,avoid = is_bad)

if sm.found:
found_state = sm.found[0]
password_str = found_state.solver.eval(password,cast_to = bytes).decode('utf-8')
print("Solution:{}".format(password_str))
else:
raise Exception("solution not found")



if __name__ == '__main__':
main(sys.argv)

结果:

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
33
34
35
36
37
38
import angr
import sys
import claripy

def main(argv):
bin_path = "./08_angr_constraints"
p = angr.Project(bin_path)

start_addr = 0x08048625
init_state = p.factory.blank_state(addr = start_addr)

buffer_addr = 0x0804A050
password = init_state.solver.BVS("password",16*8)
init_state.memory.store(buffer_addr,password)

sm = p.factory.simgr(init_state)

check_addr = 0x08048565
sm.explore(find = check_addr)
if sm.found:
check_state = sm.found[0]

desired_string = "AUPDNNPROEZRJWKB"
check_param1 = buffer_addr
check_param2 = 0x10
#从内存中加载
check_bvs = check_state.memory.load(check_param1,check_param2)

check_constraint = desired_string == check_bvs
#添加约束
check_state.add_constraints(check_constraint)

password1 = check_state.solver.eval(password,cast_to = bytes).decode('utf-8')
print("Solution:{}".format(password1))


if __name__ == '__main__':
main(sys.argv)

结果:

09_angr_hooks

这里把输入加密与password比较,然后再把password加密与输入比较,所以就不能简单的用上题的方法

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
41
42
43
44
45
46
47
import angr
import sys
import claripy

def main(argv):
bin_path = "./09_angr_hooks"
p = angr.Project(bin_path)

init_state = p.factory.entry_state()

check_addr = 0x080486B3
check_skip_size = 5

@p.hook(check_addr,length = check_skip_size)
def check_hook(state):
user_input_addr = 0x804A054
user_input_length = 0x10

user_input_bvs = state.memory.load(
user_input_addr,
user_input_length
)

desired = "XYMKBKUHNIQYNQXE"

state.regs.eax = claripy.If(
desired == user_input_bvs,
claripy.BVV(1,32),
claripy.BVV(0,32)
)
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)

sm = p.factory.simgr(init_state)

sm.explore(find = is_good,avoid = is_bad)
if sm.found:
found_state = sm.found[0]

print("Solution:{}".format(found_state.posix.dumps(0)))
else:
raise Exception("solution not found")

if __name__ == '__main__':

结果:

10_angr_simprocedures

这次函数的比较我们需要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
35
36
37
38
39
40
41
42
43
44
mport angr
import sys
import claripy

def main(argv):
bin_path = "./10_angr_simprocedures"
p = angr.Project(bin_path)
init_state = p.factory.entry_state()

class mySimPro(angr.SimProcedure):
def run(self,user_input_addr,user_input_length):
angr_bvs = self.state.memory.load(
user_input_addr,
user_input_length
)
desired = "ORSDDWXHZURJRBDH"
return claripy.If(
desired == angr_bvs,
claripy.BVV(1,32),
claripy.BVV(0,32)
)

#以函数名字hook
check_symbol = "check_equals_ORSDDWXHZURJRBDH"
p.hook_symbol(check_symbol,mySimPro())

sm = p.factory.simgr(init_state)

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)

sm.explore(find = is_good,avoid = is_bad)

if sm.found:
found_state = sm.found[0]
password = found_state.posix.dumps(0).decode('utf-8')
print("Solution:{}".format(password))
else:
raise Exception("solution not found")


if __name__ == '__main_

结果:

11_angr_sim_scanf

这里我们需要模拟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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import sys
import angr
import claripy

def main(argv):
binary_path = './11_angr_sim_scanf'
p = angr.Project(binary_path)

initial_state = p.factory.entry_state()

class ReplacementScanf(angr.SimProcedure):

def run(self, fmt, scanf0_addr, scanf1_addr):
scanf0 = claripy.BVS('scanf0', 4*8)
scanf1 = claripy.BVS('scanf1', 4*8)

self.state.memory.store(scanf0_addr, scanf0, endness=p.arch.memory_endness)
self.state.memory.store(scanf1_addr, scanf1, endness=p.arch.memory_endness)
# 将scanf0和scanf1保存到当前状态
self.state.globals['solution0'] = scanf0
self.state.globals['solution1'] = scanf1
scanf_symbol = '__isoc99_scanf'
p.hook_symbol(scanf_symbol, ReplacementScanf())

sm = p.factory.simgr(initial_state)

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)

sm.explore(find=is_good, avoid=is_bad)

if sm.found:
solution_state = sm.found[0]
#从当前状态取出scanf0和scanf1
solution0 = solution_state.globals['solution0']
solution1 = solution_state.globals['solution1']

solution = '%u %u' % (solution_state.solver.eval(solution0), solution_state.solver.eval(solution1))
print(solution)
else:
raise Exception('Could not find the solution')

if __name__ == '__main__':
main(sys.argv)

结果:

12_angr_veritesting

程序输入32个字符,然后加密并在每次加密之后进行比较

如果直接搜索路径,分支太多很浪费时间,所以的想办法简化

angr有自动简化路径的选项

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 sys
import angr

def main(argv):
bin_path = './12_angr_veritesting'
p = angr.Project(bin_path)

initial_state = p.factory.entry_state()
sm = p.factory.simgr(initial_state, veritesting=True) # 设置自动合并路径

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)

sm.explore(find=is_good, avoid=is_bad)

if sm.found:
found_state = sm.found[0]

solution = found_state.posix.dumps(0)
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)

结果:

13_angr_static_binary

对于静态库函数

angr为我们实现了一部分库函数,我们可以直接在脚本中调用

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
import angr
import sys

def main(argv):
bin_path = './13_angr_static_binary'
p = angr.Project(bin_path)
printf_addr = 0x0804ED40
scanf_addr = 0x0804ED80
strcmp_addr = 0x08048280
puts_addr = 0x0804F350
libc_start_main_addr = 0x08048D10

init_state = p.factory.entry_state()
sm = p.factory.simgr(init_state, veritesting=True)


p.hook(printf_addr,angr.SIM_PROCEDURES['libc']['printf']())
p.hook(scanf_addr,angr.SIM_PROCEDURES['libc']['scanf']())
p.hook(strcmp_addr,angr.SIM_PROCEDURES['libc']['strcmp']())
p.hook(puts_addr,angr.SIM_PROCEDURES['libc']['puts']())
p.hook(libc_start_main_addr,angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
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)

sm.explore(find = is_good,avoid = is_bad)

if sm.found:
found_state = sm.found[0]
print("Solution:{}".format(found_state.posix.dumps(0)))
else:
raise Exception("solution not found")


if __name__ == '__main__':
main(sys.argv)

结果·:

14_angr_shared_library

程序接受输入,然后将输入传递给validate函数处理,validate函数位于共享库中,作用是验证加密后的输入共享库,其实也算一种可执行文件,只是没有经过符号链接,但是在angr的帮助下,我们可以直接加载共享库,思路就是使用共享库创建项目,然后伪造参数调用共享库中的函数

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
import sys
import angr
import claripy

def main():
bin_path = './lib14_angr_shared_library.so'

base = 0x400000 # 这个地址随便写
p = angr.Project( bin_path,load_options={'main_opts' : {'custom_base_addr' : base}} ) # 加载共享库

password_addr = claripy.BVV(0x300000, 32)
password = claripy.BVS('password', 8 * 8)

validate_function_addr = base + 0x6D7
init_state = p.factory.call_state(validate_function_addr, password_addr, 8) # 构造一个指向password的指针传递给函数使用
init_state.memory.store(password_addr, password)

sm = p.factory.simgr(init_state)

success_addr = base + 0x783
sm.explore(find=success_addr) # 寻找返回指令地址

if sm.found:
solution_state = sm.found[0]
solution_state.add_constraints(solution_state.regs.eax != 0) # 约束返回

solution = solution_state.se.eval(password,cast_to = bytes)
print(long_to_bytes(solution).decode())


if __name__ == '__main__':
main()
~

结果:

15_angr_arbitrary_read

看似程序不管如何都输出try _again

我们发现输入的v4与s相差16个字节

而good_job与try_again相差四个字节,而输入会有20个字节,所以内存泄漏会导致good_job输出

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import angr
import sys
import claripy

def main():
bin_path = './15_angr_arbitrary_read'
p = angr.Project(bin_path)

init_state = p.factory.entry_state()

class ReplacementScanf(angr.SimProcedure): # hook scanf函数,符号化输入

def run(self, fmt, number_addr, string_addr):

scanf0 = claripy.BVS('scanf0', 4 * 8)
scanf1 = claripy.BVS('scanf1', 20 * 8)

for char in scanf1.chop(bits=8):
self.state.add_constraints(char >= '0', char <= 'z')

scanf0_addr = number_addr
self.state.memory.store(scanf0_addr,
scanf0,endness=p.arch.memory_endness)
scanf1_addr = string_addr
self.state.memory.store(scanf1_addr, scanf1, endmess=p.arch.memory_endness)

self.state.globals['solution0'] = scanf0
self.state.globals['solution1'] = scanf1

scanf_symbol = '__isoc99_scanf'
p.hook_symbol(scanf_symbol, ReplacementScanf())

def check_puts(state): # 检查puts的参数是否指向good job
puts_parameter = state.memory.load(state.regs.esp + 4, 4, endness=p.arch.memory_endness) # 从栈中取出puts的参数

if state.solver.symbolic(puts_parameter): # 如果参数是符号化的
good_job_string_addr = 0x4D52584B
is_vulnerable_expresion = puts_parameter == good_job_string_addr
copied_state = state.copy()
copied_state.add_constraints(is_vulnerable_expresion)

if copied_state.satisfiable(): # 如果参数指向good job
state.add_constraints(is_vulnerable_expresion)
return True
else:
return False
else:
return False

sm = p.factory.simgr(init_state)

def is_good(state):
puts_addr = 0x08048370
if state.addr == puts_addr: # 当程序执行到puts函数时
return check_puts(state)
else:
return False

sm.explore(find=is_good)

if sm.found:
solution_state = sm.found[0]
solution = '%u %s' % (solution_state.solver.eval(solution_state.globals['solution0']), solution_state.solver.eval(solution_state.globals['solution1'],cast_to = bytes).decode())
print(solution)
else:
raise Exception('Could not find the solution')

if __name__ == '__main__':
main()

结果:

16_angr_arbitrary_write

password_buffer不等于那一串,但是我们发现输入的s可以溢出到dest对dest修改使其指向password_buffer的值,然后对其修改

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import angr
import sys
import claripy

def main():
bin_path = './16_angr_arbitrary_write'
p = angr.Project(bin_path)

init_state = p.factory.entry_state()

class ReplacementScanf(angr.SimProcedure): # hook scanf函数,符号化key和s

def run(self, fmt, number_addr, string_addr):
scanf0 = claripy.BVS('scanf0', 4 * 8)
scanf1 = claripy.BVS('scanf1', 20 * 8)

scanf0_addr = number_addr
scanf1_addr = string_addr

for char in scanf1.chop(bits=8):
self.state.add_constraints(char >= '0', char <= 'z')

self.state.memory.store(scanf0_addr, scanf0)
self.state.memory.store(scanf1_addr, scanf1)
self.state.globals['solution0'] = scanf0
self.state.globals['solution1'] = scanf1

scanf_symbol = '__isoc99_scanf'
p.hook_symbol(scanf_symbol, ReplacementScanf())

def check_strncpy(state):
# 检查s和dest是否正确
strncpy_src = state.memory.load(state.regs.esp + 8, 4, endness=p.arch.memory_endness)
strncpy_des = state.memory.load(state.regs.esp + 4, 4, endness=p.arch.memory_endness)

src_contents = state.memory.load(strncpy_src, 8)

if state.solver.symbolic(src_contents) and state.solver.symbolic(strncpy_des):
password_string = 'NDYNWEUJ'
buffer_addr = 0x57584344

dose_src_hold_password = src_contents == password_string
dose_dest_equal_buffer_addr = strncpy_des == buffer_addr

if state.satisfiable(extra_constraints=(dose_dest_equal_buffer_addr, dose_src_hold_password)):
state.add_constraints(dose_src_hold_password, dose_dest_equal_buffer_addr)
return True
else:
return False
else:
return False

sm = p.factory.simgr(init_state)

def is_good(state):
# 判断是否来到strncpy函数位置
strncpy_addr = 0x08048410
if state.addr == strncpy_addr:
return check_strncpy(state)
else:
return False
sm.explore(find=is_good)

if sm.found:
solution_state = sm.found[0]

solution0 = solution_state.globals['solution0']
solution1 = solution_state.globals['solution1']

solution = "%u %s" % (solution_state.solver.eval(solution0), solution_state.solver.eval(solution1,cast_to = bytes).decode())
print(solution)
else:
raise Exception('Could not find the solution')


if __name__ == '__main__':
main()


结果:

17_angr_arbitrary_iump

栈溢出漏洞

我们只需要在read_input函数中检查返回地址是否print_good函数的地址即可

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import angr
import claripy

def main():
binary_path = './17_angr_arbitrary_jump'
project = angr.Project(binary_path)

initial_state = project.factory.entry_state()
simulation = project.factory.simgr(
initial_state,
save_unconstrained=True,
stashes={
'active' : [initial_state],
'unconstrained' : [],
'found' : [],
'not_needed' : []
}
)

class ReplacementScanf(angr.SimProcedure):

def run(self, fmt, string_addr):
exploit = claripy.BVS('exploit', 8*64)

for char in exploit.chop(bits=8):
self.state.add_constraints(char >= '0', char <= 'z')

exploit_addr = string_addr
self.state.memory.store(exploit_addr, exploit)

self.state.globals['solution'] = exploit

scanf_symbol = '__isoc99_scanf'
project.hook_symbol(scanf_symbol, ReplacementScanf())

while (simulation.active or simulation.unconstrained) and (not simulation.found):
for unconstrained_state in simulation.unconstrained:
def should_move(s):
return s is unconstrained_state

simulation.move('unconstrained', 'found', filter_func=should_move)


simulation.step()

if simulation.found:
solution_state = simulation.found[0]

solution_state.add_constraints(solution_state.regs.eip == 0x42585249)

solution = solution_state.se.eval(solution_state.globals['solution'],cast_to = bytes)
print(solution)
else:
raise Exception('Could not find the solution')


if __name__ == '__main__':
main()

结果: