#!/usr/bin/env python
"""
vulnserver.py - Trivial SQLi vulnerable HTTP server (Note: for testing purposes)
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from __future__ import print_function
import base64
import json
import random
import re
import sqlite3
import string
import sys
import threading
import traceback
PY3 = sys.version_info >= (3, 0)
UNICODE_ENCODING = "utf-8"
DEBUG = False
if PY3:
from http.client import FORBIDDEN
from http.client import INTERNAL_SERVER_ERROR
from http.client import NOT_FOUND
from http.client import OK
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from socketserver import ThreadingMixIn
from urllib.parse import parse_qs
from urllib.parse import unquote_plus
else:
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from httplib import FORBIDDEN
from httplib import INTERNAL_SERVER_ERROR
from httplib import NOT_FOUND
from httplib import OK
from SocketServer import ThreadingMixIn
from urlparse import parse_qs
from urllib import unquote_plus
SCHEMA = """
CREATE TABLE users (
id INTEGER,
name TEXT,
surname TEXT,
PRIMARY KEY (id)
);
INSERT INTO users (id, name, surname) VALUES (1, 'luther', 'blisset');
INSERT INTO users (id, name, surname) VALUES (2, 'fluffy', 'bunny');
INSERT INTO users (id, name, surname) VALUES (3, 'wu', 'ming');
INSERT INTO users (id, name, surname) VALUES (4, NULL, 'nameisnull');
INSERT INTO users (id, name, surname) VALUES (5, 'mark', 'lewis');
INSERT INTO users (id, name, surname) VALUES (6, 'ada', 'lovelace');
INSERT INTO users (id, name, surname) VALUES (7, 'grace', 'hopper');
INSERT INTO users (id, name, surname) VALUES (8, 'alan', 'turing');
INSERT INTO users (id, name, surname) VALUES (9, 'margaret','hamilton');
INSERT INTO users (id, name, surname) VALUES (10, 'donald', 'knuth');
INSERT INTO users (id, name, surname) VALUES (11, 'tim', 'bernerslee');
INSERT INTO users (id, name, surname) VALUES (12, 'linus', 'torvalds');
INSERT INTO users (id, name, surname) VALUES (13, 'ken', 'thompson');
INSERT INTO users (id, name, surname) VALUES (14, 'dennis', 'ritchie');
INSERT INTO users (id, name, surname) VALUES (15, 'barbara', 'liskov');
INSERT INTO users (id, name, surname) VALUES (16, 'edsger', 'dijkstra');
INSERT INTO users (id, name, surname) VALUES (17, 'john', 'mccarthy');
INSERT INTO users (id, name, surname) VALUES (18, 'leslie', 'lamport');
INSERT INTO users (id, name, surname) VALUES (19, 'niklaus', 'wirth');
INSERT INTO users (id, name, surname) VALUES (20, 'bjarne', 'stroustrup');
INSERT INTO users (id, name, surname) VALUES (21, 'guido', 'vanrossum');
INSERT INTO users (id, name, surname) VALUES (22, 'brendan', 'eich');
INSERT INTO users (id, name, surname) VALUES (23, 'james', 'gosling');
INSERT INTO users (id, name, surname) VALUES (24, 'andrew', 'tanenbaum');
INSERT INTO users (id, name, surname) VALUES (25, 'yukihiro','matsumoto');
INSERT INTO users (id, name, surname) VALUES (26, 'radia', 'perlman');
INSERT INTO users (id, name, surname) VALUES (27, 'katherine','johnson');
INSERT INTO users (id, name, surname) VALUES (28, 'hady', 'lamarr');
INSERT INTO users (id, name, surname) VALUES (29, 'frank', 'miller');
INSERT INTO users (id, name, surname) VALUES (30, 'john', 'steward');
CREATE TABLE creds (
user_id INTEGER,
password_hash TEXT,
FOREIGN KEY (user_id) REFERENCES users(id)
);
INSERT INTO creds (user_id, password_hash) VALUES (1, 'db3a16990a0008a3b04707fdef6584a0');
INSERT INTO creds (user_id, password_hash) VALUES (2, '4db967ce67b15e7fb84c266a76684729');
INSERT INTO creds (user_id, password_hash) VALUES (3, 'f5a2950eaa10f9e99896800eacbe8275');
INSERT INTO creds (user_id, password_hash) VALUES (4, NULL);
INSERT INTO creds (user_id, password_hash) VALUES (5, '179ad45c6ce2cb97cf1029e212046e81');
INSERT INTO creds (user_id, password_hash) VALUES (6, '0f1e2d3c4b5a69788796a5b4c3d2e1f0');
INSERT INTO creds (user_id, password_hash) VALUES (7, 'a1b2c3d4e5f60718293a4b5c6d7e8f90');
INSERT INTO creds (user_id, password_hash) VALUES (8, '1a2b3c4d5e6f708192a3b4c5d6e7f809');
INSERT INTO creds (user_id, password_hash) VALUES (9, '9f8e7d6c5b4a3928170605f4e3d2c1b0');
INSERT INTO creds (user_id, password_hash) VALUES (10, '3c2d1e0f9a8b7c6d5e4f30291807f6e5');
INSERT INTO creds (user_id, password_hash) VALUES (11, 'b0c1d2e3f405162738495a6b7c8d9eaf');
INSERT INTO creds (user_id, password_hash) VALUES (12, '6e5d4c3b2a190807f6e5d4c3b2a1908f');
INSERT INTO creds (user_id, password_hash) VALUES (13, '11223344556677889900aabbccddeeff');
INSERT INTO creds (user_id, password_hash) VALUES (14, 'ffeeddccbbaa00998877665544332211');
INSERT INTO creds (user_id, password_hash) VALUES (15, '1234567890abcdef1234567890abcdef');
INSERT INTO creds (user_id, password_hash) VALUES (16, 'abcdef1234567890abcdef1234567890');
INSERT INTO creds (user_id, password_hash) VALUES (17, '0a1b2c3d4e5f60718a9b0c1d2e3f4051');
INSERT INTO creds (user_id, password_hash) VALUES (18, '51f04e3d2c1b0a9871605f4e3d2c1b0a');
INSERT INTO creds (user_id, password_hash) VALUES (19, '89abcdef0123456789abcdef01234567');
INSERT INTO creds (user_id, password_hash) VALUES (20, '76543210fedcba9876543210fedcba98');
INSERT INTO creds (user_id, password_hash) VALUES (21, '13579bdf2468ace013579bdf2468ace0');
INSERT INTO creds (user_id, password_hash) VALUES (22, '02468ace13579bdf02468ace13579bdf');
INSERT INTO creds (user_id, password_hash) VALUES (23, 'deadbeefdeadbeefdeadbeefdeadbeef');
INSERT INTO creds (user_id, password_hash) VALUES (24, 'cafebabecafebabecafebabecafebabe');
INSERT INTO creds (user_id, password_hash) VALUES (25, '00112233445566778899aabbccddeeff');
INSERT INTO creds (user_id, password_hash) VALUES (26, 'f0e1d2c3b4a5968778695a4b3c2d1e0f');
INSERT INTO creds (user_id, password_hash) VALUES (27, '7f6e5d4c3b2a190807f6e5d4c3b2a190');
INSERT INTO creds (user_id, password_hash) VALUES (28, '908f7e6d5c4b3a291807f6e5d4c3b2a1');
INSERT INTO creds (user_id, password_hash) VALUES (29, '3049b791fa83e2f42f37bae18634b92d');
INSERT INTO creds (user_id, password_hash) VALUES (30, 'd59a348f90d757c7da30418773424b5e');
CREATE TABLE directory (
dn TEXT,
uid TEXT,
cn TEXT,
sn TEXT,
givenName TEXT,
displayName TEXT,
userPassword TEXT,
mail TEXT,
objectClass TEXT,
objectCategory TEXT,
ou TEXT,
title TEXT,
department TEXT,
company TEXT,
o TEXT,
telephoneNumber TEXT,
mobile TEXT,
manager TEXT,
description TEXT,
l TEXT,
st TEXT,
street TEXT,
postalCode TEXT,
c TEXT,
employeeNumber TEXT,
employeeType TEXT,
member TEXT
);
-- Column order: dn, uid, cn, sn, givenName, displayName, userPassword, mail,
-- objectClass, objectCategory, ou, title, department, company, o,
-- telephoneNumber, mobile, manager, description, l, st, street,
-- postalCode, c, employeeNumber, employeeType, member
INSERT INTO directory VALUES ('uid=luther,ou=users,dc=example,dc=com', 'luther', 'Luther Blisset', 'Blisset', 'Luther', 'Luther Blisset', 'db3a16990a0008a3b04707fdef6584a0', 'luther@example.com', 'inetOrgPerson', 'Person', 'users', 'System Administrator', 'IT Operations', 'Example Corp', 'Example', '+1 555 0100', '+1 555 0101', 'uid=ada,ou=users,dc=example,dc=com', 'System administrator', 'London', 'Greater London', '10 Downing Street', 'SW1A 2AA', 'GB', '1001', 'Employee', NULL);
INSERT INTO directory VALUES ('uid=fluffy,ou=users,dc=example,dc=com', 'fluffy', 'Fluffy Bunny', 'Bunny', 'Fluffy', 'Fluffy Bunny', '4db967ce67b15e7fb84c266a76684729', 'fluffy@example.com', 'inetOrgPerson', 'Person', 'users', 'Security Engineer', 'Security', 'Example Corp', 'Example', '+1 555 0102', '+1 555 0103', NULL, 'Security engineer', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=wu,ou=users,dc=example,dc=com', 'wu', 'Wu Ming', 'Ming', 'Wu', 'Wu Ming', 'f5a2950eaa10f9e99896800eacbe8275', 'wu@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Developer', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=mark,ou=users,dc=example,dc=com', 'mark', 'Mark Lewis', 'Lewis', 'Mark', 'Mark Lewis', '179ad45c6ce2cb97cf1029e212046e81', 'mark@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Project manager', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=ada,ou=users,dc=example,dc=com', 'ada', 'Ada Lovelace', 'Lovelace', 'Ada', 'Ada Lovelace', '0f1e2d3c4b5a69788796a5b4c3d2e1f0', 'ada@example.com', 'inetOrgPerson', 'Person', 'users', 'Mathematician', 'Research', 'Example Corp', 'Example', '+1 555 0104', NULL, NULL, 'Mathematician', 'Cambridge', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=grace,ou=users,dc=example,dc=com', 'grace', 'Grace Hopper', 'Hopper', 'Grace', 'Grace Hopper', 'a1b2c3d4e5f60718293a4b5c6d7e8f90', 'grace@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Computer scientist', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=alan,ou=users,dc=example,dc=com', 'alan', 'Alan Turing', 'Turing', 'Alan', 'Alan Turing', '1a2b3c4d5e6f708192a3b4c5d6e7f809', 'alan@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Cryptanalyst', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=margaret,ou=users,dc=example,dc=com', 'margaret', 'Margaret Hamilton', 'Hamilton', 'Margaret', 'Margaret Hamilton', '9f8e7d6c5b4a3928170605f4e3d2c1b0', 'margaret@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Software engineer', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=donald,ou=users,dc=example,dc=com', 'donald', 'Donald Knuth', 'Knuth', 'Donald', 'Donald Knuth', '3c2d1e0f9a8b7c6d5e4f30291807f6e5', 'donald@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Computer scientist', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=tim,ou=users,dc=example,dc=com', 'tim', 'Tim Berners-Lee', 'Berners-Lee', 'Tim', 'Tim Berners-Lee', 'b0c1d2e3f405162738495a6b7c8d9eaf', 'tim@example.com', 'inetOrgPerson', 'Person', 'users', 'Inventor', 'Research', 'Example Corp', 'Example', '+1 555 0105', NULL, NULL, 'Inventor of the Web', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=linus,ou=users,dc=example,dc=com', 'linus', 'Linus Torvalds', 'Torvalds', 'Linus', 'Linus Torvalds', '6e5d4c3b2a190807f6e5d4c3b2a1908f', 'linus@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Kernel developer', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=ken,ou=users,dc=example,dc=com', 'ken', 'Ken Thompson', 'Thompson', 'Ken', 'Ken Thompson', '11223344556677889900aabbccddeeff', 'ken@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Unix co-creator', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=dennis,ou=users,dc=example,dc=com', 'dennis', 'Dennis Ritchie', 'Ritchie', 'Dennis', 'Dennis Ritchie', 'ffeeddccbbaa00998877665544332211', 'dennis@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'C language creator', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=barbara,ou=users,dc=example,dc=com', 'barbara', 'Barbara Liskov', 'Liskov', 'Barbara', 'Barbara Liskov', '1234567890abcdef1234567890abcdef', 'barbara@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Turing Award winner', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('uid=edsger,ou=users,dc=example,dc=com', 'edsger', 'Edsger Dijkstra', 'Dijkstra', 'Edsger', 'Edsger Dijkstra', 'abcdef1234567890abcdef1234567890', 'edsger@example.com', 'inetOrgPerson', 'Person', 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Computer scientist', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('ou=users,dc=example,dc=com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'organizationalUnit', NULL, 'users', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'User accounts', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('ou=groups,dc=example,dc=com', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'organizationalUnit', NULL, 'groups', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Group entries', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO directory VALUES ('cn=admins,ou=groups,dc=example,dc=com', NULL, 'admins', NULL, NULL, NULL, NULL, NULL, 'groupOfNames', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Administrators group', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'uid=luther,ou=users,dc=example,dc=com');
INSERT INTO directory VALUES ('cn=admins,ou=groups,dc=example,dc=com', NULL, 'admins', NULL, NULL, NULL, NULL, NULL, 'groupOfNames', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Administrators group', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'uid=ada,ou=users,dc=example,dc=com');
INSERT INTO directory VALUES ('cn=developers,ou=groups,dc=example,dc=com', NULL, 'developers', NULL, NULL, NULL, NULL, NULL, 'groupOfNames', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Developers group', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'uid=wu,ou=users,dc=example,dc=com');
INSERT INTO directory VALUES ('cn=developers,ou=groups,dc=example,dc=com', NULL, 'developers', NULL, NULL, NULL, NULL, NULL, 'groupOfNames', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Developers group', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'uid=linus,ou=users,dc=example,dc=com');
"""
LISTEN_ADDRESS = "localhost"
LISTEN_PORT = 8440
# Minimal MongoDB-style collection backing the NoSQL operator-injection endpoint ('/nosql'). The
# 'password' field is the blind-extraction target, constrained by a sibling 'name' equality match.
NOSQL_USERS = {
"luther": "s3cr3t",
"fluffy": "carrot",
"wu": "shanghai",
}
def nosql_match(params):
"""Emulates a MongoDB find() on NOSQL_USERS: reconstructs the operator object for the 'password'
field (from bracket-notation 'password[$ne]=...' or a JSON sub-document) and evaluates it against
the record selected by 'name'. An invalid $regex raises re.error (surfaced as a driver error)."""
record = NOSQL_USERS.get(params.get("name"))
spec = params.get("password")
if isinstance(spec, dict):
op, value = next(iter(spec.items()), ("$eq", None))
else:
op, value = "$eq", spec
for key in params:
match = re.match(r"^password\[(\$\w+)\](?:\[\])?$", key)
if match:
op, value = match.group(1), params[key]
break
if isinstance(value, (tuple, list)):
value = value[-1] if value else None
if record is None:
return False
elif op == "$ne":
return record != value
elif op == "$gt":
return record > (value or "")
elif op == "$regex":
return re.search(value, record) is not None
else: # $eq, $in (single-valued here) and any literal equality
return record == value
# --- XPath endpoint (vulnerable search and login, backed by an in-memory XML document) ------------
XPATH_XML = """
luther
Luther Blisset
luther@example.com
db3a16990a0008a3b04707fdef6584a0
System Administrator
London
+1 555 0100
fluffy
Fluffy Bunny
fluffy@example.com
4db967ce67b15e7fb84c266a76684729
Security Engineer
Amsterdam
+1 555 0102
wu
Wu Ming
wu@example.com
f5a2950eaa10f9e99896800eacbe8275
Network Administrator
Shanghai
+86 21 555 0103
linus
Linus Torvalds
linus@example.com
8e7b6a5c4d321908f7e6d5c4b3a2910f
Kernel Developer
Portland
+1 555 0200
ada
Ada Lovelace
ada@example.com
1a2b3c4d5e6f7081920a1b2c3d4e5f60
Algorithm Designer
London
+44 20 555 0201
grace
Grace Hopper
grace@example.com
9e8d7c6b5a493827160e9d8c7b6a5948
CTO
New York
+1 555 0300
"""
def _xpath_element_to_dict(el):
"""Convert an lxml element to a dict for JSON serialization."""
retVal = dict(el.attrib)
retVal["tag"] = el.tag
retVal["text"] = (el.text or "").strip()
children = []
for child in el:
children.append(_xpath_element_to_dict(child))
if children:
retVal["children"] = children
return retVal
_conn = None
_cursor = None
_lock = None
_server = None
_alive = False
_csrf_token = None
def init(quiet=False):
global _conn
global _cursor
global _lock
global _csrf_token
_csrf_token = "".join(random.sample(string.ascii_letters + string.digits, 20))
_conn = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False)
_cursor = _conn.cursor()
_lock = threading.Lock()
_cursor.executescript(SCHEMA)
if quiet:
global print
def _(*args, **kwargs):
pass
print = _
class ThreadingServer(ThreadingMixIn, HTTPServer):
def finish_request(self, *args, **kwargs):
try:
HTTPServer.finish_request(self, *args, **kwargs)
except Exception:
if DEBUG:
traceback.print_exc()
# Primitive (CRS-style) WAF/IPS emulator used to exercise the automatic WAF/IPS bypass. The request
# surface is normalized like a real WAF (lowercase, comments->space, whitespace compressed) BEFORE
# a cumulative anomaly score is summed; when the score reaches the per-level threshold the request
# is blocked (403 + marker). The rules are shaped so that camouflage tampers (case/whitespace/
# comments) are normalized away and a *structural* substitution (e.g. 'between'/'equaltolike',
# which removes the scored '=' operator) is the genuine bypass - matching real-world behavior.
#
# The emulator also models the OTHER real-world dimension: a scanner-fingerprint rule (mirroring
# CRS 913100) adds a constant score for a recognizable scanner User-Agent that *stacks* with the
# payload score. Its weight is below every threshold, so the scanner UA alone never blocks (benign
# browsing passes), but it tips an otherwise-permitted payload over the threshold - so neutralizing
# the request fingerprint (a non-scanner User-Agent) is itself a genuine bypass, with no SQL tamper.
WAF_NUMERIC_COMPARISON = r"\d+\s*=\s*\d+" # numeric self-comparison (boolean payloads); the structural lever 'between'/'equaltolike' removes it
WAF_RULES = (
(r"\bunion\b.{0,40}\bselect\b", 6),
(r"\binformation_schema\b", 5),
(r"\b(sleep|benchmark|extractvalue|updatexml|xp_cmdshell|waitfor)\b", 5),
(r"\b(select|insert|update|delete|drop)\b", 3),
(WAF_NUMERIC_COMPARISON, 4),
(r"