session_lab.py — Source Code

Back Download
/labs/session_lab.py
#!/usr/bin/env python3
"""
Session Hijacking Lab
The Hacker's Arsenal - Lesson 7

Practice session attacks:
1. Weak session generation (predictable tokens)
2. Session fixation
3. Dashboard access with stolen sessions
4. Money transfer (CSRF vulnerable)

Run this script and open http://localhost:8888 in your browser.

WARNING: This code is INTENTIONALLY VULNERABLE for educational purposes.
"""

from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import uuid
import time
import hashlib

# User database
USERS = {
    'admin': {'password': 'admin123', 'role': 'administrator', 'balance': 10000},
    'john': {'password': 'password1', 'role': 'user', 'balance': 500},
    'jane': {'password': 'qwerty', 'role': 'user', 'balance': 750},
}

# Session storage
SESSIONS = {}


def generate_weak_session():
    """VULNERABLE: Predictable session generation"""
    return hashlib.md5(str(time.time()).encode()).hexdigest()[:16]


def generate_strong_session():
    """Secure: Random session"""
    return uuid.uuid4().hex


HTML_TEMPLATE = '''<!DOCTYPE html>
<html>
<head>
    <title>Session Lab</title>
    <style>
        body {{ font-family: Arial; max-width: 800px; margin: 50px auto; background: #1a1a1a; color: #e0e0e0; }}
        h1 {{ color: #6EFF24; }}
        h2 {{ color: #6EFF24; font-size: 1.3em; }}
        .section {{ background: #252525; padding: 20px; margin: 20px 0; border-radius: 8px; border-left: 3px solid #6EFF24; }}
        input {{ padding: 10px; margin: 5px; background: #333; border: 1px solid #6EFF24; color: white; width: 200px; }}
        button {{ background: #6EFF24; color: black; padding: 10px 20px; border: none; cursor: pointer; font-weight: bold; margin: 5px; }}
        .error {{ color: #ff4444; background: #331111; padding: 10px; border-radius: 5px; }}
        .success {{ color: #44ff44; background: #113311; padding: 10px; border-radius: 5px; }}
        .warning {{ color: #ffaa44; background: #332211; padding: 10px; border-radius: 5px; }}
        .hint {{ color: #888; font-size: 0.9em; margin-top: 10px; }}
        code {{ background: #333; padding: 2px 6px; color: #6EFF24; }}
        .info {{ background: #1a2a3a; padding: 15px; border-radius: 5px; margin: 10px 0; }}
        .dashboard {{ background: #1a3a1a; padding: 15px; border-radius: 5px; }}
    </style>
</head>
<body>
    <h1>Session Hijacking Lab</h1>

    <div class="section">
        <h2>1. Login (Weak Sessions)</h2>
        <form action="/login1" method="POST">
            <input type="text" name="username" placeholder="Username"><br>
            <input type="password" name="password" placeholder="Password"><br>
            <button type="submit">Login</button>
        </form>
        {login1_result}
        <p class="hint">Hint: Session tokens are generated from timestamps. Can you predict them?</p>
    </div>

    <div class="section">
        <h2>2. Dashboard (Test Session)</h2>
        <form action="/dashboard" method="GET">
            <input type="text" name="session" placeholder="Enter session token"><br>
            <button type="submit">Access Dashboard</button>
        </form>
        {dashboard_result}
        <p class="hint">Hint: Try entering a stolen or predicted session token</p>
    </div>

    <div class="section">
        <h2>3. Login (Session Fixation)</h2>
        <form action="/login2" method="POST">
            <input type="text" name="username" placeholder="Username"><br>
            <input type="password" name="password" placeholder="Password"><br>
            <input type="text" name="session_id" placeholder="Session ID (optional)"><br>
            <button type="submit">Login</button>
        </form>
        {login2_result}
        <p class="hint">Hint: What if you could set the session ID yourself?</p>
    </div>

    <div class="section">
        <h2>4. Transfer Money (CSRF Vulnerable)</h2>
        <p>Logged in as: <strong>{current_user}</strong></p>
        <form action="/transfer" method="POST">
            <input type="text" name="to" placeholder="Recipient username"><br>
            <input type="text" name="amount" placeholder="Amount"><br>
            <button type="submit">Transfer</button>
        </form>
        {transfer_result}
        <p class="hint">Hint: This form has no CSRF protection. Can you make a victim submit it?</p>
    </div>

    <div class="section">
        <h2>5. Active Sessions</h2>
        <div class="info">
            <strong>Current sessions (for demonstration):</strong><br>
            {active_sessions}
        </div>
        <p class="hint">In a real app, you'd never see this. But attackers find ways...</p>
    </div>

    <div class="section" style="border-left-color: #ff4444;">
        <h2>Challenge Mode</h2>
        <ol>
            <li>Predict the next session token</li>
            <li>Hijack admin's session</li>
            <li>Perform a session fixation attack</li>
            <li>Steal money via CSRF</li>
        </ol>
    </div>
</body>
</html>'''


