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

WhiteHat Challenge 02 Writeup

CTF writeup

この大会は2017/3/25 13:00(JST)~2017/3/20 21:00(JST)に開催されました。
今回もチームで参戦。結果は80点で81チーム中20位でした。
自分で解けた問題をWriteupとして書いておきます。

Crypto001 (Cryptography 20)

n(modulus)をFermat法で素因数分解し、復号する。

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)

    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

c = 0x42e08bb01f0cb9ba959ddcb771eb641afe87b775adfee9e02f9941d6a0f127ce3e4c794f81661295a3f6f26b5bf5b97fb244c49fe6bcebd202c337d18da4c37520461872c9e0f4d735b45f03db80288d8a4b1e2e9c8350860c0bb7bc4e461cff6e2827720450c189ff7946a48ecc234a1ad8107ed1baf3d32d4b5d678a9972e768f4f8fc854ba03c36d9f67ea1ff058c3e5390c5a3ce16e7803d6f70d2514b977911427ac92694065e1bf4f51791d0cd1e0426ced501e125fe7a03d1514b0c41dfb4c36b8c12128a84ec8bd7776089fd5918315fe4fa01a9021897f48d77ea4719f46f91ed2f07ea2cbe57214cddbccafabc2d04881ccc02cab2e6a12f9e4291
n = 22538226557359593572346358546448534316502374936010448386594814842974948185264245943532391888185780963684478526253798386491706856055721928437429885241499953118882150091346829521458455087101372254666403540557260438634164283165429965553504233799473121743076739557259202565372789362450321949620402058911471334565735242774625841491381660958586223360222338739572747101258430902493093450151421824669407116051626021283885808048507068886635263867243474018292757027989902382327148650784375980240979112130712113839597585132552988013197038652273781471554107489186108861150933302755959031058580590411316776473912540458121516196981
e = 65537

p, q = fermat(n)

a = (p - 1) * (q - 1)

x = 0
while True:
    if (a * x + 1) % e == 0:
        d = (a * x + 1) / e
        break
    x = x + 1

m = pow(c, d, n)

flag = ('%x' % m).decode('hex')
print flag

実行すると、次の文字列になる。

flag is close_primes_is_bad
$ echo -n close_primes_is_bad | sha1sum
0732e65c5c2769ffb5ea0e408f1bf13ae6288767  -
WhiteHat{0732e65c5c2769ffb5ea0e408f1bf13ae6288767}

Crypto002 (Cryptography 15)

逆算し、keyについてブルートフォースで元に戻す。

import string

L2I = dict(zip(string.uppercase+string.lowercase+string.digits,range(64)))
I2L = dict(zip(range(64),string.uppercase+string.lowercase+string.digits))

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

for key in range(64):
    b64text = ''
    for c in ciphertext:
        if L2I.has_key(c):
            index = (L2I[c] - key) % 64
            if I2L.has_key(index):
                b64text += I2L[index]
            else:
                break
        else:
            break
    try:
        flag = b64text.decode('base64')
        print str(key) + ': ' + flag
    except:
        pass

この実行結果は以下の通り。

