AlexCTF 供養(Writeup)

AlexCTFに参加。990ptで259位。

TR1: Hello there (Trivia 10)

IRCのチャンネル名にフラグがある。

IRC: #alexctf @freenode

#alexctf: Alexandria University student held capture the flag event ctf.oddcoder.com ALEXCTF{W3_w15h_y0u_g00d_luck}

TR2: SSL 0day (Trivia 20)

It lead to memory leakage between servers and clients rending large number of private keys accessible. (one word)

heartbleed

TR3: CA (Trivia 30)

What is the CA that issued Alexctf https certificate (flag is lowercase with no spaces)

letsencrypt

TR4: Doesn’t our logo look cool ? (Trivia 40)

トップページにあるアスキーアートのロゴの中にある。

$ grep -oP '[\w{}]' logo.txt | tr -d '\n'
ALEXCTF{0UR_L0G0_R0CKS}

RE1: Gifted (Reversing 50)

stringsするとフラグがある。

$ strings gifted
(snip)
Enter the flag:
AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
You got it right dude!
Try harder!
(snip)

RE2: C++ is awesome (Reversing 100)

特定のアドレスで動作を止めてメモリに入っているデータを見ると、文字列と数字の配列がある。

$ gdb --args ./re2 AAAA
Reading symbols from ./re2...(no debugging symbols found)...done.
(gdb) b *0x400c24
Breakpoint 1 at 0x400c24
(gdb) r
Starting program: /tmp/re2 AAAA
Breakpoint 1, 0x0000000000400c24 in ?? ()
1: x/i $pc
=> 0x400c24:    lea    rax,[rbp-0x50]
(gdb) x/80i $pc
=> 0x400c24:    lea    rax,[rbp-0x50]
   0x400c28:    mov    rdi,rax
   0x400c2b:    call   0x4009f0 <std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::end()@plt>
   0x400c30:    mov    QWORD PTR [rbp-0x20],rax
   0x400c34:    lea    rdx,[rbp-0x20]
   0x400c38:    lea    rax,[rbp-0x60]
   0x400c3c:    mov    rsi,rdx
   0x400c3f:    mov    rdi,rax
   0x400c42:    call   0x400d3d
   0x400c47:    test   al,al
   0x400c49:    je     0x400c95
   0x400c4b:    lea    rax,[rbp-0x60]
   0x400c4f:    mov    rdi,rax
   0x400c52:    call   0x400d9a
   0x400c57:    movzx  edx,BYTE PTR [rax]
   0x400c5a:    mov    rcx,QWORD PTR [rip+0x20143f]        # 0x6020a0
   0x400c61:    mov    eax,DWORD PTR [rbp-0x14]
   0x400c64:    cdqe
   0x400c66:    mov    eax,DWORD PTR [rax*4+0x6020c0]
   0x400c6d:    cdqe
   (snip)
(gdb) x/s {long}0x6020a0
0x400e58:       "L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t"
(gdb) x/80wx 0x6020c0
0x6020c0:       0x00000024      0x00000000      0x00000005      0x00000036
0x6020d0:       0x00000065      0x00000007      0x00000027      0x00000026
0x6020e0:       0x0000002d      0x00000001      0x00000003      0x00000000
0x6020f0:       0x0000000d      0x00000056      0x00000001      0x00000003
0x602100:       0x00000065      0x00000003      0x0000002d      0x00000016
0x602110:       0x00000002      0x00000015      0x00000003      0x00000065
0x602120:       0x00000000      0x00000029      0x00000044      0x00000044
0x602130:       0x00000001      0x00000044      0x0000002b      0x00000000
0x602140 <std::cout>:   0xf7dce988      0x00007fff      0xf7dce9b0      0x00007fff
(snip)
(gdb) q
A debugging session is active.

        Inferior 1 [process 11607] will be killed.

Quit anyway? (y or n) y

数字の配列の順で文字列から文字を取り出すとフラグが得られる。

msg = "L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t"

ary = [0x24, 0x0, 0x5, 0x36, 0x65, 0x7, 0x27, 0x26, 0x2d, 0x1, 0x3, 0x0, 0xd, 0x56, 0x1, 0x3, 0x65, 0x3, 0x2d, 0x16, 0x2, 0x15, 0x3, 0x65, 0x0, 0x29, 0x44, 0x44, 0x1, 0x44, 0x2b, 0x0]
s = ''
for i in ary:
    s += msg[i]
print s
$ python test.py
ALEXCTF{W3_L0v3_C_W1th_CL45535}L

RE4: unVM me (Reversing 250)

