angr - re - asisctffinals2015_fake
IDA分析:
长度不超过10,程序会把读入的字符串转成数字,我们需要找到一个不超过10位数的数字使得程序输出flag~
angr中需要hook这个strtol函数的原因:
angv[1]输入时是一个字符串。
程序处理时会用strtol函数,将字符串转为长整型,然后计算。
而如果angv[1]参数就是一个符号变量,再将符号变量传入strtol函数,进行求解时会出错。
添加限制条件:
flag前五个字符为:ASIS{
flag的剩余每一个字符都是0-f
#!/usr/bin/env python
# coding=utf-8
import angr
unconstrained_number = None
def strtol(state):
global unconstrained_number
unconstrained_number = state.solver.BVS('strtol', 64)
state.regs.rax = unconstrained_number
def main():
p = angr.Project("./fake")
p.hook(0x4004a7, strtol, length = 5)
state = p.factory.entry_state(args=['fake','123'])
ex = p.surveyors.Explorer(find=(0x400450,), start = state)
ex.run()
found = ex.found[0]
flag_addr = found.regs.rsp + 0x8
found.add_constraints(found.memory.load(flag_addr, 5) == int("ASIS{".encode("hex"),16))
for i in xrange(0, 32):
op0 = found.memory.load(flag_addr + 5 + i, 1) >= ord('0')
op1 = found.memory.load(flag_addr + 5 + i, 1) <= ord('9')
op2 = found.memory.load(flag_addr + 5 + i, 1) >= ord('a')
op3 = found.memory.load(flag_addr + 5 + i, 1) <= ord('f')
found.add_constraints(
found.solver.Or(
found.solver.And(op0, op1),
found.solver.And(op2, op3)
)
)
found.add_constraints(found.memory.load(flag_addr + 5 + 32, 1) == ord('}'))
flag = found.solver.eval(found.memory.load(flag_addr, 8 * 5))
print 'Input Number:', found.solver.eval(unconstrained_number)
print hex(flag)[2:-1].decode("hex").strip('\0')
if __name__ == '__main__':
main()
这里主要是不太明白:这个32是怎么出来的,怎么会知道flag的长度是38位。从IDA里看到的是5个int64,应该是40位才对
另外找到了一种更好理解的方法:
https://github.com/p4-team/ctf/tree/master/2015-10-10-asisfin/re_150_fake#eng-version
用逆元思想
X * M === 'ASIS{...' (mod 2^64) <=> X === 'ASIS{...' * M^-1 (mod 2^64).
所以根据这个去暴力值即可
还学到了一种新姿势:
python fake.py > te.txt
cat te.txt | xargs -l ./fake
补充一个xargs的用法: