Netsparker’s Weekly Security Roundup 2018 – Week 05

In this week’s edition of our security roundup: why you should be careful what you put into your composer.json file, why you need to use a Package Manager, the Principle of Least Privilege and DNS Rebinding

Table of Content

  1. Why You Should Be Careful What You Put Into Your composer.json File
  2. Why You Need to Use a Package Manager
      1. Composer Package Manager Can Expose Sensitive Information
      2. The Principle of Least Privilege Limits Exploitation Opportunities
  3. It's all about SOP – How Anyone Can Steal Your Ethereum Cryptocurrency With DNS Rebinding
      1. What are DNS, TTL and SOP?
      2. The Problem With JSON-RPC and Local Web Servers

Why You Should Be Careful What You Put Into Your composer.json File

What do Joomla!, Typo3, MediaWiki and Matomo (formerly known as Piwik) have in common? Aside from the fact that all of them are popular open source PHP projects with a large number of users, there is one similarity that you will only notice if you try to install the projects yourself, or if you look at their github accounts.

Joomla! contains a composer.json file.
Joomla!

Typo3 contains a composer.json file.
Typo3

MediaWiki contains a composer.json file.
MediaWiki

Matomo contains a composer.json file.
Matomo

As you might have noticed, each project repository contains a composer.json file. What does it do? If these popular applications include it in their projects, there is probably a very good reason to use it. So what exactly is composer.json?

Why You Need to Use a Package Manager

You might be familiar with package management tools from the Linux operating system (pacman, APT, YUM), Mac OS (Homebrew), Windows (Microsoft Store), Android (Google Play) or iOS (App Store). If you're a developer, the chances are that you've also heard of the Node Package Manager (npm) or pip for Python.

If you have used any of these tools in the past (and remember the alternative – compiling and installing the programs and all of their dependencies manually), you'll realize why almost all modern programming languages and operating systems have either a native package management tool or one that was developed by their respective communities. PHP is no exception.

Composer Package Manager Can Expose Sensitive Information

The composer.json file is part of the Composer Package Manager (CPM) for the PHP programming language. The CPM enables you to update, install and manage the libraries on which your application depends. All you need is the composer.json file and the CPM in order to parse it.

Since JSON files are designed to be easy to read by both machines and humans, you can open the file with a text editor (or with a browser, if it was accidentally left in the webroot). Then, you can see which components the application depends on, and whether each is the up to date version.

You can already see where this is going. The composer.json file might reveal sensitive information to an attacker, such as the exact names and versions of your dependencies. While it's almost inevitable that your application will be exploited if you use vulnerable, out-of-date software, the information in this file can also help hackers craft a targeted attack, especially if you use dependencies that aren't widely known or audited.

This is not the only issue that may arise from using Composer. The hard truth is that many developers use Composer incorrectly. Let's look at one of the most common mistakes. This example is replicated from section 1 of PHP Composer security:

# composer.json: insecure
{
  "name": "my/awesome_project",
  "require": {
    "php": "~7.1.7",
    "ext-mysqli": "*",
    "symfony/validator": "^4.0",
    "guzzlehttp/guzzle": "^6.3",
    "phpunit/phpunit": "^6.5",
    "squizlabs/PHP_CodeSniffer": "^3.2"
  },
  "autoload": {
    "psr-4": {
      "AwesomeProject\\": "app/",
      "AwesomeProject\\Tests\\": "tests/"
    }
  }
}

Did you notice the subtle mistake? Both phpunit and validator are not designed to be used in a production environment. In addition, the autoload functionality includes the tests folder. While this is a convenient feature to have during the development process, it can lead to various vulnerabilities in production.

The Principle of Least Privilege Limits Exploitation Opportunities

The real problem here is that you broaden your attack surface if you include additional libraries that are only needed in development. It's a good idea to adhere to the Principle of Least Privilege (POLP). It means that users should have the bare minimum of privileges they need in order to conduct relevant tasks.

Let's say that you want to implement comment functionality for a blog. If you use an SQL database in order to save the comments, you only need to allow INSERT statements. Since users don't have the option to delete their comments, it doesn't make sense to allow DELETE statements as well. So, if there is an SQL injection vulnerability in the comment functionality, an attacker's exploitation options are severely restricted. Also, if the SQL user's access is restricted to the comment table only, the attacker can't add a new Admin user for example.

