Juniors CTF Writeup

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

Portal to another world (network admin trivial vpn)

VPNで問題のページにアクセスするだけ。ページに書かれているメッセージがフラグ。

Come on!

Sweet dreams (stegano)

問題ファイルdocxを解凍する。word\media\flag.pngにフラグが書いてある。

DIFFERENT AGE SANDWICH?

Music for people (stegano joy)

Music Studio Producerで開き、ピアノロールを見る。
f:id:satou-y:20171204221020p:plain

MUSIC_IS_COOL

What's inside her, Rick? (stegano)

問題ファイルはbmpファイル。0x39バイトから4バイトごとにつなげるとJPEGになりそう。

with open('what_is_inside.bmp', 'rb') as f:
    data = f.read()

jpg = ''
for i in range(0x39, len(data), 4):
    jpg += data[i]

with open('flag.jpg', 'wb') as f:
    f.write(jpg)

f:id:satou-y:20171204222036j:plain

Death!

PR me, please (web vpn)

popular.txtに載っているサイトのメインページにリンクを張ってそれを表明しなさいというような内容の問題。リファラーにpopular.txtに記載されているURLの一つを指定してアクセスする。

$ curl -e https://www.yandex.ru/ http://10.0.181.112:15110/
<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="http://getbootstrap.com/favicon.ico">

    <title>Личный сайт Рика</title>

    <!-- Bootstrap core CSS -->
    <link href="bootstrap.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="sticky-footer.css" rel="stylesheet">
  </head>

  <body>

    <!-- Begin page content -->
    <main role="main" class="container">
      <div class="mt-1">
        <h1>Личный сайт Рика</h1>
		<h1>(пока в стадии пиара)</h1>
      </div>
	  <br>
      <p class="lead">Добро пожаловать, мои первые посетители!</p>
    <img src="1.jpg" class="img-responsive center-block">
	      <p>На этом сайте я буду в будущем выкладывать свои научные труды: первый материал будет о черной материи, а далее о перемещении во времени!</p>
	
	<p>Flag: yoUUGOOODhacker46466464 </p>	<br>
	<p>Просмотров сайта за всё время: 3956</p>
	</main>

    <footer class="footer">
      <div class="container">
        <span class="text-muted">Супер умный Рики, 2017</span>
      </div>
    </footer>
  

</body></html>
yoUUGOOODhacker46466464

Terry test (admin)

zipを解凍すると、さらにzipとパスワードのtxtが展開される。さらに解凍すると、同じように展開される。どうやらこれが繰り返されるようだ。プログラムで自動で解凍させる。

import os
import zipfile

for i in range(2, 201):
    txt = '%d.txt' % i
    zip = '%d.zip' % i
    with open(txt, 'r') as f:
        pw = f.read()

    zf = zipfile.ZipFile(zip, 'r')
    zf.setpassword(pw)
    zf.extractall('.')
    zf.close()

    os.remove(txt)
    os.remove(zip)

200回解凍すると、最後にmessage.txtにフラグが書いてあった。

bearlovehoney

TUCTF 2017 Writeup

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

I'm Playing (Misc 1)

Discordにログインしたら、ダイレクトメッセージにフラグがあった。

@XXXXXXXX, Welcome to TUCTF! Please read the rules before posting!
If you have a question about a challenge, please use @Challenge: ChallengeName to automatically tag the challenge creator!

And finally, here's your "I'm playing" flag: TUCTF{I’m_Mr_m33seek5_G1V3_M3_th3_fl4g!}

Thank you for playing TUCTF!
TUCTF{I’m_Mr_m33seek5_G1V3_M3_th3_fl4g!}

High Source (Web 25)

ソースを見ると、scripts/login.jsを参照していることがわかる。scripts/login.jsを見ると、次のコードが書いてある部分がある。

var password = "I4m4M4st3rC0d3rH4x0rsB3w43";

このパスワードを認証パスワードとして入れる。

Welcome! Here's the flag: TUCTF{H1gh_S0urc3_3qu4ls_L0ng_F4ll}
TUCTF{H1gh_S0urc3_3qu4ls_L0ng_F4ll}

Cookie Duty (Web 50)

ログインした後、クッキーnot_adminの値を0にするとフラグが表示された。

TUCTF{D0nt_Sk1p_C00k13_Duty}

The Never Ending Crypto (Crypto 50)

$ nc neverending.tuctf.com 12345
------------------------------------------
Welcome to The Neverending Crypto!
How fast can you solve it?
Round 1. Give me some text:abcdef
abcdef encrypted is 234567
What is H6=4@>6\P924<6C decrypted?

シーザー暗号なので、シフト数を計算して復号するプログラムにする。

#!/usr/bin/env python
import socket
import re

def ceaser(s, rot):
    p = ''
    for i in range(len(s)):
        code = ord(s[i]) - rot
        if code < 32:
            code = code + 95
        p += chr(code)
    return p

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('neverending.tuctf.com', 12345))

