シェルコードを学べるお弁当教室【前編】

シェルコードを学べるお弁当教室【前編】

リクルートテクノロジーズでセキュリティアナリストをしている市田です。
先日、部内の下半期キックオフミーティングで「シェルコードを学べるお弁当教室 ~ icchii bento cooking studio ~」という発表をしました。好評だった!?ためTech Blogにも2回に分けて書きたいと思います!
この発表は、難しい技術を違う発想で刷り込むことで、「簡単に誤解なく理解してもらう」ことが目的でした。

「シェルコード」

まずは用語説明です!
コンピューターの世界で「シェル」とは一般的にオペレーティングシステム(以下OS)のユーザーのためにインターフェースを提供するソフトウェアです。主にカーネルへのアクセスを提供します。一方「シェルコード」とは、コンピュータセキュリティにおいてソフトウェアのセキュリティホールを利用するプログラムコードの断片を意味します。

侵入したマシンを攻撃者が制御できるようになった後にシェルを起動することが多いことが語源のようです。
と、文章で説明してもピンとこないかもしれないので、たとえば、Linux 32ビット環境でexitを実行するシェルコードは「\x31\xc0\xb0\x01\x31\xdb\xcd\x80」と書くことができます。16進数の0xで始まるHEX表記の「0」を「\」に置換してシェルコードは表現されます。

これを細かく分類し逆アセンブルすると、

「\x31\xc0」=> xor eax eax ; EAXレジスタを0クリア
「\xb0\x01」=> mov al 1 ; EAXレジスタの下位8bit (AL)に1を設定
「\x31,\xdb」=> xor ebx ebx ;EBXレジスタを0クリア
「\xcd\x80」=> int 0x80 ; OSシステムコール呼び出し

ポイントは、EAXレジスタに1が設定されていることで、システムコールのマッピングに基づきexit関数が呼び出される、ということです。
(レジスタ/システムコールなどのコンピューター用語の説明はここでは割愛します。)

これはもっとも簡単なシェルコードなのですが、見たこともない文字を扱ったりすると理解が進みませんよね。
そこで、これってお弁当作りと似ているのでは!とふと思いつきました。

お弁当 ≒ シェルコード!?

シェルコードの構築/実行をするときは、

「CPUが メモリ(またはレジスタ)から 自身のレジスタへデータを読み出して、演算する」

一方、お弁当の盛り付けるときも

「ヒトが 料理の皿(または冷凍庫)から 自身のお弁当箱へ盛り付けて、ふたをする」

なんかフレーズが似ていませんか。
もう一段深堀りすると、そっくりですね!!というのが本ブログ記事のミソです。

%e3%81%8a%e5%bc%81%e5%bd%93%e7%ae%b1%ef%bc%9d%e3%82%b7%e3%82%a7%e3%83%ab%e3%82%b3%e3%83%bc%e3%83%89%ef%bc%91

Linuxなお客様用の弁当 その1:標準出力弁当

文字の標準出力をLinuxで実施できるシェルコード(お弁当)を作ります。攻撃コードはコンプライアンス上、公開しませんが、概要と流れをつかんでいただけると幸いです。

標準出力のシステムコール関数番号は4なので、4をEAXに入れてシステムコールですね。
標準出力弁当のレシピを書いてみました。

%e3%81%8a%e5%bc%81%e5%bd%93%e7%ae%b1%ef%bc%9d%e3%82%b7%e3%82%a7%e3%83%ab%e3%82%b3%e3%83%bc%e3%83%89%ef%bc%92

この手順に沿って、アセンブラファイルを作成し、nasm(http://www.nasm.us/index.php)などのツールで実行できるバイナリファイルに変換します。シェルコードをテキスト表示するには、xxdコマンドなどでバイナリファイルを16進数ダンプし、1バイトごとに\xを接頭語として追加すれば完成です。

最後に、上記レシピには注意点があります。

上で紹介したexit関数を呼び出していないため、自分で終了しないプロセスが生成されます。つまり、「フタ」がない弁当ということですね!! お弁当を持ち運ぶには、手順3の後にexit関数の呼び出しも加えてあげましょう。

いかがでしょうか?シェルコードの理解がお弁当という比喩を用いてわかりやすく表現できているでしょうか。

本日は以上です。次回は実際にシェルを取得するシェル奪取弁当を作成します。