Dependency Confusion
Reading time: 8 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Basic Information
Dependency Confusion (також відомий як атаки заміщення) відбувається, коли менеджер пакетів вирішує ім'я залежності з ненавмисного, менш надійного реєстру/джерела (зазвичай публічного реєстру) замість запланованого приватного/внутрішнього. Це зазвичай призводить до встановлення пакету, контрольованого зловмисником.
Загальні корінні причини:
- Typosquatting/помилки в написанні: Імпорт
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)
- Перерахувати імена:
- 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://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 Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.