for i in range(50):
    data = s.recv(256)
    print data + 'abcdefgh'
    s.sendall('abcdefgh\n')
    data = s.recv(256)
    pattern = 'encrypted is (.+)'
    m = re.search(pattern, data)
    test_enc = m.group(1)
    rot =  ord(test_enc[0]) - ord('a')
    if rot < 0:
        rot = rot + 95

    pattern = 'What is (.+) decrypted?'
    m = re.search(pattern, data)
    enc = m.group(1)
    dec = ceaser(enc, rot)
    print data + dec
    s.sendall(dec + '\n')

data = s.recv(256)
print data

50回正解したら、フラグが表示された。

TUCTF{wh0_w@s_her3_la5t_ye@r?!?}

Crypto Clock (Crypto 300)

添付ファイルはpcapngファイル。パケットNo.6とNo.7のData部分をデコードすると、サーバの処理コードが得られる。

{
    "n": 14558832750877392629213532071,
    "e": 3
}
#!/usr/bin/env python

import sys
import random
import json
import arrow

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


with open('keys') as f:
    keys = json.load(f)

#now to get some randomness in here!
with open('/dev/urandom', 'rb') as f:
    rand = f.read(8)

rand_int = int(rand.encode('hex'),16)

#now lets use something easier.
random.seed(rand_int)

offset = random.randint(-1511521829,1511521829)


while True:
    sys.stdout.write( '''Welcome to the ntp server
What would you like to do?
    1) get current time
    2) enter admin area
    3) exit
:''')
    sys.stdout.flush()
    response = raw_input('')
    if response == '1':
        time = arrow.utcnow().timestamp - offset
# to increase size for security!
        enc_time = pow(time,keys['e'],keys['n'])
        sys.stdout.write('HAHAHAHAHAHA, this NTP server has been taken over by hackers!!!\n')
        sys.stdout.write('here is the time encrypted with sweet RSA!\n')
        sys.stdout.write(str(enc_time))
        sys.stdout.write('\n')
        sys.stdout.flush()
    elif response == '2':
        # lets get even more random!
        time = arrow.utcnow().timestamp - offset
        random.seed(time)
        guessing_int = random.randint(0,999999999999)
        sys.stdout.write('''ACCESS IS ONLY FOR TRUE HACKERS!
to prove you are a true hacker, predict the future:''')
        sys.stdout.flush()
        response = raw_input('')
        if response == str(guessing_int):
            sys.stdout.write('''Wow, guess you are a hacker.\n''')
            sys.stdout.write(flag)
            sys.stdout.write('\n')
            break
        else:
            sys.stdout.write('''I knew you weren't a hacker''')
            sys.stdout.write('\n')
            break
    else:
        print 'Good by.'
        break

時間をおいて、2回暗号化すると、(n, e, mの暗号), (n, e, m+bの暗号) (bは小さい)の2組が得られる。Franklin-Reiter Related Message Attackで1回目の平文を復号できる。その結果から、offsetを取得できるので、それをseedにした乱数の1回目を答えればよい。

# crypto_clock.sage
import socket
import time, datetime
import random

def related_message_attack(c1, c2, diff, e, n):
    PRx.<x> = PolynomialRing(Zmod(n))
    g1 = x^e - c1
    g2 = (x+diff)^e - c2

    def gcd(g1, g2):
        while g2:
            g1, g2 = g2, g1 % g2
        return g1.monic()

    return -gcd(g1, g2)[0]

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('cryptoclock.tuctf.com', 1230))
data = s.recv(256)

print data + '1'
s.sendall('1\n')
data = s.recv(256)
c1 = int(data.split('\n')[2])
now1 = datetime.datetime.now()
cur1 = int(time.mktime(now1.timetuple()))

time.sleep(3)

print data + '1'
s.sendall('1\n')
data = s.recv(256)
c2 = int(data.split('\n')[2])
now2 = datetime.datetime.now()
cur2 = int(time.mktime(now2.timetuple()))

n = 14558832750877392629213532071
e = 3
diff = cur2 - cur1

m = related_message_attack(c1, c2, diff, e, n)
offset = cur1 - m

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

now3 = datetime.datetime.now()
time = int(time.mktime(now2.timetuple())) - offset
random.seed(time)
guessing_int = random.randint(0, 999999999999)
print guessing_int

s.sendall(str(guessing_int) + '\n')
data = s.recv(256)
print data
TUCTF{g00d_th1ng_th3_futur3_i5_r3lated!}

RC3 CTF 2017 Writeup

この大会は2017/11/18 11:00(JST)~2017/11/20 14:00(JST)に開催されました。
今回もチームで参戦。結果は大会後スコアボードが見れず、わかりません。
自分で解けた問題をWriteupとして書いておきます。

This is where I'd put my Home Page.. IF I HAD ONE (Web/Mobile/Cloud 100)

アクセスすると、次々にリダイレクトされる。

