cred struct overwrite¶
Yerinde root'a yükselmek için mevcut task'ın
struct cred'inin uid/gid field'larını doğrudan sıfırla.
Mechanism¶
Her task_struct iki pointer tutar: const struct cred *real_cred (objective context — task'ın kim olduğu) ve const struct cred *cred (subjective context — kim olarak davrandığı). Credential yapısı (include/linux/cred.h) şöyle başlar:
struct cred {
atomic_long_t usage;
kuid_t uid; /* real UID */
kgid_t gid; /* real GID */
kuid_t suid; kgid_t sgid;
kuid_t euid; kgid_t egid;
kuid_t fsuid; kgid_t fsgid;
unsigned securebits;
kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset, cap_ambient;
/* ... */
} __randomize_layout;
Note
Sekiz id field'ı (uid…fsgid), 8-byte'lık usage refcount'un hemen ardından paketlenmiş 4-byte'lık kuid_t/kgid_t'lerdir. Bunları sıfırlamak, task'ı hem filesystem hem de permission check'leri için root yapar. Bu, commit_creds(prepare_kernel_cred(...))'in alternatifidir: yeni bir cred allocate etmek yerine mevcut olanı yerinde mutate edersin — bir AAW artı cred'i bulmanın bir yolunu gerektirir.
İlişki, kavramsal olarak (offset/boyutlar kernel build'ine göre değişir, gösterilen sıralama illüstratiftir):
task_struct struct cred (slab object)
+----------------+ +---------------------------+
| ... | | usage (refcount) <- DOKUNMA
| real_cred *---|----+ |---------------------------|
| cred *---|--+ | | uid gid suid sgid | <- AAW ile
| comm[] | | +---->| euid egid fsuid fsgid | hepsi 0 = root
| ... | | |---------------------------|
+----------------+ | | securebits / cap_* ... |
| +---------------------------+
| (objective vs subjective)
+-------> aynı/ayrı cred object'e bakabilir
cred'i sıfırlamak subjective context'i root yapar; bazı check'ler real_cred ile tutarlılık beklediğinden ikisini de ele almak gerekebilir.
Walkthrough¶
current/task_struct'ı bul — per-CPUcurrent_task'ı oku, leak edilmiş bir kernel object'ten dolaş ya da task'ının marker'ı için kernel heap'ini tara.task_struct'tantask->cred'i (ve genellikle ayrıcareal_cred'i) oku. Yaygın bir heap-scan trick'i:setresuidüzerinden sekiz id'nin hepsini bir sentinel'e ayarlayarak process'ini benzersiz bir cred ile etiketle, sonra canlıcredobject'ini bulmak için slab'i o pattern için tara.uid,gid,suid,sgid,euid,egid,fsuid,fsgid'in 32 byte'ını AAW kullanarak sıfırla overwrite et.usage'a dokunma (refcountuid'den önce yaşar).
Beklenen: getuid() aynı process'te hemen 0 döner; bir root shell başlat.
Warning
struct cred, __randomize_layout ile annote edilmiştir, dolayısıyla CONFIG_RANDSTRUCT ile build edilmiş kernel'lerde field offset'leri build time'da randomize edilir ve hardcode edilemez — bunları türetmen ya da commit_creds'e geri dönmen gerekir. real_cred'i de handle etmeden cred'i overwrite etmek, bazı check'lerin fark ettiği tutarsızlıklar bırakabilir.
Mitigation¶
CONFIG_RANDSTRUCT cred field layout'unu randomize eder. Hardened allocator'lar ve credential object'lerinin pointer-authentication'ı (araştırma aşamasında) forge edilmiş/overwrite edilmiş cred'leri önlemeyi amaçlar. Data-only doğası bunu runtime'da tespit etmeyi zorlaştırır.