MeePwn CTF 1st 2017 Writeup

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

nub_cryptosystem (CRYPTO)

暗号化のコードが与えられているので、読んでいくとMerkle-Hellmanナップサック暗号であることがわかる。この場合、解読できる条件は秘密鍵が超増加列になっていることだが、これも当然のごとくあてはまる。ということで、復号プログラムを書く。

def load_data():
    with open('pubkey.txt', 'r') as f:
        pub_keys = f.read().strip()[1:-1].split(', ')

    with open('enc.txt', 'r') as f:
        ciphertext = int(long(f.read().strip()))

    return pub_keys, ciphertext

def create_matrix_from_knapsack(ciphertext, pub_keys):
    last_col = []
    for p in pub_keys:
        last_col.append(int(long(p)))

    last_col.append(ciphertext)
    last_row = [1 for i in pub_keys]

    my_matrix = MatrixSpace(ZZ, len(pub_keys))(2)
    m_last_row = matrix(ZZ, 1, len(last_row), last_row)
    m_last_col = matrix(ZZ, len(last_col), 1, last_col)

    my_matrix = my_matrix.stack(m_last_row)
    my_matrix = my_matrix.augment(m_last_col)

    return my_matrix

def is_short_vector(vector):
    for v in vector:
        if v != 1 and v != -1 and v != 0:
            return False
    return True

def find_short_vector(matrix):
    for row in matrix:
        if is_short_vector(row):
            return row

def main():
    pub_keys, cipher = load_data()
    my_matrix = create_matrix_from_knapsack(cipher, pub_keys)

    new_matrix = my_matrix.LLL()

    short_vector = find_short_vector(new_matrix)

    bin_flag = ''
    for v in short_vector:
        if v == 1:
            bin_flag += '0'
        elif v == -1:
            bin_flag += '1'

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

    flag = 'MeePwnCTF{' + flag + '}'
    print flag

if __name__ == '__main__':
    main()

これで復号でき、フラグが得られた。

MeePwnCTF{Merkleee-Hellmannn!}

PoliCTF 2017 参戦

この大会は2017/7/7 18:00(JST)~2017/7/9 18:00(JST)に開催されました。
今回もチームで参戦。結果は1416点で252チーム中28位でした。
今回も自分が得点した問題は1問もありませんでした。
他の人のWriteup見ても、暗号の問題はもう一息だったんだけど、本当に残念!

MNCTF 2017 Writeup

このイベントは2016/7/6 10:00(JST)~2016/7/6 11:30(JST)に
カンファレンスの一つとして開催されました。
個人戦の大会で、最初の確認の問題以外は100点が基準で
解いた人が多くなると点数が下がっていくというルール。
結果は151点であまり良くない成績でした。
解けた問題をWriteupとして書いておきます。

練習問題 (MISC 1)

フラグは問題に書かれていた。

MNCTF

昇進試験 (MISC 60)

Linuxコマンドに関するクロスワードの問題。
クロスワードを解くと、フラグが表示された。
f:id:satou-y:20170711215835p:plain

f148052f5b4eea45dd395d6f45fb19ea

脅迫文書 (MISC 90)

脅迫文の中の写真にURL(onionドメイン)とランダムな文字列がある。
まずTor BrowserでURLにアクセスする。パスワードを聞かれたので、写真のランダムな文字列を入れてみると、フラグが書いてあるページが表示された。
f:id:satou-y:20170711221311p:plain

TORPASTEBIN

SECUINSIDE CTF Quals 2017 Writeup

この大会は2017/7/1 9:00(JST)~2017/7/2 16:33(JST)に開催されました。
今回もチームで参戦。結果は60点で543チーム中153位でした。
自分で解けた問題は答えが書てあるものだけですが、Writeupとして書いておきます。

SANITY CHECK (MISC)

問題に書いてある。参加表明問題。

SECU[THIS_IS_FLAG]

CAT CARRIER (MISC)

これも一見隠されているフラグを探す問題かと思ったが、記載されているフラグが正解。

SECU[____MEOW_____MEOW____]

Trend Micro CTF 2017 - Raimund Genes Cup - Online Qualifier 参戦

