WTF!?

オンサイトCTFのWriteupとか書いてく.

CTF for Beginners 2015 横浜 with mochigoma-Beginners Writeup

CTF4bに参加してきた.
バイナリ初心者なのでバイナリガッツリコースで親方の素晴らしい講義を受けてきた.
講義は,バイナリとは何ぞやというところから話が始まり,バイナリ読経をしたり最後にはPwnの話に触れたりもした.また,講義の後に1時間半の簡易CTFがあった.1200ポイントを獲得し,193sさんと同率の2位だった.ここではそのCTFのWriteupを書いていく.

number game

fileコマンドを叩いてみると

bin3.exe: PE32 executable (console) Intel 80386, for MS Windows

とりあえずIDAに喰わせてみる.

f:id:nanuyokakinu:20150216021225p:plain

randで生成される数字と同じものを入力するのを10000回すればflagが出るらしい.
flagの生成に使われるのは[ebp+var_4]に保存されている値だけである.
[ebp+var_4]には1回入力に成功する度に,それまでの入力回数が加算される.
そこで,cmp edi, 2710hで処理を止め,ediに0x2710を,[ebp+var_4]に1+2+...+10000=50005000=0x2fb0408をセットし処理を進めてみると,

f:id:nanuyokakinu:20150216020516p:plain

保存できるかな?

fileコマンドを叩いてみると

zip.exe: PE32 executable (console) Intel 80386, for MS Windows

またPE32ファイルだ.IDAに喰わせてみる.

f:id:nanuyokakinu:20150216021748p:plain

zip.exeという名前で何かを保存しようとしており,zip.exeというファイルを作成できなければexitと表示して終了するらしい. 配られた状態で実行しようとしても実行ファイルの名前がzip.exeなので新しいファイルを開けない.そこで実行ファイルの名前を変更して実行してみる.新しく生成されたファイルにfileコマンドを叩いてみると,

C:\Users\CTF4b\Desktop>file zip.exe
zip.exe: ASCII text, with no line terminators
C:\Users\CTF4b\Desktop>cat zip.exe
H4sICJAQ3lQEAGZsYWcuemlwAHWMzwqCQBDGZ/tHeKlbYdAf6Fqn7nUqYgn23GXRylgQ67CFKL6FV28+h48gvoEnn0N3V8GT3/DNbxhmPoL7Aw2kiuR2Thf5TBez9FjYso33nrv8wa2D6V+p/fm/qMe+1HCe1GTOJiAY9Y7QlbCFWmvV2zyt2SCYQ7xbTaNLhn5sqRjq5USS4OFI3Yi6C57URwXakXISsAAAAA==

出てくる文字種と最後の"=="から察するにBase64だと思われる. Fiddlerでデコード,保存してまたfileコマンドを叩くと

dec: gzip compressed data, was "flag.zip", last modified: Fri Feb 13 23:56:16 2015, max speed, from FAT filesystem (MS-DOS, OS/2, NT)

解凍するとflag.zipが現れる.更に開くとflag.txtが出てくる.

C:\Users\CTF4b\Desktop>cat flag.txt
ctf4b{I_love_zip_and_bin!}

Do(no)tNet

