J'essaie d'apprendre à créer un shellcode, mon objectif est d'appeler execve()
. J'ai écrit le code dans Assembly et cela fonctionne parfaitement, il n'y a pas de méthodes d'adressage nul ou absolu. Le code fonctionne bien, mais quand je copie les opcodes dans un programme c et le teste pour voir s'il fonctionne, il renvoie un défaut de segmentation. Quel est le problème?
ASM:
section .text
global _start
_start:
jmp xxx
xx:
mov al,11
pop ebx
xor ecx,ecx
xor edx,edx
int 0x80
mov al,1
xor bl,bl
int 0x80
section .data
xxx:
call xx
path db "/bin/sh"
CODE C:
char shellcode[]={"\xb0\x0b\x5b\x31\xc9\x31\xd2\xcd\x80\xb0\x01\x30\xdb\xcd\x80"};
int main(){
void (*ptr) (void) = &shellcode;
ptr();
return 0;
}
Je vois plusieurs problèmes avec votre shellcode. Commençons par déboguer votre code. J'ai compilé le code C contenant votre shellcode, l'exécuter avec gdb et étape jusqu'au premier appel système (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 (")UUV\030pUV$\376\371\367$\376\371\367")
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)
[------------------------------------------------------------------------------]
Ici, nous pouvons voir quelques problèmes:
EAX
n'est pas défini sur 0xb. Cela est dû au fait que votre shellcode n'efface pas les valeurs dans le registre et qu'il définit simplement l'octet inférieur avec l'instruction mov al, 0xb
EBX
doit pointer vers le char*
avec le fichier que vous essayez d'exécuter (généralement c'est "/bin/sh"
), au lieu de cela, il pointe vers une position de mémoire aléatoire, dans ce cas dans la fonction main
.ECX
doit pointer vers le tableau de char*
qui indique la commande complète que vous souhaitez exécuter. Dans la plupart des shellcodes que j'ai vus c'est juste ["/bin/sh", 0]
, mais vous souhaiterez peut-être utiliser quelque chose de différent, comme ["/path/to/binary","-argument1",..., 0]
, dans ce cas, vous devez créer ce tableau en mémoire. Dans votre shellcode ECX
est défini sur 0x0
EDX
représente l'environnement pour l'exécution du binaire. Vous pouvez jeter un oeil à la page manuel execve (3) pour comprendre un peu plus comment il est utilisé, mais pour notre objectif ici, il est correct d'avoir une valeur NULL
dedansMaintenant, comment pouvons-nous y remédier? Eh bien, tout d'abord, nous devrons pointer EBX
vers une chaîne "/ bin/sh\0" dans une partie mémoire à laquelle nous pouvons accéder, par exemple. la pile. Et nous devons le faire dans notre shellcode. Nous pouvons le faire avec le gadget suivant:
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/sh\0", so we need to move that pointer to ebx
Ensuite, nous devons pointer ECX
vers un tableau de char*
tel que ["/bin/sh", 0]
. Nous en avons déjà une partie dans EBX
, donc en continuant notre shellcode nous pouvons faire ce qui suit:
xor 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/sh\0"
Enfin, nous devons définir le registre AL
sur 0xb
et faites l'appel système. Notre shellcode final devrait donc ressembler à ceci:
section .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
Nous pouvons le compiler nasm nasm -o shellcode.bin -f elf32 -O0 shellcode.nasm
, extrayez les opcodes et mettez-les dans le code C pour le tester:
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;
}
Compilez-le avec votre compilateur préféré, j'utilise gcc gcc -o shellcode.o -fno-stack-protector -z execstack -m32 shellcode.c
. Et lancez-le:
$ ./shellcode.o
sh-4.4$