Base64デコーダーを作る
本記事は以前筆者のqiitaに投稿していた記事を移動させたものです。
とある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/2905e2d0aa7fe46a36d41