Using components with known vulnerabilities

Hello dear readers and welcome to this new OWASP Top 10 episode. Today, you will learn why using components with known vulnerabilities is bad, how to exploit it and how to mitigate it.

So far, we’ve seen how you can write secure code which doesn’t expose security vulnerabilities. However, you might write 100% secure code and still be vulnerable. How is that possible? Well, through the usage of vulnerable components. In this episode, we will address just that!

This is the plan for this episode:

  • We will explore how developers might unintentionally be using components with known vulnerabilities.
  • From there, we will explore how to detect and exploit vulnerable components?
  • Then, we will practice on examples in OWASP WebGoat and Juice Shop
  • Also, we will discover some real-world attacks leveraging insecure components.
  • How this vulnerability might affect security?
  • Finally, we will explore how you can mitigate this issue and some tools to help you along the way.

How are you unintentionally using components with known vulnerabilities?

Unless you are writing a really simple function which doesn’t do much, you will reuse software of other people. From development to deployment, you will use libraries, frameworks, technologies, etc. And guess what! Those third-party components will also depend on other components!

This comes at a cost. In fact, part of the third-party software components you will reuse will suffer from security vulnerabilities. Besides, you might even be using some malicious components. Therefore, checking your code is a need, not a luxury.

Let’s first understand how attackers find and exploit vulnerable components.

How to detect and exploit vulnerable components?

When you hunt for assets which use components with known vulnerabilities, the first step is to fingerprint the technologies.

Step 1: Fingerprint technologies

During this step, you should gather the names and versions of the technologies which the application uses. You can use many techniques.

Checking known HTML elements

Usually, the HTTP traffic contains hints like names of Cookies, HTTP headers, title values and links, etc. However, you might not recognize most of them. Therefore, you can use tools to assist you. For example, the Wappalyzer browser extension fingerprints the technologies based on elements of the HTML page and HTTP headers.

Triggering errors

Sometimes, you can trigger verbose errors which give you a hint on the technologies being used. This is where fuzzing is handy. For example, you can remove expected parameters, send unexpected values, etc. If you receive an error, it usually contains some hints about the stack.

Forced browsing

You can directly access known directories using some publicly available dictionaries to look for typical login portals, README files, etc. which might contain the name and the version of the components. Better yet, if you find files like package.json or bower.json, you will have access to the list of all libraries and versions. You can see this is the video tutorial at the end of this blog post.

Source code

If you have access to the source code, don’t hesitate to collect the dependencies. You will have full visibility of the components being used.

Step 2: Find public vulnerabilities and exploit the weak components

If you are lucky, you might find CVEs with public exploits on multiple online resources, such as Exploit DB for public exploits, Snyk for open source libraries and CVE databases for vulnerabilities. From there, you can either directly use the public exploits or try to exploit the CVE you found in the CVEs database.

Never blindly execute public exploits without first understanding what they do! Sometimes, they contain malicious code which will exploit your machine.

Practice examples of using components with known vulnerabilities

In this section, we will see how both vulnerable and malicious libraries can affect the security of your own code.

Outdated or vulnerable dependencies

The most obvious case of reusing insecure components is when they suffer from security vulnerabilities. For instance, OWASP WebGoat uses a vulnerable version of the Xstream library to transform an XML document into a Java object. In the pom.xml file, notice that the library’s version 1.4.5.

OWASP WebGoat using components with known vulnerabilities: Xstream 1.4.5
OWASP WebGoat using components with known vulnerabilities: Xstream 1.4.5

Looking for public exploits on the internet reveals that this version suffers from a severe deserialization vulnerability, which leads to remote code execution.

Sending the following code will create the file /tmp/here on the docker container.

<sorted-set>
<string>foo</string>
  <dynamic-proxy>
    <interface>java.lang.Comparable</interface>
    <handler class='java.beans.EventHandler'>
      <target class='java.lang.ProcessBuilder'>
        <command>
          <string>touch</string><string>/tmp/here</string>
        </command>
      </target>
      <action>start</action>
    </handler>
  </dynamic-proxy>
</sorted-set>

You can see this in action on the video tutorial linked at the end of this blog post.

Malicious components and Typosquatting

Sometimes, developers might reuse a rogue component which resembles the legitimate one. This is known as Typosquatting. It is a scary thing! Especially when the malicious library is widely used by other projects. For instance, this GitHub issue reports how the attacker has been exfiltrating SSH keys and internal files using a rogue module which he had named python3-dateutil. This name was not randomly chosen. In fact, the legitimate module name is python-dateutil. Unfortunately, a few hundred developers fell for it. 

Using components with known vulnerabilities : Malicious Python package  python3-dateutil exfiltrates internal files
Using components with known vulnerabilities : Malicious Python package python3-dateutil exfiltrates internal files

On OWASP Juice Shop, I am demonstrating a typosquatting issue on the video tutorial linked at the end of this blog post.

Real-world attack examples of using components with known vulnerabilities

In this section, we will explore some real-world attacks which leveraged vulnerable components.

The most famous attack in the real-world

Probably, the most famous manifestation of this issue would be the Equifax breach. In fact, the entry point was a vulnerable version of Struts, CVE-2017-5638, to gain remote code execution and pivot inside the Equifax network and steal more than 140M customers’ personal information.

Bug bounty hunting reports

In this write-up, the hacker demonstrates how he was able to develop exploits against a vulnerable WordPress plugin when no public exploits were available. He exploited a SQL injection, a CSRF and an XSS vulnerability. This is a demonstration of how you can use a CVE to write your own exploit.

You also have this report which demonstrates how the hacker was able to exploit an XSS vulnerability due to a vulnerable version of the Tinymce library. As a side note for bug bounty hunters, note how a valid proof-of-concept can greatly impact the quality and the reward of the report.

Impact of using components with known vulnerabilities

Generally, this issue can lead to severe breaches. On the one hand, your code will be vulnerable to whatever the component is vulnerable to. On the other hand, rogue libraries will definitely affect you since they purposely leverage your code to steal your sensitive data.

How to prevent using components with known vulnerabilities?

To prevent this issue, the ideal solution would be to never trust third-party components unless you are sure of their safety. Unfortunately, this is easier said than done. In fact, it is not realistic to manually verify all the libraries you are using in your code.

In this article, Snyk explains how a library was stealing bitcoins. I recommend you read it, but here are the takeaways:

  • The widely used event-stream package contained a malicious package named flatmap-stream.
  • The event-stream package was not actively maintained: This is a criterion you should take into consideration. You should prefer components with a healthy community.
  • Mitigating the risk would simply involve removing the rogue library. However, this is not scalable due to the considerable number of components you are using. Therefore, you should constantly and automatically monitor your dependencies. Snyk provides this feature. But in general, you must have a dependency checking process for all your projects. For example, OWASP provides this dependency checker for Java projects.

Additionally, you should implement the following:

  • Have a patch management process which helps you detect and patch vulnerable components using public CVE databases.
  • Additionally, you should apply some behavioural analysis to spot any unusual activity. For instance, you should inspect any server initiating requests to external servers. You can use tools such as Rita for this purpose.

As usual, here is your video tutorial