Status codes from pentester's perspectiveA blog post by Jesse Luoto

In this post we'll take a dive to HTTP status codes by answering a few questions from the Web Application Penetration testing Study Plan.

What if you get 200 when you try something malicious?

When you are trying to impersonate someone, perform unwanted actions or elevate your privileges, the system should try its best to prevent it from happening and return a status code from the 400s or from the 500s. So if you get a 200 response, congratulations! That means that you have a high probability in succeeding in your attack – you probably did something right.

What can we do if we get a 403 - Forbidden

The important difference between 403 Forbidden and 401 Unauthorized is that you found a resource that is exists, but you just don't have the correct privileges to access that.

I've seen that sometimes developers implement 403 Forbidden as 404 Not Found as a security measure to prevent that information from leaking the system. I think that could be a good practice to give the least amount of information out that you need to, because from the end user's perspective, that resource shouldn't exist.

To get around 403 Forbidden you have a few possibilities:

  • SSRF in case of local requests having elevated privileges
  • Have somebody else do it, e.g. through XSS
  • Impersonate someone that has access e.g. via weak JWT configuration

Let's try to get a 500 status code, why so? What will it reveal?

I think the best way of remembering what's the difference between 400s and 500s is:

  • 400s = you fucked up (as the consumer)
  • 500s = we fucked up (as the server/developer)

So 500 means that the system got into that kind of a situation that wasn't expected. From the penetration testers perspective, this is always a good thing, because then you found some kind of an edge case that the developers didn't think about; there's a high chance that there is something to exploit in that situation.

For example, finding SQL injection by adding an extra " to your form field probably yields a 500 error. In that case the developers didn't know that kind of behaviour was possible, so they didn't build the system to withstand it, and the system crashed in an unpredictable way.

I think the best kind of 500s as a penetration tester are the ones that include a stack trace. Stack traces are beautiful sources of information that can leak mutliple pieces of information like:

  • The underlying programming language
  • Server components
  • What kind of libraries they are using
  • Detailed information about where the error was in the system

Especially if the 500 error originates from an open source library; you can probably trace back the exact version of the library that they were using and find the source code that caused the crash.

So as a penetration tester: 500 errors means that you're getting close.

Try to understand each status code which as a pentester you would love to see

There are a ton of different status codes, ranging from common ones to those you don't really see in the wild. I've tried to list the most important ones here that have some kind of a meaning to the penetration tester.

101 – Upgrade the what now?

It can scare you the first time you see a 101 Switching Protocols response, but don't worry. It probably means you've hit a websocket API.

A practical thing to look for is Websocket smuggling: If you can trick the server to send you a 101 without when it shouldn't be, then you can trick an intermediate server to create a persistent connection that can give you access to restricted internal API endpoints.

200s range – the A-OKs

The best thing to see in Burp when you're chasing for IDORs. If the system works correctly, you should be always getting a response from the 400s. You do have different responses depending on the effect you're chasing: 200 OK (Update), 201 Created (Create), and even 204 No Content (in case of a DELETE request).

300s – show me the way

Response code in the 300s means you're dealing with redirects. Most frequently you'll bump into one of the following:

  • 301 Moved Permanently
  • 307 Temporary Redirect
  • 308 Permanent Redirect

In these cases you'll want to be looking out for open redirects. Make sure to map all 300s out when you're doing reconnaissance and try out the open redirects to them at some point.

300s are also handy with tesing out HTTP smuggling; you want to have some responses where you get consistent 300s or 400s to be able to distinguish successful response smugglings.

429 – I tried too hard and only got so far

Sometimes you suddenly start getting weird status codes, and it's probaby a rate limit or WAF that you've managed to trigger. 429 Too Many Requests is a good example of that.

In that case you have a few options:

  • Wait for the rate limit to cool down and throttle your requests
  • Change your IP address
  • Use a server farm to distribute your requests

503 – Whoops, did I do that?

503 Service Unavailable can be a dangerous response code to have when you're doing penetration testing of a live environment. It can mean that you have hit the server so hard that it crashed completely, and may either be completely down or rebooting.

The good news is that you may have found a DoS attack! If the server recovers after a reboot, see if you have something you can reproduce.

418 – will definitely lighten up your day

418 - originally a April Fool's Day RFC for "I'm a teapot". If you ever run into that, just high five yourself, because you just hit some kind of an Easter egg that the developers have left for you.

Unless of course if we are talking about testing actual Internet connected "smart" teapot. In that case, I would be worried as much as Mikko.


Be the first to know from new blog posts

Subscribe to the mailing list to get priority access to new blog posts!