SBN

Attacking APIs by tainting data in weird places

Introduction

Never trust user input.

Every developer in the world who has attended even the most basic appsec training have had this drilled into their head. Yet, every month we continue to see examples of attacks against APIs that occur because of data that have been tampered with in unexpected ways.

Why does this keep happening?

It’s not that developers purposely write insecure code; far from it. In many cases, it comes down to the fact that we, as attackers, look to taint data in places developers aren’t even thinking about.

There are unusual areas within an HTTP request that can be modified to trick an API into working in unexpected ways… and ultimately expose a vulnerability that may be exploitable.

So let’s look at some of the weird places you can taint data when testing an API.

Tamper with Headers

With tools like BurpSuite, it’s trivial to modify the headers of an HTTP request. There are tons of known headers and even more custom app headers that can be modified to change the behavior of an API request.

Let’s explore this a bit…

The Host header has been used in several injection attacks over the years. We can send an HTTP request to an API and forge the value of the Host header or add other headers that take precedence over the value of the Host header. 

One such example is when an API mitigates Host Header Injection by checking for invalid input to the Host header itself. Depending on the web server used, you can supply the value to the X-Forwarded-Host header and possibly bypass those validation checks.

So even though the developer is doing proper input validation on the Host header, the data they sanitized may be replaced after that check, tainting the input and allowing you to manipulate code that relies on that value.

GET /api/dashboard HTTP/1.1
Host: www.example.com
X-Forwarded-Host: www.attacker.com
[...]

In some cases, you don’t even need to use the alternate header. Some web APIs may leverage web server filters for validation that can be abused by using duplicate headers.

In this attack pattern, the web server may be parsing for the first occurrence of the header, but the API framework looks for the last. This sort of header pollution is common when the web server is a frontend load balancer, proxy forwarder, or caching server that differs in its logic processing from the API itself.

GET /api/dashboard HTTP/1.1
Host: www.example.com
Host: www.attacker.com
[...]

Many times though, developers aren’t actually validating the Host header. If the value is ever relied on directly, you can abuse it. We’ve seen that in the past in attacks like URL Poisoning. Here is a code snippet from a PHP web app that relies on the server’s HOST incorrectly in a password reset workflow:

$reset_url = "https://" . $_SERVER['HTTP_HOST'] . "/reset.php?token=" .$token;

That sort of URL poisoning is typically seen and combined with phishing attacks. But there are other ways to manipulate URLs… and that’s through virtual hosts.

Sometimes, web servers are configured to support multiple sites through virtual hosts. That means a single IP can be hosting multiple domains, and the Host header is used to determine which one should be served up. You can take advantage of this configuration by tampering with the Host header to serve up different content than intended. This could include exposing more access to internal or administrative functions, especially when a web server is configured for split-horizon DNS.

For example, a company may have a single web server that hosts both its public web app (on www.example.com) and its internal admin interface (on admin.example.com, but that record only exists on the internal DNS server). Although it would not be possible to browse directly to admin.example.com from outside the network (as the domain would not resolve), it may be possible to access the admin interface by making a request from outside with the following Host header:

Host: admin.example.com

If you were to map admin.example.com in your hosts file to the same IP as www.example.com and use BurpSuite to replace the Host header with admin.example.com on every request, you would now be able to fully access the private admin interface from the outside world, even though it was configured to only work internally.

There are several other headers that you could manipulate like this to change the behavior of the API. Here are just a few to think about:

  • Referer
  • Cookie
  • X-Forwarded-For
  • User-Agent

Abuse the Parameters

It’s quite obvious that one way to tamper with data is to change what is passed into a parameter. By tainting the value of a parameter you might be able to make the API work in ways it wasn’t expecting. Many vulnerabilities like BOLA/IDOR, SQL injection, Command Injection, and Cross Site Scripting (XSS) rely on this pattern.

However, you can get much more creative.

In 2009 the concept of HTTP Parameter Pollution (HPP) was introduced at an OWASP conference by Stefano di Paola and Luca Carettoni. HPP focuses on the ability to pass multiple values into a single parameter and see how the API responds. Some APIs can be confused with this technique by processing both parameters instead of one.

Consider an example of pulling back your account data by passing in your id. If we also pass in the admin’s account id, what happens?

GET /api/account?id=<your account id>&id=<admin account id>

Depending on how the web server processes query parameters, it may use your id (the first one) or the admin (the last one).

But here is where it gets weirder. Some web servers include BOTH via comma-separated concatenation. So if your id was 2 and the admin id was 1, you would actually end up with id=2,1.

