LoginSignup
0
0

More than 3 years have passed since last update.

SECCON 2020 OnlineCTF writeup (SCSBX:Reversing)

Last updated at Posted at 2020-10-11

SECCON CTF 2020 のお知らせ (CTF 参加方法等) - SECCON2020
SECCON 2020 OnlineCTFに一人チームで参戦しました。
結果は246点で、579チーム中92位でした。
今回、WelcomeとSurveyを除くと、残念ながら1問しか解くことができませんでした…
なんとか一矢報いることができた、ともいえるが…
warmup?逆に冷えたわ…
成績グラフ

Welcome

言われたとおりにルールを読んでDiscordを見ます。
問題文には"announcement channel"とありますが、実際のチャンネル名は#announcementsでした。
flagは画面上部にあり、右クリック→「トピックをコピー」でコピーできました。

SECCON{Welcome to the SECCON 2020 Online CTF}

SCSBX:Reversing

独自と思われる仮想マシンのソースコードと、それに与えるプログラムのバイナリデータが与えられました。
ソースコードを見ると、これはスタックマシンであり、
PUSH命令(1バイト+数値4バイト=5バイト)を除く全ての命令が1バイトで表されるようでした。
各命令の具体的な動作はinstr_*.cppを、命令とバイトの値の対応はscsbx.hppをみればわかるようでした。
そこで、まずはこの仮想マシン用のバイナリデータを逆アセンブルしました。

逆アセンブラ
decode.c
#include <stdio.h>
#include <inttypes.h>

int main(int argc, char* argv[]) {
    int i;
    unsigned int cnt = 0;
    FILE* fp;
    if (argc < 2) return 1;
    fp = fopen(argv[1], "rb");
    if (fp == NULL) return 2;
    while ((i = getc(fp)) != EOF) {
        printf("%08X : ", cnt);
        switch (i) {
            case 0x20:
                {
                    uint32_t value = 0;
                    fread(&value, sizeof(value), 1, fp);
                    printf("PUSH 0x%08" PRIX32 "\n", value);
                    cnt += 4;
                }
                break;
            case 0x21: puts("POP"); break;
            case 0x22: puts("DUP"); break;
            case 0x23: puts("XCHG"); break;
            case 0x24: puts("LOAD32"); break;
            case 0x25: puts("LOAD64"); break;
            case 0x26: puts("STORE8"); break;
            case 0x27: puts("STORE16"); break;
            case 0x28: puts("STORE32"); break;
            case 0x70: puts("SHOW"); break;

            case 0x30: puts("JMP"); break;
            case 0x31: puts("JEQ"); break;
            case 0x32: puts("JGT"); break;
            case 0x33: puts("JGE"); break;
            case 0x34: puts("CALL"); break;

            case 0x40: puts("ADD"); break;
            case 0x41: puts("SUB"); break;
            case 0x42: puts("MUL"); break;
            case 0x43: puts("DIV"); break;
            case 0x44: puts("MOD"); break;

            case 0x50: puts("NOT"); break;
            case 0x51: puts("AND"); break;
            case 0x52: puts("OR"); break;
            case 0x53: puts("XOR"); break;
            case 0x54: puts("SHL"); break;
            case 0x55: puts("SHR"); break;
            case 0x56: puts("ROL"); break;
            case 0x57: puts("ROR"); break;

            case 0x60: puts("READ"); break;
            case 0x61: puts("WRITE"); break;
            case 0x62: puts("MAP"); break;
            case 0x63: puts("UNMAP"); break;
            case 0x64: puts("EXIT"); break;

            default: printf("DB 0x%02X\n", i);
        }
        cnt++;
    }
    fclose(fp);
    return 0;
}

