 Okay. I'm presenting a speech on SQL injection and out-of-band channeling. My name is Patrick Halson. I work for a small firm called Inspectit, where I'm one of the owners. I also founded a website called Secure.net back in the year 2000, where I published some of my tools. I currently work with penetration testing and application security reviews, source code reviews, general information security audits, basically. I'm going to present a speech on SQL injection with a focus on out-of-band channeling. I'm going to show a number of examples using this technique, and I'm going to finish off the talk with a demonstration of how this can be performed. The reason why is because when we perform our test, we still see a lot of vulnerable applications. However, because applications are more hard than today, maybe, than before, it's a bit troublesome to get the data out of them sometimes. Of course, tunneling data is fun. I'm not going to go through the basics of SQL injection that much, because it's quite a tight schedule. I hope that you're comfortable with SQL injection in order to understand everything here. I'm not presenting any arsenal of tools in order to automatically exploit these kind of vulnerabilities, and obviously not presenting a silver bullet solution to all SQL injection problems. Doing a very brief recap of SQL injection. It's a high-risk security vulnerability. We usually find it in web applications, but it's not limited to web application. It's when you have the ability to inject arbitrary SQL code through poorly validated application parameters. One might argue that this is due to inadequate design or due to improper validation controls. Having proper validation controls obviously rules out other problems such as cross-site scripting, so it's always a good idea to have it. However, it's also even better to separate the data from the actual SQL code, not like building by concatenating strings, because then you usually run into these problems. Depending on the privileges and patch levels of the database server, the consequences may obviously range from troublesome to devastating. A common misconception might be that usually just forms and URL parameters are vulnerable to this kind of problem. However, we find problems in cookies and referrer fields and user agent fields in the HTTP headers. For example, when you implement a logging mechanism in order to log improper or failed login attempts, for example, you write a row into a database and use the insert statement, then you append a lot of data like which web browser is the user using. Putting a couple of quotes in that user agent field, you can actually get control of the data. So looking at a classic example, we have the authentication function where you log in using your username and password. So basically, the user supplies a username and password, and the database retrieves a user ID for this user, which is used throughout the application. In this case, we have no parameter validation, so we can enter any data we wish for. And by entering, for example, a quote, or 1 equals 1 dash dash, we circumvent the whole login function and get access to the application. So basically, that's SQL injection in a very brief recap. So our band channeling, well, it relies on traditional SQL injection weaknesses for exploitation. However, contrary to normal SQL injection or in-band injection, it uses an alternative channel to return data. So for example, you could be using timing, like for example, does the first user begin with an A, then you wait five seconds, you would know that, okay, there's a user starting with A. You could use HTTP, which I'll show later in a couple of slides, where you send the data in a HTTP request. And you could use DNS, which is the focus on the speech later on. And several different approaches exist, which depend on the backend database. If you're running Microsoft SQL Server or Oracle, you might have to choose a different approach in order to exploit this vulnerability. So when is exploiting using out-of-band channels interesting? Well, when you don't have any detailed error messages, which you can rely on to extract data, it could be useful. When you gain access to or when you're able to control a SQL query very late in the query, like in the order by close, which I'll show also later on. When you're able to inject a second query through batching when you do a semicolon and then you append a lot of SQL code after. And when results in somewhere being limited or filtered, for example, you just get the first row of a table. And when firewall rules are lax, you can open a channel back to one of your DNS servers or one of your HTTP servers or whatever. Contrary to blind SQL injection, when you do a lot of queries in order to extract little data, out-of-band channeling turns this around, you do a lot of injection or one single query and you retrieve all the data with one single query. And obviously when blind SQL injection looks like the only option, this might come in handy in many cases. And I believe it's a much more efficient way of extracting data. So we have three examples here where we get control of the data of the SQL statement in the first case very late in the order by close. We have a store procedure, which actually logons the user. It returns true or false. So basically we'll have a hard time here retrieving any data. But using out-of-band channeling, we could retrieve anything from the database. We have also the last query here, which simply returns a single row. And depending on a number of different factors, which we'll discuss, the channel chosen can be more or less suitable. I'll show you three different channels and I'll finish up by demonstrating their DNS channel. What I'm going to talk about first is OpenRoset. It's a SQL server function. And I'm also going to talk briefly about the UTL HTTP package in Oracle and then finishing with a couple of slides of DNS. So OpenRoset, I decided to include this in my demonstration, even though it's not very likely to be able to exploit it nowadays because it's restricted in most SQL server environments. But it illustrates the problem and it shows you a good picture of how everything works. OpenRoset allows you to retrieve information from an alternative data provider. And usually it can be used together with Union in order to extract data from another database for a neighbor database. And it's disabled by default in the SQL Server 2005. And in the SQL Server 2000 Post Service Pack 3, it's also disabled and available only to sysadmin users. The syntax not very... Here's a classic example of enumerating data from a neighbor database. So basically we do a Union of our first select statement and we do the OpenRoset part, followed by we need to guess a correct user ID here. So we're like guessing system administrator blank password. And we try to extract data from the user's table on the server 10, 10, 10, 10. And we try to join this result in the original SQL query in order to get the results back in one web page. So basically we're on the top talking to the web server. The web server communicates to the database server. The database server executes a query to our very secret database, fetches the data and joins it all together in the first SQL server and returns it back to our web server. So how is this relevant in regards to out-of-band channeling? Well, OpenRoset can be reversed. So instead of using it to query data, we can use it to insert data. So actually we can fetch the data from one source and insert it to another. And the destination database could be any host reachable from the source. And in this way we can insert data into one of our own database servers through batching statements. So we try to terminate the first query and then we do a semicolon and then we add an insert into OpenRoset, which would look something like this. So we have the first query here where we fetch user ID, the login function, remember from the first slides. We do a semicolon after our password and we do an insert into OpenRoset. We point out our server, database server, for which we already know the username and password. And then using the first select statement actually points out which table we want to insert data into in our database. And the second query says which table we want to fetch the data from. So basically you don't need to know any username or password since it's our own database. And after the others we have a comma 443. This is the which port we want to use in order to insert our data. So you can choose any port here. You could use HTTPS, HTTP, FTP, Telnet, whatever, become suitable in the environment you're actually attacking. You can also use it for port scanning. So you could use a higher timeout. Use like a timeout of five. Then you can easily check which ports are allowed outbound. And once you find a suitable port, you can just execute everything. In order to illustrate it with a picture, it would look something like this. We still talk to the web application server, which talks to the database server, which opens up a connection through our firewall back to us. So the obstacles in this solution is that you need to have the database server where you want to insert your data and it needs to be reachable from the source database. So in a tight network you might have problems reaching the correct ports. Also we need to have the source and destination tables they need to be identical. We need to know what columns we have in our user table in order to insert them in our own user tables. We have to know the column names, the data types, the size of the data types. Usually when we do this kind of attack, we're successful in using HTTPS or HTTP or any of the common protocols. And as we have in SQL Server, we have something called sys objects and sys columns, which are meta tables containing information about all objects in the database, like all tables, all columns for all tables and all data types for all columns. So by knowing the layout of these tables we can create our own similar tables in our database and we can extract all the data we need. So first we start off by extracting, okay so which tables do you actually have? Oh well I have the user table and the payments table. That's interesting. So we do an identical payments table and then we just extract everything through this batching technique. Looking at the summary of the OpenRosa then, like I mentioned in the beginning, only sys admin members post ssql server service pack 3 are allowed to actually access these functions. But for some reason we've been able to do it quite a lot this year so actually it's still possible in many installations. Most hardening guides suggest disabling OpenRosa altogether. You need to have a direct connection back to your database server so in high security environments this is most probably not possible of doing and it's limited to sql server obviously. Just to illustrate that I'm not just picking on sql server I decided to include the UTL HTTP package as well from Oracle. Basically what the UTL HTTP package allows you to do is to perform a GET request on a web page. The result from the web page where the first 2,000 bytes are returned in the answer like in a normal query so you do select. In this case we do UTL HTTP request and we try to download Oracle's web page. We'll get the 2,000 first bytes of this web page. And this can also be exploited in order to tunnel data through this type of function. What we actually do is that we're dynamically building the URL that we're retrieving. So we specify one of our own web servers and then we dynamically fetch table data in order to build our URL. And then by looking at the web server log files on our web server we can see what the data actually is in the database tables. So this is an example of late exploitation. Typically when we've seen tables on different web pages, you have headers where you can sort the table data in a web page. Sometimes this is achieved through ascending or descending as a parameter in the URL. This data is then used in order to sort the table data and in order to match the actual topic that you clicked on in the header. In some cases this is injected through concatenation of strings and just concatenated at the end of a static SQL statement. In Oracle you can, if you return exactly one row of data, you could use this in order to order this first table that I just described. So in this case we're actually injecting a parent thesis instead of descending for example and then we do a UTL HTTP request. We try to access our web page, secure.net, the URL is slash ing for injection and then we do a select username and the user password from table logins where row num is less than two. So this will return exactly one row from our login table. So basically we're asking the web server to start the UTL HTTP and perform a request to our server. The UTL HTTP package accepts proxies. So in an environment where we have a proxy server you just tag along the proxy name and you go through the proxy out on the internet. Looking at the log files you would see something like this with the user names and password separated by underscore. And looking at Oracle you can see that many databases still have this package unrestricted. It's available to the public user which is a user, a pseudo user which everybody belongs to, or a role actually. So anyone can execute this function. So even if you have very limited access in Oracle database you could use this attacking technique in order to extract data. Commonly firewalls tend to be less strict on outbound traffic. So accessing HTTP or HTTPS or going through a proxy usually solves this. The limitations, yes. Well it's limited to Oracle database server. Hardening guides suggest disabling this obviously. And one other limitation. It requires a direct outgoing connection to our web server which we control. Slide 30. DNS and outbound channeling. So DNS, it's a hierarchical protocol. Most of you use it daily. So in order to illustrate the benefit of using DNS let's assume we manage a DNS server for the zone secure.net. So if somebody at the corporation X tries to look up a host in our domain the query will find its way to us as it's a hierarchical protocol. So this would allow us to monitor queries for sub-domains or hosts in our domain. So even if you have a hardened database it's our experience that usually you allow DNS. And most internal DNS servers are allowed to forward their queries. And most hardening guides if you look at general hardening guides available from the vendors they failed to actually mention a lot of these packages which can be used in order to do DNS resolution. So if we could some way trigger a DNS resolution in a database we would have an indirect channel to a DNS server of our choice as we're controlling the domain name of the name resolution. We just point it to our domain and the query will travel all the way back to our DNS server. So if we could trigger DNS we could ask for any host in our zone. So in this case we do a DNS resolution to our corporate DNS server which forwards the query to the authority of service for .NET which in their turn forwarded the tower DNS server for the secure .NET DNS zone. Both Microsoft and Oracle provide functions and stored procedures and packages in order to do DNS resolution. Some of these functions are executable by the public user. So basically what I'm saying that anyone can execute these packages or stored procedures. And like I previously said some of them are not mentioned in hard name guides which makes them available in a lot of database servers. So in SQL server a number of stored procedures accept UNC path names. A UNC name is when you point out a share on a network network server and if you point a UNC path to a fully qualified domain name it will result in a DNS resolution being performed. And this can be used in order to channel database information to an attacker. So by looking for example at the extended store procedure xpdir tree xp file exists xp get file details sp add job step they all accept UNC paths in their file parameter. The backup database when you choose to backup a database as the database owner of a database you can point it to a file to be backed up. You can point this file to any network based server. So basically you can do DNS resolution through the backup command as well. If you look at Oracle you have the UTL in adder package which basically does DNS resolution that's what it's meant for. You have the UTL HTTP that I described where you do a connection or request to a web server. So even if you're not allowed to talk to the web server in outbound traffic maybe the firewall blocks it you can still use the package in order to do DNS resolution. So DNS traffic will most probably go through the firewall and out to our DNS server. There are packages like UTL TCP and most probably there are a lot of more packages. I just had a brief look in both SQL server and Oracle and I found this one so far. And what I was interested in was packages that have public privileges so basically whoever can execute. So even if you just have read access in a database you can still execute these packages. So how do we extract data using DNS? Well, basically we need to put the whole data or a payload so to speak in the DNS hostname. As the zone name, secure.net just directs it to our DNS server. The actual hostname is the query that's being performed to our DNS server. It means that our hostname has to be built dynamically using table data. So we stuff all the data into the hostname and then we try to fire it away using a DNS resolution and it will end up in our database or in our DNS server. And by using cursors and variables in the SQL you could actually build these hostnames dynamically. Once you have built the hostname you just fire it away using Expedure Tree or XP GetFileDetails or whatever your stored procedure of choice is. So I'm providing a sample here. We have the variable s declared where we start off by saying that we want to use the Expedure Tree stored procedure in the master database. We add a double backslash in order to explain that we want to use the UNC pop. We tag along the user underscore name function which will result to the current username. Then we just tag along our suffix or our domain .inni for injection .secure.net then another backslash and then the directory we want to perform a directory tree inside. The directory tree is never being performed as in our demonstration I'll always be returning the loopback address in the DNS resolution. So basically we're just interested in the name resolution. We're not interested in doing a directory tree we're just interested in performing the DNS resolution. That's it. We can do the same thing with basically any parameter or any function in SQL server. In this case we're fetching the server name with the name of the instance as well and we're tagging it along with our domain name in order to get the resolution to work. So looking at DNS we have some challenges. DNS records are cached. This is true for both successful DNS requests and host names that are not found. We also have length restrictions on our fully qualified domain name 255 characters and on our labels. The labels is the data between the dots in a fully qualified domain name. We have the problems with some characters which cannot be in a fully qualified domain name and the obvious solutions are setting a low or zero time to live. If you have control of the DNS server in our case I'll show you a small DNS server written in Perl which always returns a very low TTL. But if you're running TCP dump on a bind database for example you might not have the opportunity to set a low TTL value. In these cases you can always you can add a unique value to the data being queried. So you tag it along before the actual data you want to see. So performing the same request 10 times always sends a different seed so to speak which will always result in unique DNS resolutions being made. And the obvious solution for length limitations are obviously to truncate or split values exceeding length. And for the nasty characters we just convert them prior to our resolution. If you look at the caching part then either you try to set a low TTL value or in the demonstration I'll be using a checksum value or a seed. I'm using the checksum function in SQL server which takes one parameter and I'm feeding it the current timestamp. So if you do subsequent requests it will always be a bit different. And the end result looks similar to the following. You have a large number in the beginning, you have a dash and then you have your table data followed by the zone where you want to do the resolution in. So modifying our first example we would actually add the checksum of the current timestamp. We need to convert it to a character stream using the convert of our car function. And then it's basically exactly the same. So looking at RFC 1035 you see that the label restriction and the labels they cannot exceed the length of 63 characters. The fully qualified domain name must be 255 characters or less. So the labels are actually the data between the dots. This means that we need to in some ways slice and dice our data in order to fit these restrictions. And our goal in this case is to split a large string and send it over several consecutive DNS requests. So my proposed layout for this is to actually do it this way. So you have first indicated that the following 0x is a hex string where our data will be fitted with the limiting dots. You have an ID for the specific data being sent that you don't have a part number which specifies when we chopped up the data for suitable fully qualified domain names. It says okay this is part one of seven where the max part describes how many parts there are in total. So as DNS travels over UDP you can have some loss or you can have packets coming in the wrong sequence. This way you have control on how many packages you're actually supposed to receive and in what order. I'm not using the part and max part in the demonstration at all. However, if I would use it in the future over a more reliable network I would use it. So by first converting our data to hex we don't need to worry about any odd characters showing up. So what we're actually doing is taking any data type and using the convert or cost function in SQL server and converting it to binary. When we have it in binary form you can then use the function verb into hex string which converts our binary data into a hex string starting with 0x and then letters from a to f and 0 to 9. So we no longer have a problem with characters which will break our DNS resolution. The hex string then needs to be divided into adequate pieces and this is most easily done by using the substring function. So what we actually do is that we first split our data into suitable fully qualified domain name lengths. When we have these blocks we split them into smaller blocks divided by dots so they fit our label restrictions. We then tag along the ID and part information and when it's all built we send it using the ExpedureTree command. Like I said earlier the ExpedureTree doesn't do a directory tree in this case. The only purpose of the ExpedureTree is to perform a DNS resolution in order to send our data to our DNS server. This means that the receiving part, the DNS server, reverses the process and prints the data out. So basically we're sending character by character but in larger chunks. And using this strategy we need only to inject once. So we inject one large query and retrieve all table data instead of using like 10 requests in order to get three characters. Basically only the size of the variable receiving the data is our limitation. And obviously those database servers that don't do DNS will be a sort of limitation too. So this is time for the demonstration and hopefully it will work. So I just started our small DNS server here. We're talking to VMware server here in another window. It's running Windows with the SQL server 2005 service pack 2 all hotfixes everything. And the DNS server is set to my host where this black window is running. Oh, yeah. Let's see if we can... Yeah, like this. So I'll be cutting some copy pasting some data here in the windows. Let's see. This web application is just some application available on the internet where I just trashed all the backend and just replace it with a vulnerable code basically. So it has nothing to do with this actual website. And I'm running everything locally. So basically it's not giving us any detailed error message just saying that an error occurred, please try again later. So we're going to try to inject some data into this. And we start off by injecting the first one that I showed you with the username. So we get a query that says www.inni.secure.net The little pearl script I've written just chops off everything called inni.secure.net. So running it in a non-verbose mode won't show the queries and actually produce a more readable format. I'm going to put this small DNS server on the same web page as I'm putting the presentation later on. It's not yet there. Looking at the server name in order to as the server name actually has a backslash in it. The instance is written as well. We need to tag along this small piece here with the replace where it converts the server property. It converts the backslash to underscore. This is before we start chopping up data. Also when we chop up the data using the bigger SQL server functions we won't be needing this. So in order to defeat our caching problem I'll show you the query using the current timestamp as well. So it tags along the 21, 55, blah blah blah. If we run it once more it should give us slightly higher value. So we can do subsequent queries and always be sure to get a proper resolution. I'm going to switch into non-verbose mode because it's not going to be as pretty if I don't. Like I mentioned we're going to have a look inside the sys objects and sys columns tables which all describe the we have a small tiny injection code here. So basically we inject it here and it starts up a bit slow but hopefully we'll get the rest of the data as well. Hopefully. So here it goes. So our little query is in the background. I need to scroll the screen in order for you to see the whole but it's in the slides. So what we see here is first our database name which is webshop. Basically this script that I just injected goes through all databases in the database server. For all databases it looks for if it has permissions it looks for all tables. For all tables it looks for the column it results the data type and for all data types it results the size of the data type. So what we have here is a complete database schema basically. We see that we have the webshop we have a table called payments. We see a purchase ID, card holder, card type, card number, expiry everything. We have a products table where we're pricing information which might be handed to change. We have something called users with usernames and passwords. So as we now know our data or our table definitions we can move to the next tiny SQL statement here which might work as well. Okay so we get all the usernames and passwords. Obviously with Swedish passwords I'm sorry for that. And then moving right along to the interesting stuff we look at the credit card numbers. Yeah I think so. There they go. Please don't write them down. So we have the username or the full name as it's shown on the actual card. We have the card type, we have the number, we have the CVV. You want it? Yeah well basically that's it. That's the end of the demonstration and the end of the talk.