And this can be abused.

Here is an example API call that attempts a SQL injection attack against the prodID parameter that the modSecurity WAF for Apache blocks:

GET /api/products?prodID=9 UNION SELECT 1,2,3 FROM Users WHERE id=3 --

And here is how you can bypass the WAF and successfully complete the SQL injection attack using HPP:

GET /api/products?prodID=9 /*&prodID=*/UNION /*&prodID=*/SELECT 1 &prodID=2 &prodID=3 FROM /*&prodID=*/Users /*&prodID=*/ WHERE id=3 --

Polluting the parameter values like this to bypass validation controls is pretty neat. But let’s find an even weirder way to taint the data.

How about attacking the parameter names? While input validation may be done in parameter values, the developer is less likely to validate the parameter names themselves. If arbitrary parameter names are subsequently processed in an unsafe manner, then the API is vulnerable and can be exploited by submitting crafted input within parameter names. 

This technique has been demonstrated in the past to bypass anti-XSS security controls in web servers like IIS because while the default ASP.NET configuration blocked parameter values containing HTML markup, it does not block the same markup in parameter names.

Of course, we don’t always have to get that clever. Sometimes you can abuse an API by simply removing a parameter. If the API does not fail securely when a parameter is missing and instead just sets some defaults, it may be possible to taint the request and have the API behave differently than expected.

Taint the Payload

So when you think of typical POST and PUT actions to an API we can’t forget the payload that is left in the body of the request.

One obvious way to tamper with data is by changing the payload’s content type. I could have covered this earlier in the Tamper With Headers section, but I wanted to leave it here as the payload itself is the interesting part.

If the API expects a JSON object in the body and you change the Content-Type header to XML, how does the API handle it? Does it expose a path to insecure deserialization? Does its input validation routines understand things like XML External Entities (XXE) and adequately safeguard against XXE injection? Can you abuse form-encoded data to manipulate and reconstitute an object, possibly through parameter pollution?

Another way to taint the payload is by tampering with hidden fields. Just like removing a parameter may cause the business logic in the API to change, so too can a tampered or removed hidden field. You’d be surprised how many APIs have flawed state/session management that relies upon data you can manipulate.

One of the more fun ways I like to taint payloads is by polluting JSON properties.

A simple example is the way developers trust and sanitize JSON properties, especially in partial object updates. Let me show you what I mean.

A developer has a User object in its API that looks something like this (which you caught during a POST action):

{
 "accountType":"user",
 "userName":"dana",
 "pwd":"password"
}

The frontend includes a change password feature that sends a partial update via a PUT action:

PUT /api/user
[...]

{
 "userName":"dana",
 "pwd":"password"
}

Now an observant API hacker would notice this and probably try to add “accountType” into the JSON payload and possibly set it to “admin”. But ha-ha… the developer accounts for this and strips out that property before doing the update.

But what happens if you send this instead???

PUT /api/user
[...]

{
 "accountType":"user",
 "userName":"dana",
 "pwd":"password",
 "accountType":"admin"
}

Depending on the input sanitization used, you may have just escalated privileges to admin.

That my friend is JSON property pollution. And it’s more prevalent in the wild than you think.

You can go further than that though. You can manipulate the JSON properties by changing their data type and see how the API responds. If it doesn’t fail securely, you could end up tripping upon an entirely different attack vector.

Using userName as the field to taint, here are a few examples of what I mean:

  • {"userName": "dana"}
  • {"userName": true}
  • {"userName": null}
  • {"userName": 1}
  • {"userName": [true]}
  • {"userName": ["dana", true]}
  • {"userName": {"$eq": "dana"}}

Conclusion

We are just scratching the surface of some of the weird places we can tamper with data when interacting with an API. Try to taint anything and everything you can and observe how the API responds. The failure code paths are usually not as well tested and can expose some interesting vulnerabilities for you to exploit.

Don’t just follow the standard playbook and fuzz the regular inputs. Think about the HTTP protocol and all the areas where you can manipulate the request. From payload tampering to header injection, you would be surprised how many ways developers simply won’t be accounting for.

There are lots of online resources that cover this in more detail. If that interests you, download my free PDF on The Ultimate Guide to API Hacking Resources.

Good luck!

The post Attacking APIs by tainting data in weird places appeared first on Dana Epp's Blog.

*** This is a Security Bloggers Network syndicated blog from Dana Epp&#039;s Blog authored by Dana Epp. Read the original post at: https://danaepp.com/attacking-apis-by-tainting-data-in-weird-places