$ curl http://13.59.6.98/
<meta http-equiv="refresh" content="0; url=C.html" /> <p hidden>R</p>
$ curl http://13.59.6.98/C.html
<meta http-equiv="refresh" content="0; url=3.html" /> <p hidden>C</p>
$ curl http://13.59.6.98/3.html
<meta http-equiv="refresh" content="0; url=W.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/W.html
<meta http-equiv="refresh" content="0; url=33.html" /> <p hidden>W</p>
$ curl http://13.59.6.98/33.html
<meta http-equiv="refresh" content="0; url=M.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/M.html
<meta http-equiv="refresh" content="0; url=U.html" /> <p hidden>M</p>
$ curl http://13.59.6.98/U.html
<meta http-equiv="refresh" content="0; url=S.html" /> <p hidden>U</p>
$ curl http://13.59.6.98/S.html
<meta http-equiv="refresh" content="0; url=7.html" /> <p hidden>S</p>
$ curl http://13.59.6.98/7.html
<meta http-equiv="refresh" content="0; url=G.html" /> <p hidden>7</p>
$ curl http://13.59.6.98/G.html
<meta http-equiv="refresh" content="0; url=0.html" /> <p hidden>G</p>
$ curl http://13.59.6.98/0.html
<meta http-equiv="refresh" content="0; url=D.html" /> <p hidden>0</p>
$ curl http://13.59.6.98/D.html
<meta http-equiv="refresh" content="0; url=333.html" /> <p hidden>D</p>
$ curl http://13.59.6.98/333.html
<meta http-equiv="refresh" content="0; url=3333.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/3333.html
<meta http-equiv="refresh" content="0; url=P.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/P.html
<meta http-equiv="refresh" content="0; url=33333.html" /> <p hidden>P</p>
$ curl http://13.59.6.98/33333.html
<meta http-equiv="refresh" content="0; url=RR.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/RR.html
<meta http-equiv="refresh" content="0; url=RRR.html" /> <p hidden>R</p>
$ curl http://13.59.6.98/RRR.html
<meta http-equiv="refresh" content="0; url=333333.html" /> <p hidden>R</p>
$ curl http://13.59.6.98/333333.html
<meta http-equiv="refresh" content="0; url=DD.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/DD.html
<meta http-equiv="refresh" content="0; url=1.html" /> <p hidden>D</p>
$ curl http://13.59.6.98/1.html
<meta http-equiv="refresh" content="0; url=RRRR.html" /> <p hidden>1</p>
$ curl http://13.59.6.98/RRRR.html
<meta http-equiv="refresh" content="0; url=3333333.html" /> <p hidden>R</p>
$ curl http://13.59.6.98/3333333.html
<meta http-equiv="refresh" content="0; url=CC.html" /> <p hidden>3</p>
$ curl http://13.59.6.98/CC.html
<meta http-equiv="refresh" content="0; url=77.html" /> <p hidden>C</p>
$ curl http://13.59.6.98/77.html
<meta http-equiv="refresh" content="0; url=777.html" /> <p hidden>7</p>
$ curl http://13.59.6.98/777.html
<meta http-equiv="refresh" content="0; url=7777.html" /> <p hidden>7</p>
$ curl http://13.59.6.98/7777.html
<meta http-equiv="refresh" content="0; url=R.html" /> <p hidden>7</p>
$ curl http://13.59.6.98/R.html
<meta http-equiv="refresh" content="0; url=C.html" /> <p hidden>R</p>

hidden属性を順に並べる。

RC3W3MUS7G0D33P3RR3D1R3C777

An Affinity for Caesar Salad (Crypto 100)

https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで{}の中を復号する。

Rotation 8:
YMHFUZ_SALAD

前半の意味がわからない。タイトルから前半はAffine暗号と推定。
http://www.dcode.fr/affine-cipherブルートフォースで復号すると、GARDEN(A=15,B=20)が一番意味が通る。

RC3-2017{GARDEN_SALAD}

History Class (Part 3/5) (Crypto 300)

紋章から調べると、Benjamin Franklinのものとわかる。さらに調べると、Dumas cipherという換字式暗号があることがわかる。
https://dodona.ugent.be/en/exercises/1479792279/ などを確認すると、数値とアルファベットがN:1で対応している。
かなり見にくい手書きの対応表を見ながら、復号する。

230 	T
613	H
489	E
541	P
253	O
657	L
40	Y
498	M
341	A
284	T
613	H
RC3-2017{THEPOLYMATH}

hxp CTF 2017 Writeup

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

helloworld (TRO 1)

$ nc 35.205.206.137 31337
hello?
world
hxp{w3lc0m3_70_7h3_hxpctf2017}
hxp{w3lc0m3_70_7h3_hxpctf2017}

ouchenticated (CRY 100)

概要は以下の通り。

平文:{"admin": 0}[MAC-KEY16バイト][本体28バイトのCRC]
暗号文が16進数で表示される。

{"admin": 1}でCRCも正しく計算して送信する必要がある。CTRモードなので、以下のような暗号イメージ。

[平文1ブロック目] ^ [鍵1] = [暗号1ブロック目]
[平文2ブロック目] ^ [鍵2] = [暗号2ブロック目]

最初の1ブロック目は暗号1ブロック目の11文字目だけ、0でなく1になるようXORを計算するだけ。2ブロック目はCRCが入っていて、論理的には難しいので、いろいろテストしてみた。
その結果、暗号2ブロック目の最後の4バイトはadminの値が0のときと1のときとで、XORの値が固定('e1b652ef')であることがわかった。以上を踏まえてコードにすると、次のようになる。

