こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

SECCON Beginners CTF 2018 - Message from the future

問題文

2020年からメッセージが届きました。
0f242e412b34212e3d65501c2d7e597f47395c0751675a2b13567d5f3c7b6a1d70540a684d604759
メッセージはこのプログラムによって暗号化されています。
添付ファイル:Message_from_the_future_66d0d873b93941f6273326c1ee6c4686dbfca4f5.zip

writeup

添付ファイルを展開すると実行ファイルが1つ。

root@kali:Message from the future# file Message_from_the_future 
Message_from_the_future: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

実行してみる。

root@kali:Message from the future# ./Message_from_the_future
[-] Invalid arguments.

root@kali:Message from the future# ./Message_from_the_future A
6f

root@kali:Message from the future# ./Message_from_the_future AA
6f78

root@kali:Message from the future# ./Message_from_the_future AAA
6f7830

root@kali:Message from the future# ./Message_from_the_future AAAA
6f78303d

root@kali:Message from the future# ./Message_from_the_future AAAAA
6f78303d17

root@kali:Message from the future# ./Message_from_the_future AAAAAA
6f78303d171b

入力した文字列を1文字ずつ暗号化しているようだ。
よって、1文字ずつブルートフォースして、0f242e412b34212e3d65501c2d7e597f47395c0751675a2b13567d5f3c7b6a1d70540a684d604759になる入力文字列を特定できそうだ。

なお、stringsとobjdumpにかけるが、結果がいまいち。
パックされているのだろうか。

ブルートフォースするスクリプトは以下。

import subprocess

encrypted = "0f242e412b34212e3d65501c2d7e597f47395c0751675a2b13567d5f3c7b6a1d70540a684d604759"
flag = ""

while True:
    for e in range(1,255):
        r = subprocess.check_output(["./Message_from_the_future", "{}{}".format(flag, chr(e))])
        if encrypted.startswith(r.decode("utf-8").strip()):
            flag += chr(e)
            print("flag=" + flag)
            break

実行する。

