🌐

Web Interfaces

Authentication Forms

Simple Login
Username + Password authentication
SQL Injection
2FA Login
Username + Password + TOTP verification
Multi-factor Auth
OAuth2 Login
Authorization Code Flow with consent screen
Open Redirect No CSRF
Logout
Clear session and logout
Session Management

Protected Pages

Vulnerable Tools

Ping Tool
Network connectivity diagnostic tool
Command Injection
User Search
Query users from the database
SQL Injection
Guestbook
Sign our visitor guestbook
Reflected XSS
GraphQL Query
Execute GraphQL queries against the API
GraphQL Injection No Depth Limiting

All Web Endpoints

Endpoint Method Auth Required Description
/ GET None Home / index page
/web/login GET, POST None Simple login form — SQL Injection Bypass
/web/welcome-simple GET Session: logged_in=True Post-login welcome page — Reflected XSS
/web/login-2fa GET, POST None Login with TOTP 2FA
/web/welcome-2fa GET Session: 2fa_logged_in=True Post-2FA welcome page — Reflected XSS
/web/welcome-basic-auth GET Basic Auth Protected by HTTP Basic Auth
/web/welcome-header GET secret-header: my-secret-header Protected by secret header
/web/welcome-cookie GET secret-cookie=my-secret-cookie Protected by secret cookie
/web/logout GET None Clears current session
/web/ping GET None Network ping — Command Injection via host param
/web/users GET None User search — SQL Injection via search param
/web/guestbook GET None Visitor guestbook — Reflected XSS via name param
/web/graphql GET None GraphQL query interface (HTML form)
/web/oauth2/login GET None OAuth2 flow landing page
/web/oauth2/authorize GET, POST None OAuth2 consent screen — Open Redirect, No CSRF
/web/oauth2/callback GET None OAuth2 callback with interactive token exchange
/web/oauth2/profile GET Bearer Token OAuth2 protected profile — Token in Query String
🔓

OAuth2 Testing Guide

This lab implements two OAuth2 grant types: Authorization Code (user login via browser + API token exchange) and Client Credentials (pure API, machine-to-machine, no user involved). Multiple intentional vulnerabilities are present for pentest practice.

How the Authorization Code Flow Works

1
User clicks "Login with OAuth2" Browser
Client app redirects the user's browser to the authorization server
GET /web/oauth2/authorize?response_type=code&client_id=vulapp-client-001&redirect_uri=/web/oauth2/callback&scope=read+profile&state=random123
2
User authenticates and grants consent Browser
The authorization server shows a login form and permission consent screen. The user enters credentials (admin / easypassword) and clicks "Authorize".
3
Server redirects back with authorization code Browser
The browser is redirected to the callback URL with a short-lived authorization code in the URL.
/web/oauth2/callback?code=abc123def456&state=random123
4
Client exchanges code for access token API
Server-to-server POST request. The client sends the authorization code, client credentials, and gets back an access token.
POST /api/v1/oauth2/token
5
Client accesses protected resources API
The client uses the Bearer token to call API endpoints on behalf of the user.
GET /api/v1/oauth2/userinfo (Authorization: Bearer <token>)
Start Authorization Code Flow

How Client Credentials Works (API-only)

No browser, no user, no redirects. The application authenticates as itself with a single API call and gets a token back. Used for machine-to-machine communication.

1
Client sends credentials directly API
POST with client_id, client_secret, and desired scope. No user interaction needed.
POST /api/v1/oauth2/token (grant_type=client_credentials)
2
Client uses token to call APIs API
The token represents the application itself (not a user). The username will be "service-account-vulapp-client-001".
GET /api/v1/oauth2/userinfo (Authorization: Bearer <token>)

Try it: Client Credentials (curl)

# Step 1: Get a token with client credentials
curl -X POST http://localhost:5000/api/v1/oauth2/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "vulapp-client-001",
    "client_secret": "super-secret-client-secret",
    "scope": "read profile"
  }'

# Response:
# {
#   "access_token": "a1b2c3d4e5f6...",
#   "token_type": "Bearer",
#   "expires_in": 3600,
#   "scope": "read profile"
# }
# Step 2: Use the token to access protected resources
curl http://localhost:5000/api/v1/oauth2/userinfo \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

