Dependency Confusion
Reading time: 8 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Basic Information
Dependency Confusion (또는 대체 공격)은 패키지 관리자가 의도하지 않은, 덜 신뢰할 수 있는 레지스트리/소스(보통 공개 레지스트리)에서 의존성 이름을 해결할 때 발생합니다. 이는 일반적으로 공격자가 제어하는 패키지가 설치되는 결과를 초래합니다.
일반적인 근본 원인:
- 타이포스쿼팅/오타:
reqests
를 대신하여requests
를 가져오기(공개 레지스트리에서 해결됨). - 존재하지 않거나 방치된 내부 패키지: 더 이상 내부에 존재하지 않는
company-logging
을 가져오면, 해결자가 공개 레지스트리에서 검색하여 공격자의 패키지를 찾습니다. - 여러 레지스트리 간의 버전 선호: 내부
company-requests
를 가져오면서 해결자가 공개 레지스트리도 쿼리할 수 있고 공격자가 공개적으로 게시한 "최고의"/더 최신 버전을 선호하는 경우.
핵심 아이디어: 해결자가 동일한 패키지 이름에 대해 여러 레지스트리를 볼 수 있고 "최고" 후보를 전 세계적으로 선택할 수 있다면, 해결을 제한하지 않는 한 취약합니다.
Exploitation
warning
모든 경우에 공격자는 공개 레지스트리에서 빌드가 해결하는 의존성과 동일한 이름의 악성 패키지만 게시하면 됩니다. 설치 시 후크(예: npm 스크립트) 또는 가져오기 시 코드 경로는 종종 코드 실행을 제공합니다.
Misspelled & Inexistent
프로젝트가 개인 레지스트리에서 사용할 수 없는 라이브러리를 참조하고 도구가 공개 레지스트리로 되돌아가면, 공격자는 공개 레지스트리에 해당 이름의 악성 패키지를 심을 수 있습니다. 귀하의 러너/CI/개발 머신은 이를 가져와 실행합니다.
Unspecified Version / “Best-version” selection across indexes
개발자는 종종 버전을 고정하지 않거나 넓은 범위를 허용합니다. 해결자가 내부 및 공개 인덱스 모두로 구성된 경우, 출처에 관계없이 최신 버전을 선택할 수 있습니다. 내부 이름인 requests-company
의 경우, 내부 인덱스에 1.0.1
이 있지만 공격자가 공개 레지스트리에 1.0.2
를 게시하고 해결자가 둘 다 고려하면, 공개 패키지가 우선할 수 있습니다.
AWS Fix
이 취약점은 AWS CodeArtifact에서 발견되었습니다(자세한 내용은 이 블로그 게시물을 참조하십시오). AWS는 클라이언트가 상위 공개 레지스트리에서 "내부" 이름을 가져오지 않도록 의존성/피드를 내부와 외부로 표시하는 제어를 추가했습니다.
Finding Vulnerable Libraries
의존성 혼란에 대한 원래 게시물에서 저자는 수천 개의 노출된 매니페스트(예: package.json
, requirements.txt
, lockfiles)를 찾아 내부 패키지 이름을 유추한 다음, 더 높은 버전의 패키지를 공개 레지스트리에 게시했습니다.
Practical Attacker Playbook (for red teams in authorized tests)
- 이름 열거:
- 매니페스트/락 파일 및 내부 네임스페이스에 대한 리포지토리 및 CI 구성 grep.
- 조직 특정 접두사 찾기(예:
@company/*
,company-*
, 내부 groupIds, NuGet ID 패턴, Go의 개인 모듈 경로 등). - 공개 레지스트리에서 가용성 확인:
- 이름이 공개적으로 등록되지 않은 경우, 등록하십시오; 존재하는 경우, 내부 전이 이름을 대상으로 하여 하위 의존성 탈취를 시도하십시오.
- 우선 순위로 게시:
- "이기는" 세멘틱 버전 선택(예: 매우 높은 버전) 또는 해결자 규칙에 맞추기.
- 적용 가능한 경우 최소 설치 시간 실행 포함(예: npm
preinstall
/install
/postinstall
스크립트). Python의 경우, 휠이 일반적으로 설치 시 임의 코드를 실행하지 않으므로 가져오기 시간 실행 경로를 선호합니다. - 제어 유출:
- CI에서 귀하의 제어된 엔드포인트로의 아웃바운드가 허용되는지 확인하십시오; 그렇지 않으면 DNS 쿼리 또는 오류 메시지를 사이드 채널로 사용하여 코드 실행을 증명하십시오.
caution
항상 서면 승인을 받고, 참여를 위해 고유한 패키지 이름/버전을 사용하며, 테스트가 종료되면 즉시 게시 취소하거나 정리를 조정하십시오.
Defender Playbook (what actually prevents confusion)
생태계 전반에 걸쳐 작동하는 고급 전략:
- 고유한 내부 네임스페이스를 사용하고 이를 단일 레지스트리에 바인딩합니다.
- 해결 시간에 신뢰 수준 혼합을 피하십시오. 승인된 공개 패키지를 프록시하는 단일 내부 레지스트리를 선호하고 패키지 관리자에게 내부 및 공개 엔드포인트를 모두 제공하지 마십시오.
- 지원하는 관리자에 대해 패키지를 특정 소스에 매핑하십시오(레지스트리 간의 전역 "최고 버전" 없음).
- 고정 및 잠금:
- 해결된 레지스트리 URL을 기록하는 락파일(npm/yarn/pnpm)을 사용하거나 해시/증명 고정을 사용하십시오(pip
--require-hashes
, Gradle 의존성 검증). - 레지스트리/네트워크 계층에서 내부 이름에 대한 공개 대체를 차단하십시오.
- 가능할 경우 공개 레지스트리에서 내부 이름을 예약하여 향후 스쿼트를 방지하십시오.
Ecosystem Notes and Secure Config Snippets
다음은 의존성 혼란을 줄이거나 제거하기 위한 실용적이고 최소한의 구성입니다. CI 및 개발 환경에서 이를 시행하는 것을 선호합니다.
JavaScript/TypeScript (npm, Yarn, pnpm)
- 모든 내부 코드에 대해 범위가 지정된 패키지를 사용하고 범위를 개인 레지스트리에 고정합니다.
- CI에서 설치를 불변으로 유지합니다(npm lockfile,
yarn install --immutable
).
.npmrc (프로젝트 수준)
# Bind internal scope to private registry; do not allow public fallback for @company/*
@company:registry=https://registry.corp.example/npm/
# Always authenticate to the private registry
//registry.corp.example/npm/:_authToken=${NPM_TOKEN}
strict-ssl=true
package.json (내부 패키지용)
{
"name": "@company/api-client",
"version": "1.2.3",
"private": false,
"publishConfig": {
"registry": "https://registry.corp.example/npm/",
"access": "restricted"
}
}
Yarn Berry (.yarnrc.yml)
npmScopes:
company:
npmRegistryServer: "https://registry.corp.example/npm/"
npmAlwaysAuth: true
# CI should fail if lockfile would change
enableImmutableInstalls: true
운영 팁:
@company
범위 내에서만 내부 패키지를 게시하세요.- 서드파티 패키지의 경우, 클라이언트에서 직접가 아닌 개인 프록시/미러를 통해 공개 레지스트리를 허용하세요.
- 게시하는 공개 패키지에 대해 npm 패키지 출처를 활성화하여 추적 가능성을 높이는 것을 고려하세요 (혼란을 방지하지는 않습니다).
Python (pip / Poetry)
핵심 규칙: 신뢰 수준을 혼합하기 위해 --extra-index-url
을 사용하지 마세요. 다음 중 하나를 선택하세요:
- 승인된 PyPI 패키지를 프록시하고 캐시하는 단일 내부 인덱스를 노출하거나,
- 명시적 인덱스 선택 및 해시 고정을 사용하세요.
pip.conf
[global]
index-url = https://pypi.corp.example/simple
# Disallow source distributions when possible
only-binary = :all:
# Lock with hashes generated via pip-tools
require-hashes = true
pip-tools로 해시된 요구 사항 생성하기:
# From pyproject.toml or requirements.in
pip-compile --generate-hashes -o requirements.txt
pip install --require-hashes -r requirements.txt
공식 PyPI에 접근해야 하는 경우, 내부 프록시를 통해 접근하고 명시적인 허용 목록을 유지하십시오. CI에서 --extra-index-url
사용을 피하십시오.
.NET (NuGet)
패키지 ID 패턴을 명시적인 소스에 연결하고 예상치 못한 피드에서의 해제를 방지하기 위해 패키지 소스 매핑을 사용하십시오.
nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="corp" value="https://nuget.corp.example/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="corp">
<package pattern="Company.*" />
<package pattern="Internal.Utilities" />
</packageSource>
</packageSourceMapping>
</configuration>
Java (Maven/Gradle)
Maven settings.xml (모든 것을 내부로 미러링; Enforcer를 통해 POM에서 임시 리포지토리 허용 금지):
<settings>
<mirrors>
<mirror>
<id>internal-mirror</id>
<mirrorOf>*</mirrorOf>
<url>https://maven.corp.example/repository/group</url>
</mirror>
</mirrors>
</settings>
Enforcer를 추가하여 POM에 선언된 리포지토리를 차단하고 미러 사용을 강제합니다:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>enforce-no-repositories</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireNoRepositories />
</rules>
</configuration>
</execution>
</executions>
</plugin>
Gradle: 의존성을 중앙 집중화하고 잠금.
settings.gradle(.kts)
에서만 리포지토리 강제 적용:
dependencyResolutionManagement {
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
maven { url = uri("https://maven.corp.example/repository/group") }
}
}
- 종속성 검증(체크섬/서명)을 활성화하고
gradle/verification-metadata.xml
을 커밋합니다.
Go Modules
공용 프록시와 체크섬 DB가 사용되지 않도록 개인 모듈을 구성합니다.
# Use corporate proxy first, then public proxy as fallback
export GOPROXY=https://goproxy.corp.example,https://proxy.golang.org
# Mark private paths to skip proxy and checksum db
export GOPRIVATE=*.corp.example.com,github.com/your-org/*
export GONOSUMDB=*.corp.example.com,github.com/your-org/*
Rust (Cargo)
승인된 내부 미러 또는 공급업체 디렉토리로 crates.io를 교체하여 빌드를 수행하고, 임의의 공개 대체를 허용하지 마십시오.
.cargo/config.toml
[source.crates-io]
replace-with = "corp-mirror"
[source.corp-mirror]
registry = "https://crates-mirror.corp.example/index"
게시를 위해 --registry
를 명시적으로 사용하고 자격 증명을 대상 레지스트리로 제한하십시오.
Ruby (Bundler)
소스 블록을 사용하고 다중 소스 Gemfile을 비활성화하여 gem이 의도된 리포지토리에서만 오도록 하십시오.
Gemfile
source "https://gems.corp.example"
source "https://rubygems.org" do
gem "rails"
gem "pg"
end
source "https://gems.corp.example" do
gem "company-logging"
end
구성 수준에서 시행:
bundle config set disable_multisource true
CI/CD 및 레지스트리 제어
- 단일 진입점으로서의 개인 레지스트리:
- 개발자/CI가 접근할 수 있는 유일한 엔드포인트로 Artifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifacts를 사용합니다.
- 내부 네임스페이스가 항상 업스트림 공개 소스에서 해결되지 않도록 차단/허용 규칙을 구현합니다.
- CI에서 잠금 파일은 불변입니다:
- npm:
package-lock.json
을 커밋하고,npm ci
를 사용합니다. - Yarn:
yarn.lock
을 커밋하고,yarn install --immutable
을 사용합니다. - Python: 해시된
requirements.txt
를 커밋하고,--require-hashes
를 강제합니다. - Gradle:
verification-metadata.xml
을 커밋하고, 알 수 없는 아티팩트에서 실패합니다. - 아웃바운드 이그레스 제어: 승인된 프록시를 통해서만 CI에서 공개 레지스트리에 직접 접근을 차단합니다.
- 이름 예약: 지원되는 공개 레지스트리에서 내부 이름/네임스페이스를 사전 등록합니다.
- 패키지 출처/증명: 공개 패키지를 게시할 때, 변조를 더 쉽게 감지할 수 있도록 출처/증명을 활성화합니다.
참고문헌
- https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610
- https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d
- https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping
- https://yarnpkg.com/configuration/yarnrc/
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.