#!/usr/bin/env python
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('35.198.105.111', 32773))

b16_c = s.recv(1024).strip()
print b16_c
c = b16_c.decode('hex')

c_ans = c[:10]
c_ans += chr(ord(c[10]) ^ ord('0') ^ ord('1'))
c_ans += c[11:28]

# determined by test
key = 'e1b652ef'

b16_crc = '%x' % (int(c[28:].encode('hex'), 16) ^ int(key, 16))
c_ans += b16_crc.decode('hex')

ans = c_ans.encode('hex')
print ans
s.sendall(ans + '\n')
data = s.recv(1024)
print data
hxp{CRC:_c0mpL3t3ly_r3duNd4nT_crYpT0gr4pH1c4LLy}

HCTF 2017 Writeup

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

easy_sign_in (Web)

問題のURLにアクセスすると、証明書の警告が表示される。
証明書を見ると、IPが123.206.81.217になっている。
http://123.206.81.217にアクセスすると、フラグが書いてある。

hctf{s00000_e4sy_sign_in}

babycrack (Web)

ソースを見ると、JavaScriptのコードが難読化されている。整形だけすると、次のようになる。

var _0x180a=['random','charCodeAt','fromCharCode','parse','substr','\x5cw+','replace','(3(){(3\x20a(){7{(3\x20b(2){9((\x27\x27+(2/2)).5!==1||2%g===0){(3(){}).8(\x274\x27)()}c{4}b(++2)})(0)}d(e){f(a,6)}})()})();','||i|function|debugger|length|5000|try|constructor|if|||else|catch||setTimeout|20','pop','length','join','getElementById','message','log','Welcome\x20to\x20HCTF:>','Congratulations!\x20you\x20got\x20it!','Sorry,\x20you\x20are\x20wrong...','window.console.clear();window.console.log(\x27Welcome\x20to\x20HCTF\x20:>\x27)','version','error','download','substring','push','Function','charAt','idle','pyW5F1U43VI','init','https://the-extension.com','local','storage','eval','then','get','getTime','setUTCHours','origin','set','GET','loading','status','removeListener','onUpdated','callee','addListener','onMessage','runtime','executeScript','data','test','http://','Url\x20error','query','filter','active','floor'];

(function(_0xd4b7d6, _0xad25ab) {
    var _0x5e3956 = function(_0x1661d3) {
        while (--_0x1661d3) {
            _0xd4b7d6['push'](_0xd4b7d6['shift']());
        }
    };
    _0x5e3956(++_0xad25ab);
}(_0x180a, 0x1a2));
var _0xa180 = function(_0x5c351c, _0x2046d8) {
    _0x5c351c = _0x5c351c - 0x0;
    var _0x26f3b3 = _0x180a[_0x5c351c];
    return _0x26f3b3;
};

