読者です 読者をやめる 読者になる 読者になる

sCTF 2016 Q1 Writeup

CTF writeup

この大会は2016/4/9 9:00(JST)~2016/4/16 9:00(JST)に開催されました。
今回も個人で参戦。結果は410点で91位でした。
Competitorsとしての参加チームは749チームいたので、まあまあの順位です。
解けた問題をWriteupとして書いておきます。

When in Rome (Cryptography 10)

シーザー暗号をオンラインサイト http://planetcalc.com/1434/ で解読すると、ROT9で復号できた。

Welcome to sCTF! We hope you enjoy the problems we have written for the first quarter of 2016. Here is your first of (hopefully) many flags! sctf{wh3n_1n_ctf_d0_a5_ctf3r5_d0}
sctf{wh3n_1n_ctf_d0_a5_ctf3r5_d0}

Banana Boy (Forensics 20)

JPEGファイルが与えられている。JpegAnalyzerでファイルを分割すると、分割したファイルにフラグが書かれている。
f:id:satou-y:20160419195228j:plain

sctf{tfw_d4nk_m3m3s_w1ll_a1w4y5_pr3v4il}

Ducks (Web 30)

ソースを見ると、パスワードを比較する前に extract($_POST); とあり、POSTパラメータが展開されている。比較するパラメータを2つとも同じ値で指定すればよい。
Fiddlerを起動し、Before Requestsでブレークする。POSTパラメータを「pass=a&thepassword_123=a」とするとフラグが表示された。
f:id:satou-y:20160419195840p:plain