逆アセンブル結果
decoded.txt
00000000 : PUSH 0x00001000
00000005 : PUSH 0xDEAD0000
0000000A : MAP
0000000B : PUSH 0x00000256
00000010 : CALL
00000011 : PUSH 0x0000020A
00000016 : CALL
00000017 : PUSH 0x47414C46
0000001C : PUSH 0xDEAD0004
00000021 : STORE32
00000022 : PUSH 0x0000203A
00000027 : PUSH 0xDEAD0008
0000002C : STORE16
0000002D : PUSH 0x00000006
00000032 : PUSH 0xDEAD0004
00000037 : WRITE
00000038 : PUSH 0x00000040
0000003D : PUSH 0xDEAD000A
00000042 : READ
00000043 : PUSH 0x00000008
00000048 : PUSH 0x0000010E
0000004D : JMP
0000004E : PUSH 0x00000000
00000053 : DUP
00000054 : PUSH 0x00000008
00000059 : SUB
0000005A : PUSH 0x00000008
0000005F : MUL
00000060 : PUSH 0x00000000
00000065 : DUP
00000066 : PUSH 0xDEAD000A
0000006B : ADD
0000006C : PUSH 0x00000000
00000071 : DUP
00000072 : LOAD32
00000073 : PUSH 0x00000000
00000078 : XCHG
00000079 : PUSH 0x00000002
0000007E : XCHG
0000007F : PUSH 0xDEAD000E
00000084 : ADD
00000085 : PUSH 0x00000000
0000008A : DUP
0000008B : PUSH 0x00000003
00000090 : XCHG
00000091 : PUSH 0x00000001
00000096 : XCHG
00000097 : LOAD32
00000098 : PUSH 0x00000003
0000009D : PUSH 0x000000DD
000000A2 : JMP
000000A3 : PUSH 0x00000002
000000A8 : DUP
000000A9 : PUSH 0x00000002
000000AE : DUP
000000AF : PUSH 0x00000000
000000B4 : DUP
000000B5 : PUSH 0x00000216
000000BA : CALL
000000BB : PUSH 0x00000002
000000C0 : DUP
000000C1 : XOR
000000C2 : PUSH 0x00000004
000000C7 : XCHG
000000C8 : POP
000000C9 : PUSH 0x00000004
000000CE : XCHG
000000CF : POP
000000D0 : POP
000000D1 : PUSH 0x00000001
000000D6 : PUSH 0x00000001
000000DB : XCHG
000000DC : SUB
000000DD : PUSH 0x00000000
000000E2 : DUP
000000E3 : PUSH 0x00000000
000000E8 : PUSH 0x000000A3
000000ED : PUSH 0x000000F3
000000F2 : JEQ
000000F3 : PUSH 0x00000004
000000F8 : XCHG
000000F9 : STORE32
000000FA : PUSH 0x00000001
000000FF : XCHG
00000100 : STORE32
00000101 : POP
00000102 : PUSH 0x00000001
00000107 : PUSH 0x00000001
0000010C : XCHG
0000010D : SUB
0000010E : PUSH 0x00000000
00000113 : DUP
00000114 : PUSH 0x00000000
00000119 : PUSH 0x0000004E
0000011E : PUSH 0x00000124
00000123 : JEQ
00000124 : POP
00000125 : PUSH 0x00000000
0000012A : PUSH 0x00000008
0000012F : PUSH 0x00000195
00000134 : JMP
00000135 : PUSH 0x00000000
0000013A : DUP
0000013B : PUSH 0x00000001
00000140 : PUSH 0x00000001
00000145 : XCHG
00000146 : SUB
00000147 : PUSH 0x00000008
0000014C : MUL
0000014D : PUSH 0xDEAD000A
00000152 : ADD
00000153 : PUSH 0x00000000
00000158 : DUP
00000159 : PUSH 0x00000040
0000015E : ADD
0000015F : LOAD64
00000160 : PUSH 0x00000002
00000165 : XCHG
00000166 : LOAD64
00000167 : PUSH 0x00000002
0000016C : XCHG
0000016D : SUB
0000016E : PUSH 0x00000002
00000173 : XCHG
00000174 : SUB
00000175 : OR
00000176 : PUSH 0x00000001
0000017B : XCHG
0000017C : PUSH 0x00000002
00000181 : XCHG
00000182 : OR
00000183 : PUSH 0x00000001
00000188 : XCHG
00000189 : PUSH 0x00000001
0000018E : PUSH 0x00000001
00000193 : XCHG
00000194 : SUB
00000195 : PUSH 0x00000000
0000019A : DUP
0000019B : PUSH 0x00000000
000001A0 : PUSH 0x00000135
000001A5 : PUSH 0x000001AB
000001AA : JEQ
000001AB : PUSH 0x000001B6
000001B0 : PUSH 0x000001DD
000001B5 : JEQ
000001B6 : PUSH 0x6E6F7257
000001BB : PUSH 0xDEAD0000
000001C0 : STORE32
000001C1 : PUSH 0x0A212167
000001C6 : PUSH 0xDEAD0004
000001CB : STORE32
000001CC : PUSH 0x00000008
000001D1 : PUSH 0xDEAD0000
000001D6 : WRITE
000001D7 : PUSH 0x00000204
000001DC : JMP
000001DD : PUSH 0x72726F43
000001E2 : PUSH 0xDEAD0000
000001E7 : STORE32
000001E8 : PUSH 0x0A746365
000001ED : PUSH 0xDEAD0004
000001F2 : STORE32
000001F3 : PUSH 0x00000008
000001F8 : PUSH 0xDEAD0000
000001FD : WRITE
000001FE : PUSH 0x00000204
00000203 : JMP
00000204 : PUSH 0x00000000
00000209 : EXIT
0000020A : PUSH 0x06D35BCD
0000020F : PUSH 0xDEAD0000
00000214 : STORE32
00000215 : JMP
00000216 : PUSH 0xDEAD0000
0000021B : LOAD32
0000021C : PUSH 0x0000077F
00000221 : MUL
00000222 : PUSH 0x0000032A
00000227 : PUSH 0x00000001
0000022C : XCHG
0000022D : SUB
0000022E : PUSH 0x305EB3EA
00000233 : PUSH 0x00000001
00000238 : XCHG
00000239 : MOD
0000023A : PUSH 0x00000000
0000023F : DUP
00000240 : PUSH 0xDEAD0000
00000245 : STORE32
00000246 : PUSH 0x00000002
0000024B : DUP
0000024C : XOR
0000024D : NOT
0000024E : PUSH 0x00000002
00000253 : XCHG
00000254 : POP
00000255 : JMP
00000256 : PUSH 0x46761223
0000025B : PUSH 0xDEAD004A
00000260 : STORE32
00000261 : PUSH 0x54BEA5C5
00000266 : PUSH 0xDEAD004E
0000026B : STORE32
0000026C : PUSH 0x7A22E8F6
00000271 : PUSH 0xDEAD0052
00000276 : STORE32
00000277 : PUSH 0x5DB493C9
0000027C : PUSH 0xDEAD0056
00000281 : STORE32
00000282 : PUSH 0x055D175E
00000287 : PUSH 0xDEAD005A
0000028C : STORE32
0000028D : PUSH 0x022FCD33
00000292 : PUSH 0xDEAD005E
00000297 : STORE32
00000298 : PUSH 0x42C46BE6
0000029D : PUSH 0xDEAD0062
000002A2 : STORE32
000002A3 : PUSH 0x6D10A0E8
000002A8 : PUSH 0xDEAD0066
000002AD : STORE32
000002AE : PUSH 0x53F4C278
000002B3 : PUSH 0xDEAD006A
000002B8 : STORE32
000002B9 : PUSH 0x7279EC2A
000002BE : PUSH 0xDEAD006E
000002C3 : STORE32
000002C4 : PUSH 0x5491FB39
000002C9 : PUSH 0xDEAD0072
000002CE : STORE32
000002CF : PUSH 0x49AC421F
000002D4 : PUSH 0xDEAD0076
000002D9 : STORE32
000002DA : PUSH 0x49AB3A37
000002DF : PUSH 0xDEAD007A
000002E4 : STORE32
000002E5 : PUSH 0x47855812
000002EA : PUSH 0xDEAD007E
000002EF : STORE32
000002F0 : PUSH 0x5718BB05
000002F5 : PUSH 0xDEAD0082
000002FA : STORE32
000002FB : PUSH 0x0540FB5B
00000300 : PUSH 0xDEAD0086
00000305 : STORE32
00000306 : JMP