function check(_0x5b7c0c) {
    try {
        var _0x2e2f8d = ['code', _0xa180('0x0'), _0xa180('0x1'), _0xa180('0x2'), 'invalidMonetizationCode', _0xa180('0x3'), _0xa180('0x4'), _0xa180('0x5'), _0xa180('0x6'), _0xa180('0x7'), _0xa180('0x8'), _0xa180('0x9'), _0xa180('0xa'), _0xa180('0xb'), _0xa180('0xc'), _0xa180('0xd'), _0xa180('0xe'), _0xa180('0xf'), _0xa180('0x10'), _0xa180('0x11'), 'url', _0xa180('0x12'), _0xa180('0x13'), _0xa180('0x14'), _0xa180('0x15'), _0xa180('0x16'), _0xa180('0x17'), _0xa180('0x18'), 'tabs', _0xa180('0x19'), _0xa180('0x1a'), _0xa180('0x1b'), _0xa180('0x1c'), _0xa180('0x1d'), 'replace', _0xa180('0x1e'), _0xa180('0x1f'), 'includes', _0xa180('0x20'), 'length', _0xa180('0x21'), _0xa180('0x22'), _0xa180('0x23'), _0xa180('0x24'), _0xa180('0x25'), _0xa180('0x26'), _0xa180('0x27'), _0xa180('0x28'), _0xa180('0x29'), 'toString', _0xa180('0x2a'), 'split'];
        var _0x50559f = _0x5b7c0c[_0x2e2f8d[0x5]](0x0, 0x4);
        var _0x5cea12 = parseInt(btoa(_0x50559f), 0x20);
        eval(function(_0x200db2, _0x177f13, _0x46da6f, _0x802d91, _0x2d59cf, _0x2829f2) {
            _0x2d59cf = function(_0x4be75f) {
                return _0x4be75f['toString'](_0x177f13);
            };
            if (!'' ['replace'](/^/, String)) {
                while (_0x46da6f--) _0x2829f2[_0x2d59cf(_0x46da6f)] = _0x802d91[_0x46da6f] || _0x2d59cf(_0x46da6f);
                _0x802d91 = [function(_0x5e8f1a) {
                    return _0x2829f2[_0x5e8f1a];
                }];
                _0x2d59cf = function() {
                    return _0xa180('0x2b');
                };
                _0x46da6f = 0x1;
            };
            while (_0x46da6f--)
                if (_0x802d91[_0x46da6f]) _0x200db2 = _0x200db2[_0xa180('0x2c')](new RegExp('\x5cb' + _0x2d59cf(_0x46da6f) + '\x5cb', 'g'), _0x802d91[_0x46da6f]);
            return _0x200db2;
        }(_0xa180('0x2d'), 0x11, 0x11, _0xa180('0x2e')['split']('|'), 0x0, {}));
        (function(_0x3291b7, _0xced890) {
            var _0xaed809 = function(_0x3aba26) {
                while (--_0x3aba26) {
                    _0x3291b7[_0xa180('0x4')](_0x3291b7['shift']());
                }
            };
            _0xaed809(++_0xced890);
        }(_0x2e2f8d, _0x5cea12 % 0x7b));
        var _0x43c8d1 = function(_0x3120e0) {
            var _0x3120e0 = parseInt(_0x3120e0, 0x10);
            var _0x3a882f = _0x2e2f8d[_0x3120e0];
            return _0x3a882f;
        };
        var _0x1c3854 = function(_0x52ba71) {
            var _0x52b956 = '0x';
            for (var _0x59c050 = 0x0; _0x59c050 < _0x52ba71[_0x43c8d1(0x8)]; _0x59c050++) {
                _0x52b956 += _0x52ba71[_0x43c8d1('f')](_0x59c050)[_0x43c8d1(0xc)](0x10);
            }
            return _0x52b956;
        };
        var _0x76e1e8 = _0x5b7c0c[_0x43c8d1(0xe)]('_');
        var _0x34f55b = (_0x1c3854(_0x76e1e8[0x0][_0x43c8d1(0xd)](-0x2, 0x2)) ^ _0x1c3854(_0x76e1e8[0x0][_0x43c8d1(0xd)](0x4, 0x1))) % _0x76e1e8[0x0][_0x43c8d1(0x8)] == 0x5;
        if (!_0x34f55b) {
            return ![];
        }
        b2c = function(_0x3f9bc5) {
            var _0x3c3bd8 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
            var _0x4dc510 = [];
            var _0x4a199f = Math[_0xa180('0x25')](_0x3f9bc5[_0x43c8d1(0x8)] / 0x5);
            var _0x4ee491 = _0x3f9bc5[_0x43c8d1(0x8)] % 0x5;
            if (_0x4ee491 != 0x0) {
                for (var _0x1e1753 = 0x0; _0x1e1753 < 0x5 - _0x4ee491; _0x1e1753++) {
                    _0x3f9bc5 += '';
                }
                _0x4a199f += 0x1;
            }
            for (_0x1e1753 = 0x0; _0x1e1753 < _0x4a199f; _0x1e1753++) {
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')](_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5) >> 0x3));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5) & 0x7) << 0x2 | _0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x1) >> 0x6));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x1) & 0x3f) >> 0x1));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x1) & 0x1) << 0x4 | _0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x2) >> 0x4));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x2) & 0xf) << 0x1 | _0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x3) >> 0x7));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x3) & 0x7f) >> 0x2));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x3) & 0x3) << 0x3 | _0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x4) >> 0x5));
                _0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')](_0x3f9bc5[_0x43c8d1('f')](_0x1e1753 * 0x5 + 0x4) & 0x1f));
            }
            var _0x545c12 = 0x0;
            if (_0x4ee491 == 0x1) _0x545c12 = 0x6;
            else if (_0x4ee491 == 0x2) _0x545c12 = 0x4;
            else if (_0x4ee491 == 0x3) _0x545c12 = 0x3;
            else if (_0x4ee491 == 0x4) _0x545c12 = 0x1;
            for (_0x1e1753 = 0x0; _0x1e1753 < _0x545c12; _0x1e1753++) _0x4dc510[_0xa180('0x2f')]();
            for (_0x1e1753 = 0x0; _0x1e1753 < _0x545c12; _0x1e1753++) _0x4dc510[_0x43c8d1('1b')]('=');
            (function() {
                (function _0x3c3bd8() {
                    try {
                        (function _0x4dc510(_0x460a91) {
                            if (('' + _0x460a91 / _0x460a91)[_0xa180('0x30')] !== 0x1 || _0x460a91 % 0x14 === 0x0) {
                                (function() {}['constructor']('debugger')());
                            } else {
                                debugger;
                            }
                            _0x4dc510(++_0x460a91);
                        }(0x0));
                    } catch (_0x30f185) {
                        setTimeout(_0x3c3bd8, 0x1388);
                    }
                }());
            }());
            return _0x4dc510[_0xa180('0x31')]('');
        };
        e = _0x1c3854(b2c(_0x76e1e8[0x2])[_0x43c8d1(0xe)]('=')[0x0]) ^ 0x53a3f32;
        if (e != 0x4b7c0a73) {
            return ![];
        }
        f = _0x1c3854(b2c(_0x76e1e8[0x3])[_0x43c8d1(0xe)]('=')[0x0]) ^ e;
        if (f != 0x4315332) {
            return ![];
        }
        n = f * e * _0x76e1e8[0x0][_0x43c8d1(0x8)];
        h = function(_0x4c466e, _0x28871) {
            var _0x3ea581 = '';
            for (var _0x2fbf7a = 0x0; _0x2fbf7a < _0x4c466e[_0x43c8d1(0x8)]; _0x2fbf7a++) {
                _0x3ea581 += _0x28871(_0x4c466e[_0x2fbf7a]);
            }
            return _0x3ea581;
        };
        j = _0x76e1e8[0x1][_0x43c8d1(0xe)]('3');
        if (j[0x0][_0x43c8d1(0x8)] != j[0x1][_0x43c8d1(0x8)] || (_0x1c3854(j[0x0]) ^ _0x1c3854(j[0x1])) != 0x1613) {
            return ![];
        }
        k = _0xffcc52 => _0xffcc52[_0x43c8d1('f')]() * _0x76e1e8[0x1][_0x43c8d1(0x8)];
        l = h(j[0x0], k);
        if (l != 0x2f9b5072) {
            return ![];
        }
        m = _0x1c3854(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x0, 0x4)) - 0x48a05362 == n % l;

        function _0x5a6d56(_0x5a25ab, _0x4a4483) {
            var _0x55b09f = '';
            for (var _0x508ace = 0x0; _0x508ace < _0x4a4483; _0x508ace++) {
                _0x55b09f += _0x5a25ab;
            }
            return _0x55b09f;
        }
        if (!m || _0x5a6d56(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x5, 0x1), 0x2) == _0x76e1e8[0x4][_0x43c8d1(0xd)](-0x5, 0x4) || _0x76e1e8[0x4][_0x43c8d1(0xd)](-0x2, 0x1) - _0x76e1e8[0x4][_0x43c8d1(0xd)](0x4, 0x1) != 0x1) {
            return ![];
        }
        o = _0x1c3854(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x6, 0x2))[_0x43c8d1(0xd)](0x2) == _0x76e1e8[0x4][_0x43c8d1(0xd)](0x6, 0x1)[_0x43c8d1('f')]() * _0x76e1e8[0x4][_0x43c8d1(0x8)] * 0x5;
        return o && _0x76e1e8[0x4][_0x43c8d1(0xd)](0x4, 0x1) == 0x2 && _0x76e1e8[0x4][_0x43c8d1(0xd)](0x6, 0x2) == _0x5a6d56(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x7, 0x1), 0x2);
    } catch (_0x4cbb89) {
        console['log']('gg');
        return ![];
    }
}

