Dependency Management

Cards (32)

  • Dependencies:
    • These libraries and SDKs are called dependencies since our application depends on them. While dependencies make our lives a lot easier, they have to be securely managed since they now form part of the overall attack surface of the application.
  • Dependency Management: We perform dependency management for several reasons:
    • Knowing what dependencies our application uses can allow us to support it better.
    • We often want to version lock dependencies to improve the stability of our application since newer versions may add new features or deprecate features that our application actively uses.
    • We can build golden images that already have all our dependencies installed, meaning we can perform faster deployment cycles.
  • Dependency Management: We perform dependency management for several reasons:
    • When new developers are onboarded, we can help them set up their development machine by installing all the required dependencies.
    • We can monitor the dependencies we use for security issues to ensure that dependencies are upgraded with the security fixes as needed.
  • Dependency Manager:
    • This allows the organisation to manage all of their dependencies from a central location and allows dependency management to be integrated into our DevOps pipeline. Build servers and agents can make requests to the dependency manager to be provided with dependencies when the application is being built or deployed.
  • External Dependencies
    An external dependency is one that has been developed and maintained outside of our organisation. Usually, these dependencies are publicly available (some are free, but some can be paid for SDKs). Some examples of popular external dependencies include:
    • Any Python pip package that you install from the PyPi public repositories.
    • JQuery and any other publicly available Node Package Manager (NPM) libraries, such as VueJS or NodeJS.
    • Paid for SDKs such as Google's ReCaptcha SDK that can be used to integrate captchas into your application.
  • Internal Dependencies
    An internal dependency is developed by someone in our organisation. These are usually only used by applications that we develop internally. Some examples of internal dependencies include:
    • An authentication library that standardises the authentication processes of all our internally developed applications.
    • A data-source connection library that provides applications with various techniques to connect to different data sources.
    • A message translation library that can convert application messages from a specific format to one that a different internal application can read.
  • Internal Dependencies:
    • Internal dependencies are usually created to standardise an internal process and ensure that we don't have to reinvent the wheel every time we want that same feature in another application. Since we develop these dependencies ourselves, we, as an organisation, are responsible for maintaining these dependencies.
  • Public CVEs
    • Vulnerabilities will be publicly disclosed, usually as a Common Vulnerabilities and Exposures (CVE), once the developers have created a patch.
    • As such, we must react as soon as possible and patch our dependency.
  • Public CVEs:
    • We may have version locked a dependency for the stability of our application. So upgrading to a new version means we will first have to determine whether such an upgrade could cause instability. The problem gets even worse when you start to talk about dependencies of dependencies. It is perhaps not the SDK that you are using that is vulnerable, but a dependency of the SDK, that is. Since that dependency has to be updated, we will also now need to update our SDK.
  • Supply Chain Attacks
    • Even if dependencies do not have any vulnerabilities and are kept up to date, they can still be leveraged to attack systems and services.
    • Instead of trying to attack the application directly, which has been hardened, an attacker instead targets one of the dependencies of the application, which may have been created by a smaller team that does not have such a large security budget. These indirect attack methods are called supply chain attacks.
  • Supply Chain Attack E.g:
    • Compromising the payment portal of British Airways' online portal led to the compromise of credit cards of customers and a fine for BA of 230 million dollars.
    • Compromising more than 100000 customers' credit cards by embedding skimmers in various payment portals of various applications.
    • Compromising more than 10000 AWS S3 buckets and embedding malware in any JavaScript found in these buckets.
  • Supply Chain Attacks:
    • There are several ways to compromise dependencies, but by far, the most common is when dependencies are insecurely hosted, allowing an attacker to alter the dependency. This could be, for example, an S3 bucket that has world-writeable permissions configured. An attacker could abuse these permissions to overwrite the hosted dependency with malicious code.
  • S3 Hosting Dependencies:
    • A quick way to see if the team perhaps misconfigured the S3 bucket to grant world-writeable permissions would be to try a simple PUT request:
    • curl -X PUT http://cdn.tryhackme.loc:9444/libraries/test.js -d "Testing world-writeable permissions"
    • Modifying a dependency, to be a credential skimmer and send us the credentials from an auth form
  • Overwriting Dependencies: Prevention:
    • Make sure to update and patch dependencies on a regular basis. This would include emergency patching of dependencies if a sufficiently serious vulnerability was discovered.
    • Dependencies can sometimes be copied and hosted internally. This will reduce the attack surface.
    • Sub-resource Integrity can be used to prevent tampered JS libraries from loading. In the HTML include, the hash of the JS library can be added. Modern web browsers will verify the hash of the JS library, and if it does not match, the library will not be loaded.
  • Internal Dependencies: Security:
    • Internal dependencies have similar security concerns as external dependencies. Although internal dependencies allow us to standardise a process, if the dependency has a vulnerability, it will affect several different applications in the organisation. We, therefore, have to perform security testing of our dependencies before they are released for use.
  • Internal Dependencies: Security:
    • Internal dependencies can become legacy code fast. The developer that created a dependency has started work elsewhere, and the dependency no longer receives updates. If such a dependency is used in several applications, it can become an issue if a vulnerability is discovered.
    • A security concern to internal dependencies is storage. Ensure that a dependency can be accessed by developers for use, but not modification. If developers can simply modify the dependency, an attacker would simply have to compromise a single developer to compromise several applications.
  • Internal Dependencies: Security:
    • Applications and tools must be used to manage internal dependencies effectively. These tools would differ based on our needs. If we develop code only in a single language such as Python, we could simply host an internal PyPi repository server. This would allow us to upload and install packages similar to how it is performed using pip and the internet-facing PyPi repository.
    • However, if we develop applications in different languages, we may opt to use a dependency manager such as JFrog Artifactory.
  • Internal Dependencies: Tools:
    • JFrog Artifactory allows dependencies to be centrally managed and integrated into the DevOps pipeline. As developers are writing code, they can make use of the various dependencies hosted on Artifactory. Artifactory also has the ability to manage external dependencies that are used internally as well. It provides a single source for all dependencies.
    • While such tools are great to help us manage dependencies internally, if they are compromised, it would lead to a significant impact. 
  • Dependency Confusion:
    • Dependency Confusion is a vulnerability that can exist if our organisation uses internal dependencies that are managed through a dependency manager. In short, a race condition can be created by an attacker that could lead to a malicious dependency being used instead of the internal one.
    • The issue stems from how internal dependencies are managed. 
  • Dependency Confusion: pip install numpy:
    • When we run this command, pip will connect to the external PyPi repository to look for a package called numpy, find the latest version, and install it. 
    E.g. Attacks:
    • Typosquatting - An attacker hosts a package called nunpy, hoping that a developer will mistype the name and install their malicious package.
    • Source Injection - An attacker contributes to the package for a new feature through a pull request but also embeds a vulnerability in the code that could be used to compromise applications that make use of the package.
  • Dependency Confusion: pip install numpy: Attacks:
    • Domain Expiry - Sometimes, the developers of packages may forget to renew the domain where their email is being hosted. If this happens, an attacker can buy the expired domain, allowing them full control over email, which could be used to reset the password of a package maintainer to gain full control over the package. This is a common risk for legacy packages on these external repositories.
  • pip installing a internal dependency the right way:
    • pip install numpy --extra-index-url https://our-internal-pypi-server.com/
    The --extra-index-url argument tells pip that an additional Pypi server should be inspected for the package. But what if numpy exists in both the internal repo and the external, public-facing PyPi repo? 
    ow does pip know which package to install? Well, it's simple, it will collect the package from all available repos, compare the version numbers, and then install the package with the highest version number. You should start to see the problem here.
  • Staging a Dependency Confusion Attack
    • All an attacker really needs to stage an internal dependency attack is the name of one of your internal dependencies. 
    How can Attacker get the name:
    • Developers often ask questions on public forums such as StackOverflow but do not obfuscate sensitive information such as the names of libraries being used, some of which could be internal dependencies.
    • Some compiled applications like NodeJS will often disclose internal package names in their package.json file, which is usually exposed in the application itself.
  • Staging a Dependency Confusion Attack
    • Once an attacker learns the name of an internal dependency, they can attempt to host a package with a similar name on one of the external package repos but with a higher version number. This will force any system that attempts to build the application and install the dependency to get confused between the internal and external package, and if the external one is chosen, the attacker's dependency confusion attack will succeed.
  • Dependency Confusion Considerations:
    • Since we only know the name of the internal package, not the actual source code of the package, if we perform a dependency confusion attack, the build process of the pipeline will most likely fail at a later step since the actual package was not installed.
    • Our external version number must be higher than the version number of the internal package for the confusion to work in our favour. However, this is easy since we can simply have a package with version number 9000 since most packages have major version numbers lower than 10.
  • Dependency Confusion Attacks:
    • To stage a Dependency Confusion attack, we will need to develop and build a malicious package that will execute code once installed. Since we only know the name of the package and don't have access to the source code, the application will most likely fail once it tries to run our package, so our safest bet is to get remote code execution earlier in the process. Hence, we want remote code execution once the package installation completes.
  • Dependency Confusion Attacks: A Pip Package:
    • package_name - This is the name of the package that we are creating.
    • __init__.py - Each Pip package requires an init file that tells Python that there are files here that should be included in the build.
    • main.py - The main file that will execute when the package is used.
    • setup.py - This is the file that contains the build and installation instructions.
  • Internal Dependency Security:
    • Internal dependencies should be actively maintained. This will ensure that vulnerabilities in these dependencies do not affect multiple applications and services.
    • As an additional defence measure against dependency confusion attacks, the names of internal dependencies can be registered on external package managers without the source code to claim the name. This will prevent an attacker from registering a similarly named package.
  • Internal Dependency Infrastructure Security:
    • Reference one private feed, not multiple. This contributes to protecting against dependency confusion attacks. With our python example, we would then use --index-url argument instead of --extra-index-url to indicate that the package must be collected from the specified index.
    • Protect your packages using controlled scopes. By controlling the scopes of dependencies, it will ensure that dependencies are locked to the applications that require them.
  • Internal Dependency Infrastructure Security:
    • Utilise client-side verification features. Controls such as sub-resource integrity or version locking will ensure that applications and services will detect when malicious code is introduced into a dependency and refuse to execute it.
  • Dependency Management:
    • Be aware of the dependencies you use in your applications and systems. Also, be aware that these dependencies may have dependencies, which will grow the list of dependencies you will need to keep tabs on.
    • Make sure to always use the latest versions of dependencies, both internal and external dependencies. More often than not, these updates to dependencies are not to introduce new features but to fix existing issues and bugs.
  • Dependency Managment:
    • It is not just the dependencies themselves that should be considered for security, but also how we configure and use our dependency managers, especially for internal dependencies.
    • Dependencies and dependency management systems should be included in the attack surface of the application or system we are developing.