Radare2 を使用してシェルコード操作をシミュレートする

アセンブリを作成しているとき、コンパイラで何が起こっているかを確認する必要がある場合があります。シェルコードの問題のトラブルシューティングを行う場合は、コマンドを辛抱強く慎重に実行する必要があります。

この記事では、x86_64 Ubuntu システム上で 32 ビット ARM シェルコードをエミュレートする方法について説明します。ほとんどのラップトップやワークステーションはまだ ARM を実行していないため、ここで必要なのは、システム上で非ネイティブ命令を実行するための代替方法です。また、生のシェルコード バイナリは実行可能形式ではなく、ほとんどのツールでは実行できないため、これらのファイルを実行するには別の方法が必要です。

ここでは、使いやすいバイナリ分析ツールのセットを統合するコンソール駆動のフレームワークである Radare2 を使用します。これらのツールをスクリプト化することも、対話型のコマンドライン インターフェイスを使用することもできます。これを Ubuntu で設定するには、いくつかの簡単なコマンドが必要です。

mkdir ~/github
cd ~/github
git clone https://github.com/radareorg/radare2.git
cd radare2
sys/install.sh

Radare2 がインストールされている場合は、最新バージョンを実行していることを確認してください。このツールは積極的にメンテナンスされ、定期的に更新されます。また、2022 年 6 月のリリース前にいくつかのバグがあったため、このトライアルをこれ以上改善することはできなかった可能性があります。

cd ~/github/radare2
git pull
sys/install.sh
r2 -V

この記事で使用するシェルコード バイナリを複製するには、bash プロンプトで次のコマンドを実行します。

nemo@hammerhead:~$ echo -n -e '\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0c\x30\xc0\x46\x01\x90\x49\x1a\x92\x1a\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x00' > shellcode-696.bin

nemo@hammerhead:~$ md5sum shellcode-696.bin 
42ba1c77446594cac3508b940926575d  shellcode-696.bin

ESIL の概要

Evaluable String Intermediate Language (ESIL) は、radare2 によって使用されるハードウェアから抽象化された命令であり、基盤となるハードウェアを考慮せずに機械語命令を「実行」できます。これは、エミュレーション環境で非ネイティブのアセンブリ命令を実行する場合に最適です。

ESIL を使用してシェルコードを実行するには、次のことを行う必要があります。

  1. シェルコードバイナリをロードします
  2. シェルコードバイナリを正しく解釈する方法を認識できるように、radare2 を設定します。
  3. ESILの初期化
  4. 必要に応じてレジスタを設定する
  5. 組み立て説明書で機能を確認してください

サイバーセキュリティの学習に役立つように、次の完全な情報セットを無料で受け取ることができます。
① サイバーセキュリティの学習と成長パスのマインド マップ
② 60 以上の古典的なサイバーセキュリティ ツールキット
③ 100 以上の SRC 分析レポート
④ サイバーセキュリティの攻撃と防御技術に関する 150 以上の電子書籍
⑤ 最も権威のある CISSP 認定試験ガイド + クエスチョンバンク
⑥ 1800 ページを超える CTF 実践スキルマニュアル
⑦ ネットワークセキュリティ企業の最新面接質問集(解答含む)
⑧ APP クライアントセキュリティテストガイド(Android+IOS)

ESIL を使用した ARM シェルコードの実行

  1. シェルコードバイナリをロードします

シェルコード バイナリに対して「file」コマンドを実行すると、Linux がそのファイル形式を判断できないことがわかります。同様に、radare2 はそれが何であるかを判断できません。

nemo@hammerhead:~/labs/shellcode/asm$ file shellcode-696.bin
shellcode-696.bin: data

これは単なるバイナリ ファイルなので、radare2 にロードして、表示したいものを指定する必要があります。ここでは、ARM ファイルを正しく分析できるように、ソフトウェアの分析設定の一部を変更します。

nemo@hammerhead:~/labs/shellcode/asm$ r2 shellcode-696.bin
[0x00000000]> e anal.arch = arm
[0x00000000]> e asm.arch = arm
[0x00000000]> e asm.bits = 32
[0x00000000]> e anal.armthumb=true
  1. シェルコードバイナリを適切に実行する方法を認識できるように、radare2 を設定します。

