最近、銀行のWebリソースのセキュリティを確認しているときに、Exim 4.89メールサーバーに脆弱性が見つかりました。これにより、リモートコードが実行される可能性があります。この脆弱性はCVE-2018-6789として知られています。PoCエクスプロイトを使用して、リモートマシンでリバースシェルを取得し、銀行のWebサイトにアクセスしました。

当然、なぜこのような脆弱性の悪用が可能になったのか疑問に思いました。
CVE-2018-6789はどこから来たのですか?
つまり、この脆弱性は、Eximが使用するbase64.c:b64decode関数のバッファー長の計算エラーが原因です。これについて詳しくは、こちら(英語)をご覧ください。
特別な長さの文字列を入力すると、1バイトの情報を上書きし、簡単なアクションを使用してサーバーコマンドを変更し、任意のコード(RCE)を実行できます。
Eximは、デコードされたデータを保持するために3 *(len / 4)+1バイトのバッファーを割り当てます。ただし、誤ったbase64文字列が関数入力に供給された場合(たとえば、4n + 3 long)、Eximはバッファーに3n +1バイトを割り当てます。しかし同時に、3n +2バイトのデータをバッファーに書き込みます。これにより、1バイトがヒープ内で上書きされます。
Eximはstore_malloc_3とstore_free_3を提供します。これらは、mallocのラッパーであり、Glibcの関数を解放します。 Glibcはデータの大きなブロックを割り当て、そのメタデータを最初の0x10バイトに格納し、ユーザーがデータを書き込むことができるメモリへのポインタを返します。これは、次のようになります。

メタデータは、前のブロック(上記メモリの1)の大きさ、現在のブロックのサイズ、およびいくつかのフラグを含んでいます。サイズの最初の3ビットは、フラグを格納するために使用されます。この例では、サイズ0x81は、現在のチャンクが0x80バイトであり、前のチャンクがすでに使用されていることを意味します。
解放されたブロックは、Eximによって使用されると、二重にリンクされたリストに配置されます。 Glibcはフラグによってそれを維持し、断片化を回避するために、隣接する解放されたチャンクをより大きなチャンクにマージします。 Glibcは、メモリ割り当て要求ごとに、これらのチャンクをFIFO順に調べ、再利用します。

パフォーマンスを向上させるために、Eximは独自のメモリ管理アドオンを使用します。ストアブロック構造に基づいています。ストアブロックの主な機能は、それぞれのサイズが少なくとも0x2000バイトであるということです。これは、悪用の制限になります。 storeblockはブロックデータでもあることに注意してください。メモリ内では次のよう

になります。ヒープ上のデータを整理するためにメールサーバーでサポートされているコマンド:
- EHLO hostname. EHLO hostname sender_host_name. , store_free store_malloc .
- . , , Exim .
- AUTH. Exim base64 . , store_get (). store_get().
- Reset EHLO/HELO, MAIL, RCPT. , Exim smtp_reset. store_reset , « ». , storeblock- store_get .
ヒープで1バイトのオーバーフローを使用するには、base64でデコードされた文字列の下にあるデータブロックを解放できる必要があります。 Sender_host_nameはこれに適しています。
ヒープは、sender_host_nameを含むブロックの上にデータのブロックを解放したままにするような方法で形成する必要があります。

これを行うには、次のことを行う必要があり
ます。1。大きなブロックをソートされていないビンに入れます。まず、ホスト名が大きすぎるEHLOメッセージを送信して、長さ0x6060のチャンクをソートされていないビンに割り当てて解放します。
2.最初のストアブロックを選択します。次に、認識されないコマンドを送信してstore_get()を呼び出し、解放されたチャンク内にストアブロックを割り当てます。
3. 2番目のブロックを選択し、最初のブロックを解放します。 2番目のブロックを受信するためにEHLOを送信します。 EHLOの完了後に呼び出されるsmtp_resetにより、最初のブロックは順次解放されます。
ヒープが準備されたら、それを使用して元のブロックサイズを上書きできます。 0x2021を0x20f1に変更します。これにより、ブロックがわずかに拡張されます。

