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 uk
This commit is contained in:
parent
ca67b7b1a2
commit
9179ebcf66
@ -1,45 +1,272 @@
|
|||||||
# Змішування залежностей
|
# Dependency Confusion
|
||||||
|
|
||||||
{{#include ../banners/hacktricks-training.md}}
|
{{#include ../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
|
|
||||||
## Основна інформація
|
## Basic Information
|
||||||
|
|
||||||
У підсумку, вразливість змішування залежностей виникає, коли проект використовує бібліотеку з **неправильно написаною** назвою, **неіснуючою** або з **непозначеною версією**, а використовуваний репозиторій залежностей дозволяє **збирати оновлені версії з публічних** репозиторіїв.
|
Dependency Confusion (також відомий як атаки заміщення) відбувається, коли менеджер пакетів вирішує ім'я залежності з ненавмисного, менш надійного реєстру/джерела (зазвичай публічного реєстру) замість запланованого приватного/внутрішнього. Це зазвичай призводить до встановлення пакету, контрольованого зловмисником.
|
||||||
|
|
||||||
- **Неправильно написана**: Імпорт **`reqests`** замість `requests`
|
Загальні корінні причини:
|
||||||
- **Неіснуюча**: Імпорт `company-logging`, внутрішньої бібліотеки, яка **більше не існує**
|
- Typosquatting/помилки в написанні: Імпорт `reqests` замість `requests` (вирішується з публічного реєстру).
|
||||||
- **Непозначена версія**: Імпорт **внутрішньої** **існуючої** бібліотеки `company-requests`, але репозиторій перевіряє **публічні репозиторії**, щоб дізнатися, чи є **новіші версії**.
|
- Неіснуючий/покинутий внутрішній пакет: Імпорт `company-logging`, який більше не існує внутрішньо, тому резольвер шукає в публічних реєстрах і знаходить пакет зловмисника.
|
||||||
|
- Перевага версій серед кількох реєстрів: Імпорт внутрішнього `company-requests`, тоді як резольвер може також запитувати публічні реєстри і віддає перевагу "найкращій"/новішій версії, опублікованій публічно зловмисником.
|
||||||
|
|
||||||
## Експлуатація
|
Ключова ідея: Якщо резольвер може бачити кілька реєстрів для одного й того ж імені пакету і має право вибрати "найкращого" кандидата глобально, ви вразливі, якщо не обмежите резолюцію.
|
||||||
|
|
||||||
|
|
||||||
|
## Exploitation
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> У всіх випадках зловмиснику просто потрібно опублікувати **шкідливий пакет з назвою** бібліотек, які використовує компанія-жертва.
|
> У всіх випадках зловмиснику потрібно лише опублікувати шкідливий пакет з таким же ім'ям, як залежність, яку ваш збірник вирішує з публічного реєстру. Хуки під час установки (наприклад, npm скрипти) або кодові шляхи під час імпорту часто дають можливість виконання коду.
|
||||||
|
|
||||||
### Неправильно написані та неіснуючі
|
### Misspelled & Inexistent
|
||||||
|
|
||||||
Якщо ваша компанія намагається **імпортувати бібліотеку, яка не є внутрішньою**, ймовірно, репозиторій бібліотек буде шукати її в **публічних репозиторіях**. Якщо зловмисник створив її, ваш код і машини, що працюють, ймовірно, будуть скомпрометовані.
|
Якщо ваш проект посилається на бібліотеку, яка недоступна в приватному реєстрі, і ваші інструменти повертаються до публічного реєстру, зловмисник може створити шкідливий пакет з цим ім'ям у публічному реєстрі. Ваші виконавці/CI/розробницькі машини отримають і виконають його.
|
||||||
|
|
||||||
### Непозначена версія
|
### Unspecified Version / “Best-version” selection across indexes
|
||||||
|
|
||||||
Досить поширено, що розробники **не вказують жодну версію** використовуваної бібліотеки або вказують лише **основну версію**. Тоді інтерпретатор спробує завантажити **остання версію**, що відповідає цим вимогам.\
|
Розробники часто залишають версії неприкріпленими або дозволяють широкі діапазони. Коли резольвер налаштований з обома внутрішніми та публічними індексами, він може вибрати найновішу версію незалежно від джерела. Для внутрішніх імен, таких як `requests-company`, якщо внутрішній індекс має `1.0.1`, але зловмисник публікує `1.0.2` у публічному реєстрі, а ваш резольвер розглядає обидва, публічний пакет може виграти.
|
||||||
Якщо бібліотека є **відомою зовнішньою бібліотекою** (такою як python `requests`), зловмисник **не може багато зробити**, оскільки він не зможе створити бібліотеку під назвою `requests` (якщо він не є оригінальним автором).\
|
|
||||||
Однак, якщо бібліотека є **внутрішньою**, як `requests-company` в цьому прикладі, якщо **репозиторій бібліотеки** дозволяє **перевіряти нові версії також зовні**, він буде шукати новішу версію, доступну публічно.\
|
|
||||||
Отже, якщо **зловмисник знає**, що компанія використовує бібліотеку `requests-company` **версії 1.0.1** (дозволяє незначні оновлення). Він може **опублікувати** бібліотеку `requests-company` **версії 1.0.2**, і компанія буде **використовувати цю бібліотеку замість** внутрішньої.
|
|
||||||
|
|
||||||
## Виправлення AWS
|
|
||||||
|
|
||||||
Цю вразливість було виявлено в AWS **CodeArtifact** (читайте [**деталі в цьому блозі**](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)).\
|
## AWS Fix
|
||||||
AWS виправив це, дозволивши вказувати, чи є бібліотека внутрішньою чи зовнішньою, щоб уникнути завантаження внутрішніх залежностей з зовнішніх репозиторіїв.
|
|
||||||
|
|
||||||
## Пошук вразливих бібліотек
|
Цю вразливість було виявлено в AWS CodeArtifact (читайте деталі в цьому блозі). AWS додав контролі, щоб позначити залежності/канали як внутрішні або зовнішні, щоб клієнт не отримував "внутрішні" імена з верхніх публічних реєстрів.
|
||||||
|
|
||||||
У [**оригінальному пості про змішування залежностей**](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610) автор шукав тисячі відкритих файлів package.json, що містять залежності проектів на javascript.
|
|
||||||
|
## Finding Vulnerable Libraries
|
||||||
|
|
||||||
|
У початковому пості про плутанину залежностей автор шукав тисячі відкритих маніфестів (наприклад, `package.json`, `requirements.txt`, lockfiles), щоб вивести внутрішні імена пакетів, а потім опублікував пакети з вищими версіями в публічних реєстрах.
|
||||||
|
|
||||||
|
|
||||||
|
## Practical Attacker Playbook (for red teams in authorized tests)
|
||||||
|
|
||||||
|
- Перерахувати імена:
|
||||||
|
- Grep репозиторії та CI конфігурації на наявність маніфестів/lock файлів та внутрішніх просторових імен.
|
||||||
|
- Шукати специфічні префікси організації (наприклад, `@company/*`, `company-*`, внутрішні groupIds, шаблони ID NuGet, приватні шляхи модулів для Go тощо).
|
||||||
|
- Перевірити публічні реєстри на наявність:
|
||||||
|
- Якщо ім'я не зареєстроване публічно, зареєструйте його; якщо воно існує, спробуйте захоплення підзалежностей, націлюючись на внутрішні транзитивні імена.
|
||||||
|
- Публікувати з перевагою:
|
||||||
|
- Виберіть semver, який "виграє" (наприклад, дуже висока версія) або відповідає правилам резольвера.
|
||||||
|
- Включити мінімальне виконання під час установки, де це можливо (наприклад, npm `preinstall`/`install`/`postinstall` скрипти). Для Python надавайте перевагу шляхам виконання під час імпорту, оскільки колеса зазвичай не виконують довільний код під час установки.
|
||||||
|
- Експортувати контроль:
|
||||||
|
- Переконайтеся, що вихідні запити дозволені з CI до вашої контрольованої точки; в іншому випадку використовуйте DNS запити або повідомлення про помилки як бічний канал для підтвердження виконання коду.
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> Завжди отримуйте письмову авторизацію, використовуйте унікальні імена/версії пакетів для залучення, і негайно знімайте або координуйте очищення, коли тестування завершується.
|
||||||
|
|
||||||
|
|
||||||
|
## Defender Playbook (what actually prevents confusion)
|
||||||
|
|
||||||
|
Стратегії високого рівня, які працюють у різних екосистемах:
|
||||||
|
- Використовуйте унікальні внутрішні просторові імена та прив'язуйте їх до одного реєстру.
|
||||||
|
- Уникайте змішування рівнів довіри під час резолюції. Віддавайте перевагу одному внутрішньому реєстру, який проксірує затверджені публічні пакети, замість того, щоб надавати менеджерам пакетів як внутрішні, так і публічні кінцеві точки.
|
||||||
|
- Для менеджерів, які це підтримують, відображайте пакети на конкретні джерела (без глобальної "найкращої версії" серед реєстрів).
|
||||||
|
- Закріплюйте та блокуйте:
|
||||||
|
- Використовуйте lockfiles, які записують 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, робіть це через ваш внутрішній проксі та підтримуйте явний список дозволених джерел. Уникайте `--extra-index-url` у CI.
|
||||||
|
|
||||||
|
### .NET (NuGet)
|
||||||
|
|
||||||
|
Використовуйте Mapping джерел пакетів, щоб прив'язати шаблони 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 (дзеркалити все на внутрішнє; заборонити ad-hoc репозиторії в POM через Enforcer):
|
||||||
|
```
|
||||||
|
<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
|
||||||
|
|
||||||
|
Налаштуйте приватні модулі так, щоб публічний проксі та база даних контрольних сум не використовувалися для них.
|
||||||
|
```
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
Використовуйте блоки джерел і вимкніть багатоджерельні Gemfiles, щоб гемы надходили лише з призначеного репозиторію.
|
||||||
|
|
||||||
|
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 та контроль реєстрів, які допомагають
|
||||||
|
|
||||||
|
- Приватний реєстр як єдиний вхід:
|
||||||
|
- Використовуйте Artifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifacts як єдину точку доступу для розробників/CI.
|
||||||
|
- Реалізуйте правила блокування/дозволу, щоб внутрішні простори імен ніколи не розв'язувалися з публічних джерел.
|
||||||
|
- Lockfiles є незмінними в 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://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610)
|
- [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://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}}
|
{{#include ../banners/hacktricks-training.md}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user