さらに、読みやすくなるように、PUSHの直後の命令でpushした値を使用するパターンを1行にまとめ、
ジャンプ先になっている場所にラベルを置き、
ラベルを起点としたスタックの状態の変化、およびその他の情報をコメントしました。

読みやすくした結果
rewrite.txt
00000000 : MAP 0xDEAD0000, 0x00001000
00000010 : CALL 0x00000256 (init)
00000016 : CALL 0x0000020A (init2)
00000021 : STORE32 0xDEAD0004, 0x47414C46
0000002C : STORE16 0xDEAD0008, 0x0000203A
00000037 : WRITE 0xDEAD0004, 6 /* FLAG:  */
00000042 : READ 0xDEAD000A, 64
00000043 : PUSH 8
0000004D : JMP 0x0000010E (start) /* 8 */
hoge1:
00000053 : DUP 0 /* [top] [top] */
00000059 : SUB 8 /* [top] (8 - [top]) */
0000005F : MUL 8 /* [top] ((8 - [top]) * 8) */
00000065 : DUP 0 /* [top] ((8 - [top]) * 8) ((8 - [top]) * 8) */
0000006B : ADD 0xDEAD000A /* [top] ((8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) */
00000071 : DUP 0
00000072 : LOAD32 /* [top] ((8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) [data A] */
00000078 : XCHG 0 /* [top] ((8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) [data A] */
0000007E : XCHG 2 /* [top] [data A] (0xDEAD000A + (8 - [top]) * 8) ((8 - [top]) * 8) */
00000084 : ADD 0xDEAD000E /* [top] [data A] (0xDEAD000A + (8 - [top]) * 8) (0xDEAD000E + (8 - [top]) * 8) */
0000008A : DUP 0 /* [top] [data A] (0xDEAD000A + (8 - [top]) * 8) (0xDEAD000E + (8 - [top]) * 8) (0xDEAD000E + (8 - [top]) * 8) */
00000090 : XCHG 3 /* [top] (0xDEAD000E + (8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) (0xDEAD000E + (8 - [top]) * 8) [data A] */
00000096 : XCHG 1 /* [top] (0xDEAD000E + (8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) [data A] (0xDEAD000E + (8 - [top]) * 8) */
00000097 : LOAD32 /* [top] (0xDEAD000E + (8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) [data A] [data E] */
00000098 : PUSH 3 /* [top] (0xDEAD000E + (8 - [top]) * 8) (0xDEAD000A + (8 - [top]) * 8) [data A] [data E] 3 */
000000A2 : JMP 0x000000DD (hoge4)
hoge5:
000000A8 : DUP 2 /* [top3] [top2] [top] [top3] */
000000AE : DUP 2 /* [top3] [top2] [top] [top3] [top2] */
000000B4 : DUP 0 /* [top3] [top2] [top] [top3] [top2] [top2] */
000000BA : CALL 0x00000216 (fuga) /* [top3] [top2] [top] [top3] [top2] (~([top2] ^ xvalue)) */
000000C0 : DUP 2 /* [top3] [top2] [top] [top3] [top2] (~([top2] ^ xvalue)) [top3] */
000000C1 : XOR /* [top3] [top2] [top] [top3] [top2] ([top3] ^ ~([top2] ^ xvalue)) */
000000C7 : XCHG 4 /* [top3] ([top3] ^ ~([top2] ^ xvalue)) [top] [top3] [top2] [top2] */
000000C8 : POP /* [top3] ([top3] ^ ~([top2] ^ xvalue)) [top] [top3] [top2] */
000000CE : XCHG 4 /* [top2] ([top3] ^ ~([top2] ^ xvalue)) [top] [top3] [top3] */
000000CF : POP
000000D0 : POP /* [top2] ([top3] ^ ~([top2] ^ xvalue)) [top] */
000000D1 : PUSH 1
000000DB : XCHG 1
000000DC : SUB /* [top2] ([top3] ^ ~([top2] ^ xvalue)) ([top] - 1) */
hoge4:
000000E2 : DUP 0 /* [top6] [top5] [top4] [top3] [top2] [top] [top] */
000000F2 : JEQ 0x000000F3, 0x000000A3, 0 /* if [top != 0] goto hoge5 */
000000F8 : XCHG 4 /* [top6] [top] [top4] [top3] [top2] [top5] */
000000F9 : STORE32 ([top2] -> address [top5]) /* [top6] [top] [top4] [top3] */
000000FF : XCHG 1 /* [top6] [top] [top3] [top4] */
00000100 : STORE32 ([top3] -> address [top4]) /* [top6] [top] */
00000101 : POP
00000102 : PUSH 1
0000010C : XCHG 1
0000010D : SUB /* ([top6] - 1) */
start:
00000113 : DUP 0 /* [top] [top] */
00000123 : JEQ 0x00000124, 0x0000004E (hoge1), 0 /* if [top] != 0 goto hoge1 */
00000124 : POP
00000125 : PUSH 0
0000012A : PUSH 8
00000134 : JMP 0x00000195 (judge)
hoge3:
0000013A : DUP 0 /* [top2] [top] [top] */
0000013B : PUSH 1
00000145 : XCHG 1
00000146 : SUB /* [top2] [top] ([top] - 1) */
0000014C : MUL 8
00000152 : ADD 0xDEAD000A
00000158 : DUP 0 /* [top2] [top] (0xDEAD000A + 8 * ([top] - 1)) (0xDEAD000A + 8 * ([top] - 1)) */
0000015E : ADD 64
0000015F : LOAD64 /* [top2] [top] (0xDEAD000A + 8 * ([top] - 1)) [data 68] [data 64] */
00000165 : XCHG 2 /* [top2] [top] [data 64] [data 68] (0xDEAD000A + 8 * ([top] - 1)) */
00000166 : LOAD64 /* [top2] [top] [data 64] [data 68] [data 4] [data 0] */
0000016C : XCHG 2 /* [top2] [top] [data 64] [data 0] [data 4] [data 68] */
0000016D : SUB /* [top2] [top] [data 64] [data 0] ([data 68] - [data 4]) */
00000173 : XCHG 2 /* [top2] [top] ([data 68] - [data 4]) [data 0] [data 64] */
00000174 : SUB /* [top2] [top] ([data 68] - [data 4]) ([data 64] - [data 0]) */
00000175 : OR /* [top2] [top] (([data 68] - [data 4]) | ([data 64] - [data 0])) */
0000017B : XCHG 1 /* [top2] (([data 68] - [data 4]) | ([data 64] - [data 0])) [top] */
00000181 : XCHG 2 /* [top] (([data 68] - [data 4]) | ([data 64] - [data 0])) [top2] */
00000182 : OR /* [top] (([data 68] - [data 4]) | ([data 64] - [data 0]) | [top2]) */
00000188 : XCHG 1 /* (([data 68] - [data 4]) | ([data 64] - [data 0]) | [top2]) [top] */
00000189 : PUSH 1
00000193 : XCHG 1 /* (([data 68] - [data 4]) | ([data 64] - [data 0]) | [top2]) 1 [top] */
00000194 : SUB /* (([data 68] - [data 4]) | ([data 64] - [data 0]) | [top2]) ([top] - 1) */
judge:
0000019A : DUP 0
000001AA : JEQ 0x000001AB, 0x00000135 (hoge3), 0
000001B5 : JEQ 0x000001DD (accepted), 0x000001B6, [stack top]
000001C0 : STORE32 0xDEAD0000, 0x6E6F7257
000001CB : STORE32 0xDEAD0004, 0x0A212167
000001D6 : WRITE 0xDEAD0000, 8 /* Wrong!! */
000001DC : JMP 0x00000204 (owari)
accepted:
000001E7 : STORE32 0xDEAD0000, 0x72726F43
000001F2 : STORE32 0xDEAD0004, 0x0A746365
000001FD : WRITE 0xDEAD0000, 8 /* Correct */
00000203 : JMP 0x00000204 (owari)
owari:
00000209 : EXIT 0
init2:
00000214 : STORE32 0xDEAD0000, 0x06D35BCD
00000215 : JMP /* ret */
fuga:
0000021B : LOAD32 0xDEAD0000 /* [data 0] */
00000221 : MUL 0x77F /* ([data 0] * 0x77F) */
00000222 : PUSH 0x32A /* ([data 0] * 0x77F) 0x32A */
0000022C : XCHG 1 /* 0x32A ([data 0] * 0x77F) */
0000022D : SUB /* (([data 0] * 0x77F) - 0x32A) */
0000022E : PUSH 0x305EB3EA
00000238 : XCHG 1
00000239 : MOD /* ((([data 0] * 0x77F) - 0x32A) % 0x305EB3EA) -> [xvalue] */
0000023F : DUP 0
00000245 : STORE32 0xDEAD0000
0000024B : DUP 2 /* [arg] [ret] [xvalue] [arg] */
0000024C : XOR /* [arg] [ret] ([arg] ^ [xvalue]) */
0000024D : NOT /* [arg] [ret] ~([arg] ^ [xvalue]) */
00000253 : XCHG 2 /* ~([arg] ^ [top]) [top1] [arg] */
00000254 : POP /* ~([arg] ^ [top]) [ret] */
00000255 : JMP /* ret */
init:
00000260 : STORE32 0xDEAD004A, 0x46761223
0000026B : STORE32 0xDEAD004E, 0x54BEA5C5
00000276 : STORE32 0xDEAD0052, 0x7A22E8F6
00000281 : STORE32 0xDEAD0056, 0x5DB493C9
0000028C : STORE32 0xDEAD005A, 0x055D175E
00000297 : STORE32 0xDEAD005E, 0x022FCD33
000002A2 : STORE32 0xDEAD0062, 0x42C46BE6
000002AD : STORE32 0xDEAD0066, 0x6D10A0E8
000002B8 : STORE32 0xDEAD006A, 0x53F4C278
000002C3 : STORE32 0xDEAD006E, 0x7279EC2A
000002CE : STORE32 0xDEAD0072, 0x5491FB39
000002D9 : STORE32 0xDEAD0076, 0x49AC421F
000002E4 : STORE32 0xDEAD007A, 0x49AB3A37
000002EF : STORE32 0xDEAD007E, 0x47855812
000002FA : STORE32 0xDEAD0082, 0x5718BB05
00000305 : STORE32 0xDEAD0086, 0x0540FB5B
00000306 : JMP /* ret */