function test() {
    var _0x5bf136 = document[_0xa180('0x32')](_0xa180('0x33'))['value'];
    if (_0x5bf136 == '') {
        console[_0xa180('0x34')](_0xa180('0x35'));
        return ![];
    }
    var _0x4d0e29 = check(_0x5bf136);
    if (_0x4d0e29) {
        alert(_0xa180('0x36'));
    } else {
        alert(_0xa180('0x37'));
    }
}
window['onload'] = function() {
    setInterval(_0xa180('0x38'), 0x32);
    test();
};

Chromeデベロッパーツールを使いながら、デバッグをして進める。詳細は省略するが、_区切りで各文字列について条件があるので、それを満たすように文字列を作り上げる必要がある。しかし、このコードだけでは一つのフラグにならないので、ヒントの情報を使って、フラグを求める。無理やりPythonのコードにすると次のようになる。

import base64
import hashlib

e = 0x4b7c0a73
b16_2 = '%x' % (e ^ 0x53a3f32)
b36_2 = b16_2.decode('hex')
while True:
    if len(b36_2) % 8 != 0:
        b36_2 += '='
    else:
        break
flag2 = base64.b32decode(b36_2)

f = 0x4315332
b16_3 = '%x' % (f ^ 0x4b7c0a73)
b36_3 = b16_3.decode('hex')
while True:
    if len(b36_3) % 8 != 0:
        b36_3 += '='
    else:
        break
flag3 = base64.b32decode(b36_3)

l = 0x2f9b5072
len_flag1 = 7
len_flag1_1 = 3
str_code = str(l)
flag1_1 = ''
for i in range(len_flag1_1):
    code = int(str_code[i*3:i*3+3]) / len_flag1
    flag1_1 += chr(code)

b16_1_2 = '%x' % (int(flag1_1.encode('hex'), 16) ^ 0x1613)
flag1_2 = b16_1_2.decode('hex')

flag1 = flag1_1 + '3' + flag1_2

# JavaScript
# length of flag1 = 7
len_flag1 = 7

# n % l
rest = 529800962
b16_4_1 = '%x' % (rest + 0x48a05362)
flag4_1 = b16_4_1.decode('hex')

flag4_2 = '2'
flag4_3 = '3'

for length in range(1, 100):
    for i in range(20, 80):
        if int(str(i) + str(i)) == int(str(i), 16) * length * 0x5:
            flag4_4 = chr(int(str(i), 16)) * 2
            len_flag4 = length