root@kali:Message from the future# python try.py 
flag=!
flag=!
flag=!_
flag=!_=
flag=!_=}
flag=!_=}n
flag=!_=}nb
flag=!_=}nbN
flag=!_=}nbNR
flag=!_=}nbNRG
flag=!_=}nbNRG[
flag=!_=}nbNRG[d
flag=!_=}nbNRG[d!
flag=!_=}nbNRG[d!]
flag=!_=}nbNRG[d!]2
flag=!_=}nbNRG[d!]2
flag=!_=}nbNRG[d!]2{

あれ、うまくいかない。

しばらく手詰りになるが、問題文を見返す。

2020年からメッセージが届きました。

引数以外の要素として、「時間」を使っていると推測する。

システム日時を2020年に変更して実行する。

root@kali:Message from the future# ./Message_from_the_future AAAA
6f78303d
root@kali:Message from the future# date -s "01/01 13:00 2020"
2020年  1月  1日 水曜日 13:00:00 JST
root@kali:Message from the future# ./Message_from_the_future AAAA
48566329

結果が変わった。ビンゴ。
なお、自動時刻同期を切っておく必要があるので注意。

いくつか試すと、年または月を変えると結果が変わり、日付と時間は影響がないようだ。
2020年の1月から順々に試すと、2020年8月で成功した。

root@kali:Message from the future# date -s "08/01 13:00 2020"
2020年  8月  1日 土曜日 13:00:00 JST

root@kali:Message from the future# python try.py 
flag=c
flag=ct
flag=ctf
flag=ctf4
flag=ctf4b
flag=ctf4b{
flag=ctf4b{4
flag=ctf4b{4r
flag=ctf4b{4r3
flag=ctf4b{4r3_
flag=ctf4b{4r3_y
flag=ctf4b{4r3_y0
flag=ctf4b{4r3_y0u
flag=ctf4b{4r3_y0u_
flag=ctf4b{4r3_y0u_l
flag=ctf4b{4r3_y0u_l0
flag=ctf4b{4r3_y0u_l00
flag=ctf4b{4r3_y0u_l00k
flag=ctf4b{4r3_y0u_l00k1
flag=ctf4b{4r3_y0u_l00k1n
flag=ctf4b{4r3_y0u_l00k1n6
flag=ctf4b{4r3_y0u_l00k1n6_
flag=ctf4b{4r3_y0u_l00k1n6_f
flag=ctf4b{4r3_y0u_l00k1n6_f0
flag=ctf4b{4r3_y0u_l00k1n6_f0r
flag=ctf4b{4r3_y0u_l00k1n6_f0rw
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4r
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_7
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_20
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_202
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020_
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020_?
flag=ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020_?}

フラグゲット。
ctf4b{4r3_y0u_l00k1n6_f0rw4rd_70_2020_?}

SECCON Beginners CTF 2018 - Activation

問題文

この問題の FLAG は ctf4b{アクティベーションコード} です。
添付ファイル:Activation_492f6d44cb836cf2cd9279ff3f51d5adc1e132d8.zip

writeup

展開するとexeファイル。実行してみる。 f:id:graneed:20180527192545p:plain

Nextボタンを押下すると強制終了。

fileコマンドで調べると、.Netの実行ファイルであるとわかる。

root@kali:Activation# file Activation.exe 
Activation.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

dnSpyで解析する。
github.com

以下のことがわかる。

  • 画面で入力した文字列をAESで暗号化している。
  • 暗号化のキーとIVは実行ファイル内に保有している。
  • 暗号化したデータをBASE64エンコードし、
    実行ファイル内に保有している文字列と突き合わせしている。

暗号化キーとIVと突き合わせ文字列を確認するため、
dnSpyでデコンパイルされたソースのうち、定数クラスを特定する。
ただ、定数としてそのまま定義されておらず、byte配列から切り出すコードになっていた。
定数の値を出力するよう改造した上で、実行して確認する。

実行したソースはこちら。

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace aaaa
{
    // Token: 0x02000009 RID: 9
    [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
    public class Hoge
    {
        // Token: 0x06000026 RID: 38 RVA: 0x00002584 File Offset: 0x00000784
        private static string get(int A_0, int A_1, int A_2)
        {
            string @string = Encoding.UTF8.GetString(Hoge.raw, A_1, A_2);
            Hoge.datacache[A_0] = @string;
            return @string;
        }

        // Token: 0x06000027 RID: 39 RVA: 0x000025AC File Offset: 0x000007AC
        public static string A()
        {
            return Hoge.datacache[0] ?? Hoge.get(0, 0, 15);
        }

        // Token: 0x06000028 RID: 40 RVA: 0x000025C2 File Offset: 0x000007C2
        public static string a()
        {
            return Hoge.datacache[1] ?? Hoge.get(1, 15, 35);
        }

        // Token: 0x06000029 RID: 41 RVA: 0x000025D9 File Offset: 0x000007D9
        public static string B()
        {
            return Hoge.datacache[2] ?? Hoge.get(2, 50, 35);
        }

        // Token: 0x0600002A RID: 42 RVA: 0x000025F0 File Offset: 0x000007F0
        public static string b()
        {
            return Hoge.datacache[3] ?? Hoge.get(3, 85, 18);
        }

        // Token: 0x0600002B RID: 43 RVA: 0x00002607 File Offset: 0x00000807
        public static string C()
        {
            return Hoge.datacache[4] ?? Hoge.get(4, 103, 8);
        }

        // Token: 0x0600002C RID: 44 RVA: 0x0000261D File Offset: 0x0000081D
        public static string c()
        {
            return Hoge.datacache[5] ?? Hoge.get(5, 111, 16);
        }

        // Token: 0x0600002D RID: 45 RVA: 0x00002634 File Offset: 0x00000834
        public static string D()
        {
            return Hoge.datacache[6] ?? Hoge.get(6, 127, 3);
        }

        // Token: 0x0600002E RID: 46 RVA: 0x0000264A File Offset: 0x0000084A
        public static string d()
        {
            return Hoge.datacache[7] ?? Hoge.get(7, 130, 21);
        }

        // Token: 0x0600002F RID: 47 RVA: 0x00002664 File Offset: 0x00000864
        public static string E()
        {
            return Hoge.datacache[8] ?? Hoge.get(8, 151, 5);
        }

        // Token: 0x06000030 RID: 48 RVA: 0x0000267D File Offset: 0x0000087D
        public static string e()
        {
            return Hoge.datacache[9] ?? Hoge.get(9, 156, 29);
        }

        // Token: 0x06000031 RID: 49 RVA: 0x00002699 File Offset: 0x00000899
        public static string F()
        {
            return Hoge.datacache[10] ?? Hoge.get(10, 185, 64);
        }

        // Token: 0x06000032 RID: 50 RVA: 0x000026B5 File Offset: 0x000008B5
        public static string f()
        {
            return Hoge.datacache[11] ?? Hoge.get(11, 249, 10);
        }

        // Token: 0x06000033 RID: 51 RVA: 0x000026D1 File Offset: 0x000008D1
        public static string G()
        {
            return Hoge.datacache[12] ?? Hoge.get(12, 259, 11);
        }

        // Token: 0x06000034 RID: 52 RVA: 0x000026ED File Offset: 0x000008ED
        public static string g()
        {
            return Hoge.datacache[13] ?? Hoge.get(13, 270, 27);
        }

        // Token: 0x06000035 RID: 53 RVA: 0x00002709 File Offset: 0x00000909
        public static string H()
        {
            return Hoge.datacache[14] ?? Hoge.get(14, 297, 37);
        }

        // Token: 0x06000036 RID: 54 RVA: 0x00002725 File Offset: 0x00000925
        public static string h()
        {
            return Hoge.datacache[15] ?? Hoge.get(15, 334, 11);
        }

        // Token: 0x06000037 RID: 55 RVA: 0x00002744 File Offset: 0x00000944
        static Hoge()
        {
            // Note: this type is marked as 'beforefieldinit'.
            Hoge.raw = new byte[]
            {
                231,
                202,
                193,
                199,
                249,
                198,
                194,
                201,
                205,
                212,
                142,
                217,
                199,
                202,
                200,
                138,
                251,
                216,
                204,
                208,
                200,
                222,
                200,
                212,
                221,
                221,
                139,
                210,
                217,
                218,
                196,
                218,
                228,
                238,
                230,
                253,
                161,
                230,
                226,
                253,
                247,
                247,
                226,
                238,
                254,
                169,
                252,
                228,
                247,
                247,
                219,
                245,
                247,
                252,
                247,
                189,
                176,
                221,
                245,
                233,
                226,
                181,
                180,
                225,
                133,
                203,
                155,
                157,
                143,
                157,
                152,
                205,
                131,
                128,
                148,
                136,
                144,
                134,
                144,
                140,
                149,
                149,
                214,
                243,
                244,
                188,
                148,
                152,
                145,
                152,
                208,
                133,
                158,
                146,
                212,
                145,
                163,
                184,
                163,
                231,
                224,
                225,
                198,
                142,
                150,
                133,
                244,
                131,
                241,
                130,
                245,
                150,
                159,
                152,
                155,
                150,
                144,
                128,
                158,
                152,
                149,
                154,
                158,
                159,
                147,
                133,
                135,
                byte.MaxValue,
                4,
                1,
                108,
                64,
                93,
                68,
                12,
                68,
                81,
                3,
                78,
                78,
                82,
                7,
                77,
                75,
                73,
                94,
                74,
                77,
                91,
                91,
                18,
                120,
                64,
                65,
                95,
                67,
                117,
                95,
                81,
                86,
                97,
                43,
                124,
                97,
                107,
                47,
                109,
                110,
                118,
                106,
                118,
                96,
                114,
                110,
                107,
                107,
                58,
                120,
                119,
                125,
                123,
                49,
                50,
                51,
                24,
                86,
                35,
                114,
                38,
                94,
                113,
                115,
                9,
                8,
                90,
                16,
                59,
                45,
                89,
                10,
                20,
                51,
                55,
                6,
                3,
                86,
                18,
                45,
                43,
                48,
                83,
                45,
                60,
                10,
                41,
                36,
                8,
                32,
                36,
                70,
                30,
                35,
                95,
                35,
                56,
                27,
                12,
                33,
                36,
                13,
                56,
                125,
                10,
                0,
                1,
                46,
                115,
                1,
                8,
                42,
                50,
                61,
                43,
                118,
                42,
                109,
                10,
                59,
                103,
                18,
                51,
                37,
                63,
                33,
                53,
                33,
                207,
                207,
                134,
                224,
                192,
                201,
                195,
                223,
                207,
                194,
                212,
                200,
                201,
                201,
                229,
                198,
                206,
                210,
                206,
                216,
                202,
                214,
                211,
                211,
                146,
                208,
                223,
                213,
                211,
                151,
                221,
                198,
                170,
                226,
                230,
                byte.MaxValue,
                239,
                227,
                229,
                233,
                172,
                172,
                193,
                226,
                242,
                238,
                242,
                228,
                238,
                242,
                247,
                247,
                165,
                252,
                243,
                240,
                226,
                252,
                254,
                244,
                248,
                227,
                187,
                248,
                139,
                130,
                134,
                158,
                135,
                129,
                136,
                130,
                149,
                205,
                152,
                128,
                139,
                139,
                183,
                145,
                155,
                143,
                141,
                138,
                178,
                158,
                158,
                152,
                158
            };
            for (int i = 0; i < Hoge.raw.Length; i++)
            {
                Hoge.raw[i] = (byte)((int)Hoge.raw[i] ^ i ^ 170);
            }
        }

        // Token: 0x0400000F RID: 15
        internal static byte[] raw;

        // Token: 0x04000010 RID: 16
        internal static string[] datacache = new string[16];
        
        public static void Main()
        {
            Console.WriteLine("A=" + A());
            Console.WriteLine("a=" + a());
            Console.WriteLine("B=" + B());
            Console.WriteLine("b=" + b());
            Console.WriteLine("C=" + C());
            Console.WriteLine("c=" + c());
            Console.WriteLine("D=" + D());
            Console.WriteLine("d=" + d());
            Console.WriteLine("E=" + E());
            Console.WriteLine("e=" + e());
            Console.WriteLine("F=" + F());
            Console.WriteLine("f=" + f());
            Console.WriteLine("G=" + G());
            Console.WriteLine("g=" + g());
            Console.WriteLine("H=" + H());
            Console.WriteLine("h=" + h());

        }
    }
}

環境用意が面倒なのでオンライン実行可能な.NET Fiddleを利用する。
dotnetfiddle.net

実行結果は以下の通り。.NET Fiddle上で実行可能なリンクも載せておく。
https://dotnetfiddle.net/7vFygo

A=MainWindow.xaml
a=/Activation;component/inputbox.xaml
B=Click "Next" to start activation.


b=Check the disk...

C=CTF4B7E1
c=SECCON_BEGINNERS
D=*.*
d=Disk is not inserted.
E=Error
e=Check the activation code...

F=E3c0Iefcc2yUB5gvPWge1vHQK+TBuUYzST7hT+VrPDhjBt0HCAo5FLohfs/t2Vf5
f=Activated.
G=Information
g=Activation code is invalid.
H=/Activation;component/mainwindow.xaml
h=StatusLabel

次に、AES暗号化しているコードを確認する。

// A.a
// Token: 0x0600000D RID: 13 RVA: 0x000020E8 File Offset: 0x000002E8
public string C()
{
    AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider();
    aesCryptoServiceProvider.BlockSize = 128;
    aesCryptoServiceProvider.KeySize = 256;
    aesCryptoServiceProvider.IV = this.b();
    aesCryptoServiceProvider.Key = this.B();
    aesCryptoServiceProvider.Mode = CipherMode.ECB;
    aesCryptoServiceProvider.Padding = PaddingMode.PKCS7;
    byte[] bytes = Encoding.ASCII.GetBytes(this.A());
    byte[] inArray = aesCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);
    this.a(Convert.ToBase64String(inArray));
    return this.a();
}

このメソッドへの値の受け渡しを解析した結果を以下に整理する。

  • 暗号化対象のthis.A()は、入力したアクティベーションコードの文字列。
  • IVにセットするthis.b()は、定数Cを2回繰り返した文字列。
  • Keyにセットするthis.B()は、定数cの文字列。
  • メソッドがリターンする文字列を定数Fと突き合わせしている。

よって、定数FをBase64デコードしてAES復号すればよさそうだ。
復号コードは以下のとおり。

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class Program
{
    public static void Main()
    {
        var plainText = string.Empty;
        var cipherText = "E3c0Iefcc2yUB5gvPWge1vHQK+TBuUYzST7hT+VrPDhjBt0HCAo5FLohfs/t2Vf5";
     
        var csp = new AesCryptoServiceProvider();
        csp.BlockSize = 128;
        csp.KeySize = 256;
        csp.Mode = CipherMode.ECB;
        csp.Padding = PaddingMode.PKCS7;
        csp.IV = Encoding.ASCII.GetBytes("CTF4B7E1CTF4B7E1");
        csp.Key = Encoding.ASCII.GetBytes("SECCON_BEGINNERS");
     
        using (var inms = new MemoryStream(Convert.FromBase64String(cipherText)))
        using (var decryptor = csp.CreateDecryptor())
        using (var cs = new CryptoStream(inms, decryptor, CryptoStreamMode.Read))
        using (var reader = new StreamReader(cs))
        {
            plainText = reader.ReadToEnd();
        }
     
        Console.WriteLine(plainText);
    }
}

実行結果は以下の通り。こちらも.NET Fiddle上で実行可能なリンクも載せておく。
https://dotnetfiddle.net/VKMTVa

ae03c6f3f9c13e6ee678a92fc2e2dcc5

フラグゲット。
ctf4b{ae03c6f3f9c13e6ee678a92fc2e2dcc5}

SECCON Beginners CTF 2018 - [Warmup] Simple Auth

問題文

認証に使われているパスワードを探せ!
添付ファイル:Simple_Auth_d6d1615ec0ca18b0e911467b58c0d8e0a4b306fa.zip

writeup

添付ファイルを展開すると、simple_authのファイル。
まずはfileコマンドで調べる。

root@kali:[Warmup] Simple Auth# file simple_auth 
simple_auth: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=12f26187ec09ac8c5d933f75e41cc68e7f544862, not stripped

実行してみる。

root@kali:[Warmup] Simple Auth# ./simple_auth 
Input Password: AAAA
Umm...Auth failed...

ltraceで実行してみる。

root@kali:[Warmup] Simple Auth# ltrace -f ./simple_auth 
[pid 21622] __libc_start_main(0x400792, 1, 0x7ffc53f12eb8, 0x400830 <unfinished ...>
[pid 21622] printf("Input Password: ")                                                                         = 16
[pid 21622] __isoc99_scanf(0x4008c5, 0x7ffc53f12da0, 0, 0Input Password: AAAA
)                                                     = 1
[pid 21622] strlen("AAAA")                                                                                     = 4
[pid 21622] strlen("ctf4b{rev3rsing_p4ssw0rd}")                                                                = 25
[pid 21622] puts("Umm...Auth failed..."Umm...Auth failed...
)                                                                       = 21
[pid 21622] +++ exited (status 0) +++

フラグゲット。
ctf4b{rev3rsing_p4ssw0rd}