前言
angr_ctf
之前一直弄环境没弄好,现在都解决了,终于可以全部过一遍了,仓库提供了三个部分的文件,一个是源码编译部分,一个是编译好的文件的集合最后是每题的题解部分分别在
值得注意的是编译好的文件都是elf类型的,所以最好采用Linux运行脚本,而且默认版本是python2的,使用它提供的模板时最好修改下print打印函数添加括号,其它部分倒没什么需要解决的
00_angr_find
可恶,编译好的windows版本一直不能运行,显示地址错误,
不知道是不是开启了随机地址,关了也没法
输入字符经过加密后等于QWSYJIQP,输出Good Job字符
#!/usr/bin/env python3
import angr
import sys
import os
def main():
proj = angr.Project('/root/桌面/python-x/angr_ctf/solutions/00_angr_find/00_angr_find',auto_load_libs=False)
initial_state = proj.factory.entry_state()
pg = proj.factory.simgr(initial_state)
pg.explore(find=0x804867d)
print(pg.found[0].posix.dumps(0))
if __name__ == '__main__':
main()
一个最基本的框架结构,事实上还可以更简化点
- Project表示新建项目,载入大致基本信息,auto_load_libs=false表示不载入相关库文件,可以删掉,但默认会载入,会浪费些时间
- entry_state创建新建状态,为后面模拟器初始化,可以理解成新建的对象,类,返回一个状态的对象
- simgr新建模拟器,参数表示以该传入对象初始化模拟器,一般angr代码中这三个之后才能开始探索一类的事务
- explore得到指定地址的输入,如果找到了返回一个数组,found[0]中保存有得到的路径的状态
不知道为什么windows中idapro反编译的地址和在Linux中的地址有一点细微的差别,导致找了半天
QTMPXTYU
01_angr_avoid
进去后main函数比较大,不能直接被反编译,当然想反编译也可以改一下配置文件但没必要,只需要知道find和avoid地址即可,因为函数比较大,不加避免条件就会一直跑卡死
explore(self, stash=None, n=None, find=None, avoid=None, find_stash=None, avoid_stash=None, cfg=None,
num_find=1, **kwargs)
分析也可以发现,不能进入avoid_me函数,他会把succeed变为0,判断的时候会影响跳转
import angr
Proj =angr.Project('/root/桌面/python-x/angr_ctf/solutions/01_angr_avoid/01_angr_avoid',auto_load_libs=False)
State =Proj.factory.entry_state()
Sim =Proj.factory.simgr(State)
Sim.explore(find =0x080485ed,avoid=0x080485a8)
print(Sim.found[0].posix.dumps(0))
RNGFXITY
02_angr_find_condition
和01不同,输出again 的地址固定都位于同一个函数中,所以我们避免执行这个函数地址即可,但这里在main函数中很多地方直接调用输出try again,不可能同时avoid这么多地址所以需要用函数进行判断,所以expolre第二种传参方式即可以通过函数传参
import angr
def good(state):
a =state.posix.dumps(1)
return True if 'Good Job' in a.decode('utf-8') else False
def Try(state):
b =state.posix.dumps(1)
return True if 'Try again' in b.decode('utf-8') else False
Proj =angr.Project('/root/桌面/python-x/angr_ctf/solutions/02_angr_find_condition/02_angr_find_condition',auto_load_libs=False)
State =Proj.factory.entry_state()
Sim =Proj.factory.simgr(State)
Sim.explore(find =good,avoid=Try)
print(Sim.found[0].posix.dumps(0))
0表示标准输入,1表示标准输出, a in b:a是否被包含在b中
03_angr_symbolic_registers
有多个变量的输入,angr无法像之前一样对输入直接爆破,需要从指定位置angr可以爆破的位置开始,所以我们需要自定义状态,entry_state默认从main函数开始
我们可以直接对寄存器赋值符号变量
可以使用project.factory.blank_state(addr=start_address)替代原有entry_state,blank中可以传递参数addr定义模块开始运行地址
import angr
import sys
import claripy
pro =angr.Project(sys.argv[1],auto_load_libs=False)
initial_state =pro.factory.blank_state(addr =0x080488D1)
#定义符号向量,给寄存器赋值
eax =claripy.BVS('eax',32)
ebx =claripy.BVS('ebx',32)
edx =claripy.BVS('edx',32)
initial_state.regs.eax =eax
initial_state.regs.ebx =ebx
initial_state.regs.edx =edx
sim =pro.factory.simgr(initial_state)
def good(state):
return 'Good Job' in state.posix.dumps(1).decode('utf-8')
def again(state):
return 'Try again' in state.posix.dumps(1).decode('utf-8')
sim.explore(find =good,avoid =again)
one =format(sim.found[0].solver.eval(eax),'x')
two =format(sim.found[0].solver.eval(ebx),'x')
three =format(sim.found[0].solver.eval(edx),'x')
print(one+' '+two+' '+three)
db01abf7 4930dc79 d17de5ce
04_angr_symbolic_stack
和上题不一样,上题可以直接通过寄存器传参这里只能通过栈
分析栈结构可知,参数地址在ebp-8~ebp-0c和ebp-0c:ebp-10所以要对赋值的ebp-8预留八位对齐参数
import angr
import sys
import claripy
pro =angr.Project(sys.argv[1])
ad =0x08048697
state =pro.factory.blank_state(addr=ad)
a1 =claripy.BVS('a1',32)
a2 =claripy.BVS('a2',32)
state.regs.ebp =state.regs.esp
state.regs.esp -=8
state.stack_push(a2)
state.stack_push(a1)
sim =pro.factory.simgr(state)
def good(a):
return 'Good' in a.posix.dumps(1).decode('utf-8')
def again(b):
return 'again' in b.posix.dumps(1).decode('utf-8')
sim.explore(find=good,avoid=again)
output1 =format(sim.found[0].solver.eval(a1),'u')
output2 =format(sim.found[0].solver.eval(a2),'u')
print(output1+' '+output2+' ')
1213922930 1153451551
05_angr_symbolic_memory
和上题的栈很像,只是这里需要将符号变量放入内存,现在理解的就是angr通过定义指定约束的符号变量,然后将这个变量放入指定位置,存储空间可以是一切存储介质,内存,寄存器,栈等
import angr
import sys
import claripy
pro = angr.Project(sys.argv[1])
ad = 0x08048603
state = pro.factory.blank_state(addr=ad)
meom1 = claripy.BVS('meom1', 64)
meom2 = claripy.BVS('meom2', 64)
meom3 = claripy.BVS('meom3', 64)
meom4 = claripy.BVS('meom4', 64)
ad1 = 0xa29faa0
ad2 = 0xa29faa8
ad3 = 0xa29fab0
ad4 = 0xa29fab8
# 将符号变量存入内存
state.memory.store(ad1, meom1)
state.memory.store(ad2, meom2)
state.memory.store(ad3, meom3)
state.memory.store(ad4, meom4)
smg = pro.factory.simgr(state)
def good(a):
return 'Good' in a.posix.dumps(1).decode('utf-8')
def bad(b):
return 'Try' in b.posix.dumps(1).decode('utf-8')
smg.explore(find=good, avoid=bad)
# 约束求解
if smg.found[0]:
s1 = smg.found[0].solver.eval(meom1, cast_to=bytes)
s2 = smg.found[0].solver.eval(meom2, cast_to=bytes)
s3 = smg.found[0].solver.eval(meom3, cast_to=bytes)
s4 = smg.found[0].solver.eval(meom4, cast_to=bytes)
print("05:{} {} {} {}".format(s1.decode('utf-8'), s2.decode('utf-8'), s3.decode('utf-8'), s4.decode('utf-8')))
else:
print("NULL")
状态初始化的地址需要为scanf后面
06_angr_symbolic_dynamic_memory
输入的空间是使用函数开辟的,因此不能像前面一样直接获得准确地址,所以我们可以直接为指针添加我们指定位置和空间作为符号向量的存储地
import angr
import sys
import claripy
pro =angr.Project(sys.argv[1])
ad =0x0804869e
state =pro.factory.blank_state(addr =ad)
m1 =claripy.BVS('m1',64)
m2 =claripy.BVS('m2',64)
ad1 =0x0a79a118
ad2 =0x0a79a120
ad3 =0x0a799cc0
ad4 =0x0a79a120
state.memory.store(ad1,ad3,endness=pro.arch.memory_endness)
state.memory.store(ad2,ad4,endness=pro.arch.memory_endness)
state.memory.store(ad3,m1)
state.memory.store(ad4,m2)
smg =pro.factory.simgr(state)
def good(a):
return 'Good' in a.posix.dumps(1).decode('utf-8')
def bad(b):
return 'Try' in b.posix.dumps(1).decode('utf-8')
smg.explore(find =good,avoid =bad)
if smg.found:
s1 = smg.found[0].solver.eval(m1, cast_to=bytes)
s2 = smg.found[0].solver.eval(m2, cast_to=bytes)
print("05:{} {}".format(s1.decode('utf-8'), s2.decode('utf-8')))
else:
print("NULL")
如果state地址不是scanf后面的地址会出现卡死,输入地址没有更改会找不到路径,相信把所有遇到的错误都记下,他们肯定是有限的,就能完全熟练了
IDMRHRCZ PLBQSLBO
07_angr_symbolic_file
输入由内存变成了文件读取输入,创建文件符号向量
状态开始地址设为88ef处,add esp,10h清空之前的栈
# -*- coding:utf-8 -*-
import angr
import sys
import claripy
pro = angr.Project(sys.argv[1])
ad = 0x080488ef
# 创建文件的符号向量
file = 'WCEXPXBW.txt'
file_size = 64
symbol = claripy.BVS('symbol', file_size * 8)
symbol_file = angr.SimFile(file, content=symbol, size=file_size)
state = pro.factory.blank_state(addr=ad, fs={file: symbol_file})
sim = pro.factory.simgr(state)
def good(a):
return 'Good' in a.posix.dumps(1).decode('utf-8')
def bad(b):
return 'Try' in b.posix.dumps(1).decode('utf-8')
sim.explore(find=good, avoid=bad)
if sim.found:
res = sim.found[0].solver.eval(symbol, cast_to=bytes)
print('06: {}'.format(res.decode('utf-8')))
else:
raise Exception('No result')
GQLWJWWI
参考链接:
https://www.cnblogs.com/level5uiharu/p/16925991.html
https://space.bilibili.com/386563875/channel/seriesdetail?sid=1835245
https://blog.gentlecp.com/article/61784.html