ASIS CTF Finals 2017 Writeup

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

V.I.R (Warm-up)

Rulesのページの最下部にフラグが書いてある。

Good luck, ASIS{_rUL35_4r3_4Lw4y5_ImP0rt4nt}
ASIS{_rUL35_4r3_4Lw4y5_ImP0rt4nt}

Vivid Spying (Forensics, Network)

pcapファイルが与えられている。FQDNで0,1の名前を1文字ずつ長くしてDNSに問い合わせしている。続きを行い、0,1を2進数として文字列にすることを考える。

import dns.resolver

r = dns.resolver.Resolver()
r.nameservers = ['95.85.26.168']

domain = '1110.000011101100101011111010110111101100101010010010110010101000001.asisctf.com'

while True:
    if len(domain) % 64 == 11:
        domain = '.' + domain
    print domain

    finish = False
    for i in [0, 1]:
        try_domain = str(i) + domain
        try:
            rdata = r.query(try_domain, 'A')
            domain = try_domain
            break
        except:
            if i == 0:
                continue
            else:
                finish = True
    if finish:
        break

enc = domain.replace('.asisctf.com', '').replace('.', '')
enc = '0' + enc[::-1]

flag = ''
for i in range(0, len(enc), 8):
    flag += chr(int(enc[i:i+8], 2))

print flag
ASIS{_Spying_with_DNS_!}

Cryptocurrency Coding (PPC)

$ nc 178.62.22.245 58901
Hi all, let's go to BTCing!!
Are you ready? [Y]es or [N]o:
y
Send us a valid BTC address with same length of given damaged address that correct it :)
----------------------------------------------------------------------------------------
the damaged BTC address is: 1CnmjSXKaPZRNb7pUR8rNGduP5UEfs5yBb
Send the correted BTC:

Bitcoinアドレスとして間違っているので、訂正する問題。チェックディジットを修正するプログラムを書く。

import socket
import re
import base58
import hashlib

def correct(btc):
    btcbytes = base58.b58decode(btc)
    chk = hashlib.sha256(hashlib.sha256(btcbytes[-25:-4]).digest()).digest()[:4]
    correct_btcbytes = btcbytes[:-4] + chk
    correct_btc = base58.b58encode(correct_btcbytes)
    return correct_btc

pattern = 'the damaged BTC address is: (.+)\n'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('178.62.22.245', 58901))

data = s.recv(256)
print data
print 'Y'
s.sendall('Y\n')
data = s.recv(256)
print data

i = 1
while True:
    print 'Round %d' % i
    data = s.recv(256)
    print data
    if data.startswith('Good job'):
        data = s.recv(256)
        print data
    m = re.match(pattern, data)
    dmg_btc = m.group(1)
    crct_btc = correct(dmg_btc)
    print crct_btc
    s.sendall(crct_btc + '\n')
    i += 1

data = s.recv(256)
print data
ASIS{!0h_BTC_h4S_aT_leas7_3_3rr0r_cOrr3ct1ng_fe4tur3!}

Simple Crypto (Crypto)

flagをkeyで繰り返し、XORしている。flagに戻すとPNGのフォーマットなっていることがわかるので、それを踏まえコードを書く。

KEY = 'musZTXmxV58UdwiKt8Tp'
key = KEY.encode('hex')

with open('flag.enc', 'rb') as f:
    enc = f.read()

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

with open('flag.png', 'wb') as f:
    f.write(flag.decode('hex'))

f:id:satou-y:20170912221548p:plain

ASIS{juSt_S!mpl3_Cryp7o_f0r_perFect_guy5_l1ke_You!}

Hash collision (Crypto)

phishで定義されたハッシュはコードをよく読むと、X[-1]の値が同じだと同じ結果になる。さらによく考えると、p, g, sの値に関係なく、ある文字列にパディング文字 '/' を追加したそのハッシュもほぼ同じ結果になる。出題者の意図とは違う気がするが、このことからコードを書き、フラグをゲットすることができた。

import socket
import re
import base58
import hashlib
import itertools
import string

def get_btc(s):
    h = hashlib.new('ripemd160')
    h.update(s)
    ripemd160 = h.digest()

    btcbytes_head = '\x00' + ripemd160
    chk = hashlib.sha256(hashlib.sha256(btcbytes_head).digest()).digest()[:4]
    btcbytes = btcbytes_head + chk

    return base58.b58encode(btcbytes)

pattern = '\| Send a BTC valid address that starts with (.+)\:'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('66.172.27.77', 11019))

data = s.recv(256)
print data
print 'Y'
s.sendall('Y\n')
data = s.recv(256)
print data
m = re.match(pattern, data)
start = m.group(1)

for c in itertools.product(string.printable, repeat=4):
    text = ''.join(c)
    try_btc = get_btc(text)
    if try_btc.startswith(start):
        print try_btc
        s.sendall(try_btc + '\n')
        break

data = s.recv(1024)
print data
data = s.recv(1024)
print data
print 'P'
s.sendall('P\n')
data = s.recv(1024)
print data
data = s.recv(1024)
print data
print 'R'
s.sendall('R\n')
data = s.recv(1024)
print data
data = s.recv(1024)
print data
print 'S'
s.sendall('S\n')
data = s.recv(1024)
print data
print 'ab'
s.sendall('ab\n')
data = s.recv(1024)
print data
print 'ab/'
s.sendall('ab/\n')
data = s.recv(1024)
print data
ASIS{ce8a30c725bdc9fea1da21102fdb480f}