2018 护网杯 Writeup

 Qiqi's Blog     2018-10-15   3399 words    & views

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_secretpf4x#.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^k6m2' = 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}