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

ヾノ*>ㅅ<)ノシ帳

技術ブログに見せかけて、ジャンル制限のないふりーだむなブログです。

セキュキャンCTF equations, hidden のWriteup

katc.hateblo.jp

昨日に引き続き、セキュリティキャンプ全国大会2016で開催されたCTFの話題です。 当日手を付けて、解けなかった問題2つ equations と hidden をピックアップしてWriteupを書きます。

equations

i386バイナリのようなので逆コンパイラ(貧乏人用)に突っ込みます。 こんな結果を得られました。
# 自分が当日になぜこの作業をしなかったのか謎い…

// Address range: 0x804847d - 0x8048547
int main(int argc, char ** argv) {
    int32_t v1 = (int32_t)argv; // 0x80484ab_0
    if (argc <= 3) {
        // 0x804848c
        printf("Usage %s <a> <b> <c>\n", (char *)*(int32_t *)argv);
        // branch -> 0x8048546
        // 0x8048546
        return -1;
    }
    int32_t str_as_i = atoi((char *)*(int32_t *)(v1 + 4)); // 0x80484b6
    int32_t str_as_i2 = atoi((char *)*(int32_t *)(v1 + 8)); // 0x80484ca
    int32_t str_as_i3 = atoi((char *)*(int32_t *)(v1 + 12)); // 0x80484de
    if (check(str_as_i, str_as_i2, str_as_i3) == 0) {
        // 0x8048535
        puts("Wrong key...");
        // branch -> 0x8048546
    } else {
        // 0x8048507
        printf("Congratz! flag is FLAG{%d}\n", calc_flag(str_as_i, str_as_i2, str_as_i3));
        // branch -> 0x8048546
    }
    // 0x8048546
    return 0;
}

// Address range: 0x8048548 - 0x80485c4
int32_t check(int32_t a1, int32_t a2, int32_t a3) {
    int32_t result = 0; // 0x80485c4_2
    if (5 * a2 + 3 * a1 == -4 * a3) {
        // 0x8048575
        if (2 * (2 * a2 + a1) == -5 * a3) {
            // 0x804859a
            result = -8 * a3 == a2 - a1;
            // branch -> 0x80485c3
        } else {
            result = 0;
        }
    }
    // 0x80485c3
    return result;
}

コードを見ると3元1次方程式の存在を確認できます。

考えるのも無駄なので Mathematica(貧乏人用) に突っ込んで終わりです。
# 3つ目の式は無くても解が変わらないというね…

Solve[{3x + 5y + 4z = 0, 2x + 4y + 5z = 0, x - y - 8z = 0}, {x,y,z}]

y = -\frac{7}{9} x, z = \frac{2}{9} x

で、解が不定になってしまいましたが、xを特定の値に縛ることをバイナリがしてないのでフラグが1つに定まりません。 ここで終わりにします。

hidden

バイナリが64ビットで、貧乏人用デコンパイラが使えないので、objdumpとテキストエディタで頑張りました。 といっても長くないので検討をつけやすいです。

見るべき箇所は main での genflag の呼び出しと、 genflag の中身です。 何をしているのかは下のpythonスクリプトを見て感じ取ってください。

0000000000400ee0 <main>:
  400ee0:   55                      push   rbp
  400ee1:   48 89 e5                mov    rbp,rsp
  400ee4:   48 81 ec 20 02 00 00    sub    rsp,0x220
  400eeb:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
  400ef2:   00 00 
  400ef4:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
  400ef8:   31 c0                   xor    eax,eax
  400efa:   48 c7 85 e0 fd ff ff    mov    QWORD PTR [rbp-0x220],0x401111 # "flag : %s"
  400f01:   11 11 40 00 
  400f05:   48 c7 85 e8 fd ff ff    mov    QWORD PTR [rbp-0x218],0x40111c # "You cannot get flag! Hahaha\n"
  400f0c:   1c 11 40 00 
  400f10:   bf 39 11 40 00          mov    edi,0x401139                   # "== HiddenFlag ==\n"
  400f15:   e8 46 fa ff ff          call   400960 <puts@plt>              # puts("== HiddenFlag ==\n")
  400f1a:   48 8d 85 f0 fd ff ff    lea    rax,[rbp-0x210]
  400f21:   be 00 02 00 00          mov    esi,0x200                      # 0x200
  400f26:   48 89 c7                mov    rdi,rax                        # [rbp-0x8]
  400f29:   b8 00 00 00 00          mov    eax,0x0                        # retval
  400f2e:   e8 34 00 00 00          call   400f67 <genflag>               # genflag([rbp-0x8], 0x200)
  400f33:   48 8b 85 e0 fd ff ff    mov    rax,QWORD PTR [rbp-0x220]      # "flag : %s"
  400f3a:   48 8d 95 f0 fd ff ff    lea    rdx,[rbp-0x210]                # = flag
  400f41:   48 89 d6                mov    rsi,rdx                        # [rbp-0x210]
  400f44:   48 89 c7                mov    rdi,rax                        # arg0
  400f47:   b8 00 00 00 00          mov    eax,0x0                        # retval
  400f4c:   e8 df f9 ff ff          call   400930 <printf@plt>            # printf("flag : %s", [rbp-0x210])
                                                                      # => printf("You cannot get flag! Hahaha\n")
  400f51:   48 8b 4d f8             mov    rcx,QWORD PTR [rbp-0x8]
  400f55:   64 48 33 0c 25 28 00    xor    rcx,QWORD PTR fs:0x28          # check stack canary
  400f5c:   00 00 
  400f5e:   74 05                   je     400f65 <main+0x85>
