Goyotanの電脳_1

書いていく

What is the deadly bug here?

個人的に面白いなと思ったPHPコードがあるので、頑張って読み解いて実際に試してみようと思います。

PHPはあまり詳しくないので、勉強になりました。

 

 ツイートの写真のコードには致命的なバグがあって、それは何かという問題です。

 

#大体の処理フロー

1, POSTパラメータでhmachostがセットされていなければ400 Bad Requestを返します。

2, $secret変数にgetenv()関数を使い、Apache環境変数の'SECRET'をセットします。「Apache環境変数はphpinfo();で全て見ることが可能です。」

 3, POSTパラメータnonceがセットされている場合、$secret変数にhash_hmac()関数を使い値をセットしていきます。

4,$hmac変数にもhash_hmac()関数を使い値をセットします。

この時、nonceパラメータが設定されていないと3の処理を行いません。従ってその場合はApache環境変数が使われます。

5, 計算された$hmac変数とPOSTパラメータhmacが異なる場合、403 Forbiddenを返します。

6, 5の式がtrueに評価されたらOSコマンドhostと、POSTパラメータhostを結合し、exec()関数で実行・表示します。

 

つまり、最初のにPOSTするパラメータhmacにセットされるハッシュ文字列と内部でゴニョゴニョ計算された変数$hmacが同じであれば、exec()関数を実行するということになります。 

 

#今回のゴール

全ての分岐正常に通れば、ユーザがパラメータ$hostにセットした値がそのままexecに渡ります。この時 www.google.com;id というようにセットすると、コマンドインジェクションすることが可能です。

 

#やっていく

処理5をいかにしてtrue評価させるかです。hash_hmac関数のある挙動を用いると、式を上手くコントロールすることができます。

 

最初にhash_hmacの仕様を見てみましょう!

PHP: hash_hmac - Manual

・パラメータ

string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] )

今回は$algo,string $data, string $keyの3つとなります。

・返り値

raw_output が true に設定されていない場合は、 メッセージダイジェストの計算結果を小文字の 16 進数値形式の文字列で 返します。もし true に設定されていた場合は、メッセージダイジェストが そのままのバイナリ形式で返されます。 algo が未知の場合は FALSE を返します。 

 チョット分かりにくいですが、raw_output=trueの設定をしていないので今回は計算結果が出てくるということは分かります。

 

次に、PHPの対話シェルを使い挙動を確認していきます。

php > echo hash_hmac('sha256','NyanNyan','12345');

設定は$algo = 'sha256' , $data = 'NyanNyan' , $key = '12345'です。

結果は以下の文字列がでてきました。
690908c6dedadb4d9d5427cb84e8a8307863a82ddb7d3df84c16bc3a6fb8760b

 基本的な挙動は確認できました。

それでは、今回のキモです。$dataの引数に対し、配列を設定するとNULLが返るというものです。

こちらの動作も確認していきます。

php > echo gettype(hash_hmac('sha256',array(1),'12345'));

gettype()関数を使い、計算結果の型を確認してみます。
PHP Warning: hash_hmac() expects parameter 2 to be string, array given in php shell code on line 1
NULL

確かにエラーの後に戻り値がNULLとなっていますね!

従って処理3の時、パラメータnonceを配列としてPOSTすれば$secret変数にはNULLがセットされることになります。

この挙動は先ほどの関数の説明を見ても分からん~~~

それでは続きを見ていきましょう!

処理4の時はどうなるでしょうか?

$secretにはNULLがセットされていますね。

つまり、

$hmac = hash_hmac('sha256',$_POST['host'],NULL)

 となります。

挙動を確認してみましょう。

php > echo hash_hmac('sha256','www.google.com',NULL);

hostには'www.google.com'をセットしています。

計算結果は次になります。

7f67e6bc0b34baaa5714d03b8776c1781bfca4a9513c7e90f92ca770fbfa3abd

ということは、式をコントロールできた事になりますね!?

 

さて、実際にシステムに対して実行してみましょう!

それぞれのパラメータは以下の通りです。

hmac'7f67e6bc0b34baaa5714d03b8776c1781bfca4a9513c7e90f92ca770fbfa3abd';

host = 'www.google.com';

nonce = 1; //適当な値もしくは空でOK

以下リクエストとレスポンスの結果です。

f:id:Goyotan:20180129234635p:plain

見事にexec()まで到達することができましたね!

 

#EXPLOOOOOOOIT!!!!

それでは最後にコマンドインジェクションにより、OSに対して攻撃を行いたいと思います。hmachostを再計算、値のセットしていきます。

パラメータは以下の通りです。

hmac = 'a5a3560643e1ecd566cff4e117a466cb621ddb852b2e826c720637344433a763';

host = 'www.google.com;id'; //Injected

nonce = 1; //適当な値もしくは空でOK

以下リクエストとレスポンスの結果です。

f:id:Goyotan:20180129235300p:plain

無事にidコマンドを実行することができました!

 

 

 

#感じたこと

今回実際手を動かして試してみたが、このような関数の挙動を知れて興味深かったです。

関数の詳細な挙動についても知る必要があると感じました。

また、PHPについて更に調べてみようと思いました。

 

それではまた次のポストで!

 

P.S.

この明日は定期テストですが、このブログを書いていたら勉強できませんでした卍