POSIX CPU Timers TOCTOU race (CVE-2025-38352)
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์ด ํ์ด์ง๋ Linux/Android์ POSIX CPU timers์์ ๋ฐ์ํ๋ TOCTOU race ์กฐ๊ฑด์ ๋ฌธ์ํํ๋ฉฐ, ์ด๋ ํ์ด๋จธ ์ํ๋ฅผ ์์์ํค๊ณ kernel์ crash์ํฌ ์ ์์ผ๋ฉฐ, ํน์ ์ํฉ์์๋ privilege escalation์ผ๋ก ์ ๋๋ ์ ์์ต๋๋ค.
- Affected component: kernel/time/posix-cpu-timers.c
- Primitive: task exit ์ expiry vs deletion race
- Config sensitive: CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (IRQ-context expiry path)
Quick internals recap (relevant for exploitation)
- ์ธ ๊ฐ์ง CPU ํด๋ก์ด 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;
}
- Arming์ 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;
}
- Fast path๋ ์บ์๋ ๋ง๋ฃ ์ ๋ณด๊ฐ ํ์ด๋จธ๊ฐ ์ค์ ๋ก ๋ฐ๋ํ ๊ฐ๋ฅ์ฑ์ ์์ฌํ๋ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ ๋น์ฉ์ด ํฐ ์ฒ๋ฆฌ๋ฅผ ํผํฉ๋๋ค:
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;
}
- Expiration์ ๋ง๋ฃ๋ ํ์ด๋จธ๋ฅผ ์์งํ๊ณ , ์ด๋ค์ firing์ผ๋ก ํ์ํ ๋ค ํ์์ ์ ๊ฑฐํฉ๋๋ค; ์ค์ ์ ๋ฌ์ ์ง์ฐ๋ฉ๋๋ค:
#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๋ฅผ ํตํด ์ฐ๊ธฐ๋จ
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: ๋ง๋ฃ๋ IRQ ์ปจํ ์คํธ์์ ์ง์ ์ฒ๋ฆฌ๋จ
POSIX CPU timer ์คํ ๊ฒฝ๋ก๋ค
```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: IRQ ์์ ์ ๋ง๋ฃ์ ํ์คํฌ ์ข ๋ฃ ์ค ๋์ ์ญ์ ์ฌ์ด์ TOCTOU Preconditions
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK is disabled (IRQ ๊ฒฝ๋ก ์ฌ์ฉ ์ค)
- ๋์ ํ์คํฌ๊ฐ ์ข ๋ฃ ์ค์ด์ง๋ง ์์ ํ ํ์๋์ง ์์
- ๋ค๋ฅธ ์ค๋ ๋๊ฐ ๋์ผํ ํ์ด๋จธ์ ๋ํด posix_cpu_timer_del()์(๋ฅผ) ๋์์ ํธ์ถํจ
Sequence
- update_process_times()๊ฐ IRQ ์ปจํ ์คํธ์์ ์ข ๋ฃ ์ค์ธ ํ์คํฌ์ ๋ํด run_posix_cpu_timers()๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
- collect_timerqueue()๋ ctmr->firing = 1๋ก ์ค์ ํ๊ณ ํ์ด๋จธ๋ฅผ ์์ firing ๋ฆฌ์คํธ๋ก ์ด๋์ํต๋๋ค.
- handle_posix_cpu_timers()๋ unlock_task_sighand()๋ฅผ ํตํด sighand๋ฅผ ํด์ ํ์ฌ ๋ฝ ๋ฐ์์ ํ์ด๋จธ๋ฅผ ์ ๋ฌํฉ๋๋ค.
- unlock ์งํ, ์ข ๋ฃ ์ค์ธ ํ์คํฌ๊ฐ ํ์๋ ์ ์๊ณ ; ํ์ ์ค๋ ๋๊ฐ posix_cpu_timer_del()๋ฅผ ์คํํฉ๋๋ค.
- ์ด ์ฐฝ์์ posix_cpu_timer_del()๋ cpu_timer_task_rcu()/lock_task_sighand()๋ฅผ ํตํด ์ํ๋ฅผ ํ๋ํ์ง ๋ชปํ ์ ์์ผ๋ฉฐ, ๋ฐ๋ผ์ timer->it.cpu.firing์ ๊ฒ์ฌํ๋ ์ผ๋ฐ์ ์ธ ์ธ-ํ๋ผ์ดํธ ๊ฐ๋๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ญ์ ๋ firing์ด ์๋ ๊ฒ์ฒ๋ผ ์งํ๋์ด ๋ง๋ฃ๋ฅผ ์ฒ๋ฆฌํ๋ ๋์ ์ํ๋ฅผ ์์์ํค๋ฉฐ, ์ถฉ๋/UB๋ก ์ด์ด์ง๋๋ค.
Why TASK_WORK mode is safe by design
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y์ธ ๊ฒฝ์ฐ, ๋ง๋ฃ๋ task_work๋ก ์ฐ๊ธฐ๋ฉ๋๋ค; exit_task_work๋ exit_notify ์ด์ ์ ์คํ๋๋ฏ๋ก IRQ ์์ ์ ํ์์์ ๊ฒน์นจ์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
- ๊ทธ ๊ฒฝ์ฐ์๋, ํ์คํฌ๊ฐ ์ด๋ฏธ ์ข ๋ฃ ์ค์ด๋ฉด task_work_add()๋ ์คํจํฉ๋๋ค; exit_state์ ๋ฐ๋ฅธ ์ ์ด๋ก ๋ ๋ชจ๋๋ฅผ ์ผ๊ด๋๊ฒ ๋ง๋ญ๋๋ค.
Fix (Android common kernel) and rationale
- ํ์ฌ ํ์คํฌ๊ฐ ์ข ๋ฃ ์ค์ด๋ฉด ์กฐ๊ธฐ ๋ฆฌํด์ ์ถ๊ฐํ์ฌ ๋ชจ๋ ์ฒ๋ฆฌ๋ฅผ ์ฐจ๋จํฉ๋๋ค:
// kernel/time/posix-cpu-timers.c (Android common kernel commit 157f357d50b5038e5eaad0b2b438f923ac40afeb)
if (tsk->exit_state)
return;
- ์ด๋ ์ข ๋ฃ ์ค์ธ ํ์คํฌ์ ๋ํด handle_posix_cpu_timers()์ ์ง์ ํ๋ ๊ฒ์ ๋ฐฉ์งํ์ฌ, posix_cpu_timer_del()๊ฐ it.cpu.firing์ ๋์น๊ณ ๋ง๋ฃ ์ฒ๋ฆฌ์ ๊ฒฝ์ํ๋ ์๋์ฐ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
Impact
- ๋์ ๋ง๋ฃ/์ญ์ ์ค ํ์ด๋จธ ๊ตฌ์กฐ์ฒด์ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ ์์์ ์ฆ์ ํฌ๋์(DoS)๋ฅผ ์ ๋ฐํ ์ ์์ผ๋ฉฐ, ์์์ ์ปค๋ ์ํ ์กฐ์ ๊ธฐํ ๋๋ฌธ์ ๊ถํ ์์น์ ์ํ ๊ฐ๋ ฅํ ํ๋ฆฌ๋ฏธํฐ๋ธ๊ฐ ๋ฉ๋๋ค.
Triggering the bug (safe, reproducible conditions) Build/config
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n์ด ์ค์ ๋์ด ์๊ณ exit_state gating fix๊ฐ ์ ์ฉ๋์ง ์์ ์ปค๋์ ์ฌ์ฉํ์ธ์.
Runtime strategy
- ์ข ๋ฃ ์ง์ ์ ์ค๋ ๋๋ฅผ ๋์์ผ๋ก ํ์ฌ CPU ํ์ด๋จธ๋ฅผ ๋ถ์ฐฉํ์ธ์ (์ค๋ ๋๋ณ ๋๋ ํ๋ก์ธ์ค ์ ์ฒด ์๊ณ):
- ์ค๋ ๋๋ณ์ ๊ฒฝ์ฐ: timer_create(CLOCK_THREAD_CPUTIME_ID, โฆ)
- ํ๋ก์ธ์ค ์ ์ฒด์ ๊ฒฝ์ฐ: timer_create(CLOCK_PROCESS_CPUTIME_ID, โฆ)
- ๋งค์ฐ ์งง์ ์ด๊ธฐ ๋ง๋ฃ ์๊ฐ๊ณผ ์์ ๊ฐ๊ฒฉ์ผ๋ก ์ค์ ํ์ฌ IRQ ๊ฒฝ๋ก ์ง์ ์ ์ต๋ํํ์ธ์:
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
}
- ๋ ์ด์ค ์ฆํญ ์์ธ: ๋์ ์ค์ผ์ค๋ฌ ํฑ ์๋, CPU ๋ถํ, ๋ฐ๋ณต์ ์ธ ์ค๋ ๋ ์ข ๋ฃ/์ฌ์์ฑ ์ฌ์ดํด. ํฌ๋์๋ ์ผ๋ฐ์ ์ผ๋ก posix_cpu_timer_del()๊ฐ unlock_task_sighand() ์งํ task ์กฐํ/์ ๊ธ์ ์คํจํ์ฌ firing์ ์ธ์งํ์ง ๋ชปํ ๋ ๋ฐ์ํฉ๋๋ค.
ํ์ง ๋ฐ ์ํ
- ์ํ: exit_state guard๋ฅผ ์ ์ฉํ์ธ์; ๊ฐ๋ฅํ๋ฉด CONFIG_POSIX_CPU_TIMERS_TASK_WORK ํ์ฑํ๋ฅผ ์ฐ์ ๊ณ ๋ คํ์ธ์.
- ๊ด์ฐฐ์ฑ: unlock_task_sighand()/posix_cpu_timer_del() ์ฃผ๋ณ์ tracepoints/WARN_ONCE๋ฅผ ์ถ๊ฐํ์ธ์; it.cpu.firing==1์ด cpu_timer_task_rcu()/lock_task_sighand() ์คํจ์ ํจ๊ป ๊ด์ธก๋๋ฉด ๊ฒฝ๋ณด๋ฅผ ๋ฐ์์ํค์ธ์; task ์ข ๋ฃ ์ฃผ๋ณ์ timerqueue ๋ถ์ผ์น๋ฅผ ๋ชจ๋ํฐ๋งํ์ธ์.
๊ฐ์ฌ ํต์ฌ ์ง์ (๊ฒํ ์์ฉ)
- update_process_times() โ run_posix_cpu_timers() (IRQ)
- __run_posix_cpu_timers() ์ ํ (TASK_WORK vs IRQ ๊ฒฝ๋ก)
- collect_timerqueue(): ctmr->firing๋ฅผ ์ค์ ํ๊ณ ๋ ธ๋๋ค์ ์ด๋
- handle_posix_cpu_timers(): firing ๋ฃจํ ์ ์ sighand๋ฅผ ํด์
- posix_cpu_timer_del(): it.cpu.firing์ ์์กดํด ์งํ ์ค ๋ง๋ฃ๋ฅผ ๊ฐ์งํจ; exit/reap ๋์ task ์กฐํ/์ ๊ธ์ด ์คํจํ๋ฉด ์ด ๊ฒ์ฌ๊ฐ ๊ฑด๋๋ฐ์ด์ง
์ต์คํ๋ก์ ์ฐ๊ตฌ ์ฐธ๊ณ
- ๊ณต๊ฐ๋ ๋์์ ์ ๋ขฐํ ์ ์๋ kernel crash primitive์ ๋๋ค; ์ด๋ฅผ privilege escalation์ผ๋ก ์ ํํ๋ ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก ๋ณธ ์์ฝ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ์ถ๊ฐ์ ์ธ ์ ์ด ๊ฐ๋ฅํ ์ค๋ฒ๋ฉ(๊ฐ์ฒด ์๋ช ๋๋ write-what-where ์ํฅ)์ด ํ์ํฉ๋๋ค. ๋ชจ๋ PoC๋ ์์คํ ์ ๋ถ์์ ํ๊ฒ ๋ง๋ค ์ ์์ผ๋ emulators/VMs์์๋ง ์คํํ์ธ์.
Chronomaly exploit strategy (priv-esc without fixed text offsets)
- Tested target & configs: x86_64 v5.10.157 under QEMU (4 cores, 3 GB RAM). Critical options:
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n,CONFIG_PREEMPT=y,CONFIG_SLAB_MERGE_DEFAULT=n,DEBUG_LIST=n,BUG_ON_DATA_CORRUPTION=n,LIST_HARDENED=n. - Race steering with CPU timers: ๋ ์ด์ฑ ์ค๋ ๋(
race_func())๊ฐ CPU๋ฅผ ์๋ชจํ๋ ๋์ CPU timers๊ฐ ๋ฐ๋ํจ;free_func()๋ ํ์ด๋จธ๊ฐ ๋ฐ๋ํ๋์ง ํ์ธํ๊ธฐ ์ํดSIGUSR1์ ํด๋งํฉ๋๋ค. ์ ํธ๊ฐ ๊ฐํ์ ์ผ๋ก๋ง ๋์ฐฉํ๋๋กCPU_USAGE_THRESHOLD๋ฅผ ์กฐ์ ํ์ธ์(๊ฐํ์ ์ผ๋ก โParent raced too late/too earlyโ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋์ด์ผ ํจ). ํ์ด๋จธ๊ฐ ํญ์ ๋ฐ๋ํ๋ฉด threshold๋ฅผ ๋ฎ์ถ๊ณ , ์ค๋ ๋ ์ข ๋ฃ ์ ์ ์ ๋ ๋ฐ๋ํ์ง ์์ผ๋ฉด ๋์ด์ธ์. - Dual-process alignment into
send_sigqueue(): ๋ถ๋ชจ/์์ ํ๋ก์ธ์ค๋send_sigqueue()๋ด๋ถ์ ๋ ๋ฒ์งธ ๋ ์ด์ค ์ฐฝ์ ๋ ธ๋ฆฝ๋๋ค. ๋ถ๋ชจ๋ ํ์ด๋จธ๋ฅผ ์ค์ ํ๊ธฐ ์ ์ PARENT_SETTIME_DELAY_US ๋ง์ดํฌ๋ก์ด๋งํผ sleepํฉ๋๋ค; ๋๋ถ๋ถ โParent raced too lateโ๊ฐ ๋ณด์ด๋ฉด ๊ฐ์ ์ค์ด๊ณ , ๋๋ถ๋ถ โParent raced too earlyโ๊ฐ ๋ณด์ด๋ฉด ๊ฐ์ ๋๋ฆฌ์ธ์. ๋ ๋ค ๋ณด์ด๋ฉด ์ฐฝ์ ๊ฑด๋๋ฐ๊ณ ์๋ ์ํ์ ๋๋ค; ํ๋์ด ์๋ฃ๋๋ฉด ์ฝ 1๋ถ ๋ด์ ์ฑ๊ณต์ด ๊ธฐ๋๋ฉ๋๋ค. - Cross-cache UAF replacement: ์ต์คํ๋ก์์
struct sigqueue๋ฅผ ํด์ ํ ๋ค ํ ๋น๊ธฐ ์ํ๋ฅผ ์ ๋ฆฌ(sigqueue_crosscache_preallocs())ํ์ฌ danglinguaf_sigqueue์ ๊ต์ฒด๋realloc_sigqueue๊ฐ pipe buffer ๋ฐ์ดํฐ ํ์ด์ง์ ๊ฐ์ด ๋ฐฐ์น๋๋๋ก ํฉ๋๋ค(ํฌ๋ก์ค-์บ์ ์ฌํ ๋น). ์ ๋ขฐ์ฑ์ ์ด์ ์ ์ ์ ์์sigqueueํ ๋น์ด ์๋ ์กฐ์ฉํ ์ปค๋์ ๊ฐ์ ํฉ๋๋ค; ์ด๋ฏธ per-CPU/per-node ๋ถ๋ถ ์ฌ๋ฉ ํ์ด์ง๊ฐ ์กด์ฌํ๋ ๋ฐ์ ์์คํ ์์๋ ๊ต์ฒด๊ฐ ์คํจํ๊ณ ์ฒด์ธ์ด ๊นจ์ง๋๋ค. ์์ฑ์๋ ์๋๋ฌ์ด ์ปค๋์ ๋ํ ์ต์ ํ๋ฅผ ์ผ๋ถ๋ฌ ์๋ตํ์ต๋๋ค.
See also
Ksmbd Streams Xattr Oob Write Cve 2025 37947
References
- Race Against Time in the Kernelโs Clockwork (StreyPaws)
- Android security bulletin โ September 2025
- Android common kernel patch commit 157f357d50b5โฆ
- Chronomaly exploit PoC (CVE-2025-38352)
- CVE-2025-38352 analysis โ Part 1
- CVE-2025-38352 analysis โ Part 2
- CVE-2025-38352 analysis โ Part 3
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


