IoT ボットネットはいかにして検知と分析を回避するか - パート1

IoT ボットネットはいかにして検知と分析を回避するか - パート1

とらえどころのないマルウェアを追う

IoT セクターを狙うマルウェアファミリーは、研究者とセキュリティ製品の両方による検出を回避しようとするなど、Windows ベースのものと複数の共通点がある。彼らの目的は、できるだけ長い間レーダーの下にとどまることだ。ボットネット・コードのリバース・エンジニアリングを阻止する重要なテクニックの1つは、実行可能ファイルを圧縮または暗号化することでコードを難読化することです。

この投稿では、Nozomi Networks ハニーポットによって収集されたデータを使用して、IoT マルウェアによって使用されるパッカーの現状を探ります。また、難読化されたサンプルを分析する際に研究者が直面する様々な障害についても深く掘り下げ、その対処方法を紹介します。

IoT ボットネット攻撃統計

ハニーポットとは、研究、検知、防御の目的で悪意のある活動に関する情報を収集できるよう、敵対者が意図的に利用できるようにした脆弱なシステムのことです。Nozomi Networks ラボでは、攻撃者によく悪用される複数のプロトコルをエミュレートしたパッシブ・ハニーポットのネットワークをさまざまな地域で運用しています。収集されたデータは集約され、研究と検知の取り組みに使用されます。

7 日間にわたり、Nozomi Networks ハニーポットは攻撃から 205 のユニークなサンプルを収集しました。収集されたファイルの大部分は、32ビットアーキテクチャのLinux実行可能ファイルです。

ハニーポットが収集したさまざまなファイルタイプの統計
当社のハニーポットが収集したさまざまなファイルタイプの統計。

攻撃者は、パッカーを使用してコードを難読化し、検出を回避してマルウェア解析をより困難で時間のかかるものにする目的で、元のコードを隠蔽します。私たちが収集したサンプルのうち、約3分の1は、合法的な企業と悪意のある行為者の両方によって広く使用されている無料のオープンソースパッカーであるUPXの複数のバージョンを使用してパックされていました。UPXは、今回のサンプル群で使用された唯一のパッカーです。

ハニーポットで採取されたUPXパックサンプルと非パックサンプルの割合
ハニーポットで採取されたUPXパックサンプルと非パックサンプルの割合。

分析時点では、205個のサンプルのうち49個が、マルウェアの詳細と調査のための共有サイトであるVirusTotalに存在していなかったため、これらの潜在的に新しい脅威に焦点を当てることにしました。このファイルのサブセットは、採用されたパッカーとバージョンに関して同様の割合分布に従っています。新しいファイルの大部分(ほぼ80%)はまったくパックされておらず、残りはUPXでパックされていました。

初期調査によると、これらのサンプルの1つは、他の内部調査(Threat Intelligence )でも確認されたマルウェア・ファミリーに属しているようです。また、UPXのパッキング構造が特別に変更されているため、際立っています。

VirusTotalに存在しない新しいサンプルのうち、80%はパックされておらず、残りはUPXでパックされていた。
VirusTotalに存在しない新しいサンプルのうち、80%はパックされておらず、残りはUPXでパックされていた。

課題を解く

サンプルがUPXでのみパックされている場合、標準のUPXツールで -dコマンドライン引数を使用して解凍することは非常に簡単です。そのため、攻撃者はパックされたサンプルのUPX構造を変更し、実行可能なまま、標準UPXツールで認識・解凍できないようにするのが一般的です。

UPXはオープンソースのツールなので、GitHubでソースコードをチェックし、その構造や使用するフィールドを理解することができる。(ファイル構造の詳細はこちらで見ることができる)。

UPXファイルの構成例。
UPXファイルの構成例。

UPX がパックされたIoT サンプルのほとんどは、ヘッダ内の l_info 構造体と p_info 構造体を変更します。例えば、以前SBIDIOTマルウェアで見たように、マルウェア作者はUPXでパックされたサンプルのl_info構造体のl_magic値を変更するのが一般的です。この場合、サンプルのアンパックは、変更されたl_magic値をUPX!

Mozi IoT マルウェア・ファミリーのように、p_info 構造体が修正されて p_filesize と p_blocksize がゼロに設定されるケースもあります。解決策としては、バイナリのトレイラーで利用可能なfilesize値に置き換えることで、ゼロになった2つの値を修復します。

しかし、目的のサンプルを解凍しようとすると、UPXは異常なエラーを返した:

マルウェアのサンプルは、UPXで解凍できるかどうかのテスト中に失敗しました。
マルウェアサンプルがUPXで解凍できるかどうかのテスト中に失敗。

この場合、UPXはb_info構造体に問題があったことを伝えています。b_infoは各圧縮ブロックの前に置かれる構造体で、圧縮サイズと非圧縮サイズ、圧縮に使用されたアルゴリズムとパラメータに関する情報が含まれています。ファイル内のb_info構造体を確認したところ、明らかな方法でゼロにされたり変更されたりしていないことがわかりました。

UPXの内部を深く掘り下げると、この例外を発生させるコードの正確な場所がわかった。圧縮サイズ(sz_cpr)が非圧縮サイズ(sz_unc)より大きい場合、UPXは失敗する。しかし、両者の値は一致していたので、問題の原因としてこの修正を破棄した。これらのコード行を見ると、最も有力な原因は、宣言された非圧縮セクションのサイズの合計と、宣言された非圧縮ファイルのサイズの違いに問題がある可能性があることがわかる。私たちのサンプルでは、sz_uncの値の合計がp_filesizeの値よりも大きかったので、適切なp_info構造体を修正し、そのp_filesizeフィールドにこの例外をトリガーしない値を設定しました。

これらの値を変更すると、ヘッダー・チェックサム例外が発生した。このチェックサム値を計算することは、ソースコードがあったので可能であったが、時間がかかるので、一時的に別の研究経路に移った。私たちは、悪意のあるサンプルとできるだけ類似したパック・サンプルを作成し、違いを発見しやすくすることにした。

upx -fileinfoの助けを借りて、ほぼ同じ圧縮・解凍アルゴリズムで別の実行ファイルをパックするのに必要なパラメーターを得た。

マルウェアサンプルからの圧縮情報の抽出
マルウェアサンプルから圧縮情報を抽出する。

To compress the sample, the attackers used a command similar to upx --best --nrv2d <elf_file>. As a starting point to check differences, we used the rz-diff tool to compare the main decompression functions:

似たようなパッキングとアンパッキング関数を持つ実行可能ファイルの作成と比較
同じようなパッキングとアンパッキング関数を持つ実行ファイルを作成する。

私たちは関数の違いを比較し、攻撃者が解凍プロセスに追加したと思われるコードを探し始めた。予想外の違いが現れた:

UPX 4.0.0を使用してパックされたマルウェアのサンプル
UPX 4.0.0を使用してパックされたマルウェアのサンプル。

現在、UPXの安定バージョンはv3.96で、バージョン4.0.0が開発中である。Changelogには、ELF圧縮の動作に大きな変更はないようだが、これらの値の計算に関わるコードの一部に影響を与えるコミットが多数ある。

次に、UPX のプレリリース・バージョンをダウンロードしてコンパイルすることで、この新バージ ョンがどのように問題を処理しているかをチェックした。UPX!文字列ヘッダーのみを修正し(b_infoとp_info構造体はそのまま)、この実行ファイルをUPXバージョン4.0.0に渡したところ、サンプルは正確に解凍された。

UPX 4.0.0での抽出に成功(コミット a46b63)
UPX 4.0.0での抽出に成功しました(コミットa46b63)。

攻撃者は、このUPXのバージョン(まだ開発中)が、誰もがデフォルトで使用するUPXの標準的な製品バージョンでは抽出できない機能サンプルを生成することに気づいた可能性がある。

ユニバーサル・マニュアル 開梱

