VirtualBox Slirp NAT Packet Heap Exploitation

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

TL;DR

  • Το VirtualBox διαθέτει ένα έντονα τροποποιημένο fork του Slirp, όπου οι packet buffers (mbufs) βρίσκονται σε έναν προσαρμοσμένο zone allocator με inline metadata και function-pointer callbacks (pfFini, pfDtor).
  • Ένας guest μπορεί να επανεγγράψει το αξιόπιστο m->m_len με μήκος κεφαλίδας IP που ελέγχεται από τον επιτιθέμενο, το οποίο καταστρέφει όλους τους επακόλουθους ελέγχους ορίων και παρέχει τόσο infoleak όσο και overwrite primitives.
  • Καταχρηστικά χρησιμοποιώντας UDP πακέτα με checksum 0 και υπερμεγέθες ip_len, ο guest μπορεί να εξάγει τα mbuf tails και τα metadata των γειτονικών chunks για να μάθει τις διευθύνσεις του heap και της zone.
  • Η παροχή επιμελώς κατασκευασμένων IP options αναγκάζει το ip_stripoptions() να κάνει memcpy() υπερβολική ποσότητα δεδομένων επιτόπου, επιτρέποντας στον επιτιθέμενο να επαναγράψει την struct item κεφαλίδα της επόμενης mbuf και να δείξει το πεδίο zone σε πλήρως ελεγχόμενα δεδομένα.
  • Η απελευθέρωση της κατεστραμμένης mbuf ενεργοποιεί το zone->pfFini() με επιχειρήματα που παρέχονται από τον επιτιθέμενο· δείχνοντάς το προς memcpy@plt αυτό δίνει ένα αυθαίρετο copy/write primitive που μπορεί να κατευθυνθεί προς GOT entries ή άλλα control δεδομένα μέσα στο non-PIE VirtualBox binary.

Packet allocator anatomy

VirtualBox allocates every ingress Ethernet frame from a per-interface zone named zone_clust. Each 0x800-byte data chunk is preceded by an inline header:

struct item {
uint32_t magic;      // 0xdead0001
void    *zone;       // uma_zone_t pointer with callbacks
uint32_t ref_count;
LIST_ENTRY(item) list; // freelist / used list links
};

Όταν ένα mbuf απελευθερώνεται, η στοίβα κλήσεων m_freem -> ... -> slirp_uma_free() εμπιστεύεται την ενσωματωμένη κεφαλίδα:

  1. uma_zfree_arg() επανυπολογίζει item = (struct item *)mem - 1 και θα έπρεπε να επικυρώνει item->zone, αλλά το Assert() δεν περιλαμβάνεται στις release builds.
  2. slirp_uma_free() φορτώνει zone = item->zone και εκτελεί χωρίς όρους zone->pfFini(zone->pData, data_ptr, zone->size) ακολουθούμενο από zone->pfDtor(...).

Επομένως, οποιοδήποτε write-what-where στην κεφαλίδα του mbuf μεταφράζεται σε έναν ελεγχόμενο indirect call κατά το free().

Infoleak via m->m_len override

Στην αρχή του ip_input() η VirtualBox πρόσθεσε:

if (m->m_len != RT_N2H_U16(ip->ip_len))
m->m_len = RT_N2H_U16(ip->ip_len);

Because the assignment happens before verifying the IP header, a guest can advertise any length up to 0xffff. The rest of the stack (ICMP, UDP, fragmentation handlers, etc.) assumes m->m_len is trustworthy and uses it to decide how many bytes to copy off the mbuf.

Use UDP packets with checksum 0 (meaning “no checksum”). The NAT fast-path forwards m->m_len bytes without inspecting payload integrity, so inflating ip_len causes Slirp to read past the real buffer and return heap residues to the guest or to a cooperating external helper beyond the NAT. Because the chunk size is 2048 bytes, the leak can include:

  • The next mbuf’s inline struct item, revealing the freelist order and the real zone pointer.
  • Heap cookies such as magic fields, helping to craft valid-looking headers when performing corruptions later.

Επανεγγραφή των επικεφαλίδων γειτονικών chunks με IP options

Το ίδιο ψευδές μήκος μπορεί να μετατραπεί σε primitive εγγραφής αναγκάζοντας το πακέτο να περάσει από ip_stripoptions() (προκαλείται όταν το IP header έχει options και το payload είναι UDP/TCP). Ο helper υπολογίζει ένα μήκος αντιγραφής από το m->m_len και μετά καλεί memcpy() για να μετακινήσει το transport header πάνω από τα stripped options:

  1. Προμηθεύστε ένα μεγάλο ip_len ώστε το υπολογιζόμενο μήκος μετακίνησης να επεκταθεί πέρα από το τρέχον mbuf.
  2. Συμπεριλάβετε έναν μικρό αριθμό IP options ώστε το Slirp να μπει στη διαδρομή stripping.
  3. Όταν τρέξει το memcpy(), θα διαβάσει από το επόμενο mbuf και θα γράψει πάνω στο payload και το inline header του τρέχοντος mbuf, διαφθείροντας magic, zone, ref_count, κ.λπ.

