2017-04-09 2 views
1

Je suis actuellement en train d'apprendre le langage d'assemblage 64 bits à partir du cours Pentester Academy associé. Le code je travaille crée l'erreur suivante lorsqu'il est lancé dans GDB:GDB - Programme d'assemblage renvoie/bin/sh: 0: Impossible d'ouvrir

/bin/sh: 0: Impossible d'ouvrir [1 Inferior (processus 4049) liquide' avec le code 0177]

J'ai googlé l'erreur et le code de sortie et n'ai rien trouvé d'utile. J'ai essayé d'analyser le code dans GDB encore et encore, mais toutes les bonnes valeurs semblent être dans les bons registres. Je n'arrive pas à trouver ce qui ne va pas.

Vous pouvez trouver le code ci-dessous. Mon but est simplement d'invoquer le syscall execve en utilisant la technique jump-call-pop.

global _start 
section .text 

_start: 

jmp bash 

code: 

xor rax, rax 
pop rdi 
mov [rdi +7], al  

push rdi 
mov rsi, rsp 
push rax 
mov rdx, rsp 
mov al, 59 
syscall 

bash: 

call code 
string:  db  '/bin/shABBBBBBBBCCCCCCCC' 

EDIT:

Voici comment je construit le programme:

nasm -f elf64 -o execve_stack_jcp.o execve_stack_jcp.asm 
ld -o execve_stack_jcp execve_stack_jcp.o 

J'utilise ensuite objdump -M intel -d execve_stack_jcp pour sortir le démontage que je puis entrée dans ce programme c:

#include <stdio.h> 
#include <string.h> 

unsigned char code[] = \ 
"\xeb\x13\x48\x31\xc0\x5f\x88\x47\x07\x57\x48\x89\xe6\x50\x48\x89\xe2\xb0\x3b\x0f\x05\xe8\xe8\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x41\x42\x42\x42\x42\x42\x42\x42\x42\x43\x43\x43\x43\x43\x43\x43\x43"; 

int main(void) { 

printf("Shellcode length: %d\n", (int)strlen(code)); 

int (*ret)() = (int(*)())code; 

ret(); 

return 0; 
} 

Enfin, je compile le programme c en utilisant:

gcc -fno-stack-protector -z execstack -o shellcode shellcode.c 
+2

Comment avez-vous construit ce code? –

+0

Bien sûr, la méthode JMP/CALL/POP n'est pas requise dans le code 64 bits si vous utilisez l'adressage RiP (relatif). –

+0

Serait utile si vous avez montré comment vous construisez et exécutez votre programme. Mais une observation est que avec 'execve'' argv' et 'argp' ont besoin d'être des listes terminées NULL de chaînes, mais vous ne pouvez terminer que null en argp (en appuyant d'abord sur' rax'). Vous devez NULL terminer 'argv' aussi. Donc ** avant ** 'push rdi' vous devriez aussi faire' push rax' –

Répondre

2

execve sous Linux est défini ainsi:

int execve (const char * nom de fichier, const char * argv [], char * const envp []);

[snip]

argv est un tableau de chaînes d'arguments transmis au nouveau programme. Par convention, la première de ces chaînes (c'est-à-dire argv [0]) doit contenir le nom de fichier associé au fichier en cours d'exécution. envp est un tableau de chaînes, classiquement de la forme clé = valeur, qui sont passées en environnement au nouveau programme. Les argv et matrices de envp doivent comporter chacun un pointeur null à la fin du tableau .

Si vous deviez exécuter votre programme par strace ./shellcode vous auriez probablement voir quelque chose de semblable à ceci:

exec ("/ bin/sh", [ "/ bin/sh", "\ 270", "\ 1", "\ 353 \ 23H1 \ 300_ \ 210G \ 7WH \ 211 \ 346PH \ 211 \ 342 \ 260; \ 17 \ 5 \ 350 \ 350 \ 377 \ 377 \ 377/bin/s » ...], [/ * 0 * vars /]) = 0

Vous remarquerez que le deuxième argument argv a un tas d'entrées supplémentaires dans le tableau. C'est parce que vous n'avez pas NULL terminer le tableau argv.Pour corriger cela, vous pouvez modifier votre code en appuyant sur 0 (via RAX) sur la pile comme ceci:

xor rax, rax 
pop rdi 
mov [rdi +7], al 

push rax  ; NULL terminates the `argv` array 
push rdi 
mov rsi, rsp 
push rax 
mov rdx, rsp 

Si vous deviez exécuter ce changement par strace à nouveau, vous verriez quelque chose comme:

exec ("/ bin/sh", [ "/ bin/sh"], [/ * 0 * vars /]) = 0

Cela devrait finir par être un appel execve réussi.