class SessionLabHandler(BaseHTTPRequestHandler):
    def get_session_user(self):
        cookies = self.headers.get('Cookie', '')
        for cookie in cookies.split(';'):
            if 'session=' in cookie:
                session_id = cookie.split('=')[1].strip()
                if session_id in SESSIONS:
                    return SESSIONS[session_id]['username']
        return None

    def do_GET(self):
        parsed = urlparse(self.path)
        params = parse_qs(parsed.query)

        dashboard_result = ''
        current_user = self.get_session_user() or 'Not logged in'

        active = '<br>'.join([f'{s[:8]}... = {SESSIONS[s]["username"]}'
                              for s in SESSIONS]) or 'No active sessions'

        if parsed.path == '/dashboard':
            session_token = params.get('session', [''])[0]
            if session_token in SESSIONS:
                user = SESSIONS[session_token]['username']
                user_data = USERS[user]
                dashboard_result = f'''
                <div class="dashboard">
                    <strong>Welcome, {user}!</strong><br>
                    Role: {user_data['role']}<br>
                    Balance: ${user_data['balance']}<br>
                    Session: {session_token}
                </div>'''
            else:
                dashboard_result = '<p class="error">Invalid session token</p>'

        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

        page = HTML_TEMPLATE.format(
            login1_result='',
            login2_result='',
            dashboard_result=dashboard_result,
            transfer_result='',
            current_user=current_user,
            active_sessions=active
        )
        self.wfile.write(page.encode())

    def do_POST(self):
        parsed = urlparse(self.path)
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length).decode()
        params = parse_qs(post_data)

        login1_result = ''
        login2_result = ''
        transfer_result = ''
        current_user = self.get_session_user() or 'Not logged in'
        set_cookie = None

        active = '<br>'.join([f'{s[:8]}... = {SESSIONS[s]["username"]}'
                              for s in SESSIONS]) or 'No active sessions'

        if parsed.path == '/login1':
            username = params.get('username', [''])[0]
            password = params.get('password', [''])[0]

            if username in USERS and USERS[username]['password'] == password:
                # VULNERABLE: Predictable session token
                session_id = generate_weak_session()
                SESSIONS[session_id] = {'username': username, 'created': time.time()}
                set_cookie = f'session={session_id}; Path=/'
                login1_result = f'''
                <p class="success">Logged in as {username}</p>
                <p class="info">Your session token: <code>{session_id}</code></p>
                <p class="warning">Note: This token was generated at timestamp {time.time():.2f}</p>
                '''
                current_user = username
            else:
                login1_result = '<p class="error">Invalid credentials</p>'

        elif parsed.path == '/login2':
            username = params.get('username', [''])[0]
            password = params.get('password', [''])[0]
            fixed_session = params.get('session_id', [''])[0]

            if username in USERS and USERS[username]['password'] == password:
                # VULNERABLE: Session fixation
                if fixed_session:
                    session_id = fixed_session
                else:
                    session_id = generate_strong_session()

                SESSIONS[session_id] = {'username': username, 'created': time.time()}
                set_cookie = f'session={session_id}; Path=/'
                login2_result = f'''
                <p class="success">Logged in as {username}</p>
                <p class="info">Session: <code>{session_id}</code></p>
                '''
                current_user = username
            else:
                login2_result = '<p class="error">Invalid credentials</p>'

        elif parsed.path == '/transfer':
            to_user = params.get('to', [''])[0]
            amount = params.get('amount', ['0'])[0]

            from_user = self.get_session_user()

            if not from_user:
                transfer_result = '<p class="error">Not logged in</p>'
            elif to_user not in USERS:
                transfer_result = '<p class="error">Recipient not found</p>'
            else:
                try:
                    amount = int(amount)
                    if amount > USERS[from_user]['balance']:
                        transfer_result = '<p class="error">Insufficient funds</p>'
                    elif amount <= 0:
                        transfer_result = '<p class="error">Invalid amount</p>'
                    else:
                        # VULNERABLE: No CSRF protection
                        USERS[from_user]['balance'] -= amount
                        USERS[to_user]['balance'] += amount
                        transfer_result = f'''
                        <p class="success">Transferred ${amount} to {to_user}</p>
                        <p class="info">Your new balance: ${USERS[from_user]["balance"]}</p>
                        '''
                except:
                    transfer_result = '<p class="error">Invalid amount</p>'

        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        if set_cookie:
            self.send_header('Set-Cookie', set_cookie)
        self.end_headers()

        active = '<br>'.join([f'{s[:8]}... = {SESSIONS[s]["username"]}'
                              for s in SESSIONS]) or 'No active sessions'

        page = HTML_TEMPLATE.format(
            login1_result=login1_result,
            login2_result=login2_result,
            dashboard_result='',
            transfer_result=transfer_result,
            current_user=current_user,
            active_sessions=active
        )
        self.wfile.write(page.encode())

    def log_message(self, format, *args):
        print(f"[{args[0]}]")


if __name__ == '__main__':
    server = HTTPServer(('localhost', 8888), SessionLabHandler)
    print("=" * 50)
    print("  SESSION HIJACKING LAB RUNNING")
    print("  Open http://localhost:8888 in your browser")
    print("=" * 50)
    server.serve_forever()