2021CTF鹤城杯-Re

"本文作者通过IDA工具分析并利用Unicorn库破解了一个逐位校验的程序,通过hook函数找到flag的输入位置,最终成功获取FLAG:flag{96c69646-8184-4363-8de9-73f7398066c1}
摘要由CSDN通过智能技术生成

1、Petition

总的来说还是比较喜欢这类题目的,因为它的flag是一位一位校验的,能爆破当然是一件很爽的事情。
回到正文:IDA载入文件:
在这里插入图片描述
程序从start开始执行,说是说"%36s",实际上要输入整整42位,骗子。
往下的start后面的一堆函数,去翻看的话会发现每个都长得差不多,然后就猜测flag会不会是逐位校验,一位flag对应一个函数。
调试什么的还是比较累的(我不会告诉你其实我根本看不懂flag是怎么校验的),为了偷懒,这里是直接使用了Unicorn,将start函数里面调用printf、scanf 的地方给patch掉,再对scanf 做一个hook以保证flag能输入到内存。这样就能把程序的输入和校验功能给运行起来了,下面是我对这个程序写的Unidbg类:

from unicorn import *
from unicorn.x86_const import *
from capstone import *
import binascii

Petition_base = 0x0  # 程序加载的地址
Petition_stack_base = 0x10000
with open("Petition", "rb") as f:
    code = f.read()
xxx = [b'\x00', b'\x01', b'\x02', b'\x03', b'\x04', b'\x05', b'\x06', b'\x07', b'\x08', b'\x09', b'\x0a', b'\x0b',
       b'\x0c', b'\x0d', b'\x0e', b'\x0f', b'\x10', b'\x11', b'\x12', b'\x13', b'\x14', b'\x15', b'\x16', b'\x17',
       b'\x18', b'\x19', b'\x1a', b'\x1b', b'\x1c', b'\x1d', b'\x1e', b'\x1f', b'\x20', b'\x21', b'\x22', b'\x23',
       b'\x24', b'\x25', b'\x26', b'\x27', b'\x28', b'\x29', b'\x2a', b'\x2b', b'\x2c', b'\x2d', b'\x2e', b'\x2f',
       b'\x30', b'\x31', b'\x32', b'\x33', b'\x34', b'\x35', b'\x36', b'\x37', b'\x38', b'\x39', b'\x3a', b'\x3b',
       b'\x3c', b'\x3d', b'\x3e', b'\x3f', b'\x40', b'\x41', b'\x42', b'\x43', b'\x44', b'\x45', b'\x46', b'\x47',
       b'\x48', b'\x49', b'\x4a', b'\x4b', b'\x4c', b'\x4d', b'\x4e', b'\x4f', b'\x50', b'\x51', b'\x52', b'\x53',
       b'\x54', b'\x55', b'\x56', b'\x57', b'\x58', b'\x59', b'\x5a', b'\x5b', b'\x5c', b'\x5d', b'\x5e', b'\x5f',
       b'\x60', b'\x61', b'\x62', b'\x63', b'\x64', b'\x65', b'\x66', b'\x67', b'\x68', b'\x69', b'\x6a', b'\x6b',
       b'\x6c', b'\x6d', b'\x6e', b'\x6f', b'\x70', b'\x71', b'\x72', b'\x73', b'\x74', b'\x75', b'\x76', b'\x77',
       b'\x78', b'\x79', b'\x7a', b'\x7b', b'\x7c', b'\x7d']

