AlexCTF writeup

AlexCTF writeup

いつものチームで参加.
結果は 105th, 1740pts で結構頑張った.
自分が解いた問題の writeup を書きます.

(追記)
暗号系をメインに問いてくれたメンバーの writeup をおいておきます. liniku.hatenablog.com

RE1: Gifted

思考停止して strings するだけだった.

$ strings gifted | grep AlexCTF
AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}

RE2: C++ is awesome

実行すると引数にフラグを与える様子.
何度か適当な文字列を入れて実行してみると,

$ ./re2 aaaa
Better luck next time
$ ./re2 ALEX
You should have the flag by now

どうやら,引数にとる文字列が途中まででも良いので正しければ出力が変わるっぽい.
ということなので以下みたいなクソみたいなスクリプトを書いて,1文字づつ確かめていった.

#!/bin/bash

for c in a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 _ { }; do
  echo -n "$c: "
  ./re2 $1$c
done

以下のように実行.フラグとして完成しても “L” がまだ出るのだけどどうもいらない模様だった.

$ ./re2.sh ALEXCTF{W3_L0v3_C_W1th_CL45535} | grep "You should"
L: You should have the flag by now

RE3: Catalyst system

とても時間がかかった….
ひとまず実行してみると “Loading…” みたいな感じで何もできない.
ひとまず objdump してみると sleep してたりするところがあって,
どうも rand した値によって再び sleep するかどうかを判定しているようだった.

  400e83:       e8 d8 f8 ff ff          call   400760 <sleep@plt>
  400e88:       bf 2e 00 00 00          mov    edi,0x2e
  400e8d:       e8 2e f8 ff ff          call   4006c0 <putchar@plt>
  400e92:       48 8b 05 2f 12 20 00    mov    rax,QWORD PTR [rip+0x20122f]        # 6020c8 <stdout>
  400e99:       48 89 c7                mov    rdi,rax
  400e9c:       e8 8f f8 ff ff          call   400730 <fflush@plt>
  400ea1:       83 45 fc 01             add    DWORD PTR [rbp-0x4],0x1
  400ea5:       83 7d fc 1d             cmp    DWORD PTR [rbp-0x4],0x1d
  400ea9:       7e bc                   jle    400e67 <rand@plt+0x6f7>

上記のような箇所が2箇所あるので以下のような感じで jle を潰した.

0x00000EAA 7E 90
0x00000EAB BC 90
0x00000F63 7E 90
0x00000F64 C2 90

これでようやく入力を受けつけるところにいける.
Username と Password を求められるので適当に実行してみるがよくわからず.
ひとまず Username を解析していくと…,

  400cdd:    55                       push   rbp
  400cde:    48 89 e5                 mov    rbp,rsp
  400ce1:    48 83 ec 30              sub    rsp,0x30
  400ce5:    48 89 7d d8              mov    QWORD PTR [rbp-0x28],rdi
  400ce9:    48 8b 45 d8              mov    rax,QWORD PTR [rbp-0x28]
  400ced:    48 89 45 f8              mov    QWORD PTR [rbp-0x8],rax
  400cf1:    48 8b 45 f8              mov    rax,QWORD PTR [rbp-0x8]
  400cf5:    8b 00                    mov    eax,DWORD PTR [rax]
  400cf7:    89 c0                    mov    eax,eax
  400cf9:    48 89 45 f0              mov    QWORD PTR [rbp-0x10],rax
  400cfd:    48 8b 45 f8              mov    rax,QWORD PTR [rbp-0x8]
  400d01:    48 83 c0 04              add    rax,0x4
  400d05:    8b 00                    mov    eax,DWORD PTR [rax]
  400d07:    89 c0                    mov    eax,eax
  400d09:    48 89 45 e8              mov    QWORD PTR [rbp-0x18],rax
  400d0d:    48 8b 45 f8              mov    rax,QWORD PTR [rbp-0x8]
  400d11:    48 83 c0 08              add    rax,0x8
  400d15:    8b 00                    mov    eax,DWORD PTR [rax]
  400d17:    89 c0                    mov    eax,eax
  400d19:    48 89 45 e0              mov    QWORD PTR [rbp-0x20],rax
  400d1d:    48 8b 45 f0              mov    rax,QWORD PTR [rbp-0x10]
  400d21:    48 2b 45 e8              sub    rax,QWORD PTR [rbp-0x18]
  400d25:    48 89 c2                 mov    rdx,rax
  400d28:    48 8b 45 e0              mov    rax,QWORD PTR [rbp-0x20]
  400d2c:    48 01 d0                 add    rax,rdx
  400d2f:    48 3d 56 4b 66 5c        cmp    rax,0x5c664b56
  400d35:    75 45                    jne    400d7c <rand@plt+0x60c>
  400d37:    48 8b 55 f0              mov    rdx,QWORD PTR [rbp-0x10]
  400d3b:    48 8b 45 e0              mov    rax,QWORD PTR [rbp-0x20]
  400d3f:    48 01 c2                 add    rdx,rax
  400d42:    48 89 d0                 mov    rax,rdx
  400d45:    48 01 c0                 add    rax,rax
  400d48:    48 01 c2                 add    rdx,rax
  400d4b:    48 8b 45 e8              mov    rax,QWORD PTR [rbp-0x18]
  400d4f:    48 01 c2                 add    rdx,rax
  400d52:    48 b8 b2 c7 00 e7 02     mov    rax,0x2e700c7b2
  400d59:    00 00 00
  400d5c:    48 39 c2                 cmp    rdx,rax
  400d5f:    75 1b                    jne    400d7c <rand@plt+0x60c>
  400d61:    48 8b 45 e8              mov    rax,QWORD PTR [rbp-0x18]
  400d65:    48 0f af 45 e0           imul   rax,QWORD PTR [rbp-0x20]
  400d6a:    48 89 c2                 mov    rdx,rax
  400d6d:    48 b8 14 d3 6a 9a 68     mov    rax,0x32ac30689a6ad314
  400d74:    30 ac 32
  400d77:    48 39 c2                 cmp    rdx,rax
  400d7a:    74 14                    je     400d90 <rand@plt+0x620>
  400d7c:    bf 69 10 40 00           mov    edi,0x401069
  400d81:    e8 4a f9 ff ff           call   4006d0 <puts@plt>
  400d86:    bf 00 00 00 00           mov    edi,0x0
  400d8b:    e8 c0 f9 ff ff           call   400750 <exit@plt>
  400d90:    90                       nop
  400d91:    c9                       leave
  400d92:    c3                       ret