fileこまんd(ry

Do(no)tNet.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

実行してみると次のようなウィンドウが出てくる.

f:id:nanuyokakinu:20150216023228p:plain

パスワードをテキストボックスに入力しボタンを押せばflagが出るっぽい.
.Netはシンボルとかが残っていればほぼ完全にソースコードまで戻せるのでILSpyに喰わせ,ボタンが押されたときの処理を見てみる.

f:id:nanuyokakinu:20150216023519p:plain

"GBHkoogsk2ZG4CJp5oEGKtrjPoz33ycC"が入力されていればいいらしい.
この文字列を入力して実行を押すと,

f:id:nanuyokakinu:20150216023651p:plain

というメッセージと共にDo(not)tNet_Flag.pngというファイルが生成された.メッセージの通りQRコードを読み取ると, ctf4b{fb943d6b2acbb2e45798f1c508ad33c76acd9c12}

ここから先は時間内には解けなかった問題のWriteup

気長に待ちましょう

実行してみるとpingを送っているような表示の間々にflagが表示されている.
無駄な表示をさせないようにさせて実行すると,

f:id:nanuyokakinu:20150216024230p:plain

表示されてますか?

IDAで開いてみるとFLAGっぽいものが見える.

f:id:nanuyokakinu:20150216024509p:plain

.rdataセクションを見てみると,

f:id:nanuyokakinu:20150216024714p:plain

unicode文字列がある.
この16進数の列をバイナリエディタでファイルにしてunicodeに対応しているテキストエディタで開くと,

f:id:nanuyokakinu:20150216024912p:plain

YAGIHASHOO SYSTEM

fileこm(ry

hashoo.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

ILSpyで逆コンパイルしたmain関数はこんな感じ.

private static void Main(string[] args)
{
    if (args.Length == 1 && args[0] == "HELLO")
    {
        Console.WriteLine("HELLO, YAGIHASHOO SYSTEM.");
        Console.WriteLine();
        List<object> array = Program.getArray();
        Console.WriteLine("Boot....");
        string decryptString = Program.getDecryptString(array);
        Console.Clear();
        Console.WriteLine("YAGIHASHOO SYSTEM VERSION 1.0");
        Console.WriteLine();
        Console.WriteLine("COPYRIGHT : 2015 MIMURA.");
        Console.WriteLine();
        Console.WriteLine("------------------------");
        int num = 0;
        string flag = "";
        while (flag != null)
        {
            Console.Write("User: ");
            Thread.Sleep(20);
            Console.WriteLine("mimura1133");
            Console.Write("Password: ");
            flag = Console.ReadLine();
            string text = Program.checkFlag(flag, decryptString);
            Console.WriteLine(text);
            if (text.Substring(0, 4) == "GOOD")
            {
                Console.ReadLine();
                return;
            }
            Console.WriteLine();
            num++;
            if (num == 3)
            {
                Console.WriteLine("ERROR...");
                Console.ReadLine();
                return;
            }
            Console.WriteLine("RETRY..");
        }
        return;
    }
    string text2 = Path.GetTempPath() + "svchost.exe";
    if (File.Exists(text2))
    {
        File.Delete(text2);
    }
    File.Copy(Assembly.GetExecutingAssembly().Location, text2);
    Process.Start(text2, "HELLO");
}

checkFlag関数で判定してるらしい.checkFlag関数はこんな感じ.

private static string checkFlag(string flag, string data)
{
    string text = "";
    for (int i = 0; i < flag.Length; i++)
    {
        if (!(flag.Substring(i, 1) == data.Substring(0, 1)))
        {
            return "AUTH FAILED!\n" + text + "?";
        }
        data = data.Substring(1);
        try
        {
            data = Program.validateKey(flag.Substring(i, 1), data);
        }
        catch (Exception)
        {
        }
        text += flag.Substring(i, 1);
    }
    if (flag.Length == 17)
    {
        return "GOOD WORK!\nFLAG IS : " + text;
    }
    return "AUTH FAILED!\n" + text + "?";
}

入力した文字列を先頭から順番にdataの先頭と比較し,
1回比較する度にvalidateKey関数でdataの内容を書き換えているらしい.
これらの処理をデバッガで追うのは大変なので,
判定を行わずに同じ動作をするC#のプログラムを書くと,

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

class Program
{
    private static string validateKey(string flag, string data)
    {
        Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(flag, Encoding.UTF8.GetBytes("yagihashoo"));
        rfc2898DeriveBytes.IterationCount = 1024;
        RijndaelManaged rijndaelManaged = new RijndaelManaged();
        rijndaelManaged.KeySize = 256;
        rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
        rijndaelManaged.BlockSize = 128;
        rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
        MemoryStream stream = new MemoryStream(Convert.FromBase64String(data));
        return new StreamReader(new CryptoStream(stream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Read)).ReadToEnd();
    }
    
    private static void checkFlag(string data)
    {
        string text = "";
        string tmp;
        for (int i = 0; i < 17; i++)
        {
            tmp = data.Substring(0, 1);
            data = data.Substring(1);
            data = Program.validateKey(tmp, data);
            text += tmp;
        }
        Console.WriteLine(text);
    }
    
    private static void Main(string[] args) {
        string decryptString = "c+rjfHaWKqehpXSBj7jAhulnXCJRNDcJQw+L5f0oIavJmqjfEo6PY7CP4pDUVP6eLR9IiPr0nkMZbOiBBRltDq0qdxNMBrOQHMTcdcYAoyxMSNjk0oxy2Y5HfsXMN7aX++sZLpmOx00xce/aPoMVvnKVcb9ds9KVi5c3Bzz3fuIKjRYoNSlwOqr5ZGhzFhIFVuurt+jxLciE+ie2Gih7WXItuVSl3xIoOPcL28VpXGLKNGHiU+Bu6Lif6neAHq2VVCGj7/cMrSGQjy8tly5TOcPhMVAt7Md1PIDLMIBhr1Lc1aWCk2h+ybEtec6UWeblvZbZgTACJ/VjcAgbLWoPZDLB2Z2BXsHCpvx0eYeJnufe2S15Q4G2IB2nG+8e32JQJDRL3UpBMF8u2MnTkYFSds8894jUtJwYKS9n32NOcZXU0gdpUp5uTzOggPu46BgoVTSA/xDui+ElRo7SZWw9aoATt6JPZ27Wcp+bfNhx99cESPFzzxHhG3Pq1yrs/2O73b49C4o7EjdljxAHkEHAZ75Tc+ftvSv2TG+V0y20ysre64ouXIh7kM6t3m1sHAmXBGrmx56ZS5uTfWvmjdXWM90Hl3rr8dh6aBKnWaYrEKNMACv67Xm9yaKqOLpa/zndNmDj80HUB8LhE7YiJSc+RrLrxlvDtGpRQefBYuSOn8LXWr0HQx+fanrALNJdifSYExKFfcHTiI1pGcTee5ZwtCpW0HV7bGcmeuIFsAkrJA1DaqAZabwajO9KeAF+eDP52rlzT3q5lWZveEDUQreaDZA1gj4V1OGQ1uLvBm5TsHEJVgmKwcGE2xwMs0CetxlMuxvK1AxQLFC3DxSZKG6Of8i8yIoVXALqTdY3OX70R//b8Z1IYQqKS6gnacf/Gz/yYbVhU2CDPKdKublC6fcdqBSPkxFIKTdMs+MckUGgwp5gm5+0gE+MwQO/rNxW7AyG0+SOWiN//Ynd59267wOurNs+oDiTyiRGfFIhBXVw+lfocCwqYMhoZ18bN51raasKbuQFZRR4ZYhCOjfkvpjha7itZjNhS5O/697TJ0aEcUusX+1BUlmnVmgyz8d9YSv8SNPZhHLfVm76xWScCgw7jFS2X7w7vIWcsEW6DzyTO6uo5mx2GjNQDaoE15h6VAzx6py32Fh7wSBEqcp0uplOHCmB9bocmPkWdoa90dHpqAim78Zmcv+C0rjdcbs/TCFx7FzoodW2yhLDL4qoREsK0LOztmJzpdkLzdcfh2vxtlxl9QfuDu5cfajX5+K41Cwf3Mt2Q46fkRQFXzfN1lIbSYwKwKnj7oFzd0DzBhwiZjTUYzvv6xWOllmlsjkhb8jq9HRs20kGy7+A2FqiE4WmmpPJ3IE1h8+wGk1xQPZN46is4jNAyy2cuIfLz3R40+Hyr2rBd2s8ro7y5/2yGp7jBtFKEkHES3hzXwYebrvakYxj9KTDe4HP/A9V0G16rqmKaP/L8VUdp8OZWJKEi6MZHmDhQc1XcrvlDo/eGa9TL7WRPKHe2spP7PpGX6VlV+zELfM9AE1gBddO9GLBPhUcT7HGoYGiYfIKNKzwHwTGt3FomyH2jZL4EsS8kopQb3bIlZv0pFaBeXMMPQtVj5jOVz00/SV7AygBiGXeZxAh1kXve6gXNU9o4Gzf3uPV+xmsoDgtsym0cGStepg99feZiSY0Ka/GnXLYGK3n7y+gC/Mw/ThXqI9YkoDZy+qLVdOXSvdm0dwHHIxlEN/W4v5PbV4jpZrwg16oHz+DUI6oqCoZWynHYXGgAQMhP8oefH1WI9FSPJjGjJc6HJZoaLFAxQtgzTWoqUOuWQwuWLD68f1ikyCvt1PVOq3b+yOAFi6YJa0MNAznf0gNJDhGgZGRKIz5vDUWLt4FV0DyOAFBJnriQqGkCWwo7YLJhH2gn8zeV9kW6ihjDMzriw+EIsHxOe40oyX+ao6rqdnCOyfU8S6SA7ZxIVlpD/pA+aXxdNSiSx+P7j7i+GbhYh5oao5w//vjBtnc6Hagnh3yu48YFxW0WEcLoJEBUaUJ7j65lU8vK4SSKqQaFeYuU0tTQFiRntGwOjAdszmTnrmblRftPGz+TqoMNWC0HICDutDoLV4JlFKe4SPJRCkWlgP9LzTeqs7Wqr36peb3OW75qXm9eaC0njrVjIV1U3NFmtJQJZrpTyALK5x7nsmWpDmesVxtBWDohQIvXyKPcXKYazJvloJJGopXrPOlkL/aWxPWNmoZtbGos/5l+2aUL2ErLfHNPPqzo8JnEa98iLiFWf0QAtqiDRc8eNKLdgLhFPZ511uehDMqPJf/vmyZaaO6vmeHN1ZU2cqS7k0oiOMuOaYpazj8rWOqgeJyy7SGT6fhvWwFajG5laD19NACBSoWNWOq0OHlYaUMSCtie+U716vh2f06WSzJueMqkr3fRdl4dtlskWlR1r9uJr6IspvW7z5BTzyOENRqAY/f3eurVUHoA9zQYrBAcsQ8k2+M4idol/tXCaxO2p5lNbseuzGiHQjOb5OxfsrrRer1QYJMR3yCmaB4rgr3BQIEHVOe5ZxKXvk85ox9RJmGRFhP8P4QpTaqd1gTF6GrTkg9uMdGOD2Umczo9AADJ0vFlzodjQkFKYYsuvz+BcgF0SpKr35E3taaM7UGy6+8RDX4OlEqaF9cR+qcytvzZtHCrj9qHlp4S1GYS6TAL0C4IW/40D6VXZVKt7QLRSNHO3pmgeZ+oNUwj0LC/Gxy/7xDkVtXsbyHsCS3FlIu7uneZTYcjUU3GoELAZQzfaaRxOqEOm0icoNg2EK/3QLtyEZATSrsNvdxqaJUnqtcRBGPWiC7vlpep9CKQJdDs+dsTkpnIlIGcxrf9w9HPQaOtKLS8DkNegeC9lw0VyH0g+dHG72+Nl81Ud1JEnZtkZwy+eLmIfX3nM7WuLPGY7p9uXnHf3+EXNNRc+gVNfFfA48qDGRjOQxzVObYgSJK4JGD+nCg31V7S81B0/wQNYr96LZoXNZmWGYYXqqnWPvBVb/q+6D9jvzT+WBpCr/BQiMFJiwKu73s5yd5Rjlu1z/5urAJGc9zMsbn8vRxANbmgWmS4ghc5tEbYk6El5wHN0+ZfMF3HWzKTFjmqW8wkRRvSWtwD1oW2uCmIfttDl9AH0fiMjkeU9hyFIyApSd/Jlh6sSIuwiKDe+xIzA0Gv8OnXLU9FDJ2ktWee8Tc4IfN7kWizKwrrRWfdXFpDxqjdJnaTtcO5yfGL8Xzjai+vT7EVZ4I3kvgZ1MdPfnCqQibp1D+boLrv6HrltdaIEYq1o8uQVOtV+QhqeD/fjv0AmUdrPbV0Q3FWdIFKyQmfTQPV4HfRTlQEnwdqeMZl5Rw4YU0p3fEOGGTqvE44PRIgCGlYs5dzHn4e1G5Lkv2Yr0pg0tH2nch0xUwmSZMN/7crRYzHdo1Il+TxD94fwiW1LSsp+TG4796qZrHMFgaUFBuvzVJCbYRtBBBWGROF3hzVusFFn0lZq0hBk+kQbEQQTlpQt281D6syYY4aVC/+c65pN96ekukvhGHQksChrJbpzMjyDQ1OTedpbMr3iKMNkMaQMriz/S4gKUuNDvuQWry1jFuW2MhMNinhDdOtENBQHGuA9gM98GLGBuiOEU1aTfOrqA6iqlUIjjuoRKLf2sAXELyBqEb0Hxo2eHFiSoIf0yppWAl3kKp/++wmFpMEkzrtiAjTcsoLiK4OdMgM5rq+3kCL+PYq9ImnxsjhLK/mCaw3dJQpS9/M2mtIE5odA7l2EjGDlxZQ+THF/5IV2yxjZ/0PfabyX7MMe74jNb8oMGD9QVy5nQcZAOL4BDWDLafBAnPe29P8oerW4xv22wP84iCma93ntrFF6qjQkRhYimb23OByftsYpCIP6ibLc810rkwnB2ywENrBM31ZPEgTBmcIoimCQr50fqoMjVAyTEkMnhhby5SxkgpBfSuPBZMB8kUfGaypV/eKf2imxQePg1wcPq0Csmhf9fn7f+scfHdc5gJXqiauEvOQQJosvb+WpaohPzLOI37stxOThCAvafR8vwl7bvtIxPU1yWGQI12CmJI3enXaf4kRY8ZFCsIx1phxiUHAwR+sjtPfBeIx5Ljn9qVEZ1CrEtR2hx1DscVK/3IkP7dEZTlqkKotLW+Mq+8Nm8QB0OoM1kdn1evOvK2qjukW+ILZgdg/8p3kXtMM7LTdfk90S4/xO5SeSDOf02H3zebDwYDlCA3UzdrkrFBSjKeEKifh4Jhe/MlMTYflhlW911DxmjEtKG+hCk6D6dUyIYRRQrs6IQz6DKUvXacjQuUBMzDEfzKIfhBdcot6WB6WprFX71juc4DpkQXjzi+CDjwPzngSQyDxmm6CoR5hdU4z+4i/hEsVMqu5hiCgZk5yhLqMdwycisjuvtfe2cTkBqRrbMraAFQPpV31XfEDi9nK4S5ckCAzQJHlHeOwjU1tKw49SQtDbNWhRWuZzNCcoQqR5c3C02kX0Ywq4A214nTOpKM8VOqe7Syoblr2/v40vBN2U70p6BjNDUvI4saR19RQ227PquOsqENxd+0Jbm2E2cAwOnESoCyo6e/M0/topSuE29ELN8EQyF9nOBRNUPzUmw8beMIabcknJHqFJ+xRUolPVISTrdG1FlSjq0is1X1nDv1x5lrANigQ5Z6Kdnj//Kc0JqeYsuyUPEKRv07kaAWELBwfOCc0vtw64fojgv9R6YLGBTUq2evgbslRMFfXiNzzdhfLD3lbAw45xUJ5vTt62F92HqDJcBRr1UruVwQqP2qiBlMscmv8UoYf8GYXxx0VU2RERptFtDfxqDsKFIJbi/udi+DMAA7RbEAmXqL7cBqinGAH/50aQ8+vK224WWL4OZC9C5QCj7ITPp4kWzuOFN7OSQwG+w7LOFhy/1j25whjRG/0/ZtcFsjimVO2mNVF3UDdMUyTkHHifS6VYssUfUZ5MDYCSRpLbJxIwA+wJYvXFMzx0axb0Wd3SdtWmSd8uXA4dSiBDIZLLynITJfEj0lyVaurZwG40l3edIFYmD8j/LoJZ34Bf4EruNJS8u4yO9EgAWdoPsuswdJ9UcPwUd/nXb2kui+qkarFyTxztSDGd4+CtgOKfvXQPqnkV69UDAMFyhKYA2fUjmt63qSPdl+eedoGPksZLH5O2UvqA6DkIXmIrMy7ILah7MVctTZFifOrz8gJWor6g+jP2r9gWZNyfJsQ9SxOLjB80a5F4BtJu4cwP2q86xN+1BJMYkgGFdr1YjRsDUseupBI99gphtImxTS37zzv5mUb5vwkjDy9v9TINANSTXshzri2F/u7NilE8PAdGqXiiRxE2a4Bp2lL14L7UoymSK0gegbbi2GVX2FkB/PgotdTpZEVw9KPdy2NhqFVNaKqi0ncFXx6dYvJVNV2sgY622C/GVfQvXbzsHxPtZoZ9SBbrWP+cnCLxhv78o8QGYjVx3tL+P7N7lhNy9ki3YSFrSkWyqJdXM2UBFZGrUN0JnXdHo8n6Xh/hzwkAJNHAgW6BrK1Lx2nnV32s2vjS5rljadbmaABUJO+OIkI/4rLJc6cyAkoLgBAVIW1Z3kxeDHRXkDeul6ziv6xyHjgaWMKAWepCgliigG6x6fhXOIESXtOAE7FXv3gsEGuCWccPgS43s2R3eXjeavXF4SViVaqbZu2B4Mj1M3tEzD7IRV/MNB+eaUhOVNkzM8WJLj6R2iVj/pVYDH1dDXPnE+h03Hm3CuGGCdyPxmjMYnefyOmpZWeNVFSda2OG8uXheRp9Ld5Fp+AIoqgIiHAC1VYGqHfSjTU0en3WIit88/ZSdyKF/SWRSctpqSp4aqcsDf4Adi8Z6TeqYVguDcgDg==";
        Program.checkFlag(decryptString);
    }
}

これを実行すると, ctf4b{matryoshka} と表示される.

感想

今振り返ってみると何で解けなかったんだろうという問題ばかりで,あと200ポイントとれば1位になれたのにという悔しさがある.(CTFの度に何で解けなかったと悔しがっている気がする.) それでも2位という結果は残せたのでそれなりには良かったと思う.
CTF4bの運営の皆様,本当にありがとうございました.