angstromCTF 2020 writeup
2020年 3月 14日 09:00~2020年 3月 19日 09:00に開催されたangstromCTF 2020に1人で参加しました。
結果は今サーバーにアクセスできないので分かりませんが、最後に見たときは300位以内には入っていたぐらいだったような気がします。
簡単な問題しか解けていませんが、誰かの参考になれば幸いです。
Misc
Sanity Check
discordに書いてあるFlagを入力するだけ...のはずなのにFlagを見つけるのに無駄に苦労しました。
ずっと #general なんて無いじゃん💢とか思っていましたが、ちゃんと書いてありました。
旗のやつを押さないと #general にアクセス出来ないようになっていました。
ws1よりも解けた人が少ないのを見ると、結構ここで沼っている人が多かったのではないでしょうか。
Flag:actf{never_gonna_let_you_down}
ws1
pcapファイルなのでとりあえずwiresharkで開いてみます。
普通にHTTP通信をしているだけでした。
すでにFlagが見えていますが、HTTPのところで 右クリック>追跡>HTTPストリーム で見やすくなります。
Flag:actf{wireshark_isn't_so_bad_huh-a9d8g99ikdf}
clam clam clam
とりあえず指定された場所に接続してみると、clamとmalcを叫び続けているだけでした。
ヒントにある改行からエンターキーを連打してみてもとくに何もありません。
埒が明かないので、pythonで取得内容を確認してみると、calmとmalcに紛れて以下のようなものがありました。
type "clamclam" for salvation\r
google先生に翻訳してもらいます。
救いのために「clamclam」と入力します
再度接続してcalmとmalcが流れている中、ダメ元で clamclam と入力してエンターしてみると、Flagが表示されました。
Flag:actf{cl4m_is_my_f4v0rite_ctfer_in_th3_w0rld}
ws2
またpcapファイルだったのでwiresharkで開いてみると、どうやらflag.jpgをアップロードしていることが分かりました。
これをエクスポートします。
しかし、これをそのまま開こうとしても壊れているようで開くことが出来ません。
こんなときはforemostの出番です。
ワンパンマンとともにFlagが出てきました。
Flag:actf{ok_to_b0r0s-4809813}
Inputter
実行ファイルのほかにソースも貰えます。
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #define FLAGSIZE 128 void print_flag() { gid_t gid = getegid(); setresgid(gid, gid, gid); FILE *file = fopen("flag.txt", "r"); char flag[FLAGSIZE]; if (file == NULL) { printf("Cannot read flag file.\n"); exit(1); } fgets(flag, FLAGSIZE, file); printf("%s", flag); } int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IONBF, 0); if (argc != 2) { puts("Your argument count isn't right."); return 1; } if (strcmp(argv[1], " \n'\"\x07")) { puts("Your argument isn't right."); return 1; } char buf[128]; fgets(buf, 128, stdin); if (strcmp(buf, "\x00\x01\x02\x03\n")) { puts("Your input isn't right."); return 1; } puts("You seem to know what you're doing."); print_flag(); }
引数と標準入力が一致すればFlagを出してくれるようです。
まずは第一関門。
\n'\"\x07
普通に手打ちでやると \x07 すなわち警告音を作りだすことが出来ません。
そこでechoで同じものを作ります。
echo -e -n " \n'\x22\x07"
まずはこれで第一関門はクリア。
./inputter "`echo -e -n " \n'\x22\x07"`"
第二関門。
\x00\x01\x02\x03\n
これもechoで作って、今度はパイプで渡します。
echo -e "\x00\x01\x02\x03\n" | ./a.out "`echo -e -n " \n'\x22\x07"`"
当然自分の環境にFlagは無いので、angstromのshellで同じように実行すればFlagが手に入ります。
Flag:actf{impr4ctic4l_pr0blems_c4ll_f0r_impr4ctic4l_s0lutions}
Shifter
50問解くだけです。
まずは普通にncで接続してどのような問題か確認します。
50未満の整数nと平文pが与えられ、pをnのフィボナッチ数列で暗号化したものを答えればよいようです。
たまに与えられる平文が0文字のときがあるっぽいので、そこも考慮しなくてはならないようです。
運次第では対策してなくてもFlag取れると思いますけど。
Flag:actf{h0p3_y0u_us3d_th3_f0rmu14-1985098}
Web
The Magic Word
真ん中にデカデカとgive flagと書かれたページです。
とりあえずソースを確認してみると、どうやらmagicのところがplease give flagだとFlagがもらえるようです。
デベロッパーツールでplease give flag に書き換えます。
Flagが表示されました。
Flag:actf{1nsp3c7_3l3m3nt_is_y0ur_b3st_fri3nd}
Consolation
リンク先にはボタンと$がありました。
ボタンを押すたびに$25ずつ増えていきます。よく分からない。
ソースを確認してみると、iftenmillionfireflies.jsというファイルを読み込んでいて、ボタンを押すたびにこの中の関数を呼び出しているようです。
iftenmillionfireflies.jsを覗いてみると難読化されていたので、適当なサイトで難読化解除してみましたが、それでもよく分かりませんでした。
https://beautifier.io/
最初にBase64らしき文字列がたくさん並んでいたので、何かありそうな気がしましたが、デコードしてみてもそれらしい情報は得られません。
全然手掛かりが得られないので半ば諦めていたのですが、冷静に考えると点数や解いたチームの数から察するに、難しいことを要求されているわけではないはずなんですよね。
そこで、Chromeのデベロッパーツールを使って処理を1つ1つ追ってみました。
まずは13行目にブレークポイントを設定します。
この状態で「pay me some money」のボタンをクリックするとデバッグが始まります。
処理を1つずつ進めていきます。赤丸のところをクリックするか、F11を連打します。
何も考えずに連打すると大事な情報を見逃してしまうので、なんだか大事そうな青枠のところを確認しながら適度な速さで連打します。
しかし残念ながらFlagは現れません。
なんだよ~と思いつつ、デバッグする前に何度かクリックしてから再度チャレンジしてみたら、なんと出ました!!
Flag:actf{you_would_n0t_beli3ve_your_eyes}
Git Good
普通にURLにアクセスしてみるとHello, worldになるだけです。
ところがURLの末尾にflagと入れてみると変わりました。ここから色々取ってこれそうです。
問題のタイトルや問題文にもあるようにgitが関連しているようなので、.gitディレクトリがあると推測します。
コミット履歴などが含まれている.git/logs/HEADをダウンロードするために「https://gitgood.2020.chall.actf.co/.git/logs/HEAD」にアクセスしてみると、以下のようなファイルを取ってくることができました。
0000000000000000000000000000000000000000 6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5 aplet123 <jasonqan2004@gmail.com> 1583598444 +0000 commit (initial): haha I lied this is the actual initial commit 6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5 e975d678f209da09fff763cd297a6ed8dd77bb35 aplet123 <jasonqan2004@gmail.com> 1583598464 +0000 commit: Initial commit
e975d678f209da09fff763cd297a6ed8dd77bb35は現行なので、6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5が怪しそうです。
BSides San Francisco CTF の write-up - st98 の日記帳を参考にしつつ、掘り下げていってみます。
https://gitgood.2020.chall.actf.co/.git/objects/6b/3c94c0b90a897f246f0f32dec3f5fd3e40abb5からダウンロード
↓
3c94c0b90a897f246f0f32dec3f5fd3e40abb5をデコンパイル
import zlib f=open('3c94c0b90a897f246f0f32dec3f5fd3e40abb5',mode='rb') flag = zlib.decompress(f.read()) print(flag)
↓
commit 210\x00tree b630430d9d393a6b143af2839fd24ac2118dba79\nauthor aplet123 <noneof@your.business> 1583598444 +0000\ncommitter aplet123 <jasonqan2004@gmail.com> 1583598444 +0000\n\nhaha I lied this is the actual initial commit\n
https://gitgood.2020.chall.actf.co/.git/objects/b6/30430d9d393a6b143af2839fd24ac2118dba79
↓
30430d9d393a6b143af2839fd24ac2118dba79をデコンパイル
↓
tree 242\x00100644 .gitignore\x00\xc2e\x8d}\x1b1\x84\x8c;q\x96\x05C\xcb\x03h\xe5l\xd4\xc7100644 index.html\x00c\x88\x87\xa5Is&\\B\x8c\xd5\x1c\xe6\xdf\xd4\x8f\x19m\x91\xc4100644 index.js\x00I\xb3\x19\xc3}\xc6t\xbc\xa6\x82\xca\xb0\xf2Pds\xdd\xa6\xbd\x9a100644 package-lock.json\x00x\x9f\xa5\xca\xf4R\xf5\xf6\xf2[\xfa\x9b\x1c\n\xb1\xd5\x93\xdc\xe1\xb3100644 package.json\x00\x8f\x08\xaf5 ]\x0b\xa8\x0e\x94\xb4\xf40c\x11\x03\x9db\xe18100644 thisistheflag.txt\x00\x0fRY\x80\x06\xf9\xcd\xb2\x1d\xb2\xf4\xc8\xd4MpSV0(\x9b
thisistheflag.txtというファイルがあるようです。
意気揚々とアクセスしてみると、イラッとさせられます。
ここで方針を変えることにしました。
新たに参考になりそうなページを発見しました。
BSides San Francisco CTF 2017 - Write-ups | Rawsec
gitdumperという便利なツールがあるようです。早速使ってみます。
なんだかいっぱいダウンロードできました!!
先程のページに従って色々試してみると、急にFlagが現れました。
仕組みがよく分かりません...
Flag:actf{b3_car3ful_wh4t_y0u_s3rve_wi7h}
Secret Agents
ログインページへのリンクボタンがあります。
当然ながらloginに飛んでもFlagは表示されません。
問題文のリンクからソースを確認します。
なんだかSQLインジェクションできそうな部分があります。
どうやらUser-Agentの値をそのままSQL文に突っ込んでいるだけのようなので、デベロッパーツールで値を変えながら色々試してみます。
a' OR 1 = 1;
UAには複数の値が存在すると思われるので、それを考慮するとSQLインジェクションは成立しているようです。
それではUAにはどのようなカラムが存在するのか見ていきます。
しかし、普通に information_schema.columns とかをUNIONしても、最後のif文のところで2行以上になると弾かれてしまいます。
なのでLIMITを使って1つずつ地道に特定していきます。
正直手作業でやったほうが早いような気はしましたが、pythonで自動化してみました。
以下のカラムがありました。
AAAA shrek V 123ujklaguhjnkadsuop98uij2k3l4mlgjaisdopgjk;mlkl;k234lkjhasd89f709iok23jkdf keyboard bash op neeeeeeeeeeeeeeeeeeeeeeeeum I WANT THAT KRABBY PATTY bzzzzzzztaaaa bzzz';lhjkdjsjkldfgzzzztaaaa hiiiii whatis our aaa nice try but this is harder :p
なんとなく一番複雑な123ujklaguhjnkadsuop98uij2k3l4mlgjaisdopgjk;mlkl;k234lkjhasd89f709iok23jkdf keyboard bash opが怪しそうなので突っ込んでみたらFlagが表示されました。
Flag:actf{nyoom_1_4m_sp33d}
Crypto
Keysar
暗号化されたFlagと鍵が与えられます。
ANGSTROMCTF agqr{yue_stdcgciup_padas}
パッと見でシーザー暗号かな~と思ってやってみましたが、いくらずらしてもFlagらしいものは出てきません。
これは色々試した後の話なのですが、シーザー暗号に鍵を使うことが出来たんですね。知りませんでした。
無駄にヴィジュネル暗号じゃないかとか考えて、結局全然出来なくてもはや諦めかけていました。
最終的にはこちらのサイトでいけました。
https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipher
Rotateの値を0にしてalphabet keyに先程の鍵を入力したらFlagが出てきます。
Flag:actf{yum_delicious_salad}
Reasonably Strong Algorithm
名前から察するにRSA暗号でしょうか。
リンク先にはやはりn、e、cの値がありました。
n = 126390312099294739294606157407778835887 e = 65537 c = 13612260682947644362892911986815626931
とりあえずfactordb.comに突っ込んでpとqの値を特定します。
p = 9336949138571181619 q = 13536574980062068373
あとはいい感じにプログラムを書くだけです。
Flag:actf{10minutes}
Wacko Images
暗号化された画像と暗号化用のプログラムが与えられます。
from numpy import * from PIL import Image flag = Image.open(r"flag.png") img = array(flag) key = [41, 37, 23] a, b, c = img.shape for x in range (0, a): for y in range (0, b): pixel = img[x, y] for i in range(0,3): pixel[i] = pixel[i] * key[i] % 251 img[x][y] = pixel enc = Image.fromarray(img) enc.save('enc.png')
大事なところは15行目だけです。
逆のことをすればいいだけですが、私はちょっと除算の逆の処理というものを存じ上げないので、頭悪く総当りすることにします。
総当りといっても最大で500*200*3*255=76,500,000回しかありません。十分すぐ終わる範囲です。
正直あまり自信はありませんでしたが、ちゃんと出来ていました。
Flag:actf{m0dd1ng_sk1llz}
Binary
No Canary
実行ファイルとソースがもらえます。
#include <stdlib.h> #include <stdio.h> #include <string.h> void flag() { system("/bin/cat flag.txt"); } int main() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); gid_t gid = getegid(); setresgid(gid, gid, gid); puts("Ahhhh, what a beautiful morning on the farm!\n"); puts(" _.-^-._ .--."); puts(" .-' _ '-. |__|"); puts(" / |_| \\| |"); puts(" / \\ |"); puts(" /| _____ |\\ |"); puts(" | |==|==| | |"); puts(" | |--|--| | |"); puts(" | |==|==| | |"); puts("^^^^^^^^^^^^^^^^^^^^^^^^\n"); puts("Wait, what? It's already noon!"); puts("Why didn't my canary wake me up?"); puts("Well, sorry if I kept you waiting."); printf("What's your name? "); char name[20]; gets(name); printf("Nice to meet you, %s!\n", name); }
とりあえずIDAで開いてflag関数のアドレスを調べます。
アドレスは0x00401186のようです。
そしてなんかよく分からないですが、適当に埋めるbufferは20+8で0x28とします。
あとはプログラムに落とし込みます。
実行したら見事Flagが取れました。
Flag:actf{that_gosh_darn_canary_got_me_pwned!}