斎藤千和は関係ない

これに基づいて、ジャンプ元とジャンプ先でのスタックの対応関係などをみて、頑張って考えると、
以下のような処理に相当するということがわかりました。

相当する処理
rewrite2.c
#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint32_t xvalue = UINT32_C(0x06D35BCD);
    uint32_t DEAD000A[16] = {0};
    uint32_t DEAD004A[16] = {
        UINT32_C(0x46761223), UINT32_C(0x54BEA5C5), UINT32_C(0x7A22E8F6), UINT32_C(0x5DB493C9),
        UINT32_C(0x055D175E), UINT32_C(0x022FCD33), UINT32_C(0x42C46BE6), UINT32_C(0x6D10A0E8),
        UINT32_C(0x53F4C278), UINT32_C(0x7279EC2A), UINT32_C(0x5491FB39), UINT32_C(0x49AC421F),
        UINT32_C(0x49AB3A37), UINT32_C(0x47855812), UINT32_C(0x5718BB05), UINT32_C(0x0540FB5B)
    };
    int main_cnt, sub_cnt;
    uint64_t judge_value;
    printf("FLAG: ");
    fread(DEAD000A, 1, 64, stdin);
    for (main_cnt = 8; main_cnt > 0; main_cnt--) {
        /* hoge1 */
        uint32_t dataA = DEAD000A[(8 - main_cnt) * 2];
        uint32_t dataE = DEAD000A[(8 - main_cnt) * 2 + 1];
        /* hoge4, hoge5 */
        for (sub_cnt = 3; sub_cnt > 0; sub_cnt--) {
            uint32_t top3, top2;
            xvalue = (((xvalue * 0x77F) - 0x32A) % 0x305EB3EA);
            top3 = dataE;
            top2 = dataA ^ ~(dataE ^ xvalue);
            dataA = top3;
            dataE = top2;
        }
        DEAD000A[(8 - main_cnt) * 2 + 1] = dataE;
        DEAD000A[(8 - main_cnt) * 2] = dataA;
    }
    judge_value = 0;
    for (main_cnt = 8; main_cnt > 0; main_cnt--) {
        judge_value |=
            (DEAD004A[2 * (main_cnt - 1) + 1] - DEAD000A[2 * (main_cnt - 1) + 1]) |
            (DEAD004A[2 * (main_cnt - 1)] - DEAD000A[2 * (main_cnt - 1)]);
    }
    if (judge_value == 0) {
        puts("Correct");
    } else {
        puts("Wrong!!");
    }
    return 0;
}

