Dependency Confusion
Reading time: 9 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Basic Information
Dependency Confusion (poznat i kao napadi zamene) se dešava kada menadžer paketa rešava ime zavisnosti iz nepredviđene, manje pouzdane registracije/izvora (obično javne registracije) umesto iz predviđene privatne/interni. Ovo obično dovodi do instalacije paketa koji kontroliše napadač.
Uobičajeni uzroci:
- Typosquatting/pravopisne greške: Uvoz
reqests
umestorequests
(rešava iz javne registracije). - Nepostojeći/napušteni interni paket: Uvoz
company-logging
koji više ne postoji interno, pa resolver gleda u javne registracije i pronalazi paket napadača. - Preferencija verzije preko više registrija: Uvoz internog
company-requests
dok resolver može da pretražuje javne registracije i preferira “najbolju”/noviju verziju koju je objavio napadač.
Ključna ideja: Ako resolver može da vidi više registrija za isto ime paketa i dozvoljeno mu je da izabere “najboljeg” kandidata globalno, ranjivi ste osim ako ne ograničite rešavanje.
Exploitation
warning
U svim slučajevima, napadaču je potrebno samo da objavi zlonameran paket sa istim imenom kao zavisnost koju vaša izgradnja rešava iz javne registracije. Hooks u vreme instalacije (npr. npm skripte) ili putanje koda u vreme uvoza često omogućavaju izvršavanje koda.
Misspelled & Inexistent
Ako vaš projekat referencira biblioteku koja nije dostupna u privatnoj registraciji, i vaši alati se vraćaju na javnu registraciju, napadač može da postavi zlonameran paket sa tim imenom u javnoj registraciji. Vaši runneri/CI/dev mašine će ga preuzeti i izvršiti.
Unspecified Version / “Best-version” selection across indexes
Programeri često ostavljaju verzije neodređene ili dozvoljavaju široke opsege. Kada je resolver konfiguran sa internim i javnim indeksima, može izabrati najnoviju verziju bez obzira na izvor. Za interna imena kao što je requests-company
, ako interni indeks ima 1.0.1
ali napadač objavi 1.0.2
u javnoj registraciji i vaš resolver uzima u obzir oboje, javni paket može pobediti.
AWS Fix
Ova ranjivost je pronađena u AWS CodeArtifact (pročitajte detalje u ovom blog postu). AWS je dodao kontrole da označi zavisnosti/izvore kao interne ili eksterne tako da klijent neće preuzimati “interno” imena iz uzvodnih javnih registracija.
Finding Vulnerable Libraries
U originalnom postu o konfuziji zavisnosti, autor je tražio hiljade izloženih manifestacija (npr. package.json
, requirements.txt
, lockfiles) da bi inferirao interna imena paketa i zatim objavio pakete sa višim verzijama u javnim registracijama.
Practical Attacker Playbook (for red teams in authorized tests)
- Enumerate names:
- Grep repos and CI configs for manifest/lock files and internal namespaces.
- Look for organization-specific prefixes (npr.
@company/*
,company-*
, interni groupIds, NuGet ID obrasci, privatne putanje modula za Go, itd.). - Check public registries for availability:
- Ako ime nije registrovano javno, registrujte ga; ako postoji, pokušajte sa otmicom subzavisnosti ciljanjem internih tranzitivnih imena.
- Publish with precedence:
- Izaberite semver koji “pobeđuje” (npr. veoma visoka verzija) ili se poklapa sa pravilima resolvera.
- Uključite minimalno izvršavanje u vreme instalacije gde je primenljivo (npr. npm
preinstall
/install
/postinstall
skripte). Za Python, preferirajte putanje izvršavanja u vreme uvoza, jer točkići obično ne izvršavaju proizvoljan kod prilikom instalacije. - Exfil control:
- Osigurajte da je izlaz dozvoljen iz CI ka vašem kontrolisanom kraju; inače koristite DNS upite ili poruke o grešci kao bočni kanal za dokazivanje izvršavanja koda.
caution
Uvek dobijte pisanu autorizaciju, koristite jedinstvena imena paketa/verzije za angažovanje, i odmah povucite ili koordinirajte čišćenje kada testiranje završi.
Defender Playbook (what actually prevents confusion)
Visok nivo strategija koje funkcionišu širom ekosistema:
- Koristite jedinstvene interne prostore imena i povežite ih sa jednom registracijom.
- Izbegavajte mešanje nivoa poverenja u vreme rešavanja. Preferirajte jednu internu registraciju koja proksira odobrene javne pakete umesto da dajete menadžerima paketa i interne i javne krajnje tačke.
- Za menadžere koji to podržavaju, mapirajte pakete na specifične izvore (bez globalne “najbolje verzije” preko registrija).
- Pin and lock:
- Koristite lockfiles koji beleže rešene URL-ove registracija (npm/yarn/pnpm) ili koristite hash/attestation pinning (pip
--require-hashes
, Gradle verifikacija zavisnosti). - Blokirajte javno vraćanje za interna imena na registracionom/mrežnom sloju.
- Rezervišite svoja interna imena u javnim registracijama kada je to moguće da biste sprečili buduće squat.
Ecosystem Notes and Secure Config Snippets
Ispod su pragmatične, minimalne konfiguracije za smanjenje ili eliminisanje konfuzije zavisnosti. Preferirajte primenu ovih u CI i razvojnim okruženjima.
JavaScript/TypeScript (npm, Yarn, pnpm)
- Koristite skopirane pakete za sav interni kod i pinujte sklop na vašu privatnu registraciju.
- Održavajte instalacije nepromenljive u CI (npm lockfile,
yarn install --immutable
).
.npmrc (project-level)
# 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 (za internu paket)
{
"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
Operational tips:
- Objavite samo interne pakete unutar
@company
opsega. - Za pakete trećih strana, dozvolite javni registar putem vašeg privatnog proksija/ogledala, ne direktno od klijenata.
- Razmotrite omogućavanje npm paketa porekla za javne pakete koje objavljujete kako biste povećali traganje (to samo po sebi ne sprečava konfuziju).
Python (pip / Poetry)
Osnovno pravilo: Ne koristite --extra-index-url
za mešanje nivoa poverenja. Ili:
- Izložite jedan interni indeks koji proksira i kešira odobrene PyPI pakete, ili
- Koristite eksplicitnu selekciju indeksa i pinovanje heša.
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
Generišite heširane zahteve pomoću pip-tools:
# From pyproject.toml or requirements.in
pip-compile --generate-hashes -o requirements.txt
pip install --require-hashes -r requirements.txt
Ako morate da pristupite javnom PyPI, učinite to putem vašeg internog proksija i održavajte eksplicitnu dozvoljenu listu tamo. Izbegavajte --extra-index-url
u CI.
.NET (NuGet)
Koristite Mapiranje Izvora Paketa da povežete obrasce ID-a paketa sa eksplicitnim izvorima i sprečite rešavanje iz neočekivanih izvora.
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 (ogledalo sve na interno; zabraniti ad-hoc repozitorijume u POM-ima putem Enforcer):
<settings>
<mirrors>
<mirror>
<id>internal-mirror</id>
<mirrorOf>*</mirrorOf>
<url>https://maven.corp.example/repository/group</url>
</mirror>
</mirrors>
</settings>
Dodajte Enforcer da zabranite repozitorijume deklarisane u POM-ovima i primorate korišćenje vašeg ogledala:
<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: Centralizujte i zaključajte zavisnosti.
- Primorajte repozitorijume u
settings.gradle(.kts)
samo:
dependencyResolutionManagement {
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
maven { url = uri("https://maven.corp.example/repository/group") }
}
}
- Omogućite verifikaciju zavisnosti (provere kontrolnih suma/potpisivanja) i sačuvajte
gradle/verification-metadata.xml
.
Go Moduli
Konfigurišite privatne module tako da se javni proxy i baza podataka kontrolnih suma ne koriste za njih.
# 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)
Zamenite crates.io sa odobrenim internim ogledalom ili direktorijumom dobavljača za gradnje; ne dozvolite proizvoljno javno vraćanje.
.cargo/config.toml
[source.crates-io]
replace-with = "corp-mirror"
[source.corp-mirror]
registry = "https://crates-mirror.corp.example/index"
Za objavljivanje, budite eksplicitni sa --registry
i zadržite akreditive ograničene na ciljni registar.
Ruby (Bundler)
Koristite blokove izvora i onemogućite multisource Gemfile-ove tako da gemovi dolaze samo iz nameravane biblioteke.
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
Sprovodite na nivou konfiguracije:
bundle config set disable_multisource true
CI/CD i kontrole registra koje pomažu
- Privatni registar kao jedini ulaz:
- Koristite Artifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifacts kao jedinu tačku koju developeri/CI mogu da dostignu.
- Implementirajte pravila blokiranja/dozvoljavanja tako da interni prostori imena nikada ne budu rešeni iz javnih izvora.
- Lockfajlovi su nepromenljivi u CI:
- npm: komitujte
package-lock.json
, koristitenpm ci
. - Yarn: komitujte
yarn.lock
, koristiteyarn install --immutable
. - Python: komitujte heširani
requirements.txt
, primenite--require-hashes
. - Gradle: komitujte
verification-metadata.xml
i ne uspevajte na nepoznatim artefaktima. - Kontrola izlaznog saobraćaja: blokirajte direktan pristup iz CI ka javnim registrima osim putem odobrenog proksija.
- Rezervacija imena: unapred registrujte svoja interna imena/prostore imena u javnim registrima gde je to podržano.
- Poreklo paketa / potvrde: kada objavljujete javne pakete, omogućite poreklo/potvrde kako biste učinili prepravke uočljivijim nizvodno.
Reference
- 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
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.