シェルコード

シェルコードとは



シェルコードとは、コンピュータセキュリティの分野において、ソフトウェアの脆弱性を悪用するためのペイロードとして利用されるコードの断片です。攻撃者が侵入したマシンを制御するために、シェルを起動することが多いため「シェルコード」と呼ばれています。シェルコードは、通常、機械語で記述されますが、機械語でなくても同様のタスクを実行できるコードであれば、シェルコードと見なされます。シェルコードの主な役割は、攻撃者がシステムを制御するための足がかりとなることです。シェルを起動する以外にも、様々な目的で使用されるため、シェルコードという名称は必ずしも適切ではないという意見もありますが、他の適切な用語が定着していません。

シェルコードの種類



シェルコードには、主に「ローカル型」と「リモート型」の2種類が存在します。これらは、攻撃者がどの範囲のシステムを制御しようとするかによって区別されます。

ローカル型シェルコード



ローカル型シェルコードは、攻撃者が既にマシンへの限定的なアクセス権を持っている場合に利用されます。このタイプのシェルコードは、より高い特権を持つプロセスの脆弱性を悪用し、成功すると、攻撃者はそのプロセスと同等の特権を得ることができます。ローカル型シェルコードは、比較的作成が容易で、主な目的はシェルの実行ファイルを起動することです。

リモート型シェルコード



リモート型シェルコードは、LANやインターネットを介して、ネットワーク上の別のマシンで動作する脆弱性のあるプロセスを攻撃するために使用されます。成功すると、攻撃者はネットワーク経由で対象マシンにアクセスできるようになります。リモート型シェルコードは、通常、TCP/IPソケット接続を確立し、攻撃者が対象マシン上のシェルにアクセスできるようにします。この接続を確立する方法として、以下の3つのタイプがあります。

  • - connect-back: シェルコード自体が攻撃者のマシンに接続を試みる方式です。シェルコードが攻撃者のマシンに接続し返すため、このように呼ばれます。
  • - bindshell: シェルコードが特定のポートにバインドし、攻撃者が接続を待機する方式です。攻撃者は、このバインドされたポートに接続することで、対象マシンを制御できます。
  • - socket-reuse: 既存の接続を再利用する方式です。シェルコードは、実行される前にクローズされていない接続を検出し、それを利用して攻撃者と通信します。この方式は、実装が難しいため、あまり一般的ではありません。

ファイアウォールは、connect-back方式で生成される外部への接続や、bindshell方式で生成される外部からの接続を検出できます。そのため、ファイアウォールは、脆弱性があるマシンに対する一定の保護を提供します。しかし、socket-reuse方式は新しい接続を作成しないため、検出がより困難です。

ダウンロード実行型シェルコード



リモート型シェルコードの一種として、ダウンロード実行型シェルコードがあります。このタイプのシェルコードは、シェルを起動する代わりに、ネットワーク経由で特定の実行ファイルをダウンロードし、それを実行します。これは、マルウェアをインストールする際によく使用され、ドライブバイダウンロード攻撃として知られています。

シェルコードの実行戦略



シェルコードを対象プロセスに注入する際には、プログラムカウンタの制御を奪う脆弱性も同時に利用されます。プログラムカウンタは、シェルコードの開始アドレスを指すように変更され、これによりシェルコードが実行されます。シェルコードの注入は、ネットワーク経由でのデータ送信や、ローカルファイルへの仕込み、コマンドライン引数や環境変数への埋め込みなど、様々な方法で行われます。

シェルコードの符号化



シェルコードは、注入されるデータの制限に対応するために、符号化されることがよくあります。これらの制限には、コードサイズの最小化、ヌル文字の使用禁止、英数字のみの使用などが含まれます。符号化技術は、これらの制限を回避するために使用され、自己書き換えコードやポリモーフィックコードなどが利用されます。

符号化方法の例



ブラウザを標的とした場合、シェルコードはJavaScriptの文字列として符号化されることがあります。パーセントエンコーディング、\uXXXXエンコーディング、HTMLエンコーディングなどが使用されます。例えば、IA-32アーキテクチャで2つのNOP命令を符号化すると、以下のようになります。

  • - 符号化なし:


90 NOP
90 NOP




unescape("%u9090");


  • - \uXXXXエンコーディング:


"\u9090";


  • - HTMLエンコーディング:


"邐"

または

"邐"


ヌル文字の排除



シェルコードは、通常、ヌル文字で終了する文字列として扱われるため、シェルコード内にヌル文字を含めることはできません。ヌル文字が含まれていると、そこで文字列が途切れてしまいます。ヌル文字を排除するには、同じ効果を持つ別の命令列に置き換える必要があります。例えば、IA-32アーキテクチャでは、ヌル文字を含む命令を、ヌル文字を含まない命令に置き換えることができます。

英数字または印字可能文字のみを使用



特定の状況では、印字可能な文字や英数字のみを使用してシェルコードを記述する必要があります。この制限に対応するためには、自己書き換えコードなどの技術を使用します。デコーダ部分は制限されたコードで記述し、シェルコード本体は符号化しておき、デコーダがそれを展開して実行します。

Unicode



最近のプログラムでは、Unicodeが使用されることが一般的です。ASCII文字列は、しばしばUnicodeに変換されます。UTF-16では、各文字に2バイト(一部は4バイト)が使用されるため、ASCII文字列をUTF-16に変換すると、各バイトの後にゼロバイトが挿入されます。UTF-16で正しく動作するシェルコードを記述するには、自己書き換えコードを使用します。

プラットフォーム依存性



シェルコードは、通常、機械語で記述されるため、プラットフォームに依存します。CPUアーキテクチャ、オペレーティングシステムのバージョン、サービスパックなど、環境に合わせてシェルコードを調整する必要があります。また、脆弱性によっては、使用できるシェルコードの形式が大きく制限される場合があります。汎用的なシェルコードを作成するには、複数のプラットフォームに対応したバージョンを作成し、実行時に適切なものを選択する必要があります。

関連項目




外部リンク



もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。