田舎院生のセキュログ

自分用のメモとかWrite-up

Vigenere (Crypto, 100)

SECCON2016 Online CTF の Vigenere

ヴィジュネル暗号を解読する問題
暗号についてはWikipediaで見てください!
この暗号は見たことある気がするけど、暗号名を知ったのは初めてかも。。笑

問題

鍵: ????????????
平文: SECCON{???????????????????????????????????}
暗号: LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ
使われている文字列:ABCDEFGHIJKLMNOPQRSTUVWXYZ{}

それと、答えとなる平文のハッシュ値が与えられている。


要は、暗号文と少しの平文から鍵を予測して、その鍵を使って暗号文を平文に復号してくださいっていう問題ですね。
ヴィジュネル暗号は「鍵」「平文」「暗号文」のうち二つの情報を知っていれば、残り一つの値を導くことができます。最初に平文は7文字まで分かっているので、鍵も7文字だけ分かり、「VIGENER」という文字列が出てきます。8文字目は「E」になるかな?と予想はできるのですが、それ以降の鍵を予想するのは難しいですよね…
ということで、あとは総当たりによって鍵を導き出すプログラムを作ってみます。

自分はJavaが得意なのですが、あえて勉強中のPythonで組みました!

# coding:utf-8

import sys
import hashlib

# 引数:読み込みファイル名
input = sys.argv
file_name = str(input[1])
key_string = "VIGENERAAAAA"

# ファイル読み込み
file = open(file_name, 'rt')
text = file.read()
string_list = list(text)

# キーを総当たりでチェック
for a in range(65, 91):
    key_string = key_string[0:7]
    key_string += chr(a)
    for b in range(65, 91):
        key_string = key_string[0:8]
        key_string += chr(b)
        for c in range(65, 91):
            key_string = key_string[0:9]
            key_string += chr(c)
            for d in range(65, 91):
                key_string = key_string[0:10]
                key_string += chr(d)
                for e in range(65, 91):
                    key_string = key_string[0:11]
                    key_string += chr(e)

                    # メイン処理
                    count = 0
                    new_string = ""
                    for string in string_list:
                        ascii = ord(string[0])
                        new_ascii = ""
                        key_number = count % len(key_string)
                        key_ascii = ord(key_string[key_number])

                        if key_ascii == 123:
                            key_ascii = 27
                        elif key_ascii == 125:
                            key_ascii = 28
                        else:
                            key_ascii -= 64

                        # 大文字
                        if 64 < ascii < 91:
                            new_ascii = (ascii - 64) - key_ascii
                            if new_ascii < 0:
                                 new_ascii += 28
                            new_ascii += 65

                        # {
                        elif ascii == 123:
                            new_ascii = 27 - key_ascii
                            if new_ascii < 0:
                                new_ascii += 28
                            new_ascii += 65

                        # }
                        elif ascii == 125:
                            new_ascii = 28 - key_ascii
                            if new_ascii < 0:
                                new_ascii += 28
                            new_ascii += 65

                        # 文字コードが91なら { に変換
                        if new_ascii == 91:
                            new_ascii = 123

                        # 文字コードが92なら } に変換
                        if new_ascii == 92:
                            new_ascii = 125

                        new_string += chr(new_ascii)
                        count += 1

                    # ハッシュ処理
                    check = hashlib.md5(new_string.encode()).hexdigest()
                    check2 = "f528a6ab914c1ecf856a1d93103948fe"
                    if check == check2:
                        print("KEY is " + key_string)
                        print(new_string)
                        break

print("Not found!!")

初心者だと丸わかりのコードですね…
鍵を見つけても実行停止しないという( ;∀;)笑
まぁ答えさえ分ればいいので、その辺りは置いといて…

処理の流れとしては…
総当たりで鍵を作る ⇒ その鍵を使って暗号文を平文に復号 ⇒ 平文のハッシュ値を生成して、答えのハッシュ値と比較 ⇒ 一致すれば答えを出力

ちなみに、

平文 = 暗号文 - 鍵

の関係を用いて計算しています。

このプログラムを実行して数分待つと…
f:id:swime:20161214205012j:plain
フラグゲットです!

下手なコードでスミマセン…少しずつPython勉強していきます。。