0: 」P08ャ杠枡・]・1枷4l%・f・l2ヲh8ォZ
8: む(ヲ0薯
}ラ:}肅呑;・)}・O」辣蓍・*・0韓
9: ~ヘ・・求ノyニモヲ礁禸∬yヤ・逃・ヲ}ル驕ユ・ネァ
10: zスヲ{qョ?・カクuテe脅ケ|qァuトェGテ}トeyノィ}ナョずf
11: vュewamヂGqヲwqウ$・xxafqエiCs$yエ$uケgyオm~ィ%
12: r・sQ,Qm・m「繝・tQ%m、(?b縉」縡ゥ&u・,z嶺
13: n後o@・@ナi・i弔怪p@臺鍋;R「q討m伜q罷v・
14: j|「k0ェw0・uエeB{yオl0」eΘ7Bamヂi愛m━rwb
15: flag is Caesar with base32 is exciting!
16: b\ c(o]U2]a゚sY3d!]c$/!゚eb゚ah"ed(jV
21: N
ロNホ綮ホI鋹喟畯ホワI゚ミ啣哺ンQ綏
22: I埇Jセ「VセシDE YZOセ妣・タYMYI廴「Q
23: E鷓FョaRョ{@緻@・V輙KョZ@ーH・DHM・
26: 9ケ・}曦}ク4イィ4マUJカゥ?}・タ・酋<タU8ナ・チ暸エV
27: 5ゥU6m]Bmw0「g0ソFヲh;mV0ーY8ー4オW8ア]=、
28: 1・2]>]6,・,ョモB・7],
31: %hQ&,Y2,s ac ~6ed+,R U・($tS(pY-c
32: !X".2Q"mマ2U#'o・マ$nマ d$`)Rミ
35: 'M・!・ _=&$`・>Q・>3O?U"
.ン・-ヒ#/フヒ"ロ
・:  ・
41:
42:
43: EMigW「X
44: 
45: ・テ?ヒ
46: 鑼る8忌8、轗皮晦
47: 臈A・I・c緡S縻 T・B縵Eア: ・ 輛C・I・
56: テメ8タ・ フ・セロ
セ銷ミ゚ナ・セ・県顆ツ・ニ・ ヒワ
59: キ。uエe}タeWイェGイキ4トョHケevイクy€w4コク4カスwコケ}ソャ5
60: ウ・ーU<シUョ・ョヲ・オU5ョィ8|fァュ6カゥ<サ幺
61: ッ€D觶Dユェ嫁ェ夢シ哉アD憐xVイイ隆ョ懾イ傴キ教
62: ォpイィ4コエ4幡y┬・ク}・4ウヲ・tFqョ?ェ原ョ絢ウ{r
63: ァ`q、$yー$S「iC「v0エmDゥ$r「wup60ェw0ヲ|sェxyッk1

keyが15のときに文になっている。

flag is Caesar with base32 is exciting!
$ echo -n "Caesar with base32 is exciting!" | sha1sum
f4637ac70451282471bb368a7566c063b87b1b24  -
WhiteHat{f4637ac70451282471bb368a7566c063b87b1b24}

Web001 (Web Security 15)

Click meをクリックすると、This is a javascript challengeと表示される。
ソースにJavaScriptがあるところを探す。
hello.jsに次のように書いてある。

function sayHello() {
	alert ("This is a javascript challenge");
	showFlag=String.fromCharCode(118,97,114,32,101,110,99,111,61,39,39,59,13,10,118,97,114,32,101,110,99,111,50,61,49,50,54,59,13,10,118,97,114,32,101,110,99,111,51,61,51,51,59,13,10,118,97,114,32,99,107,61,100,111,99,117,109,101,110,116,46,85,82,76,46,115,117,98,115,116,114,40,100,111,99,117,109,101,110,116,46,85,82,76,46,105,110,100,101,120,79,102,40,39,61,39,41,41,59,13,10,32,13,10,32,13,10,102,111,114,40,105,61,49,59,105,60,49,50,50,59,105,43,43,41,13,10,123,13,10,101,110,99,111,61,101,110,99,111,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,105,44,48,41,59,13,10,125,13,10,32,13,10,102,117,110,99,116,105,111,110,32,101,110,99,111,95,40,120,41,13,10,123,13,10,114,101,116,117,114,110,32,101,110,99,111,46,99,104,97,114,67,111,100,101,65,116,40,120,41,59,13,10,125,13,10,32,13,10,105,102,40,99,107,61,61,34,61,34,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,52,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,51,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,49,57,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,54,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,48,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,48,52,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,50,45,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,49,57,56,41,41,43,34,126,126,126,126,126,126,34,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,50,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,51,41,41,13,10,123,13,10,97,108,101,114,116,40,34,80,97,115,115,119,111,114,100,32,105,115,32,34,43,99,107,46,114,101,112,108,97,99,101,40,34,61,34,44,34,34,41,41,59,13,10,125,13,10);
	eval(showFlag);
}

Chromeデベロッパーツールで以下を実行してみる。

showFlag=String.fromCharCode(118,97,114,32,101,110,99,111,61,39,39,59,13,10,118,97,114,32,101,110,99,111,50,61,49,50,54,59,13,10,118,97,114,32,101,110,99,111,51,61,51,51,59,13,10,118,97,114,32,99,107,61,100,111,99,117,109,101,110,116,46,85,82,76,46,115,117,98,115,116,114,40,100,111,99,117,109,101,110,116,46,85,82,76,46,105,110,100,101,120,79,102,40,39,61,39,41,41,59,13,10,32,13,10,32,13,10,102,111,114,40,105,61,49,59,105,60,49,50,50,59,105,43,43,41,13,10,123,13,10,101,110,99,111,61,101,110,99,111,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,105,44,48,41,59,13,10,125,13,10,32,13,10,102,117,110,99,116,105,111,110,32,101,110,99,111,95,40,120,41,13,10,123,13,10,114,101,116,117,114,110,32,101,110,99,111,46,99,104,97,114,67,111,100,101,65,116,40,120,41,59,13,10,125,13,10,32,13,10,105,102,40,99,107,61,61,34,61,34,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,52,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,51,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,49,57,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,54,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,48,48,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,48,52,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,50,50,50,45,50,41,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,95,40,49,57,56,41,41,43,34,126,126,126,126,126,126,34,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,50,41,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,101,110,99,111,51,41,41,13,10,123,13,10,97,108,101,114,116,40,34,80,97,115,115,119,111,114,100,32,105,115,32,34,43,99,107,46,114,101,112,108,97,99,101,40,34,61,34,44,34,34,41,41,59,13,10,125,13,10);

また、次のようにJavaScriptのコードになった。

"var enco='';
var enco2=126;
var enco3=33;
var ck=document.URL.substr(document.URL.indexOf('='));
 
 
for(i=1;i<122;i++)
{
enco=enco+String.fromCharCode(i,0);
}
 
function enco_(x)
{
return enco.charCodeAt(x);
}
 
if(ck=="="+String.fromCharCode(enco_(240))+String.fromCharCode(enco_(220))+String.fromCharCode(enco_(232))+String.fromCharCode(enco_(192))+String.fromCharCode(enco_(226))+String.fromCharCode(enco_(200))+String.fromCharCode(enco_(204))+String.fromCharCode(enco_(222-2))+String.fromCharCode(enco_(198))+"~~~~~~"+String.fromCharCode(enco2)+String.fromCharCode(enco3))
{
alert("Password is "+ck.replace("=",""));
}
"

再び以下を実行する。

for(i=1;i<122;i++)
{
enco=enco+String.fromCharCode(i,0);
}
 
function enco_(x)
{
return enco.charCodeAt(x);
}
"="+String.fromCharCode(enco_(240))+String.fromCharCode(enco_(220))+String.fromCharCode(enco_(232))+String.fromCharCode(enco_(192))+String.fromCharCode(enco_(226))+String.fromCharCode(enco_(200))+String.fromCharCode(enco_(204))+String.fromCharCode(enco_(222-2))+String.fromCharCode(enco_(198))+"~~~~~~"+String.fromCharCode(enco2)+String.fromCharCode(enco3)

この結果、次のようになった。

"=youaregod~~~~~~~!"

Passwordは"="を""に置換しているので、"youaregod~~~~~~~!"がフラグ

$ echo -n "youaregod~~~~~~~!" | sha1sum
1c0e74d5f61b6c3901a277bdd490ad070265f027  -
WhiteHat{1c0e74d5f61b6c3901a277bdd490ad070265f027}