CSAW CTF Qualification Round 2018 Writeup

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

Twitch Plays Test Flag (Misc 1)

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

flag{typ3_y3s_to_c0nt1nue}

babycrypto (Crypto 50)

Base64デコードしてXORで復号する。XORの鍵は1文字前提でブルートフォースでやってみる。

def is_printable(s):
    for i in range(len(s)):
        if ord(s[i]) < 32 or ord(s[i]) > 126:
            return False
    return True

with open('ciphertext.txt', 'r') as f:
    data = f.read().strip()

data = data.decode('base64')

for k in range(256):
    dec = ''
    for i in range(len(data)):
        dec += chr(ord(data[i]) ^ k)
    if is_printable(dec):
        print 'key =', k
        print 'flag =', dec

実行結果は以下の通り。

key = 224
flag = Szpq?vl?~?ompxm~rrzm?hwp?~lovmzl?kp?|mz~kz?ompxm~rl?kw~k?wzso?ozposz?{p?szll1?Wz?h~qkl?kp?ojk?~jkpr~kvpq?yvmlk3?~q{?l|~s~}vsvkf?~spqxlv{z1?Wz?{mz~rl?py?~?hpms{?hwzmz?kwz?zq{szll?~q{?kwz?vqyvqvkz?}z|prz?mz~svkvzl?kp?r~qtvq{3?~q{?hwzmz?kwz?kmjz?i~sjz?py?svyz?vl?omzlzmiz{1ys~xd{vyyvz2wzssr~q2x/ow,mem~PF.U~s+|W~YF&LHMf^N)~Wb
key = 234
flag = Ypz{5|f5t5egzrgtxxpg5b}z5tfe|gpf5az5vgptap5egzrgtxf5a}ta5}pye5epzeyp5qz5ypff;5]p5bt{af5az5e`a5t`azxta|z{5s|gfa95t{q5fvtytw|y|al5tyz{rf|qp;5]p5qgptxf5zs5t5bzgyq5b}pgp5a}p5p{qypff5t{q5a}p5|{s|{|ap5wpvzxp5gpty|a|pf5az5xt{~|{q95t{q5b}pgp5a}p5ag`p5cty`p5zs5y|sp5|f5egpfpgcpq;sytrnq|ss|p8}pyyxt{8r%e}&gogtZL$_ty!v]tSL,FBGlTD#t]h
key = 241
flag = Bka`.g}.o.~|ai|occk|.yfa.o}~g|k}.za.m|kozk.~|ai|oc}.zfoz.fkb~.~ka~bk.ja.bk}} .Fk.yo`z}.za.~{z.o{zacozga`.hg|}z".o`j.}mobolgbgzw.oba`i}gjk .Fk.j|koc}.ah.o.ya|bj.yfk|k.zfk.k`jbk}}.o`j.zfk.g`hg`gzk.lkmack.|kobgzgk}.za.co`eg`j".o`j.yfk|k.zfk.z|{k.xob{k.ah.bghk.g}.~|k}k|xkj hboiujghhgk#fkbbco`#i>~f=|t|oAW?Dob:mFoHW7]Y\wO_8oFs
key = 248
flag = Kbhi'nt'f'wuh`ufjjbu'poh'ftwnubt'sh'dubfsb'wuh`ufjt'sofs'obkw'wbhwkb'ch'kbtt)'Ob'pfist'sh'wrs'frshjfsnhi'anuts+'fic'tdfkfenkns~'fkhi`tncb)'Ob'cubfjt'ha'f'phukc'pobub'sob'bickbtt'fic'sob'nianinsb'ebdhjb'ubfknsnbt'sh'jfilnic+'fic'pobub'sob'surb'qfkrb'ha'knab'nt'wubtbuqbc)akf`|cnaanb*obkkjfi*`7wo4u}ufH^6Mfk3dOfA^>TPU~FV1fOz
key = 252
flag = Oflm#jp#b#sqldqbnnfq#tkl#bpsjqfp#wl#`qfbwf#sqldqbnp#wkbw#kfos#sflsof#gl#ofpp-#Kf#tbmwp#wl#svw#bvwlnbwjlm#ejqpw/#bmg#p`bobajojwz#bolmdpjgf-#Kf#gqfbnp#le#b#tlqog#tkfqf#wkf#fmgofpp#bmg#wkf#jmejmjwf#af`lnf#qfbojwjfp#wl#nbmhjmg/#bmg#tkfqf#wkf#wqvf#ubovf#le#ojef#jp#sqfpfqufg-eobdxgjeejf.kfoonbm.d3sk0qyqbLZ2Ibo7`KbEZ:PTQzBR5bK~
key = 254
flag = Mdno!hr!`!qsnfs`llds!vin!`rqhsdr!un!bsd`ud!qsnfs`lr!ui`u!idmq!qdnqmd!en!mdrr/!Id!v`our!un!qtu!`tunl`uhno!ghsru-!`oe!rb`m`chmhux!`mnofrhed/!Id!esd`lr!ng!`!vnsme!vidsd!uid!doemdrr!`oe!uid!hoghohud!cdbnld!sd`mhuhdr!un!l`ojhoe-!`oe!vidsd!uid!ustd!w`mtd!ng!mhgd!hr!qsdrdswde/gm`fzehgghd,idmml`o,f1qi2s{s`NX0K`m5bI`GX8RVSx@P7`I|
key = 255
flag = Leon is a programmer who aspires to create programs that help people do less. He wants to put automation first, and scalability alongside. He dreams of a world where the endless and the infinite become realities to mankind, and where the true value of life is preserved.flag{diffie-hellman-g0ph3rzraOY1Jal4cHaFY9SWRyAQ6aH}
flag{diffie-hellman-g0ph3rzraOY1Jal4cHaFY9SWRyAQ6aH}

flatcrypt (Crypto 100)

CRIME: Compression Ratio Info-leak Made Easyに関する攻撃が可能。zlib(deflate圧縮)は同じ文字列が繰り返しあると、圧縮率が高くなるという性質を使って、少しずつ文字列を試し、圧縮率の高い文字を探る。

import socket
import string

def recvuntil(s, tail):
    data = ''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

chars = string.lowercase + '_'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.chal.csaw.io', 8043))

flag = ''
while True:
    min_length = 9999
    min_char = '?'
    min_char_count = 0
    for c in chars:
        data = recvuntil(s, '\n')
        print data
        f = (c + flag) * 7
        if len(f) < 20:
            f = f * 3
        print f
        s.sendall(f + '\n')
        data = recvuntil(s, '\n')
        print data
        size = ord(data.strip()[-1])
        print size
        if size < min_length:
            min_length = size
            min_char = c
            min_char_count = 1
        elif size == min_length:
            min_char_count += 1
    if min_char_count > 1:
        break
    flag = min_char + flag

print flag

実行結果は以下の通りだが、フラグとしては通らない。

rime_doesnt_have_a_logo

CRIMEの攻撃のことを考え、以下のようにしたら通った。

crime_doesnt_have_a_logo

lowe (Crypto 200)

$ openssl rsa -pubin -text < pubkey.pem
Public-Key: (1536 bit)
Modulus:
    00:cf:70:7e:ed:97:90:17:b7:f6:f4:76:ff:3b:a6:
    55:59:ad:b1:82:e0:7c:fa:23:33:b1:ec:05:6b:7f:
    7b:96:12:40:54:f1:f5:74:8b:04:c3:69:4e:90:f0:
    d9:9f:ee:05:84:a8:7a:70:81:75:80:d4:93:93:32:
    1b:b2:08:07:ff:de:25:a4:c8:ab:d4:6d:95:c1:e3:
    74:0d:9e:64:1f:e7:7f:9b:96:ce:ca:e9:18:e6:7a:
    24:89:52:b5:da:81:ae:77:42:bd:ae:51:b1:29:24:
    59:73:41:50:57:ae:75:df:b7:5a:78:e8:24:37:9e:
    52:50:65:92:c3:75:0e:9a:1c:7e:70:1b:ee:8d:df:
    c7:a9:ca:72:53:4c:d3:b0:95:79:f8:7a:4e:b3:76:
    f9:26:7c:d1:a1:6e:1e:57:90:95:c5:b8:6f:4b:8f:
    24:fb:61:3f:08:a7:e0:e4:75:d2:55:56:ae:41:c8:
    ce:e2:48:e9:0d:ac:96:5d:c4:7d:db:b4:c5
Exponent: 3 (0x3)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIHdMA0GCSqGSIb3DQEBAQUAA4HLADCBxwKBwQDPcH7tl5AXt/b0dv87plVZrbGC
4Hz6IzOx7AVrf3uWEkBU8fV0iwTDaU6Q8Nmf7gWEqHpwgXWA1JOTMhuyCAf/3iWk
yKvUbZXB43QNnmQf53+bls7K6RjmeiSJUrXaga53Qr2uUbEpJFlzQVBXrnXft1p4
6CQ3nlJQZZLDdQ6aHH5wG+6N38epynJTTNOwlXn4ek6zdvkmfNGhbh5XkJXFuG9L
jyT7YT8Ip+DkddJVVq5ByM7iSOkNrJZdxH3btMUCAQM=
-----END PUBLIC KEY-----
n = 0x00cf707eed979017b7f6f476ff3ba65559adb182e07cfa2333b1ec056b7f7b96124054f1f5748b04c3694e90f0d99fee0584a87a70817580d49393321bb20807ffde25a4c8abd46d95c1e3740d9e641fe77f9b96cecae918e67a248952b5da81ae7742bdae51b129245973415057ae75dfb75a78e824379e52506592c3750e9a1c7e701bee8ddfc7a9ca72534cd3b09579f87a4eb376f9267cd1a16e1e579095c5b86f4b8f24fb613f08a7e0e475d25556ae41c8cee248e90dac965dc47ddbb4c5
e = 3

eは小さいので、そのまま3乗根を出そうとしたが、うまくいかない。問題からfile.encはXORで復号できるはず。
この文字列より短い鍵であると仮定すると、3乗してもnを少し超える程度と予想できる。nをプラスしながら、復号する。鍵を復号で来たら、XORでフラグを復号する。

from Crypto.PublicKey import RSA
import gmpy

with open('pubkey.pem', 'r') as f:
    pub_data = f.read()

pubkey = RSA.importKey(pub_data)
n = pubkey.n
e = pubkey.e

with open('key.enc', 'r') as f:
    c = int(f.read().strip())

while True:
    m = gmpy.root(c, e)[0]
    if m**e == c:
        break
    c += n

key = '%x' % m
if len(key) % 2 == 1:
    key = '0' + key
key = key.decode('hex')

with open('file.enc', 'r') as f:
    data = f.read().strip().decode('base64')

flag = ''
for i in range(len(data)):
    code = ord(data[i]) ^ ord(key[i%len(key)])
    flag += chr(code)
print flag
flag{saltstacksaltcomit5dd304276ba5745ec21fc1e6686a0b28da29e6fc}