#---------------------------------------------------------------------
  400f60:   e8 6b fa ff ff          call   4009d0 <__stack_chk_fail@plt>
  400f65:   c9                      leave  
  400f66:   c3                      ret  
from ctypes import CDLL
libc = CDLL('libc.so.6')

arr = [
    0x21, 0x8a, 0x28, 0x34, 0x2a, 0xca, 
    0x7b, 0x81, 0x59, 0xa1, 0x89, 0xf4, 
    0x91, 0xca, 0x93, 0x2e, 0x4f, 0xb0, 
    0xb, 0xf8, 0x0, 0x0, 0x0, 0x0
    ]

arr2 = [
    0x10, 0xf7, 0x5e, 0x1b, 0xe, 0xca, 
    0x7d, 0x9e, 0x1d, 0xa3, 0xdd, 0x98, 
    0xad, 0x96, 0xd0, 0x25, 0x14, 0xf6, 
    0x3a, 0xc9, 0x2e, 0x85, 0x9a, 0x8d
    ]

libc.srand(0)
for i in range(0x18):
    arr[i] ^= (0xff & libc.rand())

libc.srand(0)
for i in range(0x18):
    arr2[i] ^= (0xff & libc.rand())

flag  = ''.join(map(lambda x: chr(x), arr)) 
flag += ''.join(map(lambda x: chr(x), arr2))
print(flag)

"""
[katc@K_atc seccamp-2016]$ python hidden.py 
FLAG{51mpl3_c1ph3r_çw17h_57r4ng3_m3ch4n15m}
"""

