142 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Χρονικό Namespace
{{#include ../../../../banners/hacktricks-training.md}}
## Βασικές Πληροφορίες
Το χρονικό namespace στο Linux επιτρέπει για ανά namespace offsets στους συστήματος μονοτονικούς και χρόνους εκκίνησης ρολόγια. Χρησιμοποιείται συνήθως σε κοντέινερ Linux για να αλλάξει την ημερομηνία/ώρα εντός ενός κοντέινερ και να ρυθμίσει τα ρολόγια μετά την αποκατάσταση από ένα checkpoint ή snapshot.
## Εργαστήριο:
### Δημιουργία διαφορετικών Namespaces
#### CLI
```bash
sudo unshare -T [--mount-proc] /bin/bash
```
Με την τοποθέτηση μιας νέας παρουσίας του συστήματος αρχείων `/proc` αν χρησιμοποιήσετε την παράμετρο `--mount-proc`, διασφαλίζετε ότι το νέο namespace τοποθέτησης έχει μια **ακριβή και απομονωμένη άποψη των πληροφοριών διαδικασίας που είναι συγκεκριμένες για αυτό το namespace**.
<details>
<summary>Σφάλμα: bash: fork: Cannot allocate memory</summary>
Όταν εκτελείται το `unshare` χωρίς την επιλογή `-f`, προκύπτει ένα σφάλμα λόγω του τρόπου που το Linux χειρίζεται τα νέα PID (Process ID) namespaces. Οι βασικές λεπτομέρειες και η λύση περιγράφονται παρακάτω:
1. **Εξήγηση Προβλήματος**:
- Ο πυρήνας του Linux επιτρέπει σε μια διαδικασία να δημιουργεί νέα namespaces χρησιμοποιώντας την κλήση συστήματος `unshare`. Ωστόσο, η διαδικασία που ξεκινά τη δημιουργία ενός νέου PID namespace (αναφερόμενη ως η διαδικασία "unshare") δεν εισέρχεται στο νέο namespace; μόνο οι παιδικές της διαδικασίες το κάνουν.
- Η εκτέλεση `%unshare -p /bin/bash%` ξεκινά το `/bin/bash` στην ίδια διαδικασία με το `unshare`. Ως εκ τούτου, το `/bin/bash` και οι παιδικές του διαδικασίες βρίσκονται στο αρχικό PID namespace.
- Η πρώτη παιδική διαδικασία του `/bin/bash` στο νέο namespace γίνεται PID 1. Όταν αυτή η διαδικασία τερματίσει, ενεργοποιεί την καθαριότητα του namespace αν δεν υπάρχουν άλλες διαδικασίες, καθώς το PID 1 έχει τον ειδικό ρόλο της υιοθέτησης ορφανών διαδικασιών. Ο πυρήνας του Linux θα απενεργοποιήσει στη συνέχεια την κατανομή PID σε αυτό το namespace.
2. **Συνέπεια**:
- Η έξοδος του PID 1 σε ένα νέο namespace οδηγεί στον καθαρισμό της σημαίας `PIDNS_HASH_ADDING`. Αυτό έχει ως αποτέλεσμα τη αποτυχία της συνάρτησης `alloc_pid` να κατανοήσει ένα νέο PID κατά τη δημιουργία μιας νέας διαδικασίας, παράγοντας το σφάλμα "Cannot allocate memory".
3. **Λύση**:
- Το πρόβλημα μπορεί να επιλυθεί χρησιμοποιώντας την επιλογή `-f` με το `unshare`. Αυτή η επιλογή κάνει το `unshare` να δημιουργήσει μια νέα διαδικασία μετά τη δημιουργία του νέου PID namespace.
- Η εκτέλεση `%unshare -fp /bin/bash%` διασφαλίζει ότι η εντολή `unshare` γίνεται PID 1 στο νέο namespace. Το `/bin/bash` και οι παιδικές του διαδικασίες είναι στη συνέχεια ασφαλώς περιεχόμενες μέσα σε αυτό το νέο namespace, αποτρέποντας την πρόωρη έξοδο του PID 1 και επιτρέποντας την κανονική κατανομή PID.
Διασφαλίζοντας ότι το `unshare` εκτελείται με την επιλογή `-f`, το νέο PID namespace διατηρείται σωστά, επιτρέποντας στο `/bin/bash` και τις υπο-διαδικασίες του να λειτουργούν χωρίς να αντιμετωπίζουν το σφάλμα κατανομής μνήμης.
</details>
#### Docker
```bash
docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash
```
### Έλεγχος σε ποιο namespace βρίσκεται η διαδικασία σας
```bash
ls -l /proc/self/ns/time
lrwxrwxrwx 1 root root 0 Apr 4 21:16 /proc/self/ns/time -> 'time:[4026531834]'
```
### Βρείτε όλα τα Time namespaces
```bash
sudo find /proc -maxdepth 3 -type l -name time -exec readlink {} \; 2>/dev/null | sort -u
# Find the processes with an specific namespace
sudo find /proc -maxdepth 3 -type l -name time -exec ls -l {} \; 2>/dev/null | grep <ns-number>
```
### Είσοδος σε ένα Χρονικό namespace
```bash
nsenter -T TARGET_PID --pid /bin/bash
```
## Manipulating Time Offsets
Αρχίζοντας με το Linux 5.6, δύο ρολόγια μπορούν να εικονικοποιηθούν ανά χρονικό namespace:
* `CLOCK_MONOTONIC`
* `CLOCK_BOOTTIME`
Οι διαφορές τους ανά namespace εκτίθενται (και μπορούν να τροποποιηθούν) μέσω του αρχείου `/proc/<PID>/timens_offsets`:
```
$ sudo unshare -Tr --mount-proc bash # -T creates a new timens, -r drops capabilities
$ cat /proc/$$/timens_offsets
monotonic 0
boottime 0
```
Το αρχείο περιέχει δύο γραμμές μία ανά ρολόι με την απόκλιση σε **νανοδευτερόλεπτα**. Οι διεργασίες που κατέχουν **CAP_SYS_TIME** _στο χρονικό namespace_ μπορούν να αλλάξουν την τιμή:
```
# advance CLOCK_MONOTONIC by two days (172 800 s)
echo "monotonic 172800000000000" > /proc/$$/timens_offsets
# verify
$ cat /proc/$$/uptime # first column uses CLOCK_MONOTONIC
172801.37 13.57
```
Αν χρειάζεστε το ρολόι τοίχου (`CLOCK_REALTIME`) να αλλάξει επίσης, πρέπει ακόμα να βασιστείτε σε κλασικούς μηχανισμούς (`date`, `hwclock`, `chronyd`, …); **δεν είναι** ονοματοδοτημένο.
### `unshare(1)` helper flags (util-linux ≥ 2.38)
```
sudo unshare -T \
--monotonic="+24h" \
--boottime="+7d" \
--mount-proc \
bash
```
Οι μακροχρόνιες επιλογές γράφουν αυτόματα τις επιλεγμένες δέλτα στο `timens_offsets` αμέσως μετά τη δημιουργία του namespace, αποθηκεύοντας μια χειροκίνητη `echo`.
---
## OCI & Υποστήριξη Runtime
* Η **OCI Runtime Specification v1.1** (Νοέμβριος 2023) πρόσθεσε έναν ειδικό τύπο namespace `time` και το πεδίο `linux.timeOffsets` ώστε οι μηχανές κοντέινερ να μπορούν να ζητούν εικονικοποίηση χρόνου με φορητό τρόπο.
* **runc >= 1.2.0** υλοποιεί αυτό το μέρος της προδιαγραφής. Ένα ελάχιστο τμήμα `config.json` φαίνεται ως εξής:
```json
{
"linux": {
"namespaces": [
{"type": "time"}
],
"timeOffsets": {
"monotonic": 86400,
"boottime": 600
}
}
}
```
Στη συνέχεια, εκτελέστε το κοντέινερ με `runc run <id>`.
> ΣΗΜΕΙΩΣΗ: runc **1.2.6** (Φεβρουάριος 2025) διόρθωσε ένα σφάλμα "exec into container with private timens" που θα μπορούσε να οδηγήσει σε κρέμασμα και πιθανό DoS. Βεβαιωθείτε ότι είστε σε ≥ 1.2.6 στην παραγωγή.
---
## Σκέψεις ασφαλείας
1. **Απαιτούμενη ικανότητα** Μια διαδικασία χρειάζεται **CAP_SYS_TIME** μέσα στο namespace χρήστη/χρόνου της για να αλλάξει τις μετατοπίσεις. Η αφαίρεση αυτής της ικανότητας στο κοντέινερ (προεπιλογή στο Docker & Kubernetes) αποτρέπει την παραχάραξη.
2. **Καμία αλλαγή ρολογιού** Επειδή το `CLOCK_REALTIME` μοιράζεται με τον κεντρικό υπολογιστή, οι επιτιθέμενοι δεν μπορούν να παραποιήσουν τις διάρκειες πιστοποιητικών, την λήξη JWT, κ.λπ. μέσω timens μόνο.
3. **Αποφυγή ανίχνευσης / καταγραφής** Λογισμικό που βασίζεται στο `CLOCK_MONOTONIC` (π.χ. περιοριστές ρυθμού βασισμένοι σε χρόνο λειτουργίας) μπορεί να μπερδευτεί αν ο χρήστης του namespace ρυθμίσει τη μετατόπιση. Προτιμήστε το `CLOCK_REALTIME` για χρονικές σφραγίδες που σχετίζονται με την ασφάλεια.
4. **Επιφάνεια επίθεσης πυρήνα** Ακόμα και με την αφαίρεση του `CAP_SYS_TIME`, ο κώδικας του πυρήνα παραμένει προσβάσιμος. Κρατήστε τον κεντρικό υπολογιστή ενημερωμένο. Το Linux 5.6 → 5.12 έλαβε πολλές διορθώσεις σφαλμάτων timens (NULL-deref, ζητήματα υπογραφής).
### Λίστα ελέγχου σκληροποίησης
* Αφαιρέστε το `CAP_SYS_TIME` στο προεπιλεγμένο προφίλ runtime του κοντέινερ σας.
* Κρατήστε τα runtimes ενημερωμένα (runc ≥ 1.2.6, crun ≥ 1.12).
* Κλειδώστε το util-linux ≥ 2.38 αν βασίζεστε στους βοηθούς `--monotonic/--boottime`.
* Ελέγξτε το λογισμικό εντός του κοντέινερ που διαβάζει **uptime** ή **CLOCK_MONOTONIC** για κρίσιμη λογική ασφαλείας.
## Αναφορές
* man7.org Σελίδα εγχειριδίου για τα Time namespaces: <https://man7.org/linux/man-pages/man7/time_namespaces.7.html>
* OCI blog "OCI v1.1: νέοι χρόνοι και RDT namespaces" (15 Νοεμβρίου 2023): <https://opencontainers.org/blog/2023/11/15/oci-spec-v1.1>
{{#include ../../../../banners/hacktricks-training.md}}