次に、どの命令が ARM でどの命令が THUMB であるかを指定します。これを行うには、命令の種類が変わる関数を定義する必要があることがわかりました。この特定のシェルコードでは、ARM 命令と THUMB 命令の間で切り替えが行われます。

[0x00000000]> af
[0x00000000]> pdf
┌ 8: fcn.00000000 ();
│ rg: 0 (vars 0, args 0)
│ bp: 0 (vars 0, args 0)
│ sp: 0 (vars 0, args 0)
│           0x00000000      01308fe2       add r3, pc, 1
└           0x00000004      13ff2fe1       bx r3

このradare2コマンドのスニペットでは、アドレス0の関数を分析しています。ここには実際には関数は存在しませんが、「関数」を ARM または THUMB として指定できるようにしています。「pdf」コマンドは、add 命令と bx 命令を含む関数の逆アセンブリ命令を出力するだけです。

<p>[0x00000000]> s 8
[0x00000008]> af
[0x00000008]> pdf
┌ 24: fcn.00000008 (int32_t arg1, int32_t arg2);
│           ; arg int32_t arg1 @ r0
│           ; arg int32_t arg2 @ r1
│           0x00000008      78460c30       andlo r4, ip, r8, ror r6
│           0x0000000c      c0460190       andls r4, r1, r0, asr 13    ; arg2
│       ┌─< 0x00000010      491a921a       bne 0xfe48693c
│       │   0x00000014      0b2701df       svcle 0x1270b
│       │   0x00000018      2f62696e       cdpvs p2, 6, c6, c9, c15, 1
└       │   0x0000001c      2f736800       rsbeq r7, r8, pc, lsr 6
[0x00000008]> afB 16</p>

アドレス 8 で始まる次の命令セットは THUMB 命令です。「s 8」命令はファイル内で8バイトを検索し、行きたい場所にジャンプし、次の「関数」を定義します。「af」で関数を作成した後、それを「pdf」で表示しようとすると、少しおかしくなります。これは、ツールが依然としてこれらの命令を ARM として解釈するためです。

ビット数を 16 に設定することで、この「関数」が THUMB であることを指定できます。つまり、この関数に対してのみ asm.bits を 16 に設定します。通常の ARM バイナリでは、radare2 はこの区別を自動的に行おうとしますが、シェルコード命令の文字列しかないため、それでも手動で行う必要があります。


最初の 2 つの命令を削除して、完全な THUMB シェルコードを使用できることに注意してください。こうすると、関数を再定義することなく、ファイルを開くときに「e asm.bits=16」を設定できます。必要に応じて 2 つの命令タイプを区別できるというだけです。

Radare2 には、「izz」コマンドを使用してバイナリ ファイル内のすべての文字列を表示する、より便利な方法もあります。

> izz
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x00000008 0x00000008 4   5            ascii xF\f0
1   0x00000018 0x00000018 7   8            ascii /bin/sh</p>

これで、シェルコード バイナリを適切にロードできるようになりました。

  1. ESILの初期化

前述したように、radare2 には多くの組み込みコマンドがあり、コマンドの接頭辞に「?」を追加すると、関連するすべてのコマンドを一覧表示できます。「ae?」コマンドは、ESIL とエミュレーションに関連するコマンドをリストします。

[0x00000000]> ae?
Usage: ae[idesr?] [arg]  ESIL code emulation
| ae [expr]                evaluate ESIL expression
| ae?                      show this help
| ae??                     show ESIL help
| aea[f] [count]           analyse n esil instructions accesses (regs, mem..)
| aeA[f] [count]           analyse n bytes for their esil accesses (regs, mem..)
| aeb ([addr])             emulate block in current or given address
| aeC[arg0 arg1..] @ addr  appcall in esil
| aec[?]                   continue until ^C
| aef [addr]               emulate function
| aefa [addr]              emulate function to find out args in given or current offset
| aeg [expr]               esil data flow graph
| aegf [expr] [register]   esil data flow graph filter
| aei[?]                   initialize ESIL VM state (aei- to deinitialize)
| aek[?] [query]           perform sdb query on ESIL.info
| aeL                      list ESIL plugins
| aep[?] [addr]            manage esil pin hooks (see “e cmd.esil.pin”)
| aepc [addr]              change esil PC to this address
| aer[?] [..]              handle ESIL registers like “ar” or “dr” does
| aes[?]                   perform emulated debugger step
| aets[?]                  esil Trace session
| aev [esil]        visual esil debugger for the given expression or current instruction
| aex [hex]                evaluate opcode expression

