0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KSNCTF #9 Digest is secure!

Posted at

Digest is secure!

.pcapファイル

添付されているファイルで追跡してみると、Digest認証に成功している情報が出てきました。
スクリーンショット 2025-07-17 100122.png
スクリーンショット 2025-07-17 100139.png

これらの変数にどのような役割があるか、以下を参考にしました。


flag.htmlにアクセスすることを目標とします。
スクリーンショット 2025-07-17 101152.png

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にアクセスしたとき、responsenccnonce以外一致しています。

  • response:暗号結果
  • nc:同じnonceを使った回数
    • nonce:サーバ側が生成するランダム値
  • cnonce:リプレイ攻撃を避けるためのクライアント側が生成するランダム値

userが変わっていないのでpasswordは変わっていないと推測できます。


そして、/q9/htdigest/アクセスしているので、user:realm:MD5(A1)がわかります。
(最初は何も気にしてなかった)

スクリーンショット 2025-07-17 102559.png

A1 = username ":" realm ":" passwordですから、常に一定と言えます。
つまり、私がA1を出そうとしていた行為は全くの無駄でした…

Digest認証の突破

MD5(A1)がわかれば、任意のnccnonceに対して認証が通る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/にアクセスします。
スクリーンショット 2025-07-17 104120.png

ここでinterceptをオンにしてログインします。すると、必要な情報が出てきます。
これらの情報をコードに入力し、実行するとresponse=74eb2d08e10461eb7210b2123f4d1cef
スクリーンショット 2025-07-17 104945.png

responseを書き換えて、Forwardを押すとアクセスできました。
スクリーンショット 2025-07-17 112249.png

hereを押すと、/q9/flag.htmlで同じ認証が求められます。
上記と同様の方法でアクセスすることができます。(URI="/q9/flag.html"に変わります!)
スクリーンショット 2025-07-17 112617.png

まとめ

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?