こんな感じでやる気がなくなりそうになりながらも解析していく.
ユーザ名は12文字で,ひとまず XXXXYYYYZZZZ とすると,
rbp - 0x10 = "XXXX", rbp - 0x18 = "YYYY", rbp - 0x20 = "ZZZZ" で,
XXXX = X, YYYY = Y, ZZZZ = Z とおくと,上記の部分は以下の式を満たす X, Y, Z である必要がある.

X - Y + Z == 0x5c664b56
3X + Y + 3Z == 0x2e700c7b2
Y * Z == 0x32ac30689a6ad314

適当に計算すると,

X = 0x61746163 // cata
Y = 0x7473796c // lyst
Z = 0x6f65635f // _ceo

で username は catalyst_ceo であることがわかった.
次にパスワードを解析していく.パスワードは以下のようなコードで比較している.

  400a4c:       48 8b 45 e0             mov    rax,QWORD PTR [rbp-0x20]
  400a50:       8b 10                   mov    edx,DWORD PTR [rax]
  400a52:       48 8b 45 e0             mov    rax,QWORD PTR [rbp-0x20]
  400a56:       48 83 c0 04             add    rax,0x4
  400a5a:       8b 00                   mov    eax,DWORD PTR [rax]
  400a5c:       01 c2                   add    edx,eax
  400a5e:       48 8b 45 e0             mov    rax,QWORD PTR [rbp-0x20]
  400a62:       48 83 c0 08             add    rax,0x8
  400a66:       8b 00                   mov    eax,DWORD PTR [rax]
  400a68:       01 d0                   add    eax,edx
  400a6a:       89 c7                   mov    edi,eax
  400a6c:       e8 8f fc ff ff          call   400700 <srand@plt>
  400a71:       48 8b 45 d8             mov    rax,QWORD PTR [rbp-0x28]
  400a75:       8b 18                   mov    ebx,DWORD PTR [rax]
  400a77:       e8 f4 fc ff ff          call   400770 <rand@plt>
  400a7c:       29 c3                   sub    ebx,eax
  400a7e:       89 d8                   mov    eax,ebx
  400a80:       3d 2a 05 eb 55          cmp    eax,0x55eb052a
  400a85:       74 14                   je     400a9b <rand@plt+0x32b>
  400a87:       bf 69 10 40 00          mov    edi,0x401069
  400a8c:       e8 3f fc ff ff          call   4006d0 <puts@plt>
  400a91:       bf 00 00 00 00          mov    edi,0x0
  400a96:       e8 b5 fc ff ff          call   400750 <exit@plt>

srand に渡っているのは X + Y + Z とユーザ名を4文字づつに区切って足した結果だった.
これで常にシードは固定されているので rand の値は一意に定まる.
パスワードの4文字 - rand() = 0x55eb052a(ここの16進数は上記逆汗結果の後続にあと9個ある) で比較しているので,
パスワード4文字は 0x55eb052a - rand() で求まる.
ltrace とかすると rand によって吐かれた値はわかるので,あとは objdump の結果から計算していく.
最終的には, sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj というパスワードが得られる.
あとは,求めたユーザ名とパスワードを入力するとフラグに出る.

$ ./catalyst
 ▄▄▄▄▄▄▄▄▄▄▄  ▄            ▄▄▄▄▄▄▄▄▄▄▄  ▄       ▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄
▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░░▌▐░▌     ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
▐░█▀▀▀▀▀▀▀█░▌▐░▌          ▐░█▀▀▀▀▀▀▀▀▀  ▐░▌   ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀  ▀▀▀▀█░█▀▀▀▀ ▐░█▀▀▀▀▀▀▀▀▀
▐░▌       ▐░▌▐░▌          ▐░▌            ▐░▌ ▐░▌  ▐░▌               ▐░▌     ▐░▌
▐░█▄▄▄▄▄▄▄█░▌▐░▌          ▐░█▄▄▄▄▄▄▄▄▄    ▐░▐░▌   ▐░▌               ▐░▌     ▐░█▄▄▄▄▄▄▄▄▄
▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░░▌    ▐░▌    ▐░▌               ▐░▌     ▐░░░░░░░░░░░▌
▐░█▀▀▀▀▀▀▀█░▌▐░▌          ▐░█▀▀▀▀▀▀▀▀▀    ▐░▌░▌   ▐░▌               ▐░▌     ▐░█▀▀▀▀▀▀▀▀▀
▐░▌       ▐░▌▐░▌          ▐░▌            ▐░▌ ▐░▌  ▐░▌               ▐░▌     ▐░▌
▐░▌       ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄  ▐░▌   ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄      ▐░▌     ▐░▌
▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌     ▐░▌▐░░░░░░░░░░░▌     ▐░▌     ▐░▌
 ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀       ▀  ▀▀▀▀▀▀▀▀▀▀▀       ▀       ▀
Welcome to Catalyst systems
Loading
Username: catalyst_ceo
Password: sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj
Logging in
your flag is: ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}

RE4: unVM me

バイコンパイルされた python が与えられる.
uncompyle2 を使ってデコンパイルする.

$ uncompyle2 unvm_me.pyc
# 2017.02.06 19:16:30 JST
#Embedded file name: unvm_me.py
import md5
md5s = [174282896860968005525213562254350376167L,
 137092044126081477479435678296496849608L,
 126300127609096051658061491018211963916L,
 314989972419727999226545215739316729360L,
 256525866025901597224592941642385934114L,
 115141138810151571209618282728408211053L,
 8705973470942652577929336993839061582L,
 256697681645515528548061291580728800189L,
 39818552652170274340851144295913091599L,
 65313561977812018046200997898904313350L,
 230909080238053318105407334248228870753L,
 196125799557195268866757688147870815374L,
 74874145132345503095307276614727915885L]
print 'Can you turn me back to python ? ...'
flag = raw_input('well as you wish.. what is the flag: ')
if len(flag) > 69:
    print 'nice try'
    exit()
if len(flag) % 5 != 0:
    print 'nice try'
    exit()
for i in range(0, len(flag), 5):
    s = flag[i:i + 5]
    if int('0x' + md5.new(s).hexdigest(), 16) != md5s[i / 5]:
        print 'nice try'
        exit()

print 'Congratz now you have the flag'

どうやらフラグは65文字で5文字ずつ md5 と比較して一致するかどうかを判定している.
13個の md5 を16進数に変換して md5online に投げて結合した.

CR1: Ultracoded

ZERO と ONE が書かれたファイルが与えられる.
2進数かな?と重い ZERO = 0, ONE = 1 に置換する.
次に 8bit づつ区切って ASCII に変換すると以下のようになる.

Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==

どうみても base64 なので decode すると,

$ echo "Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==" | base64 -D
.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -

モールス信号なので適当なサイトに投げてデコードすると,

ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT

このままではフラグの形式じゃないので

ALEXCTF{TH15O1SO5UP3RO5ECR3TOTXT}

としてみるも駄目.O のところは普段 _ だよなぁ…とか思って置換したら正解だった.

Fore1: Hit the core

思考停止して strings してみると,

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

大文字だけみると ALEXCTF になっている.先頭の cvq を落として5文字ごとに読むとフラグになるのでは?
と思って適当なスクリプトで5文字ごと抜いてみるとフラグになった.

ALEXCTF{K33P_7H3_g00D_w0rk_up}

SC1: Math bot

nc すると計算式が与えられる.ひたすら解くゲーかと思って以下のような適当なスクリプトを書いて走らせた.

import sys
import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('195.154.53.62', 1337))

msg = s.recv(1024).strip().split('\n')
s.send(str(eval(msg[22][:-2])) + '\n')

while True:
    msg = s.recv(1024).strip().split('\n')
    print msg
    s.send(str(eval(msg[1][:-2])) + '\n')

実行すると,

['Question  500 :', '29361097422042903253933445930908 * 312827792771128387861804825784952 =']
['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}']

な感じでフラグが取れた.

TR2: SSL 0day

騒ぎになった Heartbleed だった.

TR3: CA

見てみると Let’s encrypt だったので,何度か入力すると letsencrypt で正解だった.