SQLi Lab 1 Confusion

I’m very confused on “Detecting the current DB User”. Under “Detecting the first character” they list some information:

  • Character interval: [a-z] - The only part that makes sense to me
  • ASCII interval: [97 - 122] - ASCII interval?
  • ASCII flag: 109 - Don’t think I’ve seen this anywhere before. I see 109 down in the payload? But what’s 109?
  • Character flag: m - Same here. Character flag?
  • Payload: ' OR ASCII(SUBSTRING(user(),1,1))<=109 #

I have no idea what’s going on here. The payload returns False. Which confuses me because I thought we were checking for characters between a-z?

The next payload says it’s checking between n-z? Why n? The following says u-z and so on. I’m just very confused with this manual enumeration section.

I can get the exploit working with SQLMap but the goal here isn’t to be a script kiddie.

Hello Christopher,
Don’t worry, it’s all cloudy at the beginning.

In this kind of payload you’re comparing ASCII codes of specific characters to the right hand side of your expression (see ASCII(...) part of your payload). I think you should read up about ASCII first and then it will become clear why you have numbers instead of letters.

Then, picking number 109 along with < or > operators has its purpose (which letter does ASCII code 109 represent?). Yes, you could just use = operator and try every possible letter. But if you pick a letter from the very middle of the alphabet, use < or > operator and get the result you can discard half of the options right off the bat.

I highly recommend playing with your own instance of database locally. Tool like Navicat (it has free trial) may help a lot.

I hope that you will find some food for thought in this post.

All the best

Is it checking ‘m’ and below? M, L, K, J…I think the most confusing part is the a-z. We aren’t actually check a-z with that payload are we? We’re only checking a-m?

I think I’m starting to put it together:
a-z have the ASCII values 97-122 (the ASCII interval).
The ASCII flag is the decimal number that corresponds with the character flag?

But in the next query they’re checking <=116 wouldn’t that be a-t? An even larger interval?

That’s right, the payload checks if the username’s first letter is in ASCII range 109 and below. If this results in False condition, it means that our letter is above 109 (which means it’s somewhere between n and z, assuming we look for lower case letters only).

Now we know that our answer isn’t in range [a-m]. Again, from here we could now try all [m-z] letters with = operator, but we don’t do that because it’s a lot of work. Instead we split our remaining range [n-z] into half again, i.e. we pick t because its somewhere in the center of [n-z] range and use < or > operator.

But in the next query they’re checking <=116 wouldn’t that be a-t? An even larger interval?

It is but we don’t care about letters lower than m anymore, we already know the letter we look for is not in range [a-m]. Instead we split the remaining range into 2 halves again.

This way we minimize the number of request required to guess letter we look for. We get smaller and smaller ranges until the range becomes single letter. This method, I believe is derived from “binary search” algorithm if you’re interested to go deeper.

Hope this helps

1 Like

Hmm, I must be missing something. It seems like we’re expanding our search interval not reducing it. First we search a-m with <=109 (so 0-109). Then we search <=116 (0-116) which is an even wider search?

I think of using 116 as a way to determine whether the letter we look for is in
range [n-t] or [u-z].

This reduces the search interval into one of those 2 ranges. Now we have to look for our letter inside only one of those ranges.

You’re also right that we technically expand the range: [0-109] has more numbers than [0-116] of course. But the key here is that this range contains numbers that aren’t our answer, if the payload returns False. So at the end of the day our space containing the letter we look for (search interval) is shrinking.

Did it click? :wink:

Edit:
I don’t want to confuse you more but maybe this will help you to understand it better:

  • At the beginning we have whole range to check i.e. [a-z].
  • The first payload tells us if our letter is in range [a-m] or [n-z]. From now we care only about [a-m] OR [n-z], depending on first payload’s result. Let’s assume that the result we got is False → now we care only about [n-z] because this is where our letter lives.
  • We split range that left on half again, by picking new ASCII code from range we inspect ([n-z]). It happens to be t.
  • Our second payload will tell us if the letter we look for is in range [n-t] or [o-z]. Based on response we will know which one it is.
  • We continue this way until our range will contain only single letter, it will be our answer.

Also, be aware that this is only optimisation. You can successfully check all alphabet letters one by one and it will do the job - it will just take more time (in case of alphabet, not noticably longer). Tools like sqlmap have already implemented these kinds of optimisation mechanisms. You can see what kind of payload sqlmap sends if you use -v 3 flag.

Good luck

Ok. I think this helps. I really appreciate you taking the time to write these responses!