ここでは、まず「aei」コマンドで ESIL を初期化する必要があります。その後、スタックを初期化する必要があります。Radare2 はスタックの場所を自動的に選択しますが、これは「aeim」コマンド パラメータを使用して指定することもできます。

[0x00000008]> aei
[0x00000008]> aeim
  1. 必要に応じてレジスタを設定する

シェルコード命令はゼロベースであるため、「aepc 0」コマンドを使用してプログラム カウンター (PC) をゼロに設定する必要があります。オフセット 0 以外の場所で実行を開始したい場合は、「aepc」を使用できます。

"を使用して開始アドレスを設定します。

[0x00000008]> aepc 0

シェルコードの命令 (「subs r1, r1, r1」) は r1 を 0 に設定します。このレジスターはデフォルトですでに 0 なので、ステッピング中にいつ変更が発生するかを確認できるように 0xffff に設定しましょう。これを行うには、「aer」コマンドを使用する必要があります。

[0x00000008]> aer r1 = 0xffff
  1. セットアップで機能を確認します

さて、準備は完了です。ビジュアル モードに切り替えて、デバッガー パネルに入ることができます。ビジュアル モードでは複数のオプション (パネル) があるため、正しいパネルに移動するには「p」を 2 回押す必要があります。視覚化モードを終了したい場合は、エスケープ キーを押すだけです。「?」を押して、使用可能なコマンドのリストを表示することもできます。

[0x00000008]> V
(hit “p” twice to get to the debugger panel)

次に、上部近くに一連のレジスタがあることに気づくでしょう。次のようになります。

通常コンソールで入力される r2 コマンドは、ビジュアル モードでも入力できます。たとえば、オフセット 0x18 の文字列を出力したい場合は、次のコマンドを実行する必要があります。

# Hit “:” while in visual mode.

> ps @0x18
/bin/sh
> # Hit enter on a blank line to return to visual mode.

これで、「s」キーを使用してアセンブリ命令を実行できるようになりました。参照すると、スタック データ (最初の図の 0x00178000 から始まる) とともに上部のレジスタが更新されていることがわかります。また、次に実行する命令 (別名 PC) のアドレスがアセンブリ命令内で強調表示されていることにも気づくでしょう (最初の図の 0x00000010)。

上の図は、r1 レジスタが 0x0000ffff を保持していることを示していることに注意してください。また、次の命令、つまり「subs r1, r1, r1」が実行されることにも注目してください。この命令は、それ自体から r1 を減算し、それを r1 に戻して格納し、実質的に 0 にします。

もう一度「s」キーを押すと、次のコマンドに進みます。

これで、「svc 1」コマンドを使用してデーモンを介してすべてを呼び出す準備が整いました。ここでは「execve」呼び出しを行っているので、r7 レジスタに 0xb を設定する必要があります。r0 の最初のパラメータは、実行するバイナリのパスへのポインタでなければなりません。r0 が 0x18 を保持していることがわかります。以下を実行することで、それが指していることを確認できます。

# Hit “:” while at the “svc 1” instruction in visual mode.

> ps @r0
/bin/sh
>

ここでは、「/bin/sh」にパラメータを渡さず、環境変数も設定していないため、r1 と r2 の両方が 0 に設定されていることがわかります。

ARM システム上で実行していないため、デーモン呼び出し (「svc 1」) 命令を正しく使用できません。より複雑なシェルコードをテストする場合は、このことに留意してください。

要約する

カスタム シェルコードのトラブルシューティングを行う場合でも、表示されている静的コンテンツを確認する場合でも、命令が実際に何を行っているかを確認する必要がある場合があります。Radare2 を使用すると、未知のファイル形式 (シェルコード バイナリやファームウェア イメージなど) から非ネイティブ アセンブリ ファイルをロードし、手順をステップごとに実行できます。

おすすめ

転載: blog.csdn.net/qq_38154820/article/details/130529200