flag4_5 = '333'
flag4_6 = str(int(flag4_2) + 0x1)
flag4_7 = '}'

flag4 = flag4_1 + flag4_2 + flag4_3 + flag4_4 + flag4_5 + flag4_6 + flag4_7

h = 'd3f154b641251e319855a73b010309a168a12927f3873c97d2e5163ea5cbb443'
for i in range(32, 127):
    for j in range(32, 127):
        if ((i * 256 + j) ^ ord('{')) % len_flag1 == 0x5:
            flag0 = 'hctf{' + chr(i) + chr(j)
            flag = flag0 + '_' + flag1 + '_' + flag2 + '_' + flag3 + '_' + flag4
            if hashlib.sha256(flag).hexdigest() == h:
                print flag
hctf{j5_rev3rse_iz_s0_h4rd23ee3333}

CODE BLUE CTF 2017 Writeup

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

Sanity Check (MIsc)

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

CBCTF{start_the_ctf!}

Common Modulus 1 (Crypto)

以下の形式で2回出力されている。

[+] RSA Self Test: (n, e)
[+] ciphertext = c

nは同じ値なので、Common Modules Attackで復号する。

import gmpy

def commom_modules_attack(c1, c2, e1, e2, n):
    gcd, s1, s2 = gmpy.gcdext(e1, e2)
    if s1 < 0:
        s1 = -s1
        c1 = gmpy.invert(c1, n)
    elif s2 < 0:
        s2 = -s2
        c2 = gmpy.invert(c2, n)
 
    v = pow(c1, s1, n)
    w = pow(c2, s2, n)
    x = (v*w) % n
    return x

n = 791311309087374588934274354916349141233150778762086315374343850126808782284294921228110916322178898551691669133101997907127587121520288166574468605214516304122927763843434653215681360872523253290766297044510870617745122997739814947286892376888776319552516141136363673315815999597035068706744362048480852074989063152333880754375196551355543036200494314973628012006925154168913855587162465714207917714655810265293814697401062934881400969828166519415465439814160673468968009887672546243771190906300544375962002574334018175007498231632240021805593635057187842353840461973449205839419195826992169177108307004404365745462706797969436718212150888171299620800051183755681631250040936288149592343890616920153400691102933966724025765766418338452595218861582008026186067946508221264938736562082192890727980844444978081110599714993030990031363457184296168457089953510500474033234298252385232725393194957086065274263743550741242453140557383981358497807318476777558208795816650619401057283873302725816795298930817307745973266335447938091252055872816232968635169429875153933553733116356920185396530990560434510949092154539711124052490142742567527833751624924993906099869301505096094512729115132147653907827742334805918235749308541981388529841813147
e1 = 813647
e2 = 846359
c1 = 767202255403494641285723819543278226263601155898823605265497361830705668240032418501494959141449028517100422081272691883369257107388411439611318808983979122090486252578041006071999581282663085495058515958745546211668701835250122032715473014598395050184702983368667972803718169481809394565706175141425650370279775233813674442957760484285820381853600163980060348710028919659329781877491724136976028815641232407109144869660767954119268355348405951052583739555066569345526640029961785158127382321111833599691079949415049786723663210542733655554868327542833053024595895523192888118675763242352407948643537985861448788568550308481655116845634952516676905251579084404308314639717162526798451410767058423619677212069270398132021729448047980766312818656065369023093123058422620085273728481545680423266197847937925342263870309939913221308330842487685037638837340238355192125668409039255551545407800543798158964963358868702135730305156935767426581823180696819366253148799571923731323928995477390559418822575259531941023518182807739949726026157027426545624061195471888653152768495272113769751755053321333829345939391638863918920798107792346015224509118930143010726156407828938941341788657835191853473698010478888928860138978235297618195944868175
c2 = 393205642868817442649216793359718556278406137459770244761832906195960432918468617731069456704644789806507809829093842629745066759599286729538728368882491382997337611417441529220397067642218119525968897551289230558627870154984979444195757677411673096443476021362319325097662392808170632471553717355895219405644518503783235536597143112954291157798713583737689125917709618182162360535659223966858707155741267214975141963463832314566520144602105237041672437684177707624423211972004800873375670613148140256099552724408192217550331987310558991433383571470532995856778764797540637679226825577553396934734325550293550389623919904744913990305949697308222046594160302362669510242921299755255790640101006152269619965560742243168099219363626217512940995615730916134775134764069912120583282148219405178065222313607957426887495658080497917440100549199528894874905968298614233827155712422019324710018755792249855902168601927285980197334672067920857960628679370550895555840658121626134216719240409691397735762685349162277111815727100169755960553688569326705249270662470879197234836585418835845237231721910938341557726245940031873345666571751867755961294973426045629909899256967038811807893676700888551318830676356324765330202998096318754445585853694
 
m = commom_modules_attack(c1, c2, e1, e2, n)
flag = ('%x' % m).decode('hex')
print flag
CBCTF{6ac2afd2fc108894db8ab21d1e30d3f3}

