mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
114 lines
12 KiB
Markdown
114 lines
12 KiB
Markdown
# Off by one overflow
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Basic Information
|
||
|
||
Η πρόσβαση σε μια υπερχείλιση 1B επιτρέπει σε έναν επιτιθέμενο να τροποποιήσει το πεδίο `size` από το επόμενο κομμάτι. Αυτό επιτρέπει την παρέμβαση στο ποια κομμάτια είναι πραγματικά ελεύθερα, ενδεχομένως δημιουργώντας ένα κομμάτι που περιέχει ένα άλλο έγκυρο κομμάτι. Η εκμετάλλευση είναι παρόμοια με το [double free](double-free.md) ή τα επικαλυπτόμενα κομμάτια.
|
||
|
||
Υπάρχουν 2 τύποι ευπαθειών off by one:
|
||
|
||
- Arbitrary byte: Αυτός ο τύπος επιτρέπει την επαναγραφή αυτού του byte με οποιαδήποτε τιμή
|
||
- Null byte (off-by-null): Αυτός ο τύπος επιτρέπει την επαναγραφή αυτού του byte μόνο με 0x00
|
||
- Ένα κοινό παράδειγμα αυτής της ευπάθειας μπορεί να παρατηρηθεί στον παρακάτω κώδικα όπου η συμπεριφορά των `strlen` και `strcpy` είναι ασυνεπής, γεγονός που επιτρέπει την τοποθέτηση ενός byte 0x00 στην αρχή του επόμενου κομματιού.
|
||
- Αυτό μπορεί να εκμεταλλευτεί με το [House of Einherjar](house-of-einherjar.md).
|
||
- Εάν χρησιμοποιείται Tcache, αυτό μπορεί να αξιοποιηθεί σε μια κατάσταση [double free](double-free.md).
|
||
|
||
<details>
|
||
|
||
<summary>Off-by-null</summary>
|
||
```c
|
||
// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/
|
||
int main(void)
|
||
{
|
||
char buffer[40]="";
|
||
void *chunk1;
|
||
chunk1 = malloc(24);
|
||
puts("Get Input");
|
||
gets(buffer);
|
||
if(strlen(buffer)==24)
|
||
{
|
||
strcpy(chunk1,buffer);
|
||
}
|
||
return 0;
|
||
}
|
||
```
|
||
</details>
|
||
|
||
Μεταξύ άλλων ελέγχων, τώρα κάθε φορά που ένα κομμάτι είναι ελεύθερο, το προηγούμενο μέγεθος συγκρίνεται με το μέγεθος που έχει ρυθμιστεί στο κομμάτι των μεταδεδομένων, καθιστώντας αυτή την επίθεση αρκετά περίπλοκη από την έκδοση 2.28.
|
||
|
||
### Παράδειγμα κώδικα:
|
||
|
||
- [https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c](https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c)
|
||
- Αυτή η επίθεση δεν λειτουργεί πλέον λόγω της χρήσης Tcaches.
|
||
- Επιπλέον, αν προσπαθήσετε να την εκμεταλλευτείτε χρησιμοποιώντας μεγαλύτερα κομμάτια (έτσι ώστε να μην εμπλέκονται τα tcaches), θα λάβετε το σφάλμα: `malloc(): invalid next size (unsorted)`
|
||
|
||
### Στόχος
|
||
|
||
- Να περιέχεται ένα κομμάτι μέσα σε ένα άλλο κομμάτι, έτσι ώστε η πρόσβαση εγγραφής σε αυτό το δεύτερο κομμάτι να επιτρέπει την αντικατάσταση του περιεχόμενου.
|
||
|
||
### Απαιτήσεις
|
||
|
||
- Off by one overflow για να τροποποιηθεί η πληροφορία μεγέθους των μεταδεδομένων.
|
||
|
||
### Γενική επίθεση off-by-one
|
||
|
||
- Δεσμεύστε τρία κομμάτια `A`, `B` και `C` (ας πούμε μεγέθη 0x20), και ένα άλλο για να αποτραπεί η συγχώνευση με το top-chunk.
|
||
- Ελευθερώστε το `C` (εισαγμένο στη λίστα ελεύθερων κομματιών 0x20 Tcache).
|
||
- Χρησιμοποιήστε το κομμάτι `A` για να υπερχειλίσετε το `B`. Εκμεταλλευτείτε το off-by-one για να τροποποιήσετε το πεδίο `size` του `B` από 0x21 σε 0x41.
|
||
- Τώρα έχουμε το `B` να περιέχει το ελεύθερο κομμάτι `C`.
|
||
- Ελευθερώστε το `B` και δεσμεύστε ένα κομμάτι 0x40 (θα τοποθετηθεί ξανά εδώ).
|
||
- Μπορούμε να τροποποιήσουμε τον δείκτη `fd` από το `C`, το οποίο είναι ακόμα ελεύθερο (Tcache poisoning).
|
||
|
||
### Επίθεση off-by-null
|
||
|
||
- 3 κομμάτια μνήμης (a, b, c) δεσμεύονται το ένα μετά το άλλο. Στη συνέχεια, το μεσαίο ελευθερώνεται. Το πρώτο περιέχει μια ευπάθεια off by one overflow και ο επιτιθέμενος την εκμεταλλεύεται με ένα 0x00 (αν το προηγούμενο byte ήταν 0x10 θα έκανε το μεσαίο κομμάτι να υποδεικνύει ότι είναι 0x10 μικρότερο από ό,τι πραγματικά είναι).
|
||
- Στη συνέχεια, 2 ακόμη μικρότερα κομμάτια δεσμεύονται στο μεσαίο ελεύθερο κομμάτι (b), ωστόσο, καθώς το `b + b->size` δεν ενημερώνει ποτέ το κομμάτι c επειδή η διεύθυνση που δείχνει είναι μικρότερη από ό,τι θα έπρεπε.
|
||
- Στη συνέχεια, τα b1 και c ελευθερώνονται. Καθώς το `c - c->prev_size` δείχνει ακόμα στο b (τώρα b1), και τα δύο συγχωνεύονται σε ένα κομμάτι. Ωστόσο, το b2 είναι ακόμα μέσα ανάμεσα στο b1 και το c.
|
||
- Τέλος, εκτελείται μια νέα malloc που ανακτά αυτή την περιοχή μνήμης, η οποία στην πραγματικότητα θα περιέχει το b2, επιτρέποντας στον κάτοχο της νέας malloc να ελέγξει το περιεχόμενο του b2.
|
||
|
||
Αυτή η εικόνα εξηγεί τέλεια την επίθεση:
|
||
|
||
<figure><img src="../../images/image (1247).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks">https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks</a></p></figcaption></figure>
|
||
|
||
## Άλλα Παραδείγματα & Αναφορές
|
||
|
||
- [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks)
|
||
- [**Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/bon-nie-appetit/)
|
||
- Off-by-one λόγω του `strlen` που θεωρεί το πεδίο `size` του επόμενου κομματιού.
|
||
- Χρησιμοποιείται Tcache, οπότε μια γενική επίθεση off-by-one λειτουργεί για να αποκτήσει μια αυθαίρετη εγγραφή με Tcache poisoning.
|
||
- [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks)
|
||
- Είναι δυνατόν να εκμεταλλευτείτε ένα off by one για να διαρρεύσετε μια διεύθυνση από την heap επειδή το byte 0x00 στο τέλος μιας συμβολοσειράς που επαναγράφεται από το επόμενο πεδίο.
|
||
- Αυθαίρετη εγγραφή αποκτάται εκμεταλλευόμενοι την εγγραφή off by one για να κάνουμε τον δείκτη να δείχνει σε άλλη θέση όπου θα κατασκευαστεί μια ψεύτικη δομή με ψεύτικους δείκτες. Στη συνέχεια, είναι δυνατόν να ακολουθήσουμε τον δείκτη αυτής της δομής για να αποκτήσουμε αυθαίρετη εγγραφή.
|
||
- Η διεύθυνση libc διαρρέει επειδή αν η heap επεκταθεί χρησιμοποιώντας mmap, η μνήμη που δεσμεύεται από το mmap έχει μια σταθερή απόσταση από τη libc.
|
||
- Τέλος, η αυθαίρετη εγγραφή εκμεταλλεύεται για να γράψει στη διεύθυνση του \_\_free_hook με μια διεύθυνση one gadget.
|
||
- [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb)
|
||
- Υπάρχει μια ευπάθεια NULL off by one στη λειτουργία `getline` που διαβάζει γραμμές εισόδου χρήστη. Αυτή η λειτουργία χρησιμοποιείται για να διαβάσει το "κλειδί" του περιεχομένου και όχι το περιεχόμενο.
|
||
- Στη γραφή 5 αρχικά δημιουργούνται κομμάτια:
|
||
- chunk1 (0x200)
|
||
- chunk2 (0x50)
|
||
- chunk5 (0x68)
|
||
- chunk3 (0x1f8)
|
||
- chunk4 (0xf0)
|
||
- chunk defense (0x400) για να αποφευχθεί η συγχώνευση με το top chunk
|
||
- Στη συνέχεια, τα κομμάτια 1, 5 και 3 ελευθερώνονται, οπότε:
|
||
- ```python
|
||
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
|
||
```
|
||
- Στη συνέχεια, εκμεταλλευόμενοι το chunk3 (0x1f8) η null off-by-one εκμεταλλεύεται γράφοντας το prev_size σε `0x4e0`.
|
||
- Σημειώστε πώς τα μεγέθη των αρχικά δεσμευμένων κομματιών 1, 2, 5 και 3 συν τα headers 4 αυτών των κομματιών ισούνται με `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
|
||
- Στη συνέχεια, το κομμάτι 4 ελευθερώνεται, δημιουργώντας ένα κομμάτι που καταναλώνει όλα τα κομμάτια μέχρι την αρχή:
|
||
- ```python
|
||
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
|
||
```
|
||
- ```python
|
||
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
|
||
```
|
||
- Στη συνέχεια, δεσμεύονται `0x200` bytes γεμίζοντας το αρχικό κομμάτι 1.
|
||
- Και άλλο 0x200 bytes δεσμεύονται και το chunk2 καταστρέφεται και επομένως δεν υπάρχει καμία διαρροή και αυτό δεν λειτουργεί; Ίσως αυτό δεν θα έπρεπε να γίνει.
|
||
- Στη συνέχεια, δεσμεύει άλλο ένα κομμάτι με 0x58 "a"s (επανεγγράφοντας το chunk2 και φτάνοντας στο chunk5) και τροποποιεί το `fd` του γρήγορου bin chunk του chunk5 δείχνοντάς το στο `__malloc_hook`.
|
||
- Στη συνέχεια, ένα κομμάτι 0x68 δεσμεύεται έτσι ώστε το ψεύτικο γρήγορο bin chunk στο `__malloc_hook` να είναι το επόμενο γρήγορο bin chunk.
|
||
- Τέλος, ένα νέο γρήγορο bin chunk 0x68 δεσμεύεται και το `__malloc_hook` αντικαθίσταται με μια διεύθυνση `one_gadget`.
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|