読者です 読者をやめる 読者になる 読者になる

Shi0shishi0

とても眠い。

FIT-HACK CTF 2017 Writeup

0Shi0hShiとしてFIT-HACK CTF 2017に参加しました。1900pt入れて78位でした。

運営をされていたのは福岡工業大学のサークル(?)さんで、日本が運営元になっているCTFに参加したのは久しぶりな気がする。一週間のイベント運営、お疲れ様でしたm(_ _)m

Binary

FITRPG(50pt)

32bitのexeファイルが与えられる。

実行するとRPGゲームの戦闘のようなものが始まり、PlayerとDragonのLifeと戦闘の選択肢が表示される。DragonのLifeは5000(0x1388)から始まっており、まともに戦っても倒すのは難しそう。

Immunity DebuggerでFITRPG.exeを実行し、DragonのLifeである0x1388を処理している箇所を探す。
以下の箇所でLifeをチェックしており、これが0x00になればFLAGを出力するルーチンにジャンプするように見える。

f:id:echoha610:20170416232008p:plain

ここのLifeを低い数値に書き換えて攻撃すると簡単にDragonを倒せた。Dragonを倒すとFLAGが出力された。

FIT{1sdf3a9f}


number(50pt)

64bitのELFファイルが与えられる。

$ file number
number: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.0.0, BuildID[sha1]=9f41de34cf038d1aeedd774fbf57078c5c5a62e1, not stripped

実行すると何らかの入力を求められる。

$ ./number 
hello!! Please collect number
AAAAA
No

ELFファイルの中を見ていくと、0x466(1126)と「ユーザが入力した値から0x1a(26)を引いた値」を比較している箇所がある。1152 を入力してあげるとFLAGが出る。

f:id:echoha610:20170416015350p:plain

$ ./number 
hello!! Please collect number
1152
FIT{2.718281828}

FIT{2.718281828}


Execution(100pt)

32bitのELFファイル(ARM)が与えられる。

$ file execution
execution: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=aedce846e155a4365de5e446121703054b792243, not stripped

FLAGはハードコートされている。

FIT{3xecuti0n_c0mp1ete}


Random(100pt)

ELFファイルが与えられる。

このELFファイルは実行されるとユーザ入力を受け付け、rand関数で生成した値と入力された値を比較し、一致すればループを繰り返す。ループカウンタが0x1から0xaまでの間ループを繰り返すので、10回適切な値を入力する必要がある。

f:id:echoha610:20170416011713p:plain

rand関数で生成される値はループカウンタの値に合わせて毎回同じになっている様子。

以下の値を順番に入力するとFLAGが出力される。

01: 1804289383
02: 846,930,886
03: 1681692777
04: 1714636915
05: 1957747793
06: 424238335
07: 719885386
08: 1649760492
09: 596516649
10: 1189641421

f:id:echoha610:20170416011716p:plain

FIT{125853394}


Omikuji(200pt)

JARファイルが与えられる。
JARファイルを解凍してClassファイルを取り出し、更にソースコードに変換する。

Controllerクラスの中におみくじを引くための関数が定義されている。
Random() によって生成された値が0の時、daikichiになって flag() を実行する。

public void click()
{
        Random rnd = new Random();
        int ran = rnd.nextInt(0x989680);
        if(ran == 0)
        {
            str = "daikichi";
            flag();
        } else
        if(1 <= ran && ran <= 0x1e8480)
            str = "kichi";
        else
        if(0x1e8481 <= ran && ran <= 0x3d0900)
            str = "chukichi";
        else
        if(0x3d0901 <= ran && ran <= 0x6acfc0)
            str = "shokichi";
        else
            str = "suekichi";
        label.setText(str);
}

以下の flag() を切り出し、コンパイルし直す。

import java.io.PrintStream;
import java.security.MessageDigest;
import java.util.Random;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

public class Test
{
    public static void main(String[] args)
    {
        int i = 1024;
        int y = 0;
        String c = "flag";
        byte j[] = {
            51, 32, 66, 105, 108, 108, 105, 111, 110, 32, 
            68, 101, 118, 105, 99, 101, 115, 32, 82, 117, 
            110, 32, 74, 97, 118, 97
        };
        for(int k = 0; k <= 8; k++)
            y = k + y;

        String s;
        if(y % 2 == 0)
            s = (new StringBuilder()).append(c).append("error").toString();
        else
            s = "0eba0d68a699907bc3d765072c0735ce";
        try
        {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(c.getBytes());
            byte d[] = md.digest();
            StringBuilder sb = new StringBuilder(2 * d.length);
            byte abyte0[] = d;
            int l = abyte0.length;
            for(int i1 = 0; i1 < l; i1++)
            {
                byte b = abyte0[i1];
                sb.append(String.format("%02x", new Object[] {
                    Integer.valueOf(b & 0xff)
                }));
            }

            sb.reverse();
            String a = (new StringBuilder()).append("FIT{").append(sb).append("}").toString();
            System.out.println(a);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        String m;
        try
        {
            m = new String(j, "US-ASCII");
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return;
        }
        System.out.println(m);
    }
}

実行するとFLAGが出力された。

FIT{78b4c64c4477e3705c221401639fdfaa0286f46658d4d81502b4c7eacbf0d708}


Recon

Specific(100pt)

位置情報が残っている画像ファイルを与えられる。この写真に写っている橋の名前をローマ字で答えろという内容の問題。

f:id:echoha610:20170416013222p:plain

画像に残っていた位置情報を参照し、Googleストリートビューで橋を見てみる。

f:id:echoha610:20170416012052p:plain

f:id:echoha610:20170416012056p:plain

橋の名前は「天大橋」とあるが、読み方がわからない。橋の反対側も眺めて見ると読み方が「てんたいばし」であることがわかる。

FIT{tentaibashi}


これにミスリードされた結果、かなり手間取りました...「てんおおはし」ではないらしい。

f:id:echoha610:20170416013006p:plain


Forensic

Unknown password(200pt)

open_me.zipというパスワード付きZip圧縮ファイルを渡されるが、パスワードは不明。
中に Flagが書かれていそうなファイル flag.png と、 Fukkoudai.jpg というファイルが格納されている。

既知平文攻撃でいけそうなのでpkcrackを使う。平文ファイルは福岡工業大学Wikipediaのページにある。(ファイルサイズ、ファイル名が一致)

$ wget https://upload.wikimedia.org/wikipedia/commons/6/6c/Fukkoudai.jpg
$ zip Fukkoudai.zip Fukkoudai.jpg
   adding: Fukkoudai.jpg (deflated 20%)
$ pkcrack -C /home/user/open_me.zip -c Fukkoudai.jpg -P Fukkoudai.zip -p Fukkoudai.jpg -d /home/user/decrypt.zip

出力されたZipファイルを解凍するとflag.pngが取得できる。

FIT{feqDnwJ9YtMrhh0}


他にも色々解きましたがとりあえずこのぐらいで。。。