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}

School CTF 2017 Writeup

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

StRiNgMuTaToR 1.0 (ppc 100)

オペコードに従い、反転やシフトを行う。

import socket
import re

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

def reverse(s):
    return s[::-1]

def swap(s):
    l = len(s) / 2
    s1 = s[l:]
    s2 = s[:l]
    return s1 + s2

def reverse_halves(s, code):
    l = len(s) / 2
    s1 = s[:l]
    s2 = s[l:]
    if code == 2:
        s1 = s1[::-1]
    elif code == 3:
        s2 = s2[::-1]
    return s1 + s2

def reverse_quoters(s, code):
    l = len(s) / 4
    s1 = s[:l]
    s2 = s[l:l*2]
    s3 = s[l*2:l*3]
    s4 = s[l*3:]
    if code == 4:
        s1 = s1[::-1]
    elif code == 5:
        s2 = s2[::-1]
    elif code == 6:
        s3 = s3[::-1]
    elif code == 7:
        s4 = s4[::-1]
    return s1 + s2 + s3 + s4

def cycle_left_quoters(s, code):
    l = len(s) / 4
    s1 = s[:l]
    s2 = s[l:l*2]
    s3 = s[l*2:l*3]
    s4 = s[l*3:]
    if code == 8:
        s1 = s1[1:l] + s1[0]
    elif code == 9:
        s2 = s2[1:l] + s2[0]
    elif code == 10:
        s3 = s3[1:l] + s3[0]
    elif code == 11:
        s4 = s4[1:l] + s4[0]
    return s1 + s2 + s3 + s4

def cycle_right_quoters(s, code):
    l = len(s) / 4
    s1 = s[:l]
    s2 = s[l:l*2]
    s3 = s[l*2:l*3]
    s4 = s[l*3:]
    if code == 12:
        s1 = s1[l-1] + s1[:l-1]
    elif code == 13:
        s2 = s2[l-1] + s2[:l-1]
    elif code == 14:
        s3 = s3[l-1] + s3[:l-1]
    elif code == 15:
        s4 = s4[l-1] + s4[:l-1]
    return s1 + s2 + s3 + s4

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('nc.task.school-ctf.org', 41447))

pattern = 'program \'(.+)\' to the sequence \'(.+)\''

data = recvuntil(s, '\n')
data += recvuntil(s, '\n')
data += recvuntil(s, ' ')
print data + 'start'
s.sendall('start\n')

for i in range(100):
    print 'Round %d' % (i+1)
    data = recvuntil(s, '\n')
    m = re.search(pattern, data)
    opcodes = m.group(1)
    seq = m.group(2)
    data += recvuntil(s, ' ')

    for opcode in opcodes:
        code = int(opcode, 16)
        if code == 0:
            seq = reverse(seq)
        elif code == 1:
            seq = swap(seq)
        elif code >= 2 and code <= 3:
            seq = reverse_halves(seq, code)
        elif code >= 4 and code <= 7:
            seq = reverse_quoters(seq, code)
        elif code >= 8 and code <= 11:
            seq = cycle_left_quoters(seq, code)
        else:
            seq = cycle_right_quoters(seq, code)

    print data + seq
    s.sendall(seq + '\n')
    data = recvuntil(s, '\n')
    print data

data = recvuntil(s, '\n')
print data
SchoolCTF{U/c@n-n3v3r_0wN_M3}

WhiteHat Challenge 05 参戦

この大会は2017/10/28 11:00(JST)~2017/10/28 19:00(JST)に開催されました。
今回もチームで参戦。結果は35点で61チーム中24位でした。
今回は自分が得点した問題は1問もありませんでした。
暗号の問題のうち1問は復号できていたはずなのに、なぜかフラグが通らず。
何が正解だったのか教えてほしい!

Pwn2Win CTF 2017 Writeup

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

Differential Privacy (Crypto)

$ nc 200.136.213.143 9999
Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
1
You can query the flag, but the characters are private (indistinguishable).
Differential privacy mechanism: Laplace
Sensitivity: ||125 - 45|| = 80
Epsilon: 6.5

Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
2
[60, 93, 88, 40, 79, 77, 147, 80, 136, 86, 109, 82, 111, 118, 108, 116, 76, 98, 102, 74, 117, 108, 95, 100, 127, 108, 99, 115, 78, 118, 81, 123, 123, 89, 115, 114, 132]
Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
Timeout! Bye...

とりあえず数回どんな数値が返ってくるか見てみる。