攻撃者によって導入された改変を深く掘り下げる代わりに、私たちが考慮できる別のアプローチがある。ここでは、コードとデータはすでにアンパックされているが、アンパックされたコードがまだ実行されていないときにデバッグプロセスを停止し、その後に起こりうるデータやコードの改変を防ぎ、アンパックされたコードとデータをディスクに書き戻すというものだ。このアプローチはWindowsサンプルのアンパックに広く使われているが、IoT の脅威についてはどうだろうか?高レベルの観点からは、確かに同じロジックを適用することができる。

ここでは、どのような修正が加えられるかに関係なく、パッカーを回避することを可能にするいくつかの普遍的なテクニックを紹介する。それらは一般的に、主にアンパッカーがその目的を達成するために行わなければならないステップに依存する:

  1. パックされたコードとデータは読み込まれ、アンパックされなければならない。
  2. アンパックされたサンプルをホストするために、大きなメモリ・ブロックが利用可能でなければならない。
  3. アンパックの結果は、この大きなメモリー・ブロックに書き込まれなければならない。
  4. このブロックの既存の保護フラグによっては、コード実行を可能にするために調整が必要な場合がある。
  5. 最後に、オリジナル・エントリ・ポイント(OEP)として知られるアンパックされたコードの最初の命令に制御を移さなければならない。

では、これらのテクニックはどのようにサンプルの解明に役立つのだろうか?

  1. 一般に、パックされたコードとデータはエントロピーが高いため、16進エディターで簡単に識別することができる。これらのブロックを見つけ、それらの相互参照を追跡することは、復号/伸長/復号ルーチンを見つけるのに役立ちます。
パックデータ

2.メモリ割り当ての追跡(mmap syscall)は、アンパックされたコードとデータの将来の仮想アドレスを見つけるのに役立つかもしれない。

大きなメモリブロックでのmmap syscall (rax = 0x09)
mmap syscall (rax = 0x09) で大きなメモリブロック長が要求された。

3.割り当てられたブロックに設定された書き込み操作のメモリー・ブレークポイントまたはハードウェア・ブレークポイントは、アンパックされたコードと目的のデータがそこに書き込まれる瞬間を阻止するのに役立つ。

IDAで書き込み操作時にハードウェアブレークポイントを設定する
IDAで書き込み操作時にハードウェアブレークポイントを設定する。

4.保護フラグの変更によく使われるmprotectシステムコールを監視していれば、この現象が起こる瞬間を特定するのに役立つ。

mprotect syscall に続く異常な制御フロー命令
mprotect syscallに続く異常な制御フロー命令。

5.異常な制御フロー命令を探すことは、アンパッカーがその仕事を終えて、アンパックされたばかりのコードの最初の命令(OEP)に制御を移す準備ができた瞬間を特定するのに役立つ。

OEPにつながる最後の異常な制御フロー命令。
OEPにつながる最後の異常な制御フロー命令。

これらのアプローチを別々に、あるいは組み合わせて行うことで、最終的に、アンパックされたコードとデータがメモリ上に存在し、その後の静的解析のためにディスクにダンプできるようになる瞬間を阻止することができる。

これらのテクニックに加え、OEPに制御を移した後にmunmap syscallを呼び出すことも、研究者がこのようなサンプルを素早く解凍できるUPXの特徴である。研究者は単純にこれをインターセプトし、実行フローを追うことができる。

munmapシステムコール(rax = 0x0B)は、OEPへの制御転送の次に実行される。
munmapシステムコール(rax = 0x0B)は、OEPに制御を移すために次に実行される。

結論

IoT セクターを標的とするマルウェアの状況は進化を続け、より有名な IT セクターから多くの特徴を借用している。この分野の最新動向を常に把握し、それらに対処できるようにしておくことは、セキュリティ・コミュニティが新たな脅威とより効率的に闘い、関連するサイバー攻撃の潜在的な影響を軽減するのに役立つ。

このブログのパート2でさらに詳しい調査を読むことができる。