DefCamp CTF Qualification 2018 Writeup

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

XORnigma (Junior)

XOR暗号。フラグはDCTF{で始まることを考慮し、キーを割り出す。キーの1バイト目と5バイト目が同じなので、4バイトと考え、復号する。

import itertools

def xor_two_str(s, key):
    key = key * (len(s) / len(key) + 1)
    return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in itertools.izip(s, key))

enc = '000000003f2537257777312725266c24207062777027307574706672217a67747374642577263077777a3725762067747173377326716371272165722122677522746327743e'
enc = enc.decode('hex')
flag_head = 'DCTF{'

key = ''
for i in range(len(flag_head)):
    key += chr(ord(enc[i]) ^ ord(flag_head[i]))
key = key[:4]

flag = xor_two_str(enc, key)
print flag
DCTF{fcc34eaae8bd3614dd30324e932770c3ed139cc2c3250c5b277cb14ea33f77a0}

Multiple Flags (Junior)

手旗信号の画像。
f:id:satou-y:20180926185751p:plain
https://ja.wikipedia.org/wiki/%E6%89%8B%E6%97%97%E4%BF%A1%E5%8F%B7を参考に、文字にしていく。

(文字)DCTFSPECIALFLAG(数字)00(文字)AA(数字)00(文字)AA(数字)00991337(文字)DCTF
DCTFSPECIALFLAG00AA00AA00991337DCTF

Passport (Junior)

demo.binと異なるバイナリで、md5が同じファイルをアップロードすればフラグが表示されるようだ。
試しにdemo.binのmd5の値で調べてみる。

cee9a457e790cf20d4bdaa6d69f01e41

http://www.xefan.com/archives/83875.htmlに衝突する2つのファイルが書いてあり、片方はdemo.binと一致する。もう一つのバイナリを作成すればよい。
バイナリエディタでdemoの一部を修正する。

・オフセット0x15:0x70→0x74
・オフセット0x2b:0x5c→0xdc

この作成したバイナリファイルをアップロードすると、フラグが表示された。

DCTF{04c8d0052e3ffd8d21934e392c272a0494f23433901941c93fab82b50be27c1a}

Ransomware (Reverse)

ransomware.pycをEasyPythonDecompilerでデコンパイルする。

import string
from random import *
import itertools

def caesar_cipher(OOO0O0O00OOO0O0OO, O0O0O0O0OOOO0OOOO):
    O0O0O0O0OOOO0OOOO = O0O0O0O0OOOO0OOOO * (len(OOO0O0O00OOO0O0OO) / len(O0O0O0O0OOOO0OOOO) + 1)
    return ''.join((chr(ord(O0O0O00O0000O00O0) ^ ord(OO0000000O0OO00OO)) for O0O0O00O0000O00O0, OO0000000O0OO00OO in itertools.izip(OOO0O0O00OOO0O0OO, O0O0O0O0OOOO0OOOO)))


f = open('./FlagDCTF.pdf', 'r')
buf = f.read()
f.close()
allchar = string.ascii_letters + string.punctuation + string.digits
password = ''.join((choice(allchar) for OOO0OO0OO00OO0000 in range(randint(60, 60))))
buf = caesar_cipher(buf, password)
f = open('./youfool!.exe', 'w')
buf = f.write(buf)
f.close()

cease_cipher関数は読みにくいので、置き換える。

def caesar_cipher(x, y):
    y = y * (len(x) / len(y) + 1)
    return ''.join((chr(ord(a) ^ ord(b)) for a, b in itertools.izip(x, y)))

簡単に言えば, XOR関数で、実行している部分を見ると、鍵の長さは60であることがわかる。PDFに復号できることを前提に少しずつ調整しながら鍵を見つけていく。

def str_xor(s1, s2):
    return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2))

with open('youfool!.exe', 'rb') as f:
    data = f.read()

key = ''
#### key 0-6
PDF_HEAD = '%PDF-1.'
key += str_xor(PDF_HEAD, data[:len(PDF_HEAD)])

#### key 7-9
AFTER_FIL = 'ter'
key += str_xor(AFTER_FIL, data[1387:1390])

#### key 10-11
AFTER_LENG = 'th'
key += str_xor(AFTER_LENG, data[8470:8472])

#### key 12-15
AFTER_CAT = 'alog'
key += str_xor(AFTER_CAT, data[672:676])

#### key 16-19
AFTER_MIDI = 'aBox'
key += str_xor(AFTER_MIDI, data[856:860])

#### key 20-22
AFTER_FLATEDEC = 'ode'
key += str_xor(AFTER_FLATEDEC, data[10220:10223])

#### key 23-24
AFTER_PARE = 'nt'
key += str_xor(AFTER_PARE, data[10043:10045])

#### key 25-27
AFTER_IM = 'age'
key += str_xor(AFTER_IM, data[9625:9628])

#### key 28-30
AFTER_LEN = 'gth'
key += str_xor(AFTER_LEN, data[1408:1411])

#### key 31-32
AFTER_FILT = 'er'
key += str_xor(AFTER_FILT, data[10531:10533])

#### key 33-34
AFTER_TY = 'pe'
key += str_xor(AFTER_TY, data[10173:10175])

#### key 35-43
AFTER_FL = 'ateDecode'
key += str_xor(AFTER_FL, data[9695:9704])

#### key 44-45
EOF_TAIL = 'OF'
key += str_xor(EOF_TAIL, data[10784:10786])

#### key 46-50
AFTER_FLATEDECODE_L = 'ength'
key += str_xor(AFTER_FLATEDECODE_L, data[1066:1071])

#### key 51-56
AFTER_EXT = 'GState'
key += str_xor(AFTER_EXT, data[10071:10077])

#### key 57-59
AFTER_RESO = 'urc'
key += str_xor(AFTER_RESO, data[897:900])

print '[+] key:', key

pdf = ''
for i in range(0, len(data), 60):
    dec = str_xor(data[i:i+60], key)
    print dec, i # for arrangement
    pdf += dec

with open('FlagDCTF.pdf', 'wb') as f:
    f.write(pdf)

復号したPDFは3ページにわたり、フラグが書かれている。
f:id:satou-y:20180926193052p:plain
f:id:satou-y:20180926193104p:plain
f:id:satou-y:20180926193113p:plain

DCTF{d915b5e076215c3efb92e5844ac20d0620d19b15d427e207fae6a3b894f91333}