4. base64データを送信し、ヒープ上で1バイトオーバーフローします。 AUTHコマンドを実行してbase64データを送信します。
5.適切なサイズの文字列を作成して送信します。データブロックを展開したので、次のチャンクの始まりは内部のどこかになります。ここで、Glibc整合性チェックに合格するために修正する必要があります。ここに別のbase64文字列を送信します。
6.拡張ブロックを解放します。拡張ブロックのコンテンツを制御するには、ブロックを直接編集できないため、最初にブロックを解放する必要があります。つまり、古いホスト名を解放するには、新しいEHLOメッセージを送信する必要があります。ただし、EHLOコマンドを処理すると、正常に実行されるとsmtp_resetが呼び出されます。これにより、プログラムが中断したり、異常終了したりする可能性があります。これを回避するために、+などの無効なホスト名を送信しています。
7.重複するストアブロックの次のポインターを上書きします。

チャンクが解放された後、AUTHでチャンクを取得し、重複するストアブロックの一部を上書きできます。ここでは、「部分録音」と呼ばれる手法を使用します。これにより、ASLRを壊すことなくポインタを変更できます。次のポインタをACL行を含むブロックに部分的に変更しました。 ACL行は、uschar * acl_smtp_heloなどの一連のグローバルによって指定されます。
これらのポインタは、Eximプロセスの開始時に初期化され、構成に従って設定されます。たとえば、構成にacl_smtp_mail = acl_check_mailという行が含まれている場合、acl_smtp_mailポインターはacl_check_mail行を指します。
サーバーがMAILFROMコマンドを受信するたびに、EximはACLチェックを実行します。これにより、最初にacl_check_mailが展開されます。拡張時に、Eximが行$ {run {cmd}}を検出すると、cmdコマンドを実行しようとするため、リモートの攻撃者がコードを実行できるようになります。
8.ストアブロックをリセットし、ACLを含むストアブロックを取得します。 ACLブロックがブロックチェーン上にあります。 smtp_reset()が実行された後に解放され、いくつかのブロックを割り当てることで再度取得できます。
9. ACL行を上書きし、ACLチェックを実行します。最後に、ACL行を含むブロック全体を書き直します。ここで、EHLO、MAIL、RCPTなどのコマンドを送信してACLチェックを実行します。
ちなみに、この脆弱性の悪用は、私たちが知らない何らかの理由で無効にされたASLRによって促進されました。
お客様はどのような問題を抱えていましたか?
1つ目は、更新管理の欠如です。古いバージョンのEximが使用されていたため、システムの侵害を整理することができました。これを回避するには、情報インフラストラクチャのコンポーネントのセキュリティ更新プログラムを定期的にチェックしてインストールすることをお勧めします。
少なくとも月に1回は、新しいセキュリティと重要な更新を確認することをお勧めします。更新を確認するには、機器メーカーのサイト/メーリングリストまたはリポジトリからの情報を使用することをお勧めします。
銀行には脆弱性管理プロセスもありませんでした。そのため、脆弱性は時間内に検出されませんでした。特殊な脆弱性スキャナー(OpenVAS、Nessus、xSpiderなど)を使用すると、状況を修正するのに役立ちます。定期的な侵入テストと脆弱性除去のタイミングの監視も役立ちます。
そして最後になりましたが、大事なことです。銀行には変更管理プロセスがありませんでした。すべての変更は、実稼働環境の管理者によって行われました。その結果、誰もこれを制御または監視しませんでした。これにより、サーバーでASLRが無効になりました。
出力
一見無関係に見えるいくつかの違反により、銀行のWebサイトが侵害されました。これは、悪意のある人物が、たとえば銀行の詳細を独自のものに変更するために使用できます。
話はうまく終わった。妥協後、すぐにクライアントに状況を通知しました。銀行は、Eximサーバーを現在のバージョンに緊急に更新しましたが、このバージョンには脆弱性は関係ありません。ただし、侵入テストではなく実際の攻撃者によって脆弱性が特定された場合、結果は異なる可能性があります。