Leviathan Security Group - Penetration Testing, Security Assessment, Risk Advisory

View Original

Our Most Common Pen Test Finding? Vulnerabilities in Third-Party Components

by Brian Myers

Historically, one of the most common findings in Leviathan penetration tests is vulnerable third-party software components. This may sound like a mundane, easily addressed finding, but maintaining such components can be surprisingly challenging, and the consequences of successful exploitation can be catastrophic. In 2017, sensitive data for 147 million people was exposed because Equifax failed to update a single piece of third-party software. The Equifax breach—one of the worst data breaches ever—resulted from a critical vulnerability in Apache Struts. Apache published a security fix that addressed this flaw that allowed malicious users to inject and execute their own code on the vulnerable system. Hackers were alert to such news and, as usual, began searching for unpatched systems and exploiting the vulnerability almost immediately. Weeks passed and Equifax failed to upgrade a consumer portal written with Struts. In mid-May, attackers had used the vulnerability to enter Equifax systems, and by the time Equifax discovered the breach on July 29, about 40% of the U.S. population had their personal data exposed. The problem of securing the software supply chain is so widespread and potentially impactful that it has drawn attention from the U.S. government, with the White House recently providing guidance for federal agencies. Although addressing vulnerable third-party components can be difficult, it must be done. The potential risks are too great to ignore.

What does “vulnerable software in use” mean?

If your penetration test report says “vulnerable software in use” then your code includes a piece of software from a third-party vendor that contains a security vulnerability. The vulnerable software could be part of infrastructure you rely on, such as a web server, or source code you incorporated, such as a JavaScript library. The problem is in the software you’re using, not the software you wrote. Vendor software vulnerabilities are documented in publicly available lists, so anyone—including hackers—can find the vulnerability by simply looking it up.

What are some real-world examples?

We recently performed an assessment on an application that received requests using the Apache JServe Protocol (AJP). The tester determined that the server used a vulnerable version of the AJP protocol (version 1.3) that left the application exposed to Local File Inclusion (NIST published the details here). By exploiting the vulnerability, the tester was able to get unauthorized access to sensitive content (source code) from the server. This critical vulnerability was addressed simply by upgrading Apache Tomcat to a newer version.

Are third-party component vulnerabilities always critical?

No, they are not. Third-party components are vulnerable in various ways with different consequences, ranging from inconsequential to devastating, with most falling somewhere in between. Third-party component vulnerabilities are, however, the root cause of more major breaches than any other class of web vulnerability (Snyk 2017).

Is the use of vulnerable third-party software common?

OWASP, an international nonprofit dedicated to fostering application security, has been calling attention to the prevalence of this vulnerability type by listing it in their OWASP Top Ten since 2013. Third-party component vulnerabilities are one of the most common findings in vulnerability scans, and historically they have been the most common finding in Leviathan penetration tests.

Why is this problem so common?

Use of vulnerable third-party components is common because it happens by default. Most modern nontrivial software products are more assembled than composed, and vulnerabilities will almost certainly emerge in already-adopted components (e.g., operating systems, servers, source code packages). Approximately 97% of all codebases contain open-source software (Synopsis 2022). The top four open-source ecosystems collectively offer over 37,000,000 components and packages, and they produce over 6,000,000 new component versions annually (Sonatype 2021). Unless you work actively to identify and update vulnerable components, your system will become more vulnerable over time.

But fixing a vulnerable component is easy, right?

It sounds simple enough—just download a new version, copy it over the old version, and done! But the details can be devilish. Here are some key considerations:

Is the new version safe?

Not always. A new version can introduce new vulnerabilities. You’ll need to test every time you update a component. If the update does introduce problems, or if it is not backward-compatible with your current version, you may have to modify your code or ask the provider for another update. If multiple new versions are available, research is often necessary to determine the best choice.

Do you know what to test?

Determining which actions in your application trigger code in a particular component can be surprisingly difficult. The code dependency may occur many layers down in the dependency tree where identifying the trigger actions is not easy. Sometimes, the component may be called by legacy code that current staff no longer understands well. Or the component may be an indirect dependency needed by some other component that you do call directly. Any of these situations may complicate testing.