この大会は2017/6/24 13:00(JST)~2017/6/25 13:00(JST)に開催されました。
今回もチームで参戦。結果は1702点で294チーム中30位でした。
今回も自分が得点した問題は1問もありませんでした。
う~ん、勉強期間と思うしかないな。無念・・・。

Google Capture The Flag 2017 (Quals) 参戦

この大会は2017/6/17 9:00(JST)~2017/6/19 9:00(JST)に開催されました。
今回もチームで参戦。結果は1002点で1977チーム中47位でした。
自分が得点した問題は1問も無く、本当に残念!

SHA2017 CTF Teaser round Writeup

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

Crypto Engine (Crypto 200)

いろいろ試して出力される色のRGBの組を確認する。まずは以下の点がわかる。

・3文字で一つのセルが生成される。
・3の倍数の文字でない場合は、3で割った余りの文字数分8ビットの16進数が表記されている。

このことからフラグの文字数は38文字であることがわかる。XORで算出された結果を色で表していると推測しながら、38文字でいろいろ試す。

■abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLの場合
RGB: 83 82 82 83 54 52 53 59 95 94 94 87 50 48 49 39 67 66 66 83 54 52 53 43 79 78 116 105 12 10 49 47 75 66 120 101 | 0x00 0x0e
文字列とRGBのXOR:
[50, 48, 49, 55, 83, 82, 82, 83, 54, 52, 53, 59, 95, 94, 94, 87, 50, 48, 49, 39, 67, 66, 66, 83, 54, 52, 53, 43, 79, 78, 116, 105, 12, 10, 49, 47, 75, 66]

■ZUHadnaopwefvnsudhaaiTjaksUkladauULandの場合
RGB: 104 101 121 86 12 11 24 57 124 124 125 95 10 18 14 42 110 122 111 75 7 46 5 42 108 93 80 65 0 60 52 32 117 105 120 65 | 0x1b 0x0d
文字列とRGBのXOR:
[50, 48, 49, 55, 104, 101, 121, 86, 12, 11, 24, 57, 124, 124, 125, 95, 10, 18, 14, 42, 110, 122, 111, 75, 7, 46, 5, 42, 108, 93, 80, 65, 0, 60, 52, 32, 117, 105]

■YZabcdefghijklMNOPqrstuVWxyzhaAjadsKKKの場合
RGB: 107 106 80 85 8 14 53 51 111 102 92 89 4 10 17 23 75 90 96 101 56 46 21 51 111 86 108 73 7 55 45 35 102 83 94 104 | 0x2d 0x18
文字列とRGBのXOR:
[50, 48, 49, 55, 107, 106, 80, 85, 8, 14, 53, 51, 111, 102, 92, 89, 4, 10, 17, 23, 75, 90, 96, 101, 56, 46, 21, 51, 111, 86, 108, 73, 7, 55, 45, 35, 102, 83]

■ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklの場合
RGB: 115 114 114 115 54 52 53 59 127 126 126 119 50 48 49 39 99 98 98 115 54 52 53 43 111 110 84 73 12 10 49 47 107 98 88 69 | 0x00 0x0e
文字列とRGBのXOR:
[50, 48, 49, 55, 115, 114, 114, 115, 54, 52, 53, 59, 127, 126, 126, 119, 50, 48, 49, 39, 99, 98, 98, 115, 54, 52, 53, 43, 111, 110, 84, 73, 12, 10, 49, 47, 107, 98]

以上を見ていて以下のことに気が付いた。

・XORキーの最初の4バイトは固定:50, 48, 49, 55
・XORキーの5バイト以降はRGBの値を順に並べている。

このことから復号コードを書く。

from PIL import Image

img = Image.open('flag.png').convert('RGB')
w, h = img.size

key = [50, 48, 49, 55]
enc = []
for x in range(1, w, 40):
    r, g, b = img.getpixel((x, 1))
    key.append(r)
    key.append(g)
    key.append(b)
    enc.append(r)
    enc.append(g)
    enc.append(b)
del key[-2:]
enc.append(0x2e)
enc.append(0x29)

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

print flag

この結果フラグがゲットできた。

flag{deaf983eb34e485ce9d2aff0ae44f852}