「HITCON CTF 2016 Quals 供養(Writeup)」で使ったshow_file.pyでディスアセンブルすると、5文字ごとに特定のmd5ハッシュ値と一致しているかを見ていることがわかる。

  2          12 LOAD_CONST               2 (174282896860968005525213562254350376167L)
             15 LOAD_CONST               3 (137092044126081477479435678296496849608L)
             18 LOAD_CONST               4 (126300127609096051658061491018211963916L)
             21 LOAD_CONST               5 (314989972419727999226545215739316729360L)
             24 LOAD_CONST               6 (256525866025901597224592941642385934114L)
             27 LOAD_CONST               7 (115141138810151571209618282728408211053L)
             30 LOAD_CONST               8 (8705973470942652577929336993839061582L)
             33 LOAD_CONST               9 (256697681645515528548061291580728800189L)
             36 LOAD_CONST              10 (39818552652170274340851144295913091599L)
             39 LOAD_CONST              11 (65313561977812018046200997898904313350L)
             42 LOAD_CONST              12 (230909080238053318105407334248228870753L)
             45 LOAD_CONST              13 (196125799557195268866757688147870815374L)
             48 LOAD_CONST              14 (74874145132345503095307276614727915885L)
             51 BUILD_LIST              13
             54 STORE_NAME               1 (md5s)
(snip)
 12     >>  144 SETUP_LOOP             112 (to 259)
            147 LOAD_NAME                6 (range)
            150 LOAD_CONST              20 (0)
            153 LOAD_NAME                4 (len)
            156 LOAD_NAME                3 (flag)
            159 CALL_FUNCTION            1
            162 LOAD_CONST              19 (5)
            165 CALL_FUNCTION            3
            168 GET_ITER
        >>  169 FOR_ITER                86 (to 258)
            172 STORE_NAME               7 (i)

 13         175 LOAD_NAME                3 (flag)
            178 LOAD_NAME                7 (i)
            181 LOAD_NAME                7 (i)
            184 LOAD_CONST              19 (5)
            187 BINARY_ADD
            188 SLICE+3
            189 STORE_NAME               8 (s)

 14         192 LOAD_NAME                9 (int)
            195 LOAD_CONST              21 ('0x')
            198 LOAD_NAME                0 (md5)
            201 LOAD_ATTR               10 (new)
            204 LOAD_NAME                8 (s)
            207 CALL_FUNCTION            1
            210 LOAD_ATTR               11 (hexdigest)
            213 CALL_FUNCTION            0
            216 BINARY_ADD
            217 LOAD_CONST              22 (16)
            220 CALL_FUNCTION            2
            223 LOAD_NAME                1 (md5s)
            226 LOAD_NAME                7 (i)
            229 LOAD_CONST              19 (5)
            232 BINARY_DIVIDE
            233 BINARY_SUBSCR
            234 COMPARE_OP               3 (!=)
            237 POP_JUMP_IF_FALSE      169

文字種をいろいろ変えながらブルートフォースすると元の文字列が求まる。

from itertools import product
from hashlib import md5

hashes = [
    (174282896860968005525213562254350376167L),  # md5('ALEXC')
    (137092044126081477479435678296496849608L),  # md5('TF{dv')
    (126300127609096051658061491018211963916L),  # md5('5d4s2')
    (314989972419727999226545215739316729360L),  # md5('vj8nk')
    (256525866025901597224592941642385934114L),  # md5('43s8d')
    (115141138810151571209618282728408211053L),  # md5('8l6m1')
    (8705973470942652577929336993839061582L),    # md5('n5l67')
    (256697681645515528548061291580728800189L),  # md5('ds9v4')
    (39818552652170274340851144295913091599L),   # md5('1n52n')
    (65313561977812018046200997898904313350L),   # md5('v37j4')
    (230909080238053318105407334248228870753L),  # md5('81h3d')
    (196125799557195268866757688147870815374L),  # md5('28n4b')
    (74874145132345503095307276614727915885L)    # md5('6v3k}')
]

"""
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
for t in product(chars, repeat=5):
    x = ''.join(t)
    h = md5(x).hexdigest()
    h = int(h, 16)
    if h in hashes:
        print "%d == md5(%r)" % (h, x)
"""

"""
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
for t in product(chars, repeat=2):
    x = 'TF{' + ''.join(t)
    h = md5(x).hexdigest()
    h = int(h, 16)
    if h in hashes:
        print "%d == md5(%r)" % (h, x)
"""

"""
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
for t in product(chars, repeat=5):
    x = ''.join(t)
    h = md5(x).hexdigest()
    h = int(h, 16)
    if h in hashes:
        print "%d == md5(%r)" % (h, x)
"""

chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
for t in product(chars, repeat=4):
    x = ''.join(t) + '}'
    h = md5(x).hexdigest()
    h = int(h, 16)
    if h in hashes:
        print "%d == md5(%r)" % (h, x)

# ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k}

CR1: Ultracoded (Cryptography 50)

与えられたテキストを適当に変換すると、モールス信号を表す文字列が得られる。

data = open('zero_one').read()

s = ''
for x in data.split():
    if x == 'ZERO':
        s += '0'
    else:
        s += '1'

s = "%x" % int(s, 2)
s = s.decode('hex')
s = s.decode('base64')
print s
$ python test.py
.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -

Morse Code Translator等で復号した文字列を適当に変換するとフラグが得られる。

ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT
ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}