The Composer developers are aware of this problem and provide an easy solution. They allow you to specify which packages you only want to use during development. This is relatively easy to implement. The secure version of the above composer.json file would look like this example which is replicated from section 2 of PHP Composer security:

# composer.json: autoload-dev section
{
  "name": "my/awesome_project",
  "require": {
    "php": "~7.1.7",
    "ext-mysqli": "*",
    "symfony/validator": "^4.0",
    "guzzlehttp/guzzle": "^6.3"
  },
  "require-dev": {
    "phpunit/phpunit": "^6.5",
    "squizlabs/PHP_CodeSniffer": "^3.2"
  },
  "autoload": {
    "psr-4": {
      "AwesomeProject\\": "app/",
    }
  },
  "autoload-dev": {
    "psr-4": {
      "AwesomeProject\\Tests\\": "tests/"
    }
  }
}

By loading this file with composer install --no-dev, we can make sure that we only load the libraries needed in production instead of the development ones.

To find out more about composer security best practices, see PHP Composer security.

It's all about SOP – How Anyone Can Steal Your Ethereum Cryptocurrency With DNS Rebinding

The value of Cryptocurrencies is fairly unpredictable, given that it's still a young phenomenon and it's so easy to invest in, even for unexperienced traders. It's common for the price of Bitcoin – probably the most widely known cryptocurrency – to increase by $500 within the course of a single hour. The problem is that you can lose an equal amount of money in about the same time.

Nevertheless, it looks like cryptocurrencies are gaining popularity among traders, merchants and, of course, criminals. Since many of these coins are untraceable and their value increases rapidly, they are a prime target for hackers.

Tavis Ormandy, a researcher from Google's Project Zero, painfully reminded the developers of the Transmission Torrent client that it's not a good idea to run insecure web applications on your local network. He abused an insufficiently protected JSON-RPC interface on a server running on localhost. We'll examine what JSON-RPC is later in the article. Even when these HTTP servers aren't directly accessible from outside of your home network, it's possible that websites access them through your browser.

What are DNS, TTL and SOP?

To read more on why it is a dangerous idea to run insecure web applications on localhost or on your private home network, including DNS Rebinding, see Vulnerable Web Applications on Developers' Computers Allow Hackers to Bypass Corporate Firewalls.

In this article, however, let's briefly examine what DNS rebinding is and how it can be used by attackers.

First, you have to understand Same Origin Policy (SOP). SOP makes sure that http://attacker.com can't read the responses from requests it makes to http://banking.com. SOP is one of the fundamental building blocks of the modern web. Without it, opening a website could expose your private messages on social media websites, your bank account balance or the content of your emails to risk.

Along with factors such as the protocol you used to visit a page, as well as the port running the web application, SOP is closely tied to the host name of the website. The host name is what you type into a browser when you want to visit the site. In the above example, the attacker's host name is http://attacker.com. Since it doesn't match http://banking.com, the SOP prevents it from reading the responses of requests it issues to the banking website.

In order to return its IP, a website needs to have its own name server. DNS rebinding is a very technical matter. Let's just say that for the sake of illustration, the DNS protocol is less like a phone book (even though it's often described as one) and more like a database on a server. You can change the IP your hostname points to however you like, and as often as you want (for example if you move your website to a different server).

Since this doesn't happen very often on most websites, the response of the web server contains the Time To Live (TTL). This is a numeric value (in seconds) that specifies how long a client should consider the IP address as safe to use. If there is a value of 300, this means that the IP will probably not change for the next five minutes. Therefore clients, such as browsers, won't ask the web server for its IP for at least five additional minutes, guaranteeing faster loading times as well as less requests for the DNS server to answer.

Five minutes is short. But, imagine that there was a value of zero seconds. For almost every real world client, this would mean that with every new HTTP request you would have to send a new DNS request too. Also, apparently setting a TTL of zero has different meanings depending on the client. Generally, it would be an instruction not to cache this DNS record and ask for the IP with every new request. This may be acceptable behaviour for some applications, but browsers are optimized to deliver the fastest possible loading time. This is a selling point of most modern browsers.

One extreme example of how important the loading times are for browser manufacturers is evidenced by Microsoft Edge's Windows 10 popups ('Edge is faster than Chrome, switch now!'). Unfortunately, many users found these taskbar popups annoying and spammy. In any case, what browsers usually do is ignore the TTL value if it is less than 60 seconds, which is more than enough time to load all a website's resources without additional causing overhead with too many DNS requests.

How Attackers Can Game the System to Exploit a Local Application