Alternatively, the testing needs may be obvious but ubiquitous. If, for example, the component is JavaScript code present in every page of your site, then upgrading it may call for a full regression test.

Do you know who on your team is responsible for the component?

If the component in question does not obviously belong to a part of your product under active development, teams may disagree about who should spend time fixing it.

What if no fix is available?

The creator may not have released a fix or may no longer support the software. Sometimes, the creator may not respond to requests you make. In that case, you must fix the problem in the third-party code yourself, modify your own code to avoid the vulnerable code path, or find an equivalent component to replace the vulnerable one.

If third-party vulnerabilities are generally a problem, is there a general solution

Fixing a vulnerable component is a win, but the real goal is to protect against them in your codebase systematically. That too is difficult.

Do you know which third-party components you have?

Many companies do not. This is a big problem with potentially big impacts. Recent guidance (from NIST, and more recently the White House) promotes the use of software bills of materials (SBOMs). The idea is that anyone providing software to others should include with it a list of all the third-party components it contains.

Do you know if there are vulnerabilities in these components?

Knowing what components you have is a good first step, but it doesn’t tell you which ones have vulnerabilities. That requires research, usually starting with the MITRE Corporation’s list of Common Vulnerabilities and Exposures (CVEs).

Do you know when new third-party components are added to your codebase?

Many companies do not track the addition of third-party components, yet this is now a frequent part of software development. Software packaging systems such as Maven and NuGet make finding and adding new components very easy, and developers commonly add new components as part of normal software development. Even updating an old component may introduce new dependencies you did not choose.

Do you know when new vulnerabilities are discovered in components you use?

Researchers and malicious actors find new vulnerabilities in software all the time. To keep up, you’ll need to regularly monitor public vulnerability sources and component release notes to know when vulnerabilities are found and when they are fixed.

How do people cope? What best practices tame this tangle?

Avoiding vulnerable third-party components is difficult. The problem has attracted a lot of attention—and solutions—often under the rubric of managing supply chain risks. It affects the entire secure software development lifecycle (SDLC). Automation helps, but there is no single fix. Managing supply chain risk is a matter of culture and practice as much as technology. Here are some recommendations:

  • Maintain an inventory of third-party components in use.

    • Knowing what components you use is fundamental. You’ll need the inventory list to monitor the success of your third-party component policy, to assess the impact of new vulnerabilities on your product, and to share with customers who want to be sure you are protecting their data well. You may also require your own vendors to provide you with lists of the components they use.

  • Create a policy for the use of third-party components.

    • A typical policy document might include criteria for adopting third-party components; roles and responsibilities for testing and maintaining them; approved OSS sources and licenses; and a prohibition of unsupported components. The policy should also establish a regular review of components in use.

  • Train software development teams.

    • Ensure that developers understand their responsibilities under your policy, the risks and costs in using third-party software, and how to identify safe components.

  • Gate the adoption of third-party components.

    • Establish a process for evaluating newly proposed uses of third-party components. It may be a simple checklist any developer can work through, or it may be a more formal approval from someone with architectural oversight.

  • Run software composition analysis (SCA) scanners regularly.

  • Monitor publications and newsfeeds that announce new vulnerabilities.

  • Build a strong suite of automated tests for your application.

    • Updating components may need to be a frequent operation, and analyzing the possible impact of each update can be costly. Therefore, an automated regression test suite is likely to be essential.

  • Mirror public package repositories privately.

    • Directing package requests to an internal cache of package systems on which you rely creates an access layer where you can exercise more control over what flows into your system. It can isolate you from attacks within the ecosystem that might withdraw packages or replace them with malicious code. When securing enterprise-level software, an internal repository of approved component versions is essential.

  • Regularly sunset obsolete code.

    • Aggressively deleting code and components that you no longer use reduces the attack surface, as vulnerabilities may persist in code that no one is maintaining.

Conclusion

Having vulnerable third-party components in your system is common, dangerous, and virtually unavoidable. Simply updating one component rarely fixes the deeper problem. Systematically protecting against this type of supply chain risk requires a versatile approach that includes policies, scanning tools, change management processes, test automation, and a supportive security culture.

 

If you would like help assessing and adjusting your secure software development lifecycle to mitigate supply chain risks, contact Leviathan’s Risk & Advisory Services team.

Resources