CR3: What is this encryption? (Cryptography 150)

「OpenSSLとPythonでRSA暗号の原理を知る」と同様に、RSAの復号を行うだけ。

p=0xa6055ec186de51800ddd6fcbf0192384ff42d707a55f57af4fcfb0d1dc7bd97055e8275cd4b78ec63c5d592f567c66393a061324aa2e6a8d8fc2a910cbee1ed9
q=0xfa0f9463ea0a93b929c099320d31c277e0b0dbc65b189ed76124f5a1218f5d91fd0102a4c8de11f28be5e4d0ae91ab319f4537e97ed74bc663e972a4a9119307
e=0x6d1fdab4ce3217b3fc32c9ed480a31d067fd57d93a9ab52b472dc393ab7852fbcb11abbebfd6aaae8032db1316dc22d3f7c3d631e24df13ef23d3b381a1c3e04abcc745d402ee3a031ac2718fae63b240837b4f657f29ca4702da9af22a3a019d68904a969ddb01bcf941df70af042f4fae5cbeb9c2151b324f387e525094c41
c=0x7fe1a4f743675d1987d25d38111fae0f78bbea6852cba5beda47db76d119a3efe24cb04b9449f53becd43b0b46e269826a983f832abb53b7a7e24a43ad15378344ed5c20f51e268186d24c76050c1e73647523bd5f91d9b6ad3e86bbf9126588b1dee21e6997372e36c3e74284734748891829665086e0dc523ed23c386bb520

def egcd(a, b):
    x,y, u,v = 0,1, 1,0
    while a != 0:
        q,r = b//a,b%a; m,n = x-u*q,y-v*q
        b,a, x,y, u,v = a,r, u,v, m,n
    return b, x, y

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        return None  # modular inverse does not exist
    else:
        return x % m

d = modinv(e, (p-1)*(q-1))
m = pow(c, d, p*q)
m = "%x" % m
print m.decode('hex')
$ python test.py
ALEXCTF{RS4_I5_E55ENT1AL_T0_D0_BY_H4ND}

Fore1: Hit the core (Forensics 50)

stringsすると長い文字列が見つかる。

$ strings fore1.core
(snip)
cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv}
(snip)

フラグフォーマットをヒントに、一定間隔で文字を拾うとフラグが得られる。

s = 'cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv}'
print s[3::5]
$ python test.py
ALEXCTF{K33P_7H3_g00D_w0rk_up}

Fore3: USB probing (Forensics 150)

USBのパケットキャプチャファイルが与えられる。 サイズの大きなパケットを探すと、101番のパケットでPNGファイルが転送されているのが見つかる。

f:id:inaz2:20170206205347p:plain

ALEXCTF{SN1FF_TH3_FL4G_0V3R_U58}

SC1: Math bot (Scripting 100)

与えられる数式を計算するだけ。evalを使うのは危険だが適当にやってしまった。

from minipwn import *

s = socket.create_connection(('195.154.53.62', 1337))
for i in xrange(500):
    print recvuntil(s, ':\n')
    x = recvline(s)
    print x
    y = eval(x[:-2])
    sendline(s, str(y))
interact(s)
$ python test.py
                __________
         ______/ ________ \______
       _/      ____________      \_
     _/____________    ____________\_
    /  ___________ \  / ___________  \
   /  /XXXXXXXXXXX\ \/ /XXXXXXXXXXX\  \
  /  /############/    \############\  \
  |  \XXXXXXXXXXX/ _  _ \XXXXXXXXXXX/  |
__|\_____   ___   //  \\   ___   _____/|__
[_       \     \  X    X  /     /       _]
__|     \ \                    / /     |__
[____  \ \ \   ____________   / / /  ____]
     \  \ \ \/||.||.||.||.||\/ / /  /
      \_ \ \  ||.||.||.||.||  / / _/
        \ \   ||.||.||.||.||   / /
         \_   ||_||_||_||_||   _/
           \     ........     /
            \________________/

Our system system has detected human traffic from your IP!
Please prove you are a bot
Question  1 :

51592980733851622235329877819524 % 81337315219774907248751097819108 =

Question  2 :

222530311273284491939188931042597 * 5582384329582694587240599887190 =

(snip)

Question  500 :

223942165497608593390730286109841 - 285025587991694605246774446376485 =

Well no human got time to solve 500 ridiculous math challenges
Congrats MR bot!
Tell your human operator flag is: ALEXCTF{1_4M_l33t_b0t}
*** Connection closed by remote host ***

所感

解けなかった問題は以下。

  • RE3: Catalyst system (Reversing 150)
  • RE5: packed movement (Reversing 350)
  • CR2: Many time secrets (Cryptography 100)
  • CR4: Poor RSA (Cryptography 200)
  • CR5: Bring weakness (Cryptography 300)
  • Fore2: Mail client (Forensics 100)
  • Fore4: Unknown format (Forensics 200)
  • SC2: Cutie cat (Scripting 150)

関連リンク