Harekaze CTF 2018 write-up
Introduction
2月10日から行われたHarekaze CTF 2018に参加しました。いろいろとあってあまり解くのに時間が取れませんでしたが、3つだけ解いたので記録に残しておきます。
welcome flag
Description
The flag is HarekazeCTF{Welcome to the Harekaze CTF!}. Enjoy!
Details
- Points
- 10
- Genre
- WarmUp
- Author
- isoroku
- Solves
- 440
Method
CTFで初めの問題に必ずあるやつです。問題文をコピーアンドペーストして送信すれば点がもらえました。なお、コピーするときに文字列の前後に空白が含まれていると、Incorrectってなって初回から非常に萎えますので、気をつけてコピーします。
ちゃんとフラグの送信ができるか確認するだけの問題ですが、点数付くし☆もらえるとうれしいですね。モチベーションアップできます。 なぜかこの手のは解答しない人もいますが、なぜなんでしょうか…?
Flag
HarekazeCTF{Welcome to the Harekaze CTF!}
easy probrem
Do you know ROT13? Can you decode this text? UnerxnmrPGS{Uryyb, jbeyq!}
Details
- Points
- 30
- Genere
- WarmUp
- Author
- kimiyuki
- Solves
- 426
Method
問題文にROT13と書いてあるので、ROT13暗号だと予想できます。 ぐぐるとオンラインでROT13をデコードするサイトが見つかりますので、そのサイトに入力しました。
Flag
HarekazeCTF{Hello, world!}
Obfuscated Password Checker
パスワードを手に入れてください! Get the password! src.zip
Details
- Points
- 50
- Genere
- Web
- Author
- st98
- Solves
- 112
Method
示されたsrc.zipをダウンロードすると、htmlファイルとjsファイルがありました。htmlファイルをブラウザで開いて、フォームに何かを入力すると難読化されたjsが処理して出力をくれるようです。
難読化されたjsファイルを読むわけにはいかないので、ブラウザのデバッガで動作を追おうと思ったのですが、デバッガを使ったことなかったので使い方がわからず解くのは断念しました。
Flag
-
div N
$ cat foo.c long long div(long long x) { return x / N; } $ gcc -DN=$N -c -O2 foo.c $ objdump -d foo.o foo.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 : 0: 48 89 f8 mov %rdi,%rax 3: 48 ba 01 0d 1a 82 9a movabs $0x49ea309a821a0d01,%rdx a: 30 ea 49 d: 48 c1 ff 3f sar $0x3f,%rdi 11: 48 f7 ea imul %rdx 14: 48 c1 fa 30 sar $0x30,%rdx 18: 48 89 d0 mov %rdx,%rax 1b: 48 29 f8 sub %rdi,%rax 1e: c3 retq $ echo “HarekazeCTF{$N}” > /dev/null
Details
- Points
- 100
- Genere
- Rev
- Author
- kimiyuki
- Solves
- 90
Method
div関数の逆アセンブラの出力があり、これを見てdiv関数はなんの数で割ってるかを示せばそれがフラグのようです。
アセンブリを直接見て解いてもいいですが静的解析よりも動的解析の方が圧倒的に楽なので、せっかくアセンブリがわかってるのでそれを実行してみました。 ABIがわかんないですがCTFではLinuxがほとんどなのでLinux上で実行しました。 マイコンプログラミングする人は、アセンブリ関数をよく書くと思いますが、それと同じ方法でやりました。
まずは、問題文の逆アセンブラの出力をコピーして、アセンブリファイルを用意しました。
foo.s
.global div
div:
mov %rdi,%rax
movabs $0x49ea309a821a0d01,%rdx
sar $0x3f,%rdi
imul %rdx
sar $0x30,%rdx
mov %rdx,%rax
sub %rdi,%rax
retq
次に、このdiv関数を使うためのCプログラムを用意しました。
test.c
#include <stdio.h>
long long div(long long x);
int main (void)
{
long long x;
scanf("%lld", &x);
printf("%lld", div(x));
}
コンパイルしました。
$ gcc -c foo.s $ gcc -c test.c $ gcc -0 foo.elf foo.o test.o
実行ファイルfoo.elfができたので、適当に大きな数を入力して実行してみました。
$ ./foo.elf 10000000000 0
実行できました。Linux環境で間違いなかったようです。 こんなに大きい数を入力しても割ったら0とは当てずっぽうで当たるわけがないので、素直にプログラムで探索することにしました。 (といいつつ、1になったやつを何度か当てずっぽうで入れたのは内緒)
test.c
#include <stdio.h>
#include <stdint.h>
long long div(long long x);
int main (void)
{
long long x, min = 0, max = INT64_MAX;
while (max - min - 1) {
x = min + (max - min) / 2;
if (div(x)) {
max = x;
} else {
min = x;
}
}
printf("%lld\n", max);
}
たぶん二分探索ってやつです。ループを終えると、minに割って0になる時の最大値、maxに割って1になる時の最小値=割る数が導かれます。 プログラムを書き換えたので、再度コンパイルして実行しました。
$ gcc -c test.c $ gcc -o foo.elf foo.o test.o $ ./foo.elf 974873638438446
はい。一瞬で答えが出ました。
Flag
HarekazeCTF{974873638438446}
Conclusion
時間が取れずほとんど解けなかったのが心残りでしたが、少しの間でも楽しめたので良かったです。