Now that you know the basics about TTL, SOP and DNS, let's take a look at how an attacker can game the system in order to exploit a local application, and which problems he faces. Assume that he can somehow force you to visit his website. In our example, we use attacker.com, though a real attacker would choose a slightly less obvious name! When you visit attacker.com, your browser issues a DNS request to its nameserver, which returns the server's IP, 192.0.2.2. There is usually a good reason why you were prompted to click the link, for example an article about a topic you are interested in. However, the page actually contains JavaScript code that constantly queries http://attacker.com/index.html, and sends the result back to 192.0.2.2/log.

That's a little bit weird, isn't it? After all, the attacker already knows the content of his own index.html file, so what does this achieve? Well, imagine that the attacker advised his DNS server to return 192.0.2.2 in the first request, but 127.0.0.1 (the IP address corresponding to your local machine) in all subsequent DNS requests. The attacker sets the TTL to a very small value (less than 60 seconds) and then waits. After 60 seconds, the browser's DNS cache expires and the script that queries http://attacker.com/index.html doesn't fetch the index.html file on 192.0.2.2 again, but rather the file on 127.0.0.1, your local machine.

The reason why he doesn't directly issue a request to 127.0.0.1/index.html is that he couldn't read the response due to SOP. However, since there is a script running under the origin of attacker.com and 127.0.0.1 is now also reachable under the origin of http://attacker.com, the same origin policy doesn't have any effect, and the attacker can receive and read the response from your local machine.

The Problem With JSON-RPC and Local Web Servers

Well, I'm not a developer, why would I run a web server on my local machine?

If you think about it, this is an absolutely valid question. If you don't install a server like Apache on your local machine, you shouldn't be concerned about DNS rebinding at all, should you? Unfortunately it's not that easy. A lot of developers include local HTTP servers in their applications, to let a certain website communicate with your local machine. An example for this would be an 'Open Song' button on a website that allows you to download music to your computer. The website could then communicate with the music player application through a web server running on localhost, which would then play the song. It's also common to let local applications communicate with each other through such an HTTP interface.

But of course there are more vulnerable applications that may use an HTTP interface. A researcher, who goes by the Twitter name Jazzy, took a look at the local HTTP server of certain Ethereum wallets. He found out that many of them run a JSON-RPC interface on port 8545. JSON-RPC is a protocol that allows clients to communicate with a server in order to send notifications or instruct them to execute certain actions. As the name suggests, it uses JSON encoded messages for communication.

The problem for an attacker targeting Ethereum wallets is that even though he could issue requests to the JSON-RPC interface, he couldn't read the responses. This is where DNS rebinding comes into play. Jazzy wrote a simple DNS server that he used for DNS rebinding in Python. He then wrote some JavaScript code in order to exploit the vulnerable Ethereum clients. This is now he described the process:

  • The victim opens attacker.com
  • The DNS server responds with Jazzy's server IP
  • attacker.com creates a hidden iframe, pointing to a random subdomain (corresponding to Jazzy's server IP) and the port 8545
  • The JavaScript code waits for 60 seconds, and then issues an XHR request to randomsubdomain.attacker.com/test
  • Since the DNS cache expires after a minute, the browser sends another DNS request; this time randomsubdomain.attacker.com points to 127.0.0.1
  • Since the JavaScript code is still running under the origin of attacker.com, which is now pointing to 127.0.0.1, Jazzy can easily read the responses

The reason why he uses a random subdomain for each attack is simple. DNS queries are often routed through different servers. This means that the IP the DNS server sees isn't necessarily the IP of the user. It's possible that multiple users visit the site, but their DNS requests come from the same IP. Therefore using the IP address isn't a reliable way to tell two users apart. A subsequent victim that visits attacker.com would instantly see an empty JSON-RPC response instead of the page containing the malicious JavaScript code, which is why using different subdomains for each user is the safest way to get it right.

In his blog post How your ethereum can be stolen through DNS rebinding, Jazzy explains that he was able to read Ethereum addresses and balances, and could possibly steal Ethereum if the wallet wasn't locked. Even though this sounds like a serious vulnerability that needs fixed, the Ethereum Foundation doesn't acknowledge it. It's hard to say how long it will take until someone actively exploits this vulnerability in the wild, but considering the fact that many attackers seem to be eager to make a quick buck by robbing Bitcoin exchanges and stealing cryptocurrency tokens, our guess is that attackers will act soon, especially since Geth and the C++ and Python clients seem to be vulnerable.