Introduction

2月10日から行われたHarekaze CTF 2018に参加しました。いろいろとあってあまり解くのに時間が取れませんでしたが、3つだけ解いたので記録に残しておきます。

Questions

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

時間が取れずほとんど解けなかったのが心残りでしたが、少しの間でも楽しめたので良かったです。