About this blog

I'm a developer with over 10 years experience who wants to transition to infosec. This blog is an informal record of my experiments with OWASP's Mutillidae II, a web application exhibiting a multitude of deliberate vulnerabilities. I will also take Offensive Security's PWK training course and get the OSCP certificate
Showing posts with label blind sqli. Show all posts
Showing posts with label blind sqli. Show all posts

Monday, 29 August 2016

Brute force data mining with any sqli

So on the first page I looked at - login - there was a sqli.  We can't get any SELECT output from the sqli (e.g. SELECT PASSWORD...), so I think that's called a 'blind' sqli.

Anyway, we can distinguish between an arbitrary proposition passing and failing (in our case by presence/absence of error message, although a timing attack would also do), and in conjunction with already knowing the table and column name (thanks to that chatty error message), it is enough to have a go at brute force mining the password, in case it is in plain text.

I mine the length first, for two reasons:
  1. It will cut the number of requests down (don't have to exhaust the character set at the end)
  2. My testing found that character indexes that didn't exist matched a space, and I couldn't be bothered to make a special case for detecting actual space versus a nonexistent char
I also looked up the frequency of password chars and test for them in that order, to reduce request volume.

Result:

length  9
password 'adminpass'
77  requests in total

It was plain text, which is bad.  I think most people know by now to store salted hashes, and make the hash cost high.

Brute forcing is noisy, but really 77 requests is cheap to get a password!  That sort of volume probably won't attract any attention, and nobody gets locked out of their account either (we aren't passing a username when we fail).

Really, any sqli will do.  And if I didn't know the table/column name, I could get 'meta' and start brute force mining the schema/table/column names themselves and burrow top-down into interesting strings (really noisy, but it'll work if the permissions are good).

Login sqli

The page allows you to discover whether an account exists, which is info leakage.
The username case doesn't seem to matter, admin, Admin, aDmIn are all treated the same.

Single quote in username field:

Query: SELECT username FROM accounts WHERE username='''; (0) [Exception] 

Single quote in password field:

Query: SELECT * FROM accounts WHERE username='' AND password=''' (0) [Exception]

It also shows that MySQL is being used.  An application should not be giving this kind of information away when an error happens.

Presumably if a row is returned, the app takes this as a successful auth, so let's try:

' or true;#
There are likely other accounts... and returning more than one row should have resulted in an expectations violation, but it didn't.

' or true limit 1,1;#
Not knowing Python at all (and wanting to learn it instead of using bash), it took me a while to write a satisfactory script to enumerate accounts:

Result:

{'bryce', 'dave', 'admin', 'cal', 'patches', 'jeremy', 'PPan', 'dreveil', 'samurai', 'scotty', 'jim', 'kevin', 'adrian', 'bobby', 'james', 'simba', 'john', 'rocky', 'ed', 'tim', 'ABaker', 'CHook'} 
22 accounts 

Or we could have just gunned straight for any user we know the name of, etc:

' or username = 'kevin';#