HGAME-2025-WEEK-2 WriteUp
本文最后更新于:6 小时前
WEB
Level 21096 HoneyPot
简单过一遍源码,该项目读取远程数据库内容并使用 mysqldump 复制到服务器本地
漏洞函数:
1 |
|
不难发现 config.RemotePassword 也由用户提供,但是没有经过检查,并且往后被拼接到 command 中,
根据提示
于是直接截断即可
1 |
|
Level 21096 HoneyPot_Revenge
跟上题差不多,把检验修复了,可以直接打
[CVE-2024-21096 mysqldump命令注入漏洞简析 | Ec3o](https://tech.ec3o.fun/2024/10/25/Web-Vulnerability Reproduction/CVE-2024-21096/)
部署较为麻烦,当时写题没想太多,直接服务器上编译的,花了很多时间,后面其实想想也可以本地编译了然后端口映到服务器上
注意:这里
1 |
|
源码写死了,没指定端口,所以默认为 3306
Level 111 不存在的车厢
感觉挺有意思,signinjava 没打出来随手看了下,
给了源码,主要就是 8081 对外开放,且仅允许 GET 请求
8081 收到外部请求后,将其写成 protocol 里的自定义数据包格式,并发给内部的 8080 ,并将数据包解析成http.Request{}
,再使用 httptest
进行本地请求访问
关键是 8080 的 /flag 只允许 POST 请求,在这儿矛盾了
关键看看 request 的构成和读取就行,只有这些是可控的
1 |
|
首先,很明显这个 uint16(0~65535)
太小了,十分可疑,考虑溢出攻击
简单过一下 ReadH111Request
H111 协议请求读取格式 by deepseek(
字段名 | 数据类型 | 描述 | 字节长度 | 可变长度 |
---|---|---|---|---|
methodLength | uint16 | 请求方法的字节长度 | 2 | 否 |
method | []byte | 请求方法(如 GET/POST) | methodLength | 是 |
uriLength | uint16 | 请求URI的字节长度 | 2 | 否 |
requestURI | []byte | 请求路径(如 /index.html) | uriLength | 是 |
headerCount | uint16 | 头部字段的数量 | 2 | 否 |
[header] | 重复 headerCount 次 ↓ | |||
├─ keyLength | uint16 | 单个Header键的字节长度 | 2 | 否 |
├─ key | []byte | Header键(如 Content-Type) | keyLength | 是 |
├─ valueLength | uint16 | 单个Header值的字节长度 | 2 | 否 |
├─ value | []byte | Header值(如 application/json) | valueLength | 是 |
bodyLength | uint16 | 请求体的字节长度 | 2 | 否 |
body | []byte | 请求体内容 | bodyLength | 是 |
加上前面那么小的 uint16,不妨猜测:因为字段读取的内容是由字段前的 Length 指定,于是可以通过某个地方的溢出,使得 ReadH111Request 时,比如给了 methodLength=65537
,相当于 methodLength=1
,于是 ReadH111Request 便只会读取 1 个字符,并写入 method 变量
我们再来看 WriteH111Request
1 |
|
methodBytes 和 method 的写入都直接从 req.Method 读取,很明显不可控
1 |
|
而 path 和 header 经过测试,不支持例如 \x00\x04
这种不可见字符,所以也 pass
所以最后只有 body 挺到最后
1 |
|
于是尝试构建
1 |
|
首先经过本地测试,body 的长度实际上由 Content-Length 来决定,所以在发生数据包的时候 body 的实际长度一定要大于等于 Content-Length 指定的长度,不然会卡住
上述脚本,我指定 body 长度为 65536,经过 uint16 转化变为 0,所以通过 WriteH111Request 写入数据包的内容实际为 \x00\x00 + BODY
然后在后端解析数据包的时候,由于 bodyLength 为 0,所以 body 并不会被读取
**web/main.go: **
1 |
|
因为 conn 并未关闭,所以我们传入的 payload 仍然存留在 conn 里,所以再请求一次,就会读取我们的payload,
exp.py
1 |
|
Level 257 日落的紫罗兰
给了一个用户名表
1 |
|
给出地址都无法访问,nmap 扫一下
多半就是 redis 写 ssh 公钥
可以发现 redis 未配置密码
这里尝试用给出的用户表进行访问,发现 mysid 有权限,所以本地生成公钥写入即可
1 |
|
然后 ssh 连接即可,这里使用的 Termius
根目录发现 flag
和 readflag
尝试 suid 提权,但是貌似没有可用方法
ps -ef
查看进程
发现一个 java 项目,唉,怎么还套娃上了
把 app.jar 拷下来,反编译
打一个 search 的 jndi 注入,参考
文章 - 从search入手的jndi注入技术学习 - 先知社区
注意修改 ldap 端口为 389,
命令: chmod a+r /flag
打包成 jar,上传到服务器
1 |
|
找到 java 地址
启动服务
服务器有 curl 可以使用,于是