mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/dependency-confusion.md'] to pl
This commit is contained in:
parent
8cd656bb33
commit
e2552b1eaa
@ -5,41 +5,268 @@
|
||||
|
||||
## Basic Information
|
||||
|
||||
W skrócie, luka w zależności z powodu pomyłki występuje, gdy projekt używa biblioteki o **błędnie napisanej** nazwie, **nieistniejącej** lub z **niesprecyzowaną wersją**, a używane repozytorium zależności pozwala na **zbieranie zaktualizowanych wersji z publicznych** repozytoriów.
|
||||
Dependency Confusion (znane również jako ataki substytucyjne) występuje, gdy menedżer pakietów rozwiązuje nazwę zależności z niezamierzonego, mniej zaufanego rejestru/źródła (zwykle publicznego rejestru) zamiast zamierzonego prywatnego/wewnętrznego. Zwykle prowadzi to do zainstalowania pakietu kontrolowanego przez atakującego.
|
||||
|
||||
Typowe przyczyny:
|
||||
- Typosquatting/błędne pisanie: Importowanie `reqests` zamiast `requests` (rozwiązuje z publicznego rejestru).
|
||||
- Nieistniejący/porzucony wewnętrzny pakiet: Importowanie `company-logging`, który już nie istnieje wewnętrznie, więc resolver szuka w publicznych rejestrach i znajduje pakiet atakującego.
|
||||
- Preferencje wersji w różnych rejestrach: Importowanie wewnętrznego `company-requests`, podczas gdy resolver ma również prawo do zapytań w publicznych rejestrach i preferuje „najlepszą” / nowszą wersję opublikowaną publicznie przez atakującego.
|
||||
|
||||
Kluczowa idea: Jeśli resolver może zobaczyć wiele rejestrów dla tej samej nazwy pakietu i ma prawo wybrać „najlepszego” kandydata globalnie, jesteś narażony, chyba że ograniczysz rozwiązywanie.
|
||||
|
||||
- **Błędnie napisana**: Import **`reqests`** zamiast `requests`
|
||||
- **Nieistniejąca**: Import `company-logging`, wewnętrznej biblioteki, która **już nie istnieje**
|
||||
- **Niesprecyzowana wersja**: Import **wewnętrznej** **istniejącej** biblioteki `company-requests`, ale repozytorium sprawdza **publiczne repozytoria**, aby zobaczyć, czy są **nowsze wersje**.
|
||||
|
||||
## Exploitation
|
||||
|
||||
> [!WARNING]
|
||||
> W każdym przypadku atakujący musi tylko opublikować **złośliwy pakiet o nazwie** bibliotek używanych przez firmę ofiary.
|
||||
> W każdym przypadku atakujący musi tylko opublikować złośliwy pakiet o tej samej nazwie, co zależność, którą twoja kompilacja rozwiązuje z publicznego rejestru. Hooki w czasie instalacji (np. skrypty npm) lub ścieżki kodu w czasie importu często dają możliwość wykonania kodu.
|
||||
|
||||
### Misspelled & Inexistent
|
||||
|
||||
Jeśli twoja firma próbuje **zaimportować bibliotekę, która nie jest wewnętrzna**, istnieje duże prawdopodobieństwo, że repozytorium bibliotek będzie jej szukać w **publicznych repozytoriach**. Jeśli atakujący ją stworzył, twój kod i działające maszyny prawdopodobnie zostaną skompromitowane.
|
||||
Jeśli twój projekt odnosi się do biblioteki, która nie jest dostępna w prywatnym rejestrze, a twoje narzędzia wracają do publicznego rejestru, atakujący może umieścić złośliwy pakiet o tej nazwie w publicznym rejestrze. Twoje maszyny wykonawcze/CI/deweloperskie pobiorą i wykonają go.
|
||||
|
||||
### Unspecified Version
|
||||
### Unspecified Version / “Best-version” selection across indexes
|
||||
|
||||
Programiści często pozostawiają wersje nieprzypisane lub pozwalają na szerokie zakresy. Gdy resolver jest skonfigurowany z zarówno wewnętrznymi, jak i publicznymi indeksami, może wybrać najnowszą wersję niezależnie od źródła. Dla wewnętrznych nazw, takich jak `requests-company`, jeśli wewnętrzny indeks ma `1.0.1`, ale atakujący publikuje `1.0.2` w publicznym rejestrze i twój resolver bierze pod uwagę obie, pakiet publiczny może wygrać.
|
||||
|
||||
Bardzo często programiści **nie określają żadnej wersji** używanej biblioteki lub określają tylko **główną wersję**. Wtedy interpreter spróbuje pobrać **najnowocześniejszą wersję** spełniającą te wymagania.\
|
||||
Jeśli biblioteka jest **znaną zewnętrzną biblioteką** (jak python `requests`), **atakujący nie może wiele zrobić**, ponieważ nie będzie w stanie stworzyć biblioteki o nazwie `requests` (chyba że jest jej oryginalnym autorem).\
|
||||
Jednak jeśli biblioteka jest **wewnętrzna**, jak `requests-company` w tym przykładzie, jeśli **repozytorium biblioteki** pozwala na **sprawdzanie nowych wersji również zewnętrznie**, będzie szukać nowszej wersji dostępnej publicznie.\
|
||||
Więc jeśli **atakujący wie**, że firma używa biblioteki `requests-company` **wersja 1.0.1** (pozwala na drobne aktualizacje). Może **opublikować** bibliotekę `requests-company` **wersja 1.0.2**, a firma **użyje tej biblioteki zamiast** wewnętrznej.
|
||||
|
||||
## AWS Fix
|
||||
|
||||
Ta luka została znaleziona w AWS **CodeArtifact** (przeczytaj [**szczegóły w tym poście na blogu**](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)).\
|
||||
AWS naprawiło to, pozwalając na określenie, czy biblioteka jest wewnętrzna czy zewnętrzna, aby uniknąć pobierania wewnętrznych zależności z zewnętrznych repozytoriów.
|
||||
Ta podatność została znaleziona w AWS CodeArtifact (przeczytaj szczegóły w tym poście na blogu). AWS dodało kontrole, aby oznaczyć zależności/źródła jako wewnętrzne lub zewnętrzne, aby klient nie pobierał „wewnętrznych” nazw z upstream publicznych rejestrów.
|
||||
|
||||
|
||||
## Finding Vulnerable Libraries
|
||||
|
||||
W [**oryginalnym poście o zależności z powodu pomyłki**](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610) autor przeszukał tysiące ujawnionych plików package.json zawierających zależności projektów javascript.
|
||||
W oryginalnym poście na temat zamieszania z zależnościami autor szukał tysięcy ujawnionych manifestów (np. `package.json`, `requirements.txt`, pliki blokady), aby wywnioskować wewnętrzne nazwy pakietów, a następnie publikował pakiety o wyższych wersjach w publicznych rejestrach.
|
||||
|
||||
## References
|
||||
|
||||
## 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 (e.g., `@company/*`, `company-*`, internal groupIds, NuGet ID patterns, private module paths for Go, etc.).
|
||||
- Check public registries for availability:
|
||||
- If the name is unregistered publicly, register it; if it exists, attempt subdependency hijacking by targeting internal transitive names.
|
||||
- Publish with precedence:
|
||||
- Choose a semver that “wins” (e.g., a very high version) or matches resolver rules.
|
||||
- Include minimal install-time execution where applicable (e.g., npm `preinstall`/`install`/`postinstall` scripts). For Python, prefer import-time execution paths, as wheels typically don’t execute arbitrary code on install.
|
||||
- Exfil control:
|
||||
- Ensure outbound is allowed from CI to your controlled endpoint; otherwise use DNS queries or error messages as a side-channel to prove code execution.
|
||||
|
||||
> [!CAUTION]
|
||||
> Always get written authorization, use unique package names/versions for the engagement, and immediately unpublish or coordinate cleanup when testing concludes.
|
||||
|
||||
|
||||
## Defender Playbook (what actually prevents confusion)
|
||||
|
||||
High-level strategies that work across ecosystems:
|
||||
- Use unique internal namespaces and bind them to a single registry.
|
||||
- Avoid mixing trust levels at resolution time. Prefer a single internal registry that proxies approved public packages instead of giving package managers both internal and public endpoints.
|
||||
- For managers that support it, map packages to specific sources (no global “best-version” across registries).
|
||||
- Pin and lock:
|
||||
- Use lockfiles that record the resolved registry URLs (npm/yarn/pnpm) or use hash/attestation pinning (pip `--require-hashes`, Gradle dependency verification).
|
||||
- Block public fallback for internal names at the registry/network layer.
|
||||
- Reserve your internal names in public registries when feasible to prevent future squat.
|
||||
|
||||
|
||||
## Ecosystem Notes and Secure Config Snippets
|
||||
|
||||
Below are pragmatic, minimal configs to reduce or eliminate dependency confusion. Prefer enforcing these in CI and developer environments.
|
||||
|
||||
### JavaScript/TypeScript (npm, Yarn, pnpm)
|
||||
|
||||
- Use scoped packages for all internal code and pin the scope to your private registry.
|
||||
- Keep installs immutable in 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 (dla wewnętrznego pakietu)
|
||||
```
|
||||
{
|
||||
"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:
|
||||
- Publikuj tylko wewnętrzne pakiety w obrębie zakresu `@company`.
|
||||
- W przypadku pakietów zewnętrznych, zezwól na publiczny rejestr za pośrednictwem swojego prywatnego proxy/lustra, a nie bezpośrednio z klientów.
|
||||
- Rozważ włączenie pochodzenia pakietów npm dla publicznych pakietów, które publikujesz, aby zwiększyć śledzenie (samo w sobie nie zapobiega pomieszaniu).
|
||||
|
||||
### Python (pip / Poetry)
|
||||
|
||||
Zasada podstawowa: Nie używaj `--extra-index-url`, aby mieszać poziomy zaufania. Albo:
|
||||
- Udostępnij jeden wewnętrzny indeks, który proxy i buforuje zatwierdzone pakiety PyPI, albo
|
||||
- Użyj jawnego wyboru indeksu i przypinania haszy.
|
||||
|
||||
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
|
||||
```
|
||||
Wygeneruj zhaszowane wymagania za pomocą pip-tools:
|
||||
```
|
||||
# From pyproject.toml or requirements.in
|
||||
pip-compile --generate-hashes -o requirements.txt
|
||||
pip install --require-hashes -r requirements.txt
|
||||
```
|
||||
Jeśli musisz uzyskać dostęp do publicznego PyPI, zrób to przez swój wewnętrzny proxy i utrzymuj tam wyraźną listę dozwolonych źródeł. Unikaj `--extra-index-url` w CI.
|
||||
|
||||
### .NET (NuGet)
|
||||
|
||||
Użyj mapowania źródeł pakietów, aby powiązać wzorce identyfikatorów pakietów z wyraźnymi źródłami i zapobiec rozwiązywaniu z nieoczekiwanych źródeł.
|
||||
|
||||
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 (lustro wszystko do wewnętrznego; zabroń repozytoriów ad-hoc w POM-ach za pomocą Enforcer):
|
||||
```
|
||||
<settings>
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>internal-mirror</id>
|
||||
<mirrorOf>*</mirrorOf>
|
||||
<url>https://maven.corp.example/repository/group</url>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
</settings>
|
||||
```
|
||||
Dodaj Enforcer, aby zablokować repozytoria zadeklarowane w POM-ach i wymusić użycie swojego lustra:
|
||||
```
|
||||
<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: Centralizuj i zablokuj zależności.
|
||||
- Wymuszaj repozytoria tylko w `settings.gradle(.kts)`:
|
||||
```
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
|
||||
repositories {
|
||||
maven { url = uri("https://maven.corp.example/repository/group") }
|
||||
}
|
||||
}
|
||||
```
|
||||
- Włącz weryfikację zależności (sumy kontrolne/podpisy) i zatwierdź `gradle/verification-metadata.xml`.
|
||||
|
||||
### Go Modules
|
||||
|
||||
Skonfiguruj prywatne moduły, aby publiczny proxy i baza danych sum kontrolnych nie były używane dla nich.
|
||||
```
|
||||
# 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)
|
||||
|
||||
Zastąp crates.io zatwierdzonym wewnętrznym lustrem lub katalogiem dostawcy dla kompilacji; nie zezwalaj na dowolne publiczne zapasowe źródło.
|
||||
|
||||
.cargo/config.toml
|
||||
```
|
||||
[source.crates-io]
|
||||
replace-with = "corp-mirror"
|
||||
|
||||
[source.corp-mirror]
|
||||
registry = "https://crates-mirror.corp.example/index"
|
||||
```
|
||||
Aby opublikować, bądź dokładny z `--registry` i ogranicz dane uwierzytelniające do docelowego rejestru.
|
||||
|
||||
### Ruby (Bundler)
|
||||
|
||||
Użyj bloków źródłowych i wyłącz multisource Gemfiles, aby gemy pochodziły tylko z zamierzonego repozytorium.
|
||||
|
||||
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
|
||||
```
|
||||
Wymuś na poziomie konfiguracji:
|
||||
```
|
||||
bundle config set disable_multisource true
|
||||
```
|
||||
## CI/CD i Kontrole Rejestru, Które Pomagają
|
||||
|
||||
- Prywatny rejestr jako pojedynczy punkt dostępu:
|
||||
- Użyj Artifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifacts jako jedynego punktu, do którego mogą uzyskać dostęp deweloperzy/CI.
|
||||
- Wprowadź zasady blokowania/zezwalania, aby wewnętrzne przestrzenie nazw nigdy nie były rozwiązywane z publicznych źródeł upstream.
|
||||
- Pliki blokad są niemutowalne w CI:
|
||||
- npm: zatwierdź `package-lock.json`, użyj `npm ci`.
|
||||
- Yarn: zatwierdź `yarn.lock`, użyj `yarn install --immutable`.
|
||||
- Python: zatwierdź haszowany `requirements.txt`, wymuś `--require-hashes`.
|
||||
- Gradle: zatwierdź `verification-metadata.xml` i niepowodzenie w przypadku nieznanych artefaktów.
|
||||
- Kontrola wychodzącego ruchu: zablokuj bezpośredni dostęp z CI do publicznych rejestrów, z wyjątkiem zatwierdzonego proxy.
|
||||
- Rezerwacja nazw: wstępnie zarejestruj swoje wewnętrzne nazwy/przestrzenie nazw w publicznych rejestrach, gdzie to możliwe.
|
||||
- Pochodzenie pakietów / zaświadczenia: podczas publikowania publicznych pakietów włącz pochodzenie/zaświadczenia, aby uczynić manipulacje bardziej wykrywalnymi w dalszej kolejności.
|
||||
|
||||
## Odniesienia
|
||||
|
||||
- [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}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user