VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)
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.
Bug anatomy: fixed-size realloc + scattered OOB writes
PVSCSI_FillSGIαντιγράφει τα guest scatter/gather entries σε έναν εσωτερικό πίνακα. Ξεκινά με ένα στατικό buffer 512 καταχωρήσεων (0x2000). Πάνω από 512 καταχωρήσεις κάνει realloc σε 0x4000 bytes και, λόγω λειτουργικού σφάλματος, κάνει realloc σε κάθε επανάληψη.- Το μέγεθος της επαναδόμησης δεν αυξάνεται ποτέ: 0x4000 / 0x10-byte entries = 1024 usable entries. Όταν το guest προμηθεύει >1024 entries, κάθε νέα εγγραφή γράφεται 16 bytes πέρα από το φρεσκο-κατανεμημένο chunk των 0x4000, διαφθείροντας το γειτονικό header chunk ή αντικείμενο.
- Overflow content: VMware αποθηκεύει
{u64 addr; u64 len}; το guest παρέχει{u64 addr; u32 len; u32 flags}. Το 32-bitlenείναι zero-extended, οπότε το τελευταίο dword κάθε 16-byte OOB στοιχείου είναι πάντα 0x00000000.
LFH constraints & deterministic “Ping-Pong” placement
- Οι 0x4000 allocations προσγειώνονται στο Windows 11 LFH (16 chunks/bucket, 0x10-byte metadata με keyed checksum). Οποιοδήποτε chunk του οποίου το checksum του header χτυπηθεί αργότερα θα τερματίσει τη διαδικασία, οπότε τα κατεστραμμένα headers δεν πρέπει να επαναχρησιμοποιηθούν.
- Το LFH επιστρέφει ένα τυχαίο free chunk, αλλά προτιμά τον bucket που περιέχει το πιο πρόσφατα freed chunk. Αναγκάστε να υπάρχουν μόνο δύο ελεύθερες θέσεις:
- Κατανεμήστε όλα τα διαθέσιμα 0x4000 chunks για να ευθυγραμμίσετε τον allocator· κάντε spray 32 SVGA shaders για να γεμίσετε τους κάδους B1 και B2.
- Απελευθερώστε το B1 εκτός από ένα pinned shader (Hole0) ώστε ο B1 να παραμένει ενεργός· κατανεμήστε 15 URBs μέσα στον B1.
- Απελευθερώστε ένα shader στο B2 (PONG), και αμέσως μετά απελευθερώστε το Hole0. Το LFH θα εναλλάσσει τις allocations ανάμεσα στις δύο διαθέσιμες θέσεις PING (B1) και PONG (B2).
- Η επανάληψη 1025 διαφθείρει το header μετά το PONG (ποτέ δεν αγγίζεται ξανά); η επανάληψη 1026 χτυπά τα πρώτα 16 bytes του URB μετά το PING (παρακάμπτει με ασφάλεια metadata). Επανακτήστε PING/PONG με placeholder shaders για να κρατήσετε τη διάταξη σταθερή και επαναλήψιμη.
Reap Oracle: labeling contiguous holes
- Οι UHCI URBs ζουν σε μια FIFO ουρά και απελευθερώνονται όταν ολοκληρωτικά reaped. Η περιορισμένη 16-byte overwrite μηδενίζει πάντα το
actual_len, παρέχοντας έναν marker. - Reap URBs με τη σειρά· όταν εντοπιστεί ένα μηδενισμένο
actual_len, αμέσως επαναγεμίστε τη freed θέση με ένα αναγνωρίσιμο shader. Η επανάληψη επιτρέπει να χαρτογραφήσετε τα Hole0–Hole3 ως τέσσερα συνεχόμενα chunks σε γνωστή σειρά για μετέπειτα primitives που εξαρτώνται από τη γειτνίαση.
Turning constrained writes into arbitrary overwrite (coalescing abuse)
PVSCSI συγχωνεύει (coalesces) γειτονικά entries χρησιμοποιώντας το AddrA + LenA == AddrB και συμπιέζει τα επόμενα entries προς τα πάνω.
- Two-pass overflow: Ξεκινήστε την υπερχείλιση από το PING (περιθώρια με περιττούς δείκτες) και τερματίστε νωρίς για να παραλείψετε το coalescing· ξαναπυροδοτήστε ξεκινώντας από το PONG (άρτιοι δείκτες) για να γεμίσετε τα κενά και να συνεχίσετε τη γραφή μέσα σε ένα sprayed shader που περιέχει ψεύτικα S/G entries.
- Vacuum + payload: Θέστε τα entries
[1023..2047]σε{addr=0,len=0}ώστε το coalescing να τα συμπτύξει σε ένα, δημιουργώντας μια λογική τρύπα. Τα entries του payload που τοποθετούνται έπειτα (στο shader) μετακινούνται προς τα πάνω, καταλήγοντας μέσα στο θύμα URB. - Adjacency-check bypass: Θέτοντας
LenA=0η συνθήκη γίνεταιAddrA==AddrB. Κατασκευάστε ζεύγη
{addr = X, len = 0}
{addr = X, len = Y}
ώστε το coalescing να τα συγχωνεύσει σε {addr=X,len=Y}. Τα even-indexed zero-size στοιχεία προέρχονται από το περιορισμένο overflow· τα odd-indexed τιμές ζουν στο shader. Αποτέλεσμα: αρχεία 16-byte με ό,τι θέλετε παρά το αναγκασμένο μηδενικό dword.
Hybrid URB infoleak via coalescing side-effects
- Διατάξτε συνεχόμενα chunks:
[Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)]. - Γεμίστε το URB1 με συνεχή ψεύτικα entries (μεγέθη
0xFFFFFFFF), αγγίζοντας το URB2 στο ελάχιστο. Το coalescing τα συγχωνεύει σε ένα entry· το γινόμενο0xFFFFFFFF * 0x401ρυθμίζει το ανώτερο dword στη μετατόπισηactual_lenτου URB1 σε 0x400. - Η συμπίεση αντιγράφει τα επόμενα δεδομένα προς τα πάνω, τραβώντας το header του URB2 μέσα στο URB1. Το URB1 τώρα έχει έγκυρο header (pointer pipe/list),
actual_len=0x400, και pointer δεδομένων ήδη στο τέλος του buffer του URB2. - Το reaping του URB1 αντιγράφει 0x400 bytes ξεκινώντας λίγο πριν το URB3, παράγοντας ένα OOB read του header/self-references του URB3, το οποίο αποκαλύπτει απόλυτες διευθύνσεις heap και καταργεί το ASLR για επακόλουθα forged structures.
Post-leak primitives (no re-triggering the bug)
- Forge ένα URB structure μέσα σε ένα shader που καταλαμβάνει το Hole0, και μετά χρησιμοποιήστε το coalescing “move up” για να αντικαταστήσετε το URB1 με τα forged δεδομένα.
- Κάντε το URB επίμονο: ρυθμίστε
URB1.next = Hole0και αυξήστε τοrefcount; το reaping του URB1 φέρνει το Hole0-backed fake URB στην κεφαλή της FIFO. Μελλοντικά primitives γίνονται απλώς reallocations του Hole0 με νέα fake URBs. - Arbitrary read: fake URB με επιλεγμένο
data_ptrκαιactual_len, έπειτα reap για να αντιγράψετε host μνήμη στο guest. - Arbitrary write (32-bit): fake URB του οποίου το
pipeδείχνει σε ελεγχόμενη μνήμη και κατάχρηση του UHCI TDBuffer writeback για να αποθηκεύσει ένα επιλεγμένο dword σε αυθαίρετη διεύθυνση. - Arbitrary call: αντικαταστήστε ένα USB pipe callback; ο host το καλεί με ελεγχόμενα δεδομένα στο
RCX+0x90. Εντοπίστε δυναμικά τοWinExec(guest-side read του Kernel32) και κάντε pivot μέσω ενός CFG-valid gadget μέσα στο vmware-vmx που φορτώνει επιχειρήματα από τοRCX+0x100πριν καλέσει τοWinExec("calc.exe").
LFH timing side-channel to learn the initial bucket offset
- Η ντετερμινιστική Ping-Pong απαιτεί να γνωρίζετε την αρχική LFH free-chunk offset (ποια από τις 16 θέσεις θα χτυπηθεί πρώτη). Χρησιμοποιήστε την VMware backdoor εντολή (
inl %%dx, %%eax) με την συγχρονική VMware Tools εντολήvmx.capability.unified_loopκαι ένα 0x4000-byte string, που αναγκάζει δύο 0x4000 allocations ανά κλήση. - Χρονίστε 8 κλήσεις (16 allocations) μέσω
gettimeofday; μία κλήση δείχνει ένα σταθερό spike όταν το LFH δημιουργεί νέο bucket. Επαναλάβετε με μία επιπλέον allocation: αν το spike παραμένει στο ίδιο index η offset είναι odd, αν μετατοπίζεται είναι even· διαφορετικά επανεκκινήστε λόγω θορύβου. - Σημείωση: το
unified_loopαποθηκεύει μοναδικά strings σε μια λίστα που δεν αποδεσμεύεται, προκαλώντας O(n) lookup overhead και αυξανόμενο θόρυβο, οπότε το side-channel πρέπει να συγκλίνει γρήγορα.
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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


