diff --git a/src/pentesting-web/dependency-confusion.md b/src/pentesting-web/dependency-confusion.md index 9a4b94597..6fe9160fc 100644 --- a/src/pentesting-web/dependency-confusion.md +++ b/src/pentesting-web/dependency-confusion.md @@ -1,45 +1,272 @@ -# Змішування залежностей +# Dependency Confusion {{#include ../banners/hacktricks-training.md}} -## Основна інформація +## Basic Information -У підсумку, вразливість змішування залежностей виникає, коли проект використовує бібліотеку з **неправильно написаною** назвою, **неіснуючою** або з **непозначеною версією**, а використовуваний репозиторій залежностей дозволяє **збирати оновлені версії з публічних** репозиторіїв. +Dependency Confusion (також відомий як атаки заміщення) відбувається, коли менеджер пакетів вирішує ім'я залежності з ненавмисного, менш надійного реєстру/джерела (зазвичай публічного реєстру) замість запланованого приватного/внутрішнього. Це зазвичай призводить до встановлення пакету, контрольованого зловмисником. -- **Неправильно написана**: Імпорт **`reqests`** замість `requests` -- **Неіснуюча**: Імпорт `company-logging`, внутрішньої бібліотеки, яка **більше не існує** -- **Непозначена версія**: Імпорт **внутрішньої** **існуючої** бібліотеки `company-requests`, але репозиторій перевіряє **публічні репозиторії**, щоб дізнатися, чи є **новіші версії**. +Загальні корінні причини: +- Typosquatting/помилки в написанні: Імпорт `reqests` замість `requests` (вирішується з публічного реєстру). +- Неіснуючий/покинутий внутрішній пакет: Імпорт `company-logging`, який більше не існує внутрішньо, тому резольвер шукає в публічних реєстрах і знаходить пакет зловмисника. +- Перевага версій серед кількох реєстрів: Імпорт внутрішнього `company-requests`, тоді як резольвер може також запитувати публічні реєстри і віддає перевагу "найкращій"/новішій версії, опублікованій публічно зловмисником. -## Експлуатація +Ключова ідея: Якщо резольвер може бачити кілька реєстрів для одного й того ж імені пакету і має право вибрати "найкращого" кандидата глобально, ви вразливі, якщо не обмежите резолюцію. + + +## Exploitation > [!WARNING] -> У всіх випадках зловмиснику просто потрібно опублікувати **шкідливий пакет з назвою** бібліотек, які використовує компанія-жертва. +> У всіх випадках зловмиснику потрібно лише опублікувати шкідливий пакет з таким же ім'ям, як залежність, яку ваш збірник вирішує з публічного реєстру. Хуки під час установки (наприклад, npm скрипти) або кодові шляхи під час імпорту часто дають можливість виконання коду. -### Неправильно написані та неіснуючі +### Misspelled & Inexistent -Якщо ваша компанія намагається **імпортувати бібліотеку, яка не є внутрішньою**, ймовірно, репозиторій бібліотек буде шукати її в **публічних репозиторіях**. Якщо зловмисник створив її, ваш код і машини, що працюють, ймовірно, будуть скомпрометовані. +Якщо ваш проект посилається на бібліотеку, яка недоступна в приватному реєстрі, і ваші інструменти повертаються до публічного реєстру, зловмисник може створити шкідливий пакет з цим ім'ям у публічному реєстрі. Ваші виконавці/CI/розробницькі машини отримають і виконають його. -### Непозначена версія +### Unspecified Version / “Best-version” selection across indexes -Досить поширено, що розробники **не вказують жодну версію** використовуваної бібліотеки або вказують лише **основну версію**. Тоді інтерпретатор спробує завантажити **остання версію**, що відповідає цим вимогам.\ -Якщо бібліотека є **відомою зовнішньою бібліотекою** (такою як python `requests`), зловмисник **не може багато зробити**, оскільки він не зможе створити бібліотеку під назвою `requests` (якщо він не є оригінальним автором).\ -Однак, якщо бібліотека є **внутрішньою**, як `requests-company` в цьому прикладі, якщо **репозиторій бібліотеки** дозволяє **перевіряти нові версії також зовні**, він буде шукати новішу версію, доступну публічно.\ -Отже, якщо **зловмисник знає**, що компанія використовує бібліотеку `requests-company` **версії 1.0.1** (дозволяє незначні оновлення). Він може **опублікувати** бібліотеку `requests-company` **версії 1.0.2**, і компанія буде **використовувати цю бібліотеку замість** внутрішньої. +Розробники часто залишають версії неприкріпленими або дозволяють широкі діапазони. Коли резольвер налаштований з обома внутрішніми та публічними індексами, він може вибрати найновішу версію незалежно від джерела. Для внутрішніх імен, таких як `requests-company`, якщо внутрішній індекс має `1.0.1`, але зловмисник публікує `1.0.2` у публічному реєстрі, а ваш резольвер розглядає обидва, публічний пакет може виграти. -## Виправлення AWS -Цю вразливість було виявлено в AWS **CodeArtifact** (читайте [**деталі в цьому блозі**](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)).\ -AWS виправив це, дозволивши вказувати, чи є бібліотека внутрішньою чи зовнішньою, щоб уникнути завантаження внутрішніх залежностей з зовнішніх репозиторіїв. +## AWS Fix -## Пошук вразливих бібліотек +Цю вразливість було виявлено в 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 +``` + + + + + + + + + + + + + + + + + +``` +### Java (Maven/Gradle) + +Maven settings.xml (дзеркалити все на внутрішнє; заборонити ad-hoc репозиторії в POM через Enforcer): +``` + + + +internal-mirror +* +https://maven.corp.example/repository/group + + + +``` +Додайте Enforcer, щоб заборонити репозиторії, оголошені в POM, і примусити використовувати ваше дзеркало: +``` + +org.apache.maven.plugins +maven-enforcer-plugin +3.6.1 + + +enforce-no-repositories +enforce + + + + + + + + +``` +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://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}}