class Unidbg:

    def __init__(self, flag, except_hit):
        self.except_hit = except_hit
        self.hit = 0
        self.flag = flag
        self.fff = 0
        mu = Uc(UC_ARCH_X86, UC_MODE_32)
        # 程序基址为 0x1000,分配 128 KB内存
        mu.mem_map(Petition_base, 0x10000 * 2)
        mu.mem_write(Petition_base, code)

        # 设置寄存器的值
        mu.reg_write(UC_X86_REG_EAX, 0)
        mu.reg_write(UC_X86_REG_EBX, 0)
        mu.reg_write(UC_X86_REG_ECX, 0)
        mu.reg_write(UC_X86_REG_EDX, 0)
        mu.reg_write(UC_X86_REG_ESI, 0)
        mu.reg_write(UC_X86_REG_EDI, 0)
        mu.reg_write(UC_X86_REG_EBP, 0)
        mu.reg_write(UC_X86_REG_ESP, Petition_stack_base)
        mu.reg_write(UC_X86_REG_EIP, 0x1040)
        # patch printf()
        mu.mem_write(0x10C6, b'\x90\x90\x90\x90\x90')
        # patch scanf()

        mu.mem_write(0x110B, b'\x90\x90\x90\x90\x90')
        mu.hook_add(UC_HOOK_CODE, self.hook_function_scanf, begin=0x110A, end=0x110C)
        mu.hook_add(UC_HOOK_CODE, self.hook_code, begin=0x119C, end=0x28A0)
        if self.except_hit < 127:
            mu.hook_add(UC_HOOK_CODE, self.trace)
        self.mu = mu
        self.md = Cs(CS_ARCH_X86, CS_MODE_32)

    def solve(self):
        try:
            self.mu.emu_start(0x1040, 0x29C4)
        except:
            pass
        return self.hit

    def trace(self, mu, address, size, data):
        disasm = self.md.disasm(mu.mem_read(address, size), address)
        for i in disasm:
            print(i)

    def hook_function_scanf(self, mu, address, size, data):
        if address == 0x110C:
            # self.show_reg()
            edx = mu.reg_read(UC_X86_REG_EDI)
            mu.mem_write(edx, self.flag)
            # print(self.flag, binascii.b2a_hex(mu.mem_read(edx, 36)).decode(), hex(edx))
            pass

    def show_reg(self ):
        print("EAX", hex(self.mu.reg_read(UC_X86_REG_EAX))[2:].upper().zfill(8))
        print("EBX", hex(self.mu.reg_read(UC_X86_REG_EBX))[2:].upper().zfill(8))
        print("ECX", hex(self.mu.reg_read(UC_X86_REG_ECX))[2:].upper().zfill(8))
        print("EDX", hex(self.mu.reg_read(UC_X86_REG_EDX))[2:].upper().zfill(8))
        print("ESP", hex(self.mu.reg_read(UC_X86_REG_ESP))[2:].upper().zfill(8))
        print("EBP", hex(self.mu.reg_read(UC_X86_REG_EBP))[2:].upper().zfill(8))
        print("ESI", hex(self.mu.reg_read(UC_X86_REG_ESI))[2:].upper().zfill(8))
        print("EDI", hex(self.mu.reg_read(UC_X86_REG_EDI))[2:].upper().zfill(8))
        print("EIP", hex(self.mu.reg_read(UC_X86_REG_EIP))[2:].upper().zfill(8))

    def hook_code(self, mu, address, size, data):
        Temp = False
        if address == 0x119E:   # 取每个函数中第二条指令的首地址
            Temp = True
        if address == 0x122C:
            Temp = True
        if address == 0x12BA:
            Temp = True
        if address == 0x1346:
            Temp = True
        if address == 0x13D2:
            Temp = True
        if address == 0x145E:
            Temp = True
        if address == 0x14EA:
            Temp = True
        if address == 0x1576:
            Temp = True
        if address == 0x1604:
            Temp = True
        if address == 0x1690:
            Temp = True
        if address == 0x171E:
            Temp = True
        if address == 0x17A8:
            Temp = True
        if address == 0x1836:
            Temp = True
        if address == 0x18C4:
            Temp = True
        if address == 0x1950:
            Temp = True
        if address == 0x19DC:
            Temp = True
        if address == 0x1A66:
            Temp = True
        if address == 0x1AF0:
            Temp = True
        if address == 0x1B7C:
            Temp = True
        if address == 0x1C08:
            Temp = True
        if address == 0x1C96:
            Temp = True
        if address == 0x1D22:
            Temp = True
        if address == 0x1DAC:
            Temp = True
        if address == 0x1E36:
            Temp = True
        if address == 0x1EC4:
            Temp = True
        if address == 0x1F50:
            Temp = True
        if address == 0x1FDC:
            Temp = True
        if address == 0x2066:
            Temp = True
        if address == 0x20F2:
            Temp = True
        if address == 0x217C:
            Temp = True
        if address == 0x220A:
            Temp = True
        if address == 0x2294:
            Temp = True
        if address == 0x2320:
            Temp = True
        if address == 0x23AE:
            Temp = True
        if address == 0x243C:
            Temp = True
        if address == 0x24C6:
            Temp = True
        if address == 0x2554:
            Temp = True
        if address == 0x25E0:
            Temp = True
        if address == 0x266E:
            Temp = True
        if address == 0x26FC:
            Temp = True
        if address == 0x2786:
            Temp = True
        if address == 0x2812:
            Temp = True
        if address == 0x289E:
            Temp = True

        if Temp:
            print(hex(address))
            self.hit += 1


先随便输入几个flag,验证一下之前的猜想:
在这里插入图片描述
好吧,到这里已经可以确认,我之前的猜想是成立的,这就很nice。
下面就是爆破了:

flag = b''

for j in range(42):
    for i in b'0123456789abcdef{}-_#!?ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
        tem = bytearray(flag + b'x' * (42 - len(flag)))
        tem[j] = i
        if Unidbg(bytes(tem), 127).solve() == j +1:
            flag += xxx[i]
    print(flag.decode())


效果示意:
在这里插入图片描述

FLAG : flag{96c69646-8184-4363-8de9-73f7398066c1}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值