wakatonoの戯れメモ

はてなダイアリーから引っ越してきました。

3dub 4 rememberme write up - to know to do

You access to the URL below:

Then you see 3 links to other pages in the server below:
usernames.txt, passwords.txt, login form

links to username.txt and passwords.txt has same structure like below:

access to usernames.txt looks succeed, but access to passwords.txt looks failed

accesscodes in the link to usernames.txt and passwords.txt are same, but only access to the link of usernames.txt is succeeded.

Specified access code was 60635c6862d44e8ac17dc5e144c66539.

This value is the MD5 hash of filename ( in this case, MD5 hash value of string "usernames.txt" ).
You can obtain the value of this filename string as the example command below(I executed the command on the Linux):


$ echo -n usernames.txt | md5sum
you will get the value 60635c6862d44e8ac17dc5e144c66539 as a result.

You can obtain the file by using getfile.php .

3dub 4 rememberme write up(2) - obtaining getfile.php source code by using getfile.php.

Next step: you can get getfile.php by using itself.

Acecss to URL like below:
http://rememberme.shallweplayaga.me/getfile.php?filename=getfile.php&accesscode=[result of `echo -n getfile.php | md5sum`]

You can obtain the result like below:


Acces granted to getfile.php!




$value = time();
$filename = $_GET["filename"];
$accesscode = $_GET["accesscode"];
if (md5($filename) == $accesscode){
echo "Acces granted to $filename!

";
srand($value);
if (in_array($filename, array('getfile.php', 'index.html', 'key.txt', 'login.php', 'passwords.txt', 'usernames.txt'))==TRUE){
$data = file_get_contents($filename);
if ($data !== FALSE) {
if ($filename == "key.txt") {
$key = rand();
$cyphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);
echo base64_encode($cyphertext);
}
else{
echo nl2br($data);
}

}
else{
echo "File does not exist";
}
}
else{
echo "File does not exist";
}

}
else{
echo "Invalid access code";
}
?>

You know your mission is to read key.txt .

3dub 4 rememberme write up(3) - decode the key.txt by guessing the key for encryption

When reading key.txt, getfile.php adds process after reading key.txt as below:

if ($filename == "key.txt") {
$key = rand();
$cyphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);
echo base64_encode($cyphertext);

key for encrypt looks random, but you can guess the key by the description as below:


$value = time();
// (snip)
srand($value);
Random seed is the result of time(), and you can guess the parameter of srand() execution, and you can get the time on the Web server because of raw response data contains the time of Web server like below:

you could get the time value on the server to get the key and cipher text to be decrypt.
you can try the time value on the server , before a few seconds, and after a few seconds as srand() parameter for safe.

3dub 4 rememberme write up(1) - 何をやるかを知ろう

まずは以下のURLにアクセスしてみよう.

すると,usernames.txtに対するもの,passwords.txtに対するもの,loginフォームに対するものと3つのリンクがあることに気づくはず.

usernames.txtとpasswords.txtは,以下のような構造のリンクを持っている.

ところが,usernames.txtへのアクセスは成功するが,passwords.txtへのアクセスは失敗する.

usernames.txtとpasswords.txtの両方へのリンクで指定されているアクセスコードが同じ値になっているが,この値,実はファイル名(文字列)のMD5値である.
実際に以下のコマンドラインLinuxなどで実行すると,60635c6862d44e8ac17dc5e144c66539 という値を得られるはず.得られない場合は,文字を打ち間違えているか,echo コマンドの-nオプションを指定していないために,文字列に改行も含めた形でMD5値の算出が行われているかのどちらかだろう.


$ echo -n usernames.txt | md5sum

このことに気づくと,getfile.phpそのものも取ることができるようになる.

    • -

3dub 4 rememberme write up(2) - getfile.phpを使って,getfile.phpのソースコードを取得しよう

次は,getfile.phpを実行してgetfile.phpを取得する.
余談だが,ファイルへのアクセスを行わせるCGIやWebアプリケーションの脆弱性の中に,任意のファイルへのアクセスを許してしまうこともある.任意のファイルということは,CGIやWebアプリケーションを構成するファイルにもアクセスを許すということにつながり,さらなる脆弱性の発見につながる.
具体的には,以下のようなコマンドラインになる.
accesscodeでの指定値は,適宜計算すればOKだろう.

http://rememberme.shallweplayaga.me/getfile.php?filename=getfile.php&accesscode=[result of `echo -n getfile.php | md5sum`]

すると,以下のような結果を得られる.
スクリプトとしては少しだけ不十分だが,まぁ読むには十分だ.


Acces granted to getfile.php!




$value = time();
$filename = $_GET["filename"];
$accesscode = $_GET["accesscode"];
if (md5($filename) == $accesscode){
echo "Acces granted to $filename!

";
srand($value);
if (in_array($filename, array('getfile.php', 'index.html', 'key.txt', 'login.php', 'passwords.txt', 'usernames.txt'))==TRUE){
$data = file_get_contents($filename);
if ($data !== FALSE) {
if ($filename == "key.txt") {
$key = rand();
$cyphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);
echo base64_encode($cyphertext);
}
else{
echo nl2br($data);
}

}
else{
echo "File does not exist";
}
}
else{
echo "File does not exist";
}

}
else{
echo "Invalid access code";
}
?>

ここで"key.txt"という言葉が出てくる.これを読み出せばOK,なのだが,さらに一工夫が求められる.

3dub 4 rememberme write up(3) - 暗号鍵を推測してkey.txtをもらおう

スクリプトを見ると,以下のようにkey.txtの時だけは,特別な処理を入れていることがわかる.
When reading key.txt, getfile.php adds process after reading key.txt as below:


if ($filename == "key.txt") {
$key = rand();
$cyphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC);
echo base64_encode($cyphertext);
要は「ファイル名がkey.txtだったらば,乱数を鍵にして暗号化する」というものだ.
ところがこの鍵,以下に示すようにとっても推測しやすいものであるw
rand()の前に関連する処理を見てみると,以下のとおりである.

$value = time();
// (略)
srand($value);
srand()のパラメータに,time()の実行結果を指定している.
Webサーバのレスポンスに,サーバの時刻情報が含まれるために,time()の値は推測が容易である*1

ここまでやっていくことで,鍵と暗号文が入手出来た.
ということで,時刻データ±数秒程度のデータからsrand()+rand()で鍵をいくつか生成し,暗号鍵を作って解いてやると,それっぽい文字列が出てくるだろう.

*1:処理のタイミングによっては,time()の値が1秒程度ずれることもありうるため,「推測が容易」と書いている