sctf{maybe_i_shouldn't_have_extracted_everything_huh}

Lengthy Lingo (Cryptography 35)

非常に大きい数字がカンマ区切りで多数並んでいる。
いろいろ試した結果、各データの長さをASCIIコードとして読み込むと、フラグが表示された。

with open('encrypted.dat', 'r') as f:
    data = f.read()

data = data.replace('\n', '')
nums = data.split(', ')
flag = ''
for num in nums:
    flag += chr(len(num))

print flag
sctf{101_th3_numb3r5_d1dn'7_3v3n_m4tt3r}

Tracking (Algorithmic 85)

いろんな3次元空間の位置からの4地点までの距離情報が与えられている。この位置の平均値を求める問題。高校数学レベルでx, y, zが求めることができれば答えは出る。

import math

p = float(2000)
q = float(2000)
r = float(2000)
s = float(3000)
t = float(1500)
u = float(1700)

with open('tracking.txt', 'r') as f:
    lines = f.read()

lines = lines.split('\n')
num = len(lines)
xSum = float(0)
ySum = float(0)
zSum = float(0)
for line in lines:
    pos = line.split(' ')
    a = float(pos[0])
    b = float(pos[1])
    c = float(pos[2])
    d = float(pos[3])
    x = float(p**2 - (b**2-a**2)) / (p*2)
    y = float(r**2 - (c**2-b**2)) / (r*2)
    z = float((x-s)**2 - (x-q)**2 + (y-t)**2 - (y-r)**2 + u**2 - (d**2-c**2)) / (u*2)
    xSum += x
    ySum += y
    zSum += z

xAvg = int(math.ceil(xSum / num))
yAvg = int(math.ceil(ySum / num))
zAvg = int(math.ceil(zSum / num))
print 'sctf{' + str(xAvg) + ', ' + str(yAvg) + ', ' + str(zAvg) + '}'
sctf{537, 516, 487}

Verticode (Cryptography 90)

問題の暗号は、画像の左側が色で、右側がASCIIコードを表し、色によりASCIIコードをずらすというもの。暗号アルゴリズムに従い、復号する。

import Image

UNIT = 12

img = Image.open('code1.png')
w, h = img.size

y = 0
dec = ''
while y < h:
    x = 0
    index = 0
    code = ''
    while x < w:
        r, g, b = img.getpixel((x, y))

        if index > 6:
            if r == 0 and g == 0 and b == 0:
                code += '1'
            else:
                code += '0'
        elif x == 0:
            if r == 255 and g == 0 and b == 0:
                color = 0
            elif r == 128 and g == 0 and b == 128:
                color = 1
            elif r == 0 and g == 0 and b == 255:
                color = 2
            elif r == 0 and g == 128 and b == 0:
                color = 3
            elif r == 255 and g == 255 and b == 0:
                color = 4
            elif r == 255 and g == 165 and b == 0:
                color = 5

        x += UNIT
        index += 1

    y += UNIT
    dec += chr(int(code, 2) - color)

print dec

このスクリプトを実行すると、このような長い文字列で文章になっているのだが、スペースがなく読みにくい状態。

JoeLopowasamanofmildtemperamentshortstatureandhadthegoaltobecometheworldsfastesttelephoneeaterThoughLoponeverknewevenbasicphysicshecreatedatelescopecapableofsightingthesmallesthaironanalienwholivedquiteafewlightyearsawayJoeLopoquicklydestroyedalargeboulderandusedtheshatteredremainstoformeightsmallstatuesthatstronglyresembledtinycreaturesbeingorrelatedtothewaterfleaHeplacedtheminacircularpatterntoformasortofshrineandplacedthetelescopeinthemiddleofitHethenchanneledthepowerofthestonewaterfleasintothetelescopetoviewthepoweroftheheavensHewasinatrancewiththebeautyofthemysteriousdimensionanddidntevennoticetheverylargetornadoheadingtowardhimTheshrinewasquicklydemolishedandtheimmediatewithdrawlofpowersentJoeLobointoalairofpitchblacknessfoundtobeaparalleldimensionthatcausABCiamtheflagalllowercasenojokeDEFanyonewhosefirstnamebeganwithJalongwithMLandQtobecomeratheruncomfortableJoewasalsosuddenlyintroducedtoundroclamaticolomphasisciousytheeccentrictapewormwithastrongmorrocanaccentImundroclamaticolomphasisciousytheeccentrictapewormIlikepizzasohowareyadoinIhavenoideasaidJoe

https://www.wattpad.com/72172589-now-i-see-you-phonesに原文があるので、差のある箇所を見てみる。「ABCiamtheflagalllowercasenojokeDEF」という部分が違い、ABCとDEFに挟まれた小文字の部分がフラグだった。

sctf{iamtheflagalllowercasenojoke}

Vertinet (Cryptography 140)

ncコマンドで接続してみると、Data URIスキームで画像が指定されているHTMLが返ってくる。

$ nc problems1.2016q1.sctf.io 50000
<html><img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAFoCAIAAABMtifjAAAEqUlEQVR4nO3dQY7TMBiA0QblKpyql0kPM1yKw5QlYjE0EsZO53tvHTWGT954rD/b7fa8dW3T3vR8vv5/3rYx6znzrm9D3sTbET5K+Cjho4SPEj5K+Cjho4SPEj5K+Kj9+THvvPpqtvvrZ2aesZ9xZj1n2PFRwkcJHyV8lPBRwkcJHyV8lPBRwkcJH7WvXsBXMPM8f9Tv2PFRwkcJHyV8lPBRwkcJHyV8lPBRwkcJH7VvP1cv4dpm3pk/Y9TfBez4KOGjhI8SPkr4KOGjhI8SPkr4KOGjhI/aBo1UeUujjuFHzaUxr57/Tvgo4aOEjxI+Svgo4aOEjxI+Svgo4aP224/VS7i2UffYz/zOqHe5V8+nhI8SPkr4KOGjhI8SPkr4KOGjhI8SPsq9+hdm3pmf+S47Pkr4KOGjhI8SPkr4KOGjhI8SPkr4KOGj9u2xegnXdrU786PO8+34KOGjhI8SPkr4KOGjhI8SPkr4KOGjhI/an99XL2GdUV+Nnfn92VHvsuOjhI8SPkr4KOGjhI8SPkr4KOGjhI8SPmrffq5ewvsbdWd+Jjs+Svgo4aOEjxI+Svgo4aOEjxI+Svgo4aPcqx/xOxebRX/mXXZ8lPBRwkcJHyV8lPBRwkcJHyV8lPBRwkf5tuwkV7t7b8dHCR8lfJTwUcJHCR8lfJTwUcJHCR8lfNS+egH8NvM8346PEj5K+Cjho4SPEj5K+Cjho4SPEj5K+Kj99mP1Eq5t1Pn5zDvzZuDwKeGjhI8SPkr4KOGjhI8SPkr4KOGjhI/aH/dj9RoWOl4+MWo+/MzfOcOOjxI+Svgo4aOEjxI+Svgo4aOEjxI+Svio7fmxegnrbPfXz4z6JuwZo87h3avnU8JHCR8lfJTwUcJHCR8lfJTwUcJHCR/lXv2bGXX33o6PEj5K+Cjho4SPEj5K+Cjho4SPEj5K+Kjtdpt3b/x6rjVD/oxRs3Ts+Cjho4SPEj5K+Cjho4SPEj5K+Cjho4SP2o/bY/UaljlOPDPz27Iz5+3Y8VHCRwkfJXyU8FHCRwkfJXyU8FHCRwkfta9ewFcw85uwZuDwT4SPEj5K+Cjho4SPEj5K+Cjho4SPEj7KDJwBRp2fz5yTY8dHCR8lfJTwUcJHCR8lfJTwUcJHCR8lfNT2/Fi9hHW2+7x3mVfPJQgfJXyU8FHCRwkfJXyU8FHCRwkfJXzU/rgfq9ew0PHyiZnzbWb+jh0fJXyU8FHCRwkfJXyU8FHCRwkfJXyU8FHbqQ+sflXH6gX8yQwc/jvho4SPEj5K+Cjho4SPEj5K+Cjho4SP2kyr/7urza4xA4d/InyU8FHCRwkfJXyU8FHCRwkfJXyU8FHu1b+ZUX87sOOjhI8SPkr4KOGjhI8SPkr4KOGjhI8SPmpfvYCKq829t+OjhI8SPkr4KOGjhI8SPkr4KOGjhI8SPmo73vFy+SBn/u2j7rGPMuo8346PEj5K+Cjho4SPEj5K+Cjho4SPEj5K+KjtYkfRU5059javni9F+Cjho4SPEj5K+Cjho4SPEj5K+Cjho/bHdqxew0LHyydGnY2bgcMlCB8lfJTwUcJHCR8lfJTwUcJHCR8lfNQv5m7AS/gZVBAAAAAASUVORK5CYII='></img>

BASE64デコードしてファイル保存すると、Verticodeの問題と同じような画像になるので、これを踏まえスクリプトを作成する。

import socket
import re
import base64
import Image

pattern = 'image/png;base64,(.*)\''
UNIT = 12

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('problems1.2016q1.sctf.io', 50000))

for i in range(1, 1000):
    data = s.recv(2048)
    print data
    if 'sctf{' in data:
        break
    m = re.search(pattern, data)
    img_b64 = m.group(1)
    with open('data.png', 'wb') as f:
        f.write(img_b64.decode('base64'))

    img = Image.open('data.png')
    w, h = img.size

    y = 0
    dec = ''
    while y < h:
        x = 0
        index = 0
        code = ''
        while x < w:
            r, g, b = img.getpixel((x, y))

            if index > 6:
                if r == 0 and g == 0 and b == 0:
                    code += '1'
                else:
                    code += '0'
            elif x == 0:
                if r == 255 and g == 0 and b == 0:
                    color = 0
                elif r == 128 and g == 0 and b == 128:
                    color = 1
                elif r == 0 and g == 0 and b == 255:
                    color = 2
                elif r == 0 and g == 128 and b == 0:
                    color = 3
                elif r == 255 and g == 255 and b == 0:
                    color = 4
                elif r == 255 and g == 165 and b == 0:
                    color = 5

            x += UNIT
            index += 1

        y += UNIT
        dec += chr(int(code, 2) - color)

    print '%d times: %s' %(i, dec)
    s.sendall(dec)

スクリプトを実行し、200回正解すると、フラグが表示された。

sctf{y0ub34tth3v3rt1c0d3}