11 KiB
Χρονικό Namespace
{{#include ../../../../banners/hacktricks-training.md}}
Βασικές Πληροφορίες
Το χρονικό namespace στο Linux επιτρέπει για ανά namespace offsets στους συστήματος μονοτονικούς και χρόνους εκκίνησης ρολόγια. Χρησιμοποιείται συνήθως σε κοντέινερ Linux για να αλλάξει την ημερομηνία/ώρα εντός ενός κοντέινερ και να ρυθμίσει τα ρολόγια μετά την αποκατάσταση από ένα checkpoint ή snapshot.
Εργαστήριο:
Δημιουργία διαφορετικών Namespaces
CLI
sudo unshare -T [--mount-proc] /bin/bash
Με την τοποθέτηση μιας νέας παρουσίας του συστήματος αρχείων /proc
αν χρησιμοποιήσετε την παράμετρο --mount-proc
, διασφαλίζετε ότι το νέο namespace τοποθέτησης έχει μια ακριβή και απομονωμένη άποψη των πληροφοριών διαδικασίας που είναι συγκεκριμένες για αυτό το namespace.
Σφάλμα: bash: fork: Cannot allocate memory
Όταν εκτελείται το unshare
χωρίς την επιλογή -f
, προκύπτει ένα σφάλμα λόγω του τρόπου που το Linux χειρίζεται τα νέα PID (Process ID) namespaces. Οι βασικές λεπτομέρειες και η λύση περιγράφονται παρακάτω:
- Εξήγηση Προβλήματος:
- Ο πυρήνας του 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.
- Συνέπεια:
- Η έξοδος του PID 1 σε ένα νέο namespace οδηγεί στον καθαρισμό της σημαίας
PIDNS_HASH_ADDING
. Αυτό έχει ως αποτέλεσμα τη αποτυχία της συνάρτησηςalloc_pid
να κατανοήσει ένα νέο PID κατά τη δημιουργία μιας νέας διαδικασίας, παράγοντας το σφάλμα "Cannot allocate memory".
- Λύση:
- Το πρόβλημα μπορεί να επιλυθεί χρησιμοποιώντας την επιλογή
-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
και τις υπο-διαδικασίες του να λειτουργούν χωρίς να αντιμετωπίζουν το σφάλμα κατανομής μνήμης.
Docker
docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash
Έλεγχος σε ποιο namespace βρίσκεται η διαδικασία σας
ls -l /proc/self/ns/time
lrwxrwxrwx 1 root root 0 Apr 4 21:16 /proc/self/ns/time -> 'time:[4026531834]'
Βρείτε όλα τα Time namespaces
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
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
φαίνεται ως εξής:
{
"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 στην παραγωγή.
Σκέψεις ασφαλείας
- Απαιτούμενη ικανότητα – Μια διαδικασία χρειάζεται CAP_SYS_TIME μέσα στο namespace χρήστη/χρόνου της για να αλλάξει τις μετατοπίσεις. Η αφαίρεση αυτής της ικανότητας στο κοντέινερ (προεπιλογή στο Docker & Kubernetes) αποτρέπει την παραχάραξη.
- Καμία αλλαγή ρολογιού – Επειδή το
CLOCK_REALTIME
μοιράζεται με τον κεντρικό υπολογιστή, οι επιτιθέμενοι δεν μπορούν να παραποιήσουν τις διάρκειες πιστοποιητικών, την λήξη JWT, κ.λπ. μέσω timens μόνο. - Αποφυγή ανίχνευσης / καταγραφής – Λογισμικό που βασίζεται στο
CLOCK_MONOTONIC
(π.χ. περιοριστές ρυθμού βασισμένοι σε χρόνο λειτουργίας) μπορεί να μπερδευτεί αν ο χρήστης του namespace ρυθμίσει τη μετατόπιση. Προτιμήστε τοCLOCK_REALTIME
για χρονικές σφραγίδες που σχετίζονται με την ασφάλεια. - Επιφάνεια επίθεσης πυρήνα – Ακόμα και με την αφαίρεση του
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}}