Base64デコーダーを作る
とあるCrackmeでcustom_base64なるものでエンコードされた文字列が出てきた...
Flagを手に入れるためにはこれをデコードして元の文字列を見つけなきゃいけない.
custom_base64とはなんなのか...答えを見つけるために,我々はアマゾンの奥地へと...
概要
Base64の仕組みの中で000000 ~ 111111を文字に置き換えた辞書が存在する.
通常のBase64では順番に ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
をあてはめた辞書が使われている.
これを指定した辞書に入れ替えたものがcustom_base64関数の中身であった.
Base64を実装する記事を参考に本記事ではPythonでデコーダーを実装する.
Base64の仕組み
エンコード
大まかにBase64のエンコードの処理を確認します.詳しくは他サイトを参照.
- 変更したい文字列(ASCII)をバイナリ(2進数)に変換
- バイナリを6bitづつに分割
- 分割した際に最後が6bitより少なくなるため,6bitになるように0を追加する
- 変換表を用いて6bitを文字に変換
- 4biteずつBase64では出力するために文字数が4の倍数文字になるよう"="を付け足す
- base64の文字列の完成!!
デコード
エンコードの仕組みがわかればデコードは簡単!基本的には逆の手順を踏むだけ!
- 付け足された"="を削除
-
SG9nZUhvZ2U=
→SG9nZUhvZ2U
-
- 変換表を用いて文字をバイナリに変換してつなげる.
-
SG9nZUhvZ2U
→010010 000110 111101 100111 011001 010100 100001 101111 011001 110110 010100
-
- バイナリを8bitずつに分割,エンコード3. で付け足された0が余るのでそれらを削除
01001000 01101111 01100111 01100101 01001000 01101111 01100111 01100101 00
- 2進数bitをASCIIに変換
01001000 → H
01101111 → o
01100111 → g
01100101 → e
01001000 → H
01101111 → o
01100111 → g
01100101 → e
- デコード完了!
プログラムにしてみる
import sys
import argparse
BYTE_SIZE = 8
# 000000 -> 111111まで1文字ずつ辞書型リストを作成する関数
def makeDict(base64Dict_seed):
dictionary = {}
for i in range(0, 64):
dictionary[format(i, '06b')] = base64Dict_seed[i]
return dictionary
# 文字列s をn文字で区切ってリスト化する関数
def split(string, n):
split_list = []
for i in range(0, len(string), n):
split_list.append(string[i:i+n])
return split_list
# 文字列がn文字なかったらn文字になるように`c`を足す
def fillBlank(s, n, c):
mod = len(s) % n
if mod == 0:
return s
else:
margin = n - mod
return s + c * margin
# 辞書の値を渡すと辞書のキーを返す
def getValue(key, items):
for v in items.items():
# print(v[1])
if v[1] == key:
# print(v)
return v[0]
return ''
def main():
# -kをつけるとカスタム辞書を入力できる
parser = argparse.ArgumentParser(
description='custom Base64 Decoder')
parser.add_argument('-k', '--key', help="Use custom Seed to encrypt in base64 ", \
default="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
parser.add_argument('text', help='base text')
args = parser.parse_args()
# 0. 辞書を作る
base64Dict = makeDict(args.key)
# 1. '='をはずす
text = args.text.replace("=", '')
binStr = ""
# 2. 変換表を用いて文字をバイナリに変換してつなげる.
for i in text:
binStr += getValue(i, base64Dict)
# 3. バイナリを8bitずつに分割,エンコード3. で付け足された0が余るのでそれらを削除
splitCount = 8
s = split(binStr, splitCount)
if (len(s[-1]) != 8):
s.pop(-1)
# 4. 2進数bitをASCIIに変換
result =""
for c in s:
print(c + " → " + chr(int(c, 2)))
result += chr(int(c, 2))
print(result)
if __name__ == "__main__":
main()
使い方
$ python3 customBase64Decoder.py <Base64テキスト>
$ python3 customBase64Decoder.py -k <Custom辞書> <Base64テキスト>
$ python3 customBase64Decoder.py SG9nZUhvZ2U=
$ python3 customBase64Decoder.py -k xEPOKnvADqeG0m1VkZ47CM653jrtbzLsTc2ypoYUSWJ9ludQig+awf8XF/RNHBhI 4vBUjCcQj8C=
HogeHoge
まとめ
Base64完全に理解した.
これでオリジナルBase64つくって秘密の通信ができちゃうね,やったね
サンプルコードはGitHubに置いてあります
- エンコーダー
- デコーダー
参考文献
base64ってなんぞ??理解のために実装してみた - qiita
https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4