Skip to content

Commit d0bd6ca

Browse files
authored
wind_mask's writeup (#38)
1 parent 8ebba97 commit d0bd6ca

16 files changed

+356
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
| [chihuo2104](players/chihuo2104/README.md) | 总排名第 243 名 | Hackergame 启动、猫咪小测、更深更暗、旅行照片 3.0 - 神秘奖牌、旅行照片 3.0 - 这是什么活动?、赛博井字棋、奶奶的睡前 flag 故事、组委会模拟器、虫、JSON ⊂ YAML?、Git? Git!、HTTP 集邮册、Docker for Everyone、惜字如金 2.0、🪐 高频率星球、🪐 低带宽星球(1) |
8282
| [undefined-moe](players/undefined-moe/README.md) | 总排名第 131 名 | 原神启动、猫咪小测、更深更暗、井字棋、奶奶的 flag 故事、组委会、虫、JSON/YAML、Git、集邮册、Docker、惜字如金、高频率、流式、Komm, süsser Flagge、为什么要打开 /flag、异星歧途、微积分计算小练习 2.0 |
8383
| [Xzonn](players/Xzonn/README.md) | 其他解法 | JSON ⊂ YAML? |
84+
| [wind_mask](players/wind_mask/wind_mask's%20Hackergame%202023.md) | 总排名第 134 名 | Hackergame 启动、猫咪小测、更深更暗、旅行照片 3.0(1、3)、赛博井字棋、奶奶的睡前 flag 故事、组委会模拟器、虫、JSON ⊂ YAML?、HTTP 集邮册(1、2)、Docker for Everyone、惜字如金 2.0、🪐 高频率星球、🪐 小型大语言模型星球(1、2)、🪐 低带宽星球(1)、Komm, süsser Flagge(1、2)、为什么要打开 /flag 😡(1)、 O(1) 用户登录系统|
8485

8586
## 其他资源
8687

Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
# wind_mask's Hackergame 2023
2+
3+
作为全部的记录因此也就不避开常规解了,大致还原一下这周做题的内容(并不保证和当时的过程一致,中间的弯路可能略)。
4+
5+
各题解后的闲言不放在这了,有兴趣可见[wind_mask's Hackergame 2023](https://blog.wind-mask.com/blog/wind_masks-hackergame-2023/)
6+
## 各题解
7+
8+
### Hackergame 启动
9+
10+
我本来这里就想用出录音重放了,但是显然用不到,改一下url里的参数即可。
11+
12+
### 猫咪小测
13+
14+
开始俄苏(😎
15+
16+
#### 中科大的图书馆
17+
18+
~~其实可以线下快打~~),直接到官网搜索书籍,确定是西区图书馆外文书籍,查一下外文书籍楼层所在(百度百科就有),得。
19+
20+
![外文书籍所在](image/2023-11-04-14-18-51-image.png)
21+
22+
#### 可观测宇宙鸡的密度
23+
24+
知乎上有回答[你见过哪些极品论文?](https://www.zhihu.com/question/20337132/answer/3023506910),关键词选的好,真不熟什么论文。
25+
26+
![知乎答案](image/2023-11-04-14-18-16-image.png)
27+
28+
#### TCP BBR拥塞控制
29+
30+
似乎没什么可说,随便搜一下就是了。
31+
32+
#### python类型检查的图灵完备
33+
34+
题目没提图灵完备,但是什么等价于停机问题大概也就这么证明啦。
35+
36+
搜一下`python type turing`是Python Type Hints are Turing Complete这篇。
37+
38+
![论文](image/2023-11-04-14-24-25-image.png)ECOOP,得。
39+
40+
### 更深更暗
41+
42+
在F12里搜flag即可。
43+
44+
![搜索得](image/2023-11-04-14-26-35-image.png)
45+
46+
### 旅行照片 3.0
47+
48+
原谅我第二题偷懒没看英文网页,中文页面没校园成员计划。
49+
50+
第一题注意照片中学长带的带子上的字STATPHYS28搜索可知是统计物理学会议,官网日期就那些天,金色奖牌显然诺贝尔奖根据奖牌上名字知道是东京大学,搜一下东京大学的诺贝尔奖得主(wiki上有),其中出生最晚是梶田隆章,在东京大学宇宙射线研究所即ICRR。
51+
52+
然后根据STATPHYS28的日程试一下知道是8月10日。
53+
54+
然后是白色帐篷这张识图注意到是上野公园喷泉,什么活动呢,搜不到。前往推特搜索“2023年8月10日 上野”,看到
55+
56+
![推特搜索](image/2023-11-04%2014_44_11-2023年8月10日%20上野%20-%20搜索%20_%20X.png)
57+
58+
地点时间对上了,看一眼照片是白色帐篷,ok。
59+
60+
志愿者招募表编号翻一下这个活动官网,下面就有![志愿者](image/2023-11-04%2014_48_09-ボランティアSTAFF大募集!!第6回「全国梅酒まつりin東京2023」|全国梅酒まつり.png)
61+
62+
下面翻一下google map,上野喷泉对面的博物馆,东京国立博物馆,这里中文页面没有,所以我没注意到校园会员计划以至于没做出,但其实0元这个应该猜一下的,其实后来想到了但是忘记了。
63+
64+
![校园会员](image/2023-11-04%2014_52_14-TOKYO%20NATIONAL%20MUSEUM%20-%20Education%20Campus%20Members%20---%20东京国立博物馆%20-%20教育园区会员.png)
65+
66+
下面是当晚聚集地点这个翻STATPHYS28官网日程知道10号晚上是Banquet,在Events下看一下
67+
68+
![会面点](image/2023-11-04%2014_54_09-STATPHYS28%20---%20STATPHYS28.png)
69+
70+
第六问其实两个字的一猜就是熊猫,但是你也可以搜一下确认比如
71+
72+
![熊猫](image/2023-11-04%2014_58_28-X%20上的%20株式会社P͙a͙n͙d͙a͙%20f͙a͙c͙t͙o͙r͙y͙%20文具の博覧会:“コトモノマルシェオリジナルブランド%20BUTTON&CUFFLINKSさんの.png)
73+
74+
三个字动物的去google搜(题意要用马里奥下一张图的信息,但是关键词选的好一切皆允)
75+
76+
![秋田犬](image/2023-11-04%2015_03_25-出站%20广告%203d%20动物%20-%20Google%20搜索.png)
77+
78+
### 赛博井字棋
79+
80+
抓一下包把AI下的位置覆盖了,连成3个。没注意session怎么变化,直接重放完事。
81+
82+
### 奶奶的睡前 flag 故事
83+
84+
题目加粗字体一眼注意,`pixel 截图 cve`,搜一下,CVE-2023-21036,得。
85+
搜这个cve在github上看到提到在线恢复的网站,在[acropalypse](https://acropalypse.app/)上恢复就是了。
86+
87+
### 组委会模拟器
88+
89+
打开题目抓包一看解析json+正则表达式+发包就是了。
90+
91+
```python
92+
import re
93+
import string
94+
from time import sleep
95+
import time
96+
import requests
97+
import json
98+
99+
headers = {'Cookie': '抓个就是了',
100+
'Content-Type': 'application/json',
101+
'Host': '202.38.93.111:10021'}
102+
response = requests.post(
103+
'http://202.38.93.111:10021/api/getMessages', headers=headers)
104+
t0 = time.time()
105+
msgjson = json.loads(response.text)['messages']
106+
delay = 0
107+
j = 0
108+
r = re.compile(r'hack\[[a-z]*\]')
109+
for i in msgjson:
110+
if r.search((i['text'])) != None:
111+
print(i['text'])
112+
re = requests.post(
113+
'http://202.38.93.111:10021/api/deleteMessage',
114+
headers=headers,
115+
json={"id": j})
116+
print(re.json())
117+
sleep(max(0, i['delay']-time.time()+t0))
118+
j += 1
119+
res = requests.post('http://202.38.93.111:10021/api/getflag',
120+
headers=headers)
121+
print(res.json())
122+
```
123+
124+
发包会受延迟影响,所以直接拿本地time减了。
125+
126+
###
127+
128+
注意到是国际空间站传输图片 ,一搜是什么SSTV反正不懂的无所谓抄个教程看到个RX-SSTV的软件
129+
130+
![RX-SSTV](image/2023-11-04%2015_21_59-RX-SSTV%20v.2.1.6%20_ON6MU%20(SSTVENG.DLL%20v.1.06).png)
131+
132+
播放的话,之前QQ语音的时候逗群友玩的时候安过一个虚拟麦克风
133+
134+
![虚拟麦克风](image/2023-11-04%2015_22_57-设置.png)
135+
136+
放就完了。
137+
138+
### JSON ⊂ YAML?
139+
140+
第一问搜到[What valid JSON files are not valid YAML 1.1 files? - Stack Overflow](https://stackoverflow.com/questions/21584985/what-valid-json-files-are-not-valid-yaml-1-1-files),里面`12345e999`这个例子一放就是了。
141+
142+
但是第二个要求第一个不报错,我一开始往里塞制表符无果。
143+
144+
后来仔细看ruamel.yaml的文档,发现`Duplicate keys`是不允许的,试了一下,过。
145+
146+
### Git? Git!
147+
148+
直接看[Git - 维护与数据恢复](https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E7%BB%B4%E6%8A%A4%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D#_data_recovery)
149+
150+
### HTTP 集邮册
151+
152+
嗯试就完了,改下`Method`,HTTP版本,`Path``Host``CRLF`随便插一下,5个code拿到。
153+
154+
第二问碰一下删了`Path``HTTP/1.1`之间的空格,就过了。
155+
156+
第三问感觉很多HTTP规范的样子,算了,没做。
157+
158+
### Docker for Everyone
159+
160+
docker指令时挂载宿主机上的文件就是了。
161+
162+
### 惜字如金 2.0
163+
164+
根据规则改了下载的代码复原各种可能
165+
166+
```python
167+
#!/usr/bin/python3
168+
169+
# Th size of th file may reduce after XZRJification
170+
171+
def check_equals(left, right):
172+
# check whether left == right or not
173+
if left != right:
174+
return False
175+
return True
176+
177+
178+
def get_code_dict():
179+
# prepare the code dict
180+
check_equals(set(len(s) for s in code_dict), {24})
181+
return ''.join(code_dict)
182+
183+
184+
def decrypt_data(input_codes):
185+
# retriev th decrypted data
186+
code_dict = get_code_dict()
187+
output_chars = [code_dict[c] for c in input_codes]
188+
return ''.join(output_chars)
189+
190+
191+
if __name__ == '__main__':
192+
# check som obvious things
193+
check_equals('create', 'crea' + 'te')
194+
check_equals('referer', 'refer' + 'er')
195+
# check th flag
196+
y = [[], [], [], [], []]
197+
x = ['', '', '', '', '']
198+
x[0] = 'nymeh1niwemflcir}echaet'
199+
x[1] = 'a3g7}kidgojernoetlsup?h'
200+
x[2] = 'ulw!f5soadrhwnrsnstnoeq'
201+
x[3] = 'ct{l-findiehaai{oveatas'
202+
x[4] = 'ty9kxborszstguyd?!blm-p'
203+
f = 'bcdfghjklmnpqrstvwxyz'
204+
for i in range(5):
205+
for j, c in enumerate(x[i]):
206+
if c in f:
207+
sl = list(x[i])
208+
sl.insert(j, c)
209+
s = ''.join(sl)
210+
y[i] += [s]
211+
if x[i][-1] in f:
212+
y[i] += [x[i]+'e']
213+
for k in y[i]:
214+
assert len(k) == 24
215+
print(y)
216+
for i in range(len(y[0])):
217+
for j in range(len(y[1])):
218+
for k in range(len(y[2])):
219+
for l in range(len(y[3])):
220+
for m in range(len(y[4])):
221+
code_dict = []
222+
code_dict += [y[0][i]]
223+
code_dict += [y[1][j]]
224+
code_dict += [y[2][k]]
225+
code_dict += [y[3][l]]
226+
code_dict += [y[4][m]]
227+
flag = decrypt_data([53, 41, 85, 109, 75,
228+
1, 33, 48, 77, 90,
229+
17, 118, 36, 25, 13,
230+
89, 90, 3, 63, 25,
231+
31, 77, 27, 60, 3,
232+
118, 24, 62, 54, 61,
233+
25, 63, 77, 36, 5,
234+
32, 60, 67, 113, 28])
235+
if flag.find('flag{') != -1 & flag.find('}') != -1:
236+
if check_equals(flag.index('flag{'), 0) & check_equals(flag.index('}'), len(flag) - 1):
237+
print(flag)
238+
```
239+
240+
### 高频率星球
241+
242+
观测[asciinema](https://asciinema.org/) cat出来的文件说了要Execute flag.js with nodejs to get the flag。
243+
244+
删掉前后文和各种提示符(怎么删?肉眼观测然后Ctrl+F替换啊嗯)。
245+
246+
然后`node flag.js`
247+
248+
### 小型大语言模型星球
249+
250+
第一问尝试诱导各种类似与`do i am smart`之类,最后试得
251+
252+
![smart](image/2023-10-30%2012_40_28-Gradio.png)
253+
254+
第二问手工枚举得`x`+`accept`,得
255+
256+
![accepted](image/2023-10-30%2012_40_47-Gradio.png)
257+
258+
后面几个要懂AI什么做不出来啦。
259+
260+
### Komm, süsser Flagge
261+
262+
第一个检查`POST`整个字符串,那就把`HTTP Request`分两次发吧
263+
264+
```python
265+
import socket
266+
s = socket.socket()
267+
s.connect(("202.38.93.111", 18080))
268+
s.send(b"PO")
269+
s.send(b'ST / HTTP/1.1\r\nHost: 202.38.93.111:18080 \
270+
\r\nContent-Length: 自己算\r\n \
271+
Content-Type: application/x-www-form-urlencoded\r\n\r\n你的token')
272+
buffer = []
273+
while True:
274+
# 每次最多接收1k字节:
275+
d = s.recv(1024)
276+
if d:
277+
buffer.append(d)
278+
else:
279+
break
280+
data = b''.join(buffer)
281+
s.close()
282+
print(data)
283+
```
284+
285+
同样内容对第二试了一下也过了,但其实看不懂第二个什么意思。
286+
287+
第三个想到了要往`ip option``tcp option`里插东西,但是没搞定。
288+
289+
### 为什么要打开 /flag 😡
290+
291+
不懂什么`binary`,只看出第一题C库不准打开`flag`,那就不用C吧。
292+
293+
用rust写了一个可执行文件,得
294+
295+
```rust
296+
use std::fs::File;
297+
use std::io::{ BufReader, BufRead, Error};
298+
299+
fn main() -> Result<(), Error> {
300+
let path = "flag";
301+
let input = File::open(path)?;
302+
let buffered = BufReader::new(input);
303+
for line in buffered.lines() {
304+
println!("{}", line?);
305+
}
306+
Ok(())
307+
}
308+
```
309+
310+
第二问只看到crate的文档说存在 TOCTOU(Time Of Check, Time Of Use)的风险,但是肯定不懂的,无。
311+
312+
### O(1) 用户登录系统
313+
314+
看了半天对`Merkle Tree`的第二原像攻击,其实都没用。
315+
316+
问题在于不记录树的高度,把`admin:xxx`伪造到上面节点不行,似乎可以把它伪造到一个`user:pass`的叶子下面。
317+
318+
如果输入第一截是`admin:xxx:ccc`,易见要满足(此处略去关于hash1>hash2的讨论,自行调整即可)`(sha1("admin:xxx".encode())+ccc)=sha1("uasr:pass".encode())`,
319+
320+
也即`sha1("admin:xxx".encode())+ccc="user:pass".encode()``
321+
322+
那就随机一下`xxx`,使`"admin:xxx".encode()`的Sha1值可以编码为utf8可打印字符(我懒得考虑怎么处理不可打印字符了,大不了让电脑多跑一会就是了(这里的计算量估计了一下数量级反正跑的出来就是了))
323+
324+
```python
325+
while True:
326+
ap = 'admin:'+''.join([random.choice(ascii_letters) for _ in range(10)])
327+
ha = sha1(ap.encode()).digest()
328+
try:
329+
if ha.decode().encode() != ha:
330+
continue
331+
d = ha.decode()
332+
if d.isprintable() == False:
333+
continue
334+
if d.find('\n') != -1 or d.find(' ') != -1:
335+
continue
336+
print("ha=", ha.hex())
337+
print("hd=", d.encode().hex())
338+
print("ap=", ap)
339+
print("d=", d)
340+
break
341+
except:
342+
continue
343+
```
344+
345+
接下来拿着得到的`admin:xxx``d=sha1(ap.encode()).digest().decode()``d`后面接上一串`:1451411451411451489`(随便选的就是了,补上`:`且编码后长度和sha1一样就是了,这里可能要注意一下`hash1>hash2`什么的),`前面的ccc就是':1451411451411451489'`的encode hex,即`ccc=':1451411451411451489'.encode().hex()`
346+
347+
然后输入
348+
349+
```
350+
d:1451411451411451489
351+
:
352+
EOF
353+
```
354+
355+
然后得到的proof里有`d:1451411451411451489:ppp`,我们用`admin:xxx:ccc+ppp`,即可登陆。

0 commit comments

Comments
 (0)