2018 护网杯 writeup
划了好久的水,当然这次比赛依旧划水,暑假过的过于安逸了,开学也已经一个月了,该学习了~
web
easy_tornado
tornado模版注入
正常url:/file?filename=flag.txt&signature=0b9c8664c389db9d5f87d6f38c317514
我们输入一个错误的签名的时候,就会跳转至/error?msg=签名错误
这里的msg
参数就是注入点
根据提示md5(cookie_secret + md5(filename))
我们要寻找cookie_secret
,在settings
中
尝试requestHandler
等等都不行
最后尝试handler.settings
成功拿到cookie_secret
为pf4x#.OmAiR1qNLkbT$XU_zIj3e>J8DMn~B^]7(sYl*VCQS[?9}ga)-cFG%&!vu+
再根据flag.txt
给的/fllllllllllag
访问/file?filename=/fllllllllllag&signature=faf5c748cd11c3f38115ccb0782646f7
得到flag:flag{e9c5d160a9fba25ea3f3874285db2db4}
ltshop
我们可以购买辣条,但是只能购买四个,因为是批量兑换,所以至少十个才能兑换辣条王
可以通过条件竞争,一次发多个包,这样我们购买一次就能获得多个辣条
像这样
这样我们就可以去兑换辣条王了,但是兑换flag需要9999999个辣条王,仅仅通过条件竞争是远远不够的
这里我们有可以控制的number参数,很容易想到大整数溢出
我们在cookie
的地方看到go_iris_cookie
,应该是go语言写的,查一下资料,unsigned __int64的最大值:18446744073709551615
因为五个辣条兑换一个辣条王,所以我们将其除以5,同时我们要让它溢出,还要能够买的起,所以我们再加1或者2
所以我们让number=3689348814741910324
或者number=3689348814741910325
成功购买{"message":3689348814741910324,"status":"succeed"}
我们可以看到辣条之王的数目已经远远超过所需要的了
直接兑换flag,得到
Misc
迟来的签到题
题目是一串base64,解码得到PR S%PP#TU"^V%R'RSV VT_VQ'WVSW_Q
发现是乱码,于是联想到题目提示的xor,所以写个脚本爆破一下
import base64
str = 'AAoHAR1QUiBTJVBQI1RVIl5WJVInUlNWIFZUX1ZRJ1dWU1dfURs='
str = base64.b64decode(str)
flag = ''
for i in range(255):
for j in str:
flag += chr(ord(j) ^ i)
print flag
flag = ''
其中一串是flag{64F5C66E23D80C4A450F02907A105197}
Crypto
FEZ
fez.py
import os
def xor(a,b):
assert len(a)==len(b)
c=""
for i in range(len(a)):
c+=chr(ord(a[i])^ord(b[i]))
return c
def f(x,k):
return xor(xor(x,k),7)
def round(M,K):
L=M[0:27]
R=M[27:54]
new_l=R
new_r=xor(xor(R,L),K)
return new_l+new_r
def fez(m,K):
for i in K:
m=round(m,i)
return m
K=[]
for i in range(7):
K.append(os.urandom(27))
m=open("flag","rb").read()
assert len(m)<54
m+=os.urandom(54-len(m))
test=os.urandom(54)
print test.encode("hex")
print fez(test,K).encode("hex")
print fez(m,K).encode("hex")
还附上了三个输出
2315d80c2dd73098953686be6c82aa63c1d362eb0095e4621cce28bec4c921ce016afc7f39fd93b14b6c28ce69c7096b91fd2db0862d
308e590a180473ab4d23a0c67b65fe2bf2d0a9f1b255e4e2610b0c90e8e210c8ed4f2b9a3b09c1886a781f94fee4f77488c0b30f2395
e822e918e578a7af4f0859a99aab5d7563644beb4207a73d5fc4560d3deb696320cec479431a4f724310499baf5230db7e56764915d0
我们首先把代码看懂,最重要的就是round()
函数,我们将原来的左半边当作新的右半边,把左半边异或上右半边在异或上k作为新的右半边
我们假设test的左半边是L,右半边是R,因为K的长度是7
所以如果计算fez(test,K)
,则有以下过程:
初始: L R
1: R L^R^k1
2: L^R^k1 L^k1^k2
3: L^k1^k2 R^k2^k3
4: R^k2^k3 L^R^k1^k3^k4
5: L^R^k1^k3^k4 L^k1^k2^k4^k5
6: L^k1^k2^k4^k5 R^k2^k3^k5^k6
7: R^k2^k3^k5^k6 L^R^k1^k3^k4^k6^k7
而R^k2^k3^k5^k6 + L^R^k1^k3^k4^k6^k7
再hex编码之后其实就是第二个输出
同理,假设m的左半边是m1,m的右半边是m2
m1' = m2^k2^k3^k5^k6
,m2' = m1^m2^k1^k3^k4^k6^k7
所以m = m2'^R'^m1'^L^L' + m1'^L'^R
def xor(a,b):
assert len(a)==len(b)
c=""
for i in range(len(a)):
c+=chr(ord(a[i])^ord(b[i]))
return c
test = '2315d80c2dd73098953686be6c82aa63c1d362eb0095e4621cce28bec4c921ce016afc7f39fd93b14b6c28ce69c7096b91fd2db0862d'.decode("hex")
fez1 = '308e590a180473ab4d23a0c67b65fe2bf2d0a9f1b255e4e2610b0c90e8e210c8ed4f2b9a3b09c1886a781f94fee4f77488c0b30f2395'.decode("hex")
fez2 = 'e822e918e578a7af4f0859a99aab5d7563644beb4207a73d5fc4560d3deb696320cec479431a4f724310499baf5230db7e56764915d0'.decode("hex")
L = test[0:27]
R = test[27:54]
L1 = fez1[0:27]
R1 = fez1[27:54]
m1 = fez2[0:27]
m2 = fez2[27:54]
m = xor(xor(xor(xor(m2, R1), m1), L), L1) + xor(xor(m1, L1), R)
print m
得到flag:flag{festel_weak_666_11xd77fhy33}