[103, 132, 67, 35, 61, 120, 100, 60, 104, 94, 81, 91, 148, 115, 120, 109, 96, 105, 113, 133, 125, 100, 129, 107, 92, 103, 107, 118, 109, 119, 76, 115, 91, 105, 120, 98, 114]
[60, 83, 77, 48, 84, 117, 123, 71, 101, 100, 105, 84, 111, 107, 117, 103, 86, 99, 105, 114, 99, 101, 118, 107, 110, 116, 126, 113, 85, 73, 98, 119, 93, 111, 113, 104, 115]
[72, 81, 71, 9, 59, 74, 130, 80, 96, 109, 119, 139, 101, 122, 133, 109, 106, 124, 95, 103, 49, 76, 96, 58, 122, 110, 71, 110, 94, 100, 104, 159, 113, 123, 124, 108, 138]
[68, 110, 68, 51, 55, 87, 129, 69, 100, 109, 131, 99, 56, 144, 119, 113, 89, 105, 102, 115, 117, 103, 101, 118, 141, 98, 83, 109, 76, 70, 95, 101, 118, 103, 121, 55, 124]
[69, 106, 82, 68, 95, 68, 125, 60, 89, 82, 105, 92, 88, 116, 122, 114, 90, 131, 95, 102, 96, 94, 109, 104, 103, 112, 92, 116, 101, 127, 94, 108, 116, 126, 113, 88, 214]
[78, 82, 42, 25, 30, 94, 138, 72, 108, 84, 108, 80, 104, 113, 134, 166, 102, 93, 94, 94, 116, 93, 108, 106, 157, 76, 83, 98, 104, 76, 112, 118, 123, 111, 116, 100, 131]
[67, 77, 69, 41, 70, 76, 135, 53, 94, 90, 91, 81, 103, 121, 110, 112, 75, 129, 112, 82, 106, 101, 141, 104, 106, 75, 93, 91, 119, 128, 110, 114, 143, 89, 143, 93, 138]

フラグがCTF-BRから始まることを考えると、ASCIIコードで近い数値のような感じがする。できるだけ多くの回数の平均のコード値を取り文字にしてみる。以下のコードを使い、何回か試し、フラグを推定する。

import socket

COLLECT_TIMES = 256

codes = []
for i in range(COLLECT_TIMES):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('200.136.213.143', 9999))
    data = s.recv(256)
    print data
    print '2'
    s.sendall('2\n')
    data = s.recv(256)
    print data
    codes.append(map(int, data[1:-2].split(', ')))

avg_str = ''
for i in range(len(codes[0])):
    sum = 0
    for j in range(COLLECT_TIMES):
        sum += codes[j][i]
    avg = sum / COLLECT_TIMES
    print avg
    avg_str += chr(avg)

print avg_str

3回試した結果は以下の通り。

BRF+AR}H`bn_iutr_filtfpgmg\ujd_nnjse}
CVE-@SzJ]bl^kust]finserimf_sgf^npire{
BSD,BQyH_`l^hurt^djluesgkh_the_mohte|

この結果から意味を持つように文字を前後させる。

CTF-BR{I_am_just_filtering_the_noise}

Sum (Hello World Platform) (PPC-M)

実行するだけ。

$ python solve_sum.py
received: 4 1 1 5 7 6 1 5 8 7 8 8 3 0
sent: 64
received: 4 1 4 4 9 6 5 3 0
sent: 36
received: 8 1 7 1 6 8 4 3 3 3 0
sent: 44
received: 1 8 8 3 7 8 1 2 4 4 6 0
sent: 52
received: 1 1 1 9 1 9 7 4 4 4 7 3 1 2 7 9 0
sent: 70
received: 5 6 9 9 5 6 3 8 8 0
sent: 59
received: 2 2 3 1 8 2 1 9 9 7 4 9 2 8 1 8 8 4 0
sent: 88
received: 1 4 7 5 3 8 4 9 0
sent: 41
received: 1 7 8 3 5 6 4 8 5 5 8 4 9 2 5 0
sent: 80
received: 9 2 9 2 8 3 0
sent: 33
received: 1 3 4 9 9 5 5 8 6 7 0
sent: 57
received: 9 1 4 7 4 5 3 5 6 6 3 8 0
sent: 61
received: 5 7 8 5 2 2 9 0
sent: 38
received: 9 3 9 4 6 7 9 5 4 6 9 4 8 6 2 0
sent: 91
received: 3 8 1 1 3 7 2 7 4 9 5 1 4 3 9 5 4 9 0
sent: 85
received: 4 1 8 7 1 2 7 3 5 6 8 3 4 6 9 9 7 0
sent: 90
received: 9 1 2 3 3 4 2 1 9 5 4 4 8 2 2 5 0
sent: 64
received: 2 1 6 7 2 4 7 2 0
sent: 31
received: 5 7 7 1 5 9 1 4 6 6 8 0
sent: 59
received: 3 1 5 9 3 3 4 1 5 1 7 0
sent: 42
received: CTF-BR{Congrats!_you_know_how_to_sum!}
CTF-BR{Congrats!_you_know_how_to_sum!}