ここから、以下のことがわかります。

  • 入力データは0xDEAD0004からの64バイトに格納され、その後変換をされる
  • 変換された入力データは0xDEAD004Aからの64バイトと比較され、一致したらCorrectが出力される
  • 変換は8バイトごとに行われ、他の8バイトの値は影響しない
  • xvalue (0xDEAD0000) の値は、入力データの影響を受けない

これに基づき、まずそれぞれのタイミングでxvalueの値がどうなるかを計算し、
それを用いてなるべき値から入力の値を逆算します。

逆算するプログラム
reverse.c
#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint32_t xvalue = UINT32_C(0x06D35BCD);
    uint32_t DEAD000A[16] = {0};
    uint32_t DEAD004A[16] = {
        UINT32_C(0x46761223), UINT32_C(0x54BEA5C5), UINT32_C(0x7A22E8F6), UINT32_C(0x5DB493C9),
        UINT32_C(0x055D175E), UINT32_C(0x022FCD33), UINT32_C(0x42C46BE6), UINT32_C(0x6D10A0E8),
        UINT32_C(0x53F4C278), UINT32_C(0x7279EC2A), UINT32_C(0x5491FB39), UINT32_C(0x49AC421F),
        UINT32_C(0x49AB3A37), UINT32_C(0x47855812), UINT32_C(0x5718BB05), UINT32_C(0x0540FB5B)
    };
    uint32_t xvalues[8][3];
    int i, j;
    for (i = 8; i > 0; i--) {
        for (j = 3; j > 0; j--) {
            xvalue = (((xvalue * 0x77F) - 0x32A) % 0x305EB3EA);
            xvalues[i - 1][j - 1] = xvalue;
        }
    }

    for (i = 8; i > 0; i--) {
        uint32_t dataA = DEAD004A[(8 - i) * 2];
        uint32_t dataE = DEAD004A[(8 - i) * 2 + 1];
        for (j = 1; j <= 3; j++) {
            /*
            new_dataA = old_dataE
            new_dataE = old_dataA ^ ~(old_dataE ^ xvalue)

            old_dataE = new_dataA
            old_dataA = new_dataE ^ ~(old_dataE ^ xvalue)
            */
            uint32_t old_dataE = dataA;
            uint32_t old_dataA = dataE ^ ~(dataA ^ xvalues[i - 1][j - 1]);
            dataA = old_dataA;
            dataE = old_dataE;
        }
        DEAD000A[(8 - i) * 2] = dataA;
        DEAD000A[(8 - i) * 2 + 1] = dataE;
    }

    for (i = 0; i < 16; i++) {
#if 0
        printf("%08" PRIX32 "\n", DEAD000A[i]);
#else
        for (j = 0; j < 4; j++) {
            int c = (DEAD000A[i] >> (8 * j)) & 0xff;
            if (c > 0) putchar(c);
        }
#endif
    }
    return 0;
}

これを実行すると、以下のflagが得られました。

SECCON{TfuRYYVaz8Us696t3JWNxZZPsXEmdL7cCmgzpgxXKarUOnIwhSj9tQ}

Survey

GoogleフォームのURLが提示され、回答を送信するとflagが表示されました。
回答を複数回送信していいかどうかについては書かれていないようでした。

SECCON{Thank you for playing SECCON 2020 Online CTF}
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0