# Response:
# {
#   "sub": "service-account-vulapp-client-001",
#   "username": "service-account-vulapp-client-001",
#   "email": "service-account-vulapp-client-001@vulapp.local",
#   "scope": "read profile"
# }
# Try it: request any scope you want (vulnerability #7)
curl -X POST http://localhost:5000/api/v1/oauth2/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "vulapp-client-001",
    "client_secret": "super-secret-client-secret",
    "scope": "admin write delete"
  }'

OAuth2 Endpoints

Endpoint Method Type Description
/web/oauth2/login GET Web Landing page with flow overview
/web/oauth2/authorize GET/POST Web Authorization + consent screen
/web/oauth2/callback GET Web Receives auth code, interactive token exchange
/web/oauth2/profile GET Web Protected resource (Bearer token or ?token=)
/api/v1/oauth2/token POST API Token endpoint (authorization_code + client_credentials)
/api/v1/oauth2/userinfo GET API User profile (requires Bearer token)

Try it: Authorization Code (curl)

After completing steps 1-3 in the browser above, copy the authorization code from the callback URL and run:

# Step 4: Exchange the authorization code for an access token
curl -X POST http://localhost:5000/api/v1/oauth2/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "<AUTH_CODE_FROM_STEP_3>",
    "client_id": "vulapp-client-001",
    "client_secret": "super-secret-client-secret",
    "redirect_uri": "/web/oauth2/callback"
  }'

# Response:
# {
#   "access_token": "a1b2c3d4e5f6...",
#   "token_type": "Bearer",
#   "expires_in": 3600,
#   "scope": "read profile"
# }
# Step 5: Use the token to access protected resources
curl http://localhost:5000/api/v1/oauth2/userinfo \
  -H "Authorization: Bearer <ACCESS_TOKEN>"

# Response:
# {
#   "sub": "admin",
#   "username": "admin",
#   "email": "admin@vulapp.local",
#   "scope": "read profile"
# }

Intentional Vulnerabilities

  • 1 Open Redirectredirect_uri is never validated. An attacker can change it to any URL to steal authorization codes.
  • 2 No CSRF Protection — The state parameter is passed through but never validated server-side.
  • 3 Auth Code Replay — Authorization codes are not invalidated after use and can be exchanged for tokens multiple times.
  • 4 No Client Secret Validation — The token endpoint accepts any value (or none) for client_secret.
  • 5 Token in Query String/web/oauth2/profile?token=... is accepted, leaking tokens in logs and Referer headers.
  • 6 Predictable Auth Codes — Codes are generated with MD5(username + timestamp), making them guessable.
  • 7 Unrestricted Scopes (Client Credentials) — The client_credentials grant accepts any scope value without validation. Request admin or write delete and it will be granted.
🎨

Drawing Tools

GeoSketcher
Interactive geometric shape drawing tool with snap-to-point functionality
Geometry
Polar Plotter
Create beautiful spirograph patterns with rotating lines
Visualization
⚙️

API Documentation

Swagger UI
Interactive API documentation and testing interface
OpenAPI JSON
Machine-readable API specification
Postman Collection
Import into Postman to test all API endpoints
Bruno Collection v2
Import into Bruno (v2 format, .bru files)
Bruno Collection v3
Import into Bruno (v3 format, .yml files)

All API Endpoints

Endpoint Method Auth Required Description
/api/tools/echo GET, POST, PUT, DELETE, PATCH None Echoes all request data (headers, params, body, cookies, session)
/api/tools/otp GET, POST None TOTP code generator — params: seed_b32 or seed_hex
/api/v1/get-token POST Credentials (JSON body) Authenticates and returns a Bearer token
/api/v1/get-token-form POST Credentials (form data) Authenticates and returns a Bearer token
/api/v1/is-valid-token GET, POST Bearer Token Validates the provided Bearer token
/api/v1/header-cookie GET Secret Header + Cookie Protected by secret header and cookie
/api/v1/header-cookie-auth GET Basic Auth + Header + Cookie Protected by Basic Auth, secret header, and cookie
/api/v1/users/<user_id> GET None User lookup by ID — SQL Injection
/api/v1/graphql POST Secret Header GraphQL API — SQLi, Introspection, exposes password field
/api/v1/graphql/schema GET None GraphQL schema via introspection
/api/v1/oauth2/token POST Client credentials OAuth2 token endpoint (authorization_code + client_credentials)
/api/v1/oauth2/userinfo GET Bearer Token OAuth2 user profile
/api/v1/mle/ GET None MLE — returns static info encrypted as a JWE token (RSA-OAEP + A256GCM)
/api/v1/mle/ POST None MLE — decrypts the incoming JWE token and returns an encrypted echo response