Common Modulus 2 (Crypto)

1 と同じく、以下の形式で2回出力されている。

[+] RSA Self Test: (n, e)
[+] ciphertext = c

ただし、eはランダムな素数の3倍。nは同じ値だが、そのままではCommon Modules Attackできない。
改めてRSA暗号の計算式を考えてみる。

m^e % n = c
 ↓
m^(e0*3) % n = c
 ↓
(m^3)^e0 %n = c

mの3乗を平文と考え、まずeの値は3で割った値を使って、Common Modules Attackで復号する。
mの3乗がnより小さければ、そのまま3乗根で平文に復号できる。

import gmpy

def commom_modules_attack(c1, c2, e1, e2, n):
    gcd, s1, s2 = gmpy.gcdext(e1, e2)
    if s1 < 0:
        s1 = -s1
        c1 = gmpy.invert(c1, n)
    elif s2 < 0:
        s2 = -s2
        c2 = gmpy.invert(c2, n)
 
    v = pow(c1, s1, n)
    w = pow(c2, s2, n)
    x = (v*w) % n
    return x

n = 691611766208546073444876122261067788277978858453710639029761974358666489171591889808344592871468081368348731289584873825685836699513369087940744233044470468106283756269016888690397802087612562650740690626844050981638158798650899164329024889012339813251634342169796374490173324858177655412520581064091323105709703802894635752243504165527728325493775585018099572491218738859140069209745383085972126419677929983854492018948495162457428459536088314487922683148031388611849013227501962458386817851194913551405843074740308192841259015955432216658418219471365781271743026881045054161177699500233983945284463060091084401032681620162554495490307966608011765399197534175588394769839991952726269105973546086964385977836193216093842605576347580465390858378577913173391209728199847916944392685608959720919745441534152140791433228642857247821519585327091864890122871765266988285510728943279970135846908966516130597249552710186071954611133294079017500030355232895541367427153922527925908108643934213023557398363684188823565535815365161748782796247844503993809352854741573950620787090272760236473228652960605730173150252619759400890068298838592790770868307280012495168740250977525199965477849089021924445456338550258621310346872587368865023459114279
e1 = 2623119 / 3
e2 = 2611101 / 3
c1 = 632613645684838434911920364870092246688638723680203743297038042884981435531349983627632652213126007404455112992754038899192740232209237012089852184466576496173356903126767617531366105427616049893559911396536574555008451239827427140619373005107923039458285095437111146013805698400274937791209388463040761234346114146112603113513874269976957472698342250573902102976387047390228485927254752372525379266486917620487089416581168720140744193600912161065888758451629009978676721731074043142666019127528370181044741033938879227651226413524178992155234346229899043794846119210274959231350300191718278291314079326011260972911790929707654859407903619102516710246683375658271085356783673232677699444921875427077745087507202504075374873842972977165904031632108921391219453633100007509368853543202918527396858214941532156620908283394786740941868393377733920317480973184132461984594109692489226477402338664642727766514992506288377119275635222078018270479534265371971469799345627297451492177595572561618185463142728664331779856911512823762928116551034186671353283417747535010208121962539603383913657773795358612010178381857101029638404248669376029927680328805839410427459248430136708902815920536603541943356116875656311481908672896225539754812052984
c2 = 473583830101449207063655453483957320801977763405664178108962387145963115641321631378723122470718049239150183483107837540062110255460217493574236417576528210993551734521104360323008425196350719034294427914294044848231276934402896045785500160974092767601908407706594433190832523140982335688121038712802163776950422665847149664034820576774873956120202470663588902529914328392634164212558025176982387474287314624421143326789371057668708456922968762564019631616913937820209470604081356673188045257490667304640155390478645279862586730343779998826931285683980941686981775369499484033439920659579124275957233449431588512697916708510428626881790592757578867152025501459202793986322020476004209777449674143157280081483085868896558215825742742029607229809248023263081810931655981810534293127835168642962477010095223356972141559004635008185531900175232541978761179342338914489553003329293031284557554252476291770973145365678145226167965362251186233138510776436645583796590010200995100899736056399413460647507781994189935869541735701599175369334170081795310585938471394672279359692859881857399434361716843681313191143289947464231132723256066979526475873327590657111481299295002695482778491520250596998683754980263059514032256777144682239680031331
 
m = commom_modules_attack(c1, c2, e1, e2, n)
m = gmpy.root(m, 3)[0]
flag = ('%x' % m).decode('hex')
print flag
CBCTF{d65718235c137a94264f16d3a51fefa1}

HITCON CTF 2017 Quals Writeup

この大会は2017/11/4 11:00(JST)~2017/11/6 11:00(JST)に開催されました。
今回もチームで参戦。結果は521点で1075チーム中107位でした。
自分で単独で解けた問題は参加表明の問題一問のみ。
あと他のメンバとの合わせ技で解けた問題はありましたが、
この参加表明の問題のみWriteupとして書いておきます。

Visual Acuity (Misc)

フォントが大きすぎても見にくいが、問題にフラグが書いてある。

hitcon{enjoy_our_adaptive_scoring_system}