mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
275 lines
12 KiB
Markdown
275 lines
12 KiB
Markdown
# Dependency Confusion
|
|
|
|
{{#include ../banners/hacktricks-training.md}}
|
|
|
|
|
|
## 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` umesto `requests` (rešava iz javne registracije).
|
|
- Nepostojeći/napušteni interni paket: Uvoz `company-logging` koji više ne postoji interno, pa resolver traži u javnim registracijama i pronalazi paket napadača.
|
|
- Preferencija verzije među više registracija: 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 registracija 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 odlazni saobraćaj 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/ verzije paketa 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” među registracijama).
|
|
- Pin and lock:
|
|
- Koristite lockfiles koji beleže URL-ove rešene registracije (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, a 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 hash pinovanje.
|
|
|
|
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 izgradnje; 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 unutrašnji prostori imena nikada ne budu rešeni iz javnih izvora.
|
|
- Lockfajlovi su nepromenljivi u CI:
|
|
- npm: komitujte `package-lock.json`, koristite `npm ci`.
|
|
- Yarn: komitujte `yarn.lock`, koristite `yarn 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 unutrašnja 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 da je manipulacija lakše uočljiva nizvodno.
|
|
|
|
|
|
## Reference
|
|
|
|
- [https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610)
|
|
- [https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)
|
|
- [https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping](https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping)
|
|
- [https://yarnpkg.com/configuration/yarnrc/](https://yarnpkg.com/configuration/yarnrc/)
|
|
|
|
|
|
{{#include ../banners/hacktricks-training.md}}
|