最近いくつかのサイトをテストしました。最初にログインフォームがあり、パケットキャプチャ後にユーザー名とパスワードが暗号化されていました。形式は以下の通りです:
フロントエンドでよく使用される暗号化方式は aes で、aes のキーを rsa で暗号化し、その後 aes でデータを暗号化して送信するケースもありました。
上の図は aes を直接使用した暗号化の例です。
ブラウザを通じて暗号化された js ファイルを見つけることができ、通常はソースコード / ソース内の js ディレクトリで見つけます。このサイトは比較的簡単で、crypto-js.js ファイルを直接使用しており、開くと aes のキーと暗号化方式がすぐに確認できます。
上の図から、キーが与えられ、モードは ECB、パディングは Pkcs7 であることがわかります。これらの情報があれば、データを解読することができます。
burpsuite のautodecoderプラグインを使用して、今回の解読もこのプラグインを使用しました。
autoDecoder には 4 つのタブがあります。
最初の options タブは、いくつかの設定です。
- モジュール制御:burp のどのモジュールで autodecoder の暗号化 / 復号化を実行するか
- 暗号化 / 復号化オプション:自前のアルゴリズムを使用するか、インターフェースを使用するかを制御します。
後のオプションは最初のオプションに関連しており、インターフェースを使用する場合、データヘッダーを処理する
またはリクエスト応答の異なる暗号化/復号化
オプションを設定できます。
- 暗号化 / 復号化設定:暗号化ドメインを必ず記入する必要があります。そうしないと autodecoder タブに表示されません。他はデフォルトで構いません。
- 設定が完了したら、必ず
保存
してください。
2 番目のタブは autodecoder の自前のアルゴリズムによる暗号化 / 復号化です。
3 番目のタブはインターフェースによる暗号化 / 復号化です。
インターフェースを設定する必要があります。インターフェースは作者が提供したものを参考にできます。リクエストパラメータをカスタマイズする必要がある場合、大部分はインターフェースを使用して暗号化 / 復号化する必要があります。
今回遭遇したように、2 つのパラメータが存在する場合、自前のアルゴリズムによる暗号化 / 復号化では要件を満たすことができません。
自前のアルゴリズムによる暗号化 / 復号化には正規表現パターンマッチングがあり、1 つの暗号化された文字列(name)しかマッチできず、pwd パラメータの暗号化された文字列を抽出することができません。
4 番目のタブはリクエスト応答の置換です。
権限のない脆弱性をテストするために使用でき、burp の Autorize プラグインと似ていると感じますが、使用したことはありません。
autodecoder プラグインについて簡単に紹介しました。
作者のスクリプトを変更して、現在テストしているサイトに適応しました。
from flask import Flask, request
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad
import base64
from urllib.parse import parse_qs,quote
import hashlib
def aes_encrypt(key, data):
cipher = AES.new(key, AES.MODE_ECB)
padded_data = pad(data.encode(), AES.block_size)
cipher_text = cipher.encrypt(padded_data)
return base64.b64encode(cipher_text).decode()
def aes_decrypt(key, data):
cipher = AES.new(key, AES.MODE_ECB)
decrypted_data = cipher.decrypt(base64.b64decode(data))
unpadded_data = unpad(decrypted_data, AES.block_size)
return unpadded_data.decode()
app = Flask(__name__)
@app.route('/encode', methods=["POST"])
def encrypt():
key = b'ここにaesのkeyを書く' # 16バイトのキー
str1 = '123'
param = request.form.get('dataBody') # POSTパラメータを取得
md5value = param + str1
param1 = quote(aes_encrypt(key,param))
param2 = hashlib.md5(md5value.encode()).hexdigest()
return f"Param={param1}&Autograph={param2}"
'''
data = json.loads(param)
encrypted_id = aes_encrypt(key, data["id"])
encry_param = param.replace(data["id"], encrypted_id)
return base64.b64decode(encry_param.encode()).decode()
'''
@app.route('/decode', methods=["POST"])
def decrypt():
key = b'ここにaesのkeyを書く'
param = request.form.get('dataBody')
print('param: ',param)
parsed_params = parse_qs(param)
print(parsed_params)
# 2つのパラメータを解読、nameとpwd
decrypted_name = aes_decrypt(key, parsed_params["name"][0])
decrypted_value = aes_decrypt(key, parsed_params["pwd"][0])
# 2つのパラメータを含むJSONレスポンスを返す
return f"name={decrypted_name}&pwd={decrypted_value}"
if __name__ == '__main__':
app.debug = True # デバッグモードを設定、運用時はオフにすることを忘れずに
app.run(host="0.0.0.0", port=8888)
スクリプトを書いたら、実行します。プログラムは 127.0.0.1:8888 でリッスンします。
python3 aed_decode.py
まずはパケットをキャプチャしてテストしてみてください。成功裏に解読されたことが確認できます。
現在の設定は以下の通りです:
設定が完了した後、パケットをキャプチャすると、各リクエストが自動的に解読されるのが確認でき、autoDecoder タブで解読内容を見ることができます。
また、burp の intruder モジュールを使用してログインブルートフォース攻撃を開始することもできます。
ここで、非対称暗号、対称暗号、署名、再送信禁止のテストシナリオを含むフロントエンド暗号対抗練習用の靶場をお勧めします。AES、DES、RSA などを使用したペネトレーションテストの練習に適しています。