SHA1 padding attack

勇士QさんのKernel/VM Advent Calendar 18日目: CTF 暗号問題 - 勇士Qの日記の問題の解答を書かせて頂きます。まだ、解いていなくて、挑戦したいと言う方は以下、ネタバレを含むのでご注意下さい。なお、勘違い部分もあると思うので間違いがあれば指摘して頂けるとありがたいです。
この問題はCODEGATE2010 CTFの問題が元みたいです。CODEGATEの問題は色んな所で解説が上げられているみたいです。CodeGate 2010 Challenge 15 – SHA1 padding attack
問題の内容はKernel/VM Advent Calendar 18日目: CTF 暗号問題 - 勇士Qの日記を見てください。
目的はadmin権限で認証を突破することです。サーバの認証部分はX'masのやつのヒント的なもの - 勇士Qの日記のようになっています。
つまり、secretkeyが分からない状態で、sha1(secretkey + "admin|...(0以外の何か)")を求めることが目的です。

解き方

adminと入力してLoginすると、レスポンスヘッダの中に

Set-Cookie: webauth=YWRtaW58MA==|481d4710a86d68930145eb471293c4240fc99632; Path=/crypto/

として返ってくるので

sha1(secretkey + "admin|0")

Cookieの中より既知です。(481d4710a86d68930145eb471293c4240fc99632)これを用いて、

sha1(secretkey + "admin|0....(padding)")

を求めることが可能です。これを求めるにはパディングするサイズが必要なため、secretkeyの長さ(バイト数)が必要ですが、そこは余り長くないので最終的にブルートフォースでOKです。

SHA1 extension (or padding) attack

説明しやすいように先に答えを書いてしまうと、secretkeyの長さは23バイトです。情報を整理すると、

分かっていること
sha1(secretkey + "admin|0") -> 481d4710a86d68930145eb471293c4240fc99632
len (secretkey)             -> 23
知りたいこと
sha1(secretkey + "admin|0...(padding)")

secretkeyをxxとして表し、 admin|0 の後ろに以下のように、SHA1アルゴリズムと同じようにパディングを行う。(RFC3174

00000000  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx  |................|
00000010  xx xx xx xx xx xx xx 61  64 6d 69 6e 7c 30 80 00  |.......admin|0..|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 f0  |................|

上述のデータをSHA1で計算したものは以下の手順で求められる。以下では、 PyPy lib_pypyに入っている sha.py を用いている。

% python
...(略)...
>>> import sha, struct
>>> m = sha.new()
>>> (m.H0, m.H1, m.H2, m.H3, m.H4) = struct.unpack(">IIIII", '481d4710a86d68930145eb471293c4240fc99632'.decode("hex"))
>>> m.count = [0, 512]   # 512 = 64 * 8
>>> m.hexdigest()
'10d025a4904fe30af81d4ae390db63f11d481b7e'

secretkey以降のデータをbase64エンコードしてCookieを作ります。

% echo -n '61 64 6d 69 6e 7c 30 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0' | xxd -r -p | base64 
YWRtaW58MIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA=

くっつけて、

YWRtaW58MIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA=|10d025a4904fe30af81d4ae390db63f11d481b7e

これをCookieとして送れば以下のレスポンスが得られる。

% echo "GET /crypto/ HTTP/1.1\nHost: ucq-ctf.appspot.com\nUser-Agent: nc\nCookie: webauth=YWRtaW58MIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA=|10d025a4904fe30af81d4ae390db63f11d481b7e\n" | nc ucq-ctf.appspot.com 80
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: text/plain; charset=UTF-8
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Wed, 02 Mar 2011 10:08:59 GMT
Server: Google Frontend
Transfer-Encoding: chunked

23
Congratulation!! h4ppy m3rry (7f :)
0

Congratulation!! h4ppy m3rry (7f :)

結論
@ucq : 間違った利用の仕方をするとsalt付きsha1でもクラックされるよということです(たぶん)。