"""
0000000000400f67 <genflag>:
  400f67:   55                      push   rbp
  400f68:   48 89 e5                mov    rbp,rsp
  400f6b:   41 54                   push   r12
  400f6d:   53                      push   rbx
  400f6e:   48 83 ec 40             sub    rsp,0x40
  400f72:   48 89 7d b8             mov    QWORD PTR [rbp-0x48],rdi       # [rbp-0x48] := [rbp-0x8]
  400f76:   89 75 b4                mov    DWORD PTR [rbp-0x4c],esi       # [rbp-0x4c] := 0x200
  400f79:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
  400f80:   00 00 
  400f82:   48 89 45 e8             mov    QWORD PTR [rbp-0x18],rax
  400f86:   31 c0                   xor    eax,eax
  400f88:   c6 45 d0 21             mov    BYTE PTR [rbp-0x30],0x21       # arr[0]
  400f8c:   c6 45 d1 8a             mov    BYTE PTR [rbp-0x2f],0x8a       # arr[1]
  400f90:   c6 45 d2 28             mov    BYTE PTR [rbp-0x2e],0x28       # ...
  400f94:   c6 45 d3 34             mov    BYTE PTR [rbp-0x2d],0x34
  400f98:   c6 45 d4 2a             mov    BYTE PTR [rbp-0x2c],0x2a
  400f9c:   c6 45 d5 ca             mov    BYTE PTR [rbp-0x2b],0xca
  400fa0:   c6 45 d6 7b             mov    BYTE PTR [rbp-0x2a],0x7b
  400fa4:   c6 45 d7 81             mov    BYTE PTR [rbp-0x29],0x81
  400fa8:   c6 45 d8 59             mov    BYTE PTR [rbp-0x28],0x59
  400fac:   c6 45 d9 a1             mov    BYTE PTR [rbp-0x27],0xa1
  400fb0:   c6 45 da 89             mov    BYTE PTR [rbp-0x26],0x89
  400fb4:   c6 45 db f4             mov    BYTE PTR [rbp-0x25],0xf4
  400fb8:   c6 45 dc 91             mov    BYTE PTR [rbp-0x24],0x91
  400fbc:   c6 45 dd ca             mov    BYTE PTR [rbp-0x23],0xca
  400fc0:   c6 45 de 93             mov    BYTE PTR [rbp-0x22],0x93
  400fc4:   c6 45 df 2e             mov    BYTE PTR [rbp-0x21],0x2e
  400fc8:   c6 45 e0 4f             mov    BYTE PTR [rbp-0x20],0x4f
  400fcc:   c6 45 e1 b0             mov    BYTE PTR [rbp-0x1f],0xb0
  400fd0:   c6 45 e2 0b             mov    BYTE PTR [rbp-0x1e],0xb
  400fd4:   c6 45 e3 f8             mov    BYTE PTR [rbp-0x1d],0xf8
  400fd8:   c6 45 e4 00             mov    BYTE PTR [rbp-0x1c],0x0
  400fdc:   c6 45 e5 00             mov    BYTE PTR [rbp-0x1b],0x0
  400fe0:   c6 45 e6 00             mov    BYTE PTR [rbp-0x1a],0x0
  400fe4:   c6 45 e7 00             mov    BYTE PTR [rbp-0x19],0x0        # arr[0x17]
  400fe8:   8b 45 b4                mov    eax,DWORD PTR [rbp-0x4c]
  400feb:   83 f8 18                cmp    eax,0x18
  400fee:   76 07                   jbe    400ff7 <genflag+0x90>
#---------------------------------------------------------------------
  400ff0: c7 45 b4 18 00 00 00  mov    DWORD PTR [rbp-0x4c],0x18      # [rbp-0x4c] := 0x18
#---------------------------------------------------------------------
  400ff7: bf 00 00 00 00        mov    edi,0x0                        # 0
  400ffc: e8 ef f9 ff ff        call   4009f0 <srand@plt>             # srand(0)
  401001: c7 45 cc 00 00 00 00  mov    DWORD PTR [rbp-0x34],0x0       # [rbp-0x34] = 0 
                                                                      # i := [rbp-0x34]
  401008: eb 27                 jmp    401031 <genflag+0xca>
#=====================================================================
  40100a: 8b 45 cc              mov    eax,DWORD PTR [rbp-0x34]       # arr[i] = [rbp-0x34] 
  40100d: 48 63 d0              movsxd rdx,eax
  401010: 48 8b 45 b8           mov    rax,QWORD PTR [rbp-0x48]
  401014: 48 8d 1c 02           lea    rbx,[rdx+rax*1]                # rbx := [i + [rbp-0x48]]
  401018: 8b 45 cc              mov    eax,DWORD PTR [rbp-0x34]
  40101b: 48 98                 cdqe   
  40101d: 44 0f b6 64 05 d0     movzx  r12d,BYTE PTR [rbp-0x30+rax*1] # r12d := arr[i]
  401023: e8 f8 f9 ff ff        call   400a20 <rand@plt>              # rand()
  401028: 44 31 e0              xor    eax,r12d                       # arr[i] ^= char(rand())
  40102b: 88 03                 mov    BYTE PTR [rbx],al      
  40102d: 83 45 cc 01           add    DWORD PTR [rbp-0x34],0x1       # [rbp-0x34] += 1 (i++)
#---------------------------------------------------------------------
  401031: 8b 45 cc              mov    eax,DWORD PTR [rbp-0x34]
  401034: 3b 45 b4              cmp    eax,DWORD PTR [rbp-0x4c]
  401037: 7c d1                 jl     40100a <genflag+0xa3>          # [rbp-0x34] < 0x18
#---------------------------------------------------------------------
"""