Επειδή ο allocator κρατά τα πακέτα από την ίδια interface συνεχή στη freelist, αυτό το overflow πλήττει με ντετερμινιστικό τρόπο το επόμενο chunk μετά από μέτριο heap grooming.

Forge uma_zone_t για hijack του pfFini

Μόλις το διπλανό struct item είναι επιρρεπές σε φθορά, το exploit προχωρά ως εξής:

  1. Χρησιμοποιήστε leaked heap διευθύνσεις για να χτίσετε μια ψεύτικη δομή uma_zone μέσα σε ένα mbuf πλήρως ελεγχόμενο από τον guest. Συμπληρώστε:
    • pfFini με την PLT είσοδο του memcpy().
    • pData με τον επιθυμητό δείκτη προορισμού (π.χ. GOT entry, vtable slot, function pointer array).
    • size με τον αριθμό των byte προς αντιγραφή.
    • Προαιρετικά: pfDtor ως δεύτερο στάδιο κλήσης (π.χ. για να καλεί το νεογραμμένο function pointer).
  2. Επανεγγράψτε το πεδίο zone του στοχευόμενου mbuf με τον pointer προς την ψεύτικη δομή· ρυθμίστε τους δείκτες list ώστε η bookkeeping της freelist να παραμένει αρκετά συνεπής για να αποφευχθούν crashes.
  3. Free το mbuf. Το slirp_uma_free() τώρα εκτελεί memcpy(dest=pData, src=item_data, n=size) ενώ το mbuf εξακολουθεί να περιέχει δεδομένα ελεγχόμενα από τον guest, δίνοντας ένα arbitrary write.

Επειδή το Linux VirtualBox binary είναι non-PIE, οι PLT διευθύνσεις για memcpy και system είναι σταθερές και μπορούν να χρησιμοποιηθούν απευθείας. Ο guest μπορεί επίσης να τοποθετήσει strings όπως /bin/sh μέσα σε άλλο mbuf που παραμένει referenced όταν εκτελείται η hijacked κλήση.

Grooming του heap μέσω fragmentation

Η per-interface zone του Slirp έχει βάθος 3072 chunks και αρχικά carve-άρεται ως ένα συνεκτικό array του οποίου η freelist διασχίζεται από διευθύνσεις με υψηλότερη προς χαμηλότερη. Μπορεί να επιτευχθεί ντετερμινιστική γειτνίαση μέσω:

  • Flooding του NAT με πολλά IP_MF fragments σταθερού μεγέθους ώστε ο κώδικας reassembly να κάνει predictable allocations σε ακολουθίες mbuf.
  • Recycling συγκεκριμένων chunks στέλνοντας fragments που λήγουν (time out), αναγκάζοντας frees πίσω στη freelist σε LIFO σειρά.
  • Χρησιμοποίηση της γνώσης του freelist walk για να τοποθετήσετε το μελλοντικό victim mbuf αμέσως μετά το mbuf που θα μεταφέρει το IP options overflow.

Αυτό το grooming διασφαλίζει ότι το overflow χτυπά το στοχευμένο struct item και ότι η ψεύτικη uma_zone παραμένει εντός ορίων του leak primitive.

Από arbitrary write σε εκτέλεση κώδικα στον host

Με το memcpy-on-free primitive:

  1. Αντιγράψτε ένα attacker-controlled /bin/sh string και buffer εντολών σε ένα σταθερό mbuf.
  2. Χρησιμοποιήστε το primitive για να επανεγγράψετε ένα GOT entry ή ένα indirect callsite (π.χ. έναν function pointer μέσα στο NAT device state) με την PLT είσοδο του system().
  3. Ενεργοποιήστε την επανεγγραμμένη κλήση. Επειδή ο VirtualBox τρέχει τη NAT device μέσα στη διεργασία του host, το payload εκτελείται με τα προνόμια του χρήστη που τρέχει τον VirtualBox, επιτρέποντας guest-to-host escape.

Εναλλακτικά payloads περιλαμβάνουν το φύτεμα μιας μικρής ROP αλυσίδας στη μνήμη heap και την αντιγραφή της διεύθυνσής της σε ένα συχνά κληθέν callback, ή την αναστοχαστική στόχευση των pfFini/pfDtor οι ίδιοι προς chained gadgets για επαναλαμβανόμενες εγγραφές.

References

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