Χρονικό Namespace

Reading time: 7 minutes

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

Βασικές Πληροφορίες

Το χρονικό namespace στο Linux επιτρέπει για ανά namespace offsets στους συστήματος μονοτονικούς και χρόνους εκκίνησης ρολόγια. Χρησιμοποιείται συνήθως σε κοντέινερ Linux για να αλλάξει την ημερομηνία/ώρα εντός ενός κοντέινερ και να ρυθμίσει τα ρολόγια μετά την αποκατάσταση από ένα checkpoint ή snapshot.

Εργαστήριο:

Δημιουργία διαφορετικών Namespaces

CLI

bash
sudo unshare -T [--mount-proc] /bin/bash

Με την τοποθέτηση μιας νέας παρουσίας του συστήματος αρχείων /proc αν χρησιμοποιήσετε την παράμετρο --mount-proc, διασφαλίζετε ότι το νέο namespace τοποθέτησης έχει μια ακριβή και απομονωμένη άποψη των πληροφοριών διαδικασίας που είναι συγκεκριμένες για αυτό το namespace.

Σφάλμα: bash: fork: Cannot allocate memory

Όταν εκτελείται το 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.
  1. Συνέπεια:
  • Η έξοδος του PID 1 σε ένα νέο namespace οδηγεί στον καθαρισμό της σημαίας PIDNS_HASH_ADDING. Αυτό έχει ως αποτέλεσμα τη αποτυχία της συνάρτησης alloc_pid να κατανοήσει ένα νέο PID κατά τη δημιουργία μιας νέας διαδικασίας, παράγοντας το σφάλμα "Cannot allocate memory".
  1. Λύση:
  • Το πρόβλημα μπορεί να επιλυθεί χρησιμοποιώντας την επιλογή -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

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 για κρίσιμη λογική ασφαλείας.

Αναφορές

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