"""
[katc@K_atc seccamp-2016]$ gdb -q hidden
gdb-peda$ b printf
gdb-peda$ r
gdb-peda$ disas genflag
Dump of assembler code for function genflag:
   0x0000000000400f67 <+0>:     push   rbp
   0x0000000000400f68 <+1>:     mov    rbp,rsp
   0x0000000000400f6b <+4>:     push   r12
   0x0000000000400f6d <+6>:     push   rbx
   0x0000000000400f6e <+7>:     sub    rsp,0x40
   0x0000000000400f72 <+11>:    mov    QWORD PTR [rbp-0x48],rdi       # [rbp-0x48] := [rbp-0x8]
   0x0000000000400f76 <+15>:    mov    DWORD PTR [rbp-0x4c],esi
   0x0000000000400f79 <+18>:    mov    rax,QWORD PTR fs:0x28
   0x0000000000400f82 <+27>:    mov    QWORD PTR [rbp-0x18],rax
   0x0000000000400f86 <+31>:    xor    eax,eax
   0x0000000000400f88 <+33>:    mov    BYTE PTR [rbp-0x30],0x10
   0x0000000000400f8c <+37>:    mov    BYTE PTR [rbp-0x2f],0xf7
   0x0000000000400f90 <+41>:    mov    BYTE PTR [rbp-0x2e],0x5e
   0x0000000000400f94 <+45>:    mov    BYTE PTR [rbp-0x2d],0x1b
   0x0000000000400f98 <+49>:    mov    BYTE PTR [rbp-0x2c],0xe
   0x0000000000400f9c <+53>:    mov    BYTE PTR [rbp-0x2b],0xca
   0x0000000000400fa0 <+57>:    mov    BYTE PTR [rbp-0x2a],0x7d
   0x0000000000400fa4 <+61>:    mov    BYTE PTR [rbp-0x29],0x9e
   0x0000000000400fa8 <+65>:    mov    BYTE PTR [rbp-0x28],0x1d
   0x0000000000400fac <+69>:    mov    BYTE PTR [rbp-0x27],0xa3
   0x0000000000400fb0 <+73>:    mov    BYTE PTR [rbp-0x26],0xdd
   0x0000000000400fb4 <+77>:    mov    BYTE PTR [rbp-0x25],0x98
   0x0000000000400fb8 <+81>:    mov    BYTE PTR [rbp-0x24],0xad
   0x0000000000400fbc <+85>:    mov    BYTE PTR [rbp-0x23],0x96
   0x0000000000400fc0 <+89>:    mov    BYTE PTR [rbp-0x22],0xd0
   0x0000000000400fc4 <+93>:    mov    BYTE PTR [rbp-0x21],0x25
   0x0000000000400fc8 <+97>:    mov    BYTE PTR [rbp-0x20],0x14
   0x0000000000400fcc <+101>:   mov    BYTE PTR [rbp-0x1f],0xf6
   0x0000000000400fd0 <+105>:   mov    BYTE PTR [rbp-0x1e],0x3a
   0x0000000000400fd4 <+109>:   mov    BYTE PTR [rbp-0x1d],0xc9
   0x0000000000400fd8 <+113>:   mov    BYTE PTR [rbp-0x1c],0x2e
   0x0000000000400fdc <+117>:   mov    BYTE PTR [rbp-0x1b],0x85
   0x0000000000400fe0 <+121>:   mov    BYTE PTR [rbp-0x1a],0x9a
   0x0000000000400fe4 <+125>:   mov    BYTE PTR [rbp-0x19],0x8d
   0x0000000000400fe8 <+129>:   mov    eax,DWORD PTR [rbp-0x4c]
   0x0000000000400feb <+132>:   cmp    eax,0x18
   0x0000000000400fee <+135>:   jbe    0x400ff7 <genflag+144>
#---------------------------------------------------------------------
   0x0000000000400ff0 <+137>:   mov    DWORD PTR [rbp-0x4c],0x18
   0x0000000000400ff7 <+144>:   mov    edi,0x0                        # 0
   0x0000000000400ffc <+149>:   call   0x4009f0 <srand@plt>           # srand(0)
   0x0000000000401001 <+154>:   mov    DWORD PTR [rbp-0x34],0x0       # i = 0
   0x0000000000401008 <+161>:   jmp    0x401031 <genflag+202>
#=====================================================================
   0x000000000040100a <+163>:   mov    eax,DWORD PTR [rbp-0x34]
   0x000000000040100d <+166>:   movsxd rdx,eax
   0x0000000000401010 <+169>:   mov    rax,QWORD PTR [rbp-0x48]       # rax := ?
   0x0000000000401014 <+173>:   lea    rbx,[rdx+rax*1]
   0x0000000000401018 <+177>:   mov    eax,DWORD PTR [rbp-0x34]
   0x000000000040101b <+180>:   cdqe   
   0x000000000040101d <+182>:   movzx  r12d,BYTE PTR [rbp+rax*1-0x30]
   0x0000000000401023 <+188>:   call   0x400a20 <rand@plt>
   0x0000000000401028 <+193>:   xor    eax,r12d                       
   0x000000000040102b <+196>:   mov    BYTE PTR [rbx],al
   0x000000000040102d <+198>:   add    DWORD PTR [rbp-0x34],0x1       # i++
#---------------------------------------------------------------------
   0x0000000000401031 <+202>:   mov    eax,DWORD PTR [rbp-0x34]
   0x0000000000401034 <+205>:   cmp    eax,DWORD PTR [rbp-0x4c]
   0x0000000000401037 <+208>:   jl     0x40100a <genflag+163>
#---------------------------------------------------------------------
"""

ブレークポイントが打てないし、printfの出力がobjdumpと食い違っていたのですが、何らかの仕組みが働いてコードが書き換わるようです。 フラグが前後半に分かれて出現します。前半は実行前のコード、後半はprintf呼び出し時に見ることができます。 てなわけで、

flag: FLAG{51mpl3_c1ph3r_çw17h_57r4ng3_m3ch4n15m}


明日、また会社かよ…

(報告)Docker版の方はARMのrev問が動くようになりましたー