hellogate
图片里藏源码,打php反序列化任意文件读,再拿flag即可
redjs
这里直接打React2Shell,没什么好说的
dedecms
简述思路,反正很唐
就是随便注册进去发现除了admin还有一个用户,现在知道用户名,再弱口令登录进这个账户,密码是dede
然后把自己的账户提升权限,再去传马就行了
ezJAVA
这里找到注入点就没有往下做了,感觉没学体系的东西打表达式注入比较难受
1 | <p th:text="{7*7}"></p> |
1 | T()和new都会被替换,遂尝试T加空格再到(可以反射,题目删除了命令,可以用原生类去读文件 |
Deplacted
这里看了源码,一眼注意到jwt的可能泄露公钥去打jwt伪造,但是题目可恶的sql接口,一方面不太熟悉sql,也不太懂这样严格的WAF下是否还可以注入(现在知道不行了)
这里是原题,打工具拿公钥再去伪造,可以任意读了之后再拿flag
工具:rsasign2n爆破session拿到publickey,之后跟着工具打吧
hjppx
这里ssrf探测内网,发现8080端口有个web服务,伴随的还有mysql&redis
也许是打CVE或者0day吧,不懂
complexweb
前言
难崩,赛后出的,和web队友合作出的一道题
思路
首先注意三个接口
1 | login:泄露账户是admin,密码未知,尝试弱口令,无果,无sql注入 |
这里就得注意了
没注意这道题就G了
这里可以得到admin的email
拿到email自然去reset了(这里简单测试发现好像只能用admin的email)
然后去/getPrivateInfo接口传入email会发现权限不足,这里就卡了很久
发现reset处存在弱比较,可以末尾添数字,再去email可以得到如下token接口
如下
注意这个token的组成,后半部分就是简单的base64编码,前半部分是一个未知的加密,尝试跟随接口/resetpassword,但是
会显示不是admin
上述就是前期的一个基本的思路了,我个人受困于黑盒场景,一直想找CVE打请求走私,web队友敏锐发现了两处很关键的地方,这道题就很清晰了
- 弱比较
- 时间戳加密
我们思考,既然我们要/resetpassword?token=xxxxx,但是直接reset->email无法获得admin-token,还有其他办法吗?
首先我们思考如果加密逻辑可知,是否可以通过已有token不经过email直接拿到admin的token?
如果你没有尝试弱比较,就无法更近一步了
实际发现,reset接口处是可以接受saferman@23333.private.reallybesthack.com1因为它的弱比较,这里剧透一下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
def reset():
if request.method == 'POST':
email = request.json['email']
result = {}
if (isinstance(email,str) and email.startswith(admin_email) ) or \
(isinstance(email,list) and len(email)>0 and email[0] == admin_email ) or\
(isinstance(email,tuple) and len(email)>0 and email[0] == admin_email):
# send email
# session['admintoken'] = xxxx
# /resetpassword?token=
if isinstance(email,str):
email = email.split(";")
# email = [email]
email2token = {}
for each_email in email:
email2token[each_email] = genToken(each_email)
t = {}
for k_email,v_token in email2token.items():
if k_email == admin_email:
session['admintoken'] = v_token
else:
t[k_email] = "/resetpassword?token=" + v_token
result['code'] = "OK"
result['message'] = "The reset link is sent to emails successfully!" + \
"If you don't receive the email, please see your reset link via /getPrivateInfo/?email=[your_email]"
session['linkdict'] = json.dumps(t)
# print(session['linkdict'])
else:
result['code'] = "bad"
result['message'] = "sorry, not admin's email"
return jsonify(result)
if request.method=="GET":
return render_template('reset.html', inline_css=INLINE_CSS)
嗯,然后呢?我们短时间内触发两个,看看email生成的token有什么不同
这里可以写个python脚本,这里不演示了,很明确的就能看到,就改变末尾的相邻数字,其实,最后生成的token的差距只是最后的3位字符,理论上,我们可以同时reset两个email
1 | saferman@23333.private.reallybesthack.com |
然后根据ycdhwoaj61smbkgu234末尾三位打爆破,再构造正确的token发至/resetpassword/
耐心等待即可拿到admin的密码McQKiL7FgtozW7TA0pymfeijmTkkS81G,这里爆破的时候其实发现很快,也有这层原因在
1 | if __name__ == "__main__": |
拿到密码后登录,即可以使用download接口,看来是个SSRF,就打file:///etc/passwd
en,开始找源码,/app/app.py没有,摸不着头脑
1 | /proc/self/cmdline #/app/main.py |
拿到源码之后也没什么其他讯息了,就这个接口可以打SSRF
1 |
|
这里gopher是用不了的,就好像只能file读了,内网就一个redis,也干打不了
然后就是漫长的找RCE,认为需要提权拿/root下的flag,因此错失解题机会了
上述,其实关键在于我先前读取的/proc/1/cmdline
1 | /etc/passwd/etc/start.sh |
我没有读取/etc/start.sh,因此没看到flag的文件名,苦也
1 | !/bin/bash |
1 | file:///sdgfsdfyxzfvgjnrtuwerewyrtu_flag |
整道题最关键的还是时间戳去爆破那一块,得具备想象力了
结语
- 整个比赛打的,坐牢啥也没干,看到React2shell两眼冒光火速拿下三血,没爆零()