0% found this document useful (0 votes)
55 views

Manual SQL Injection Discovery Tips

The document provides tips for manually discovering and exploiting SQL injections. It discusses testing different SQL contexts like between parentheses or quotes to trigger errors. Example techniques include adding comments, comparing system variables, and subtracting from integers. The document also covers bypassing firewalls and blacklisting by accessing the original server IP and using non-standard host headers. Exploitation involves proving differences in output or retrieving sensitive data.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views

Manual SQL Injection Discovery Tips

The document provides tips for manually discovering and exploiting SQL injections. It discusses testing different SQL contexts like between parentheses or quotes to trigger errors. Example techniques include adding comments, comparing system variables, and subtracting from integers. The document also covers bypassing firewalls and blacklisting by accessing the original server IP and using non-standard host headers. Exploitation involves proving differences in output or retrieving sensitive data.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

5/3/22, 12:55 PM Manual SQL injection discovery tips

Gerben Javado





Manual SQL injection discovery tips


August 26, 2017

According to bugbountyforum.com's AMA format one of the


most popular questions is How do you test for Server
Side vulnerabilities such as SQLi? . Up until recently I
was struggling with this question (especially towards SQLi) as
well. The SQLi's I did find were often discovered and
exploited by sqlmap after I found that the server responded
weirdly to a single quote. However in the last 2 months I was
forced to dive deeper into manual SQLi discovery since my
target has a strong firewall making sqlmap useless (and yes, I
looked into --tamper). In these two months I was able to find
over 10 SQLi which I learned a ton from. This blog will focus
on sharing my process and knowledge as well as showing real
world examples. I will divide the blog in two parts: discovery
and exploitation, since both are needed for a good report.
Finally, this blog assumes MySQL is used since it holds over
half of the market share.

Discovery
The first part of finding a valid SQLi is the discovery of the
vulnerability. Here the most important thing is to know in
which SQL context your input can end up. Here some basic
examples:

SELECT user_input FROM tournament ORDER BY r


egion;

INSERT INTO tbl_name (col1,col2) VALUES (15,


user_input);

DELETE FROM somelog WHERE texts = 'user_inpu


t'

https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 1/6
5/3/22, 12:55 PM Manual SQL injection discovery tips

Here we can see our user_input ending up in range of


different contexts: between () , between ' or without any
delimiters. What these commands all have in common is that
they will all turn invalid once a ' is injected as input. The
first two don't even have delimiters and will also give an error
if a non-existing system variable is used, like: @@versionz
(instead of @@version ).

Once you are able to make the server return an error (mostly
HTTP 500 status) you have to confirm it is the SQL command
that is causing the error and not something like a date parser.
To do this you can use a range of tricks:

If a ' is causing the error try to see if \' will result in


success message (since the backslash cancels out the
single quote in MySQL).
You can also try if commenting out the ' results in a
success message like: %23' or --' . This is because
you tell MySQL to explicitly ignore everything after the
comment include the extra ' .
If a ' is not allowed you can use comparisons between
valid and invalid system variables like @@versionz vs
@@version or invalid vs valid functions SLEP(5) vs
SLEEP(5) .
Sometimes your input will end up between () make
sure you test input)%23 as well to see if you can
break out of these and exploit Union SQLi for example
( input) order by 5%23 ).
If the normal input is just an integer you can try to
subtract some amount of it and see if that subtraction
works ( id=460-5 ).
Try to see if an even amount of quotes results in a
success message (for example 460'' or 460-'' ) and
an uneven amount results in an error (for example
460' or 460-''' ).

Example
To make this more clear we have the following URL:

https://www.example.com/php/sales_dash_poc_handle.php?
action=month-
breakdown&type_of_report=billing&city=all&month=8&year=2017&poc=3514100

https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 2/6
5/3/22, 12:55 PM Manual SQL injection discovery tips

This basic URL returns a 200 status code. The input


poc=35141008' returns a 500 error and
poc=35141008'%23 does as well, but poc=35141008''
returns a 200 status. This hints that the parameter is likely
not using any delimiters, thus I tried poc=35141008%23'
which would return a 200 status code. Now we know that we
can inject simply between 35141008 and %23 . After this I
tried a simple 35141008 OR 2 LIKE 2%23 which worked
while 35141008 OR 2 LIKE 1%23 returned a 500 error,
proving that boolean SQLi was possible here. It isn't however
always this easy and this example doesn't show much impact,
this is were the next section comes in, proving data retrieval.

Exploitation
After you have found a SQLi you always have to try to proof at
least a difference in output (for boolean and sleep based) or
sensitive data in the output (for error and union based).
Unfortunately this is not always straightforward especially
with firewalls and blacklisting in the way. This section is to
help you get around those.

Firewall
The first thing you should try when dealing with a firewall is
see if you can find a misconfiguration in the setup. For most of
these firewalls and CDN's you can access the unprotected
website by visiting the original IP (which the firewall is
standing in front of) and then using the original domain name
as host value. The first step here is to find the original IP of
the website, this is often not too hard using services that keep
track of the IP's a website has used
(http://viewdns.info/iphistory/). Often the one used before
the firewall IP comes in is the one they still use (basically the
one after it says cloudflare or akamai). Shodan can also be
really usefull when it comes to finding an original IP.

After you have found the original IP address try to access the
website with the original Host header. In cURL this works like
this (adding a header also works in sqlmap):

$ curl --header 'Host: www.example.com' 'https://


54.165.170.2/' -v -k

https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 3/6
5/3/22, 12:55 PM Manual SQL injection discovery tips

On my target this was unfortunately forbidden, thus I had to


be creative. Here I found that by adding a dot to the host
( www.example.com. ) wouldn't be restricted and still
allowed me to browse the direct IP. Adding:

54.165.170.2 www.example.com

in your /etc/hosts file will allow you to browse


www.example.com in the browser without any firewall in
between. From here any restrictions should be gone and SQLi
exploitation should be fairly easy.

Bypassing the blacklist


Sometimes you can't bypass the firewall which will require
you to bypass the (likely) blacklist that is in place. Here my
biggest tip is that Google is your friend. Find niche functions
with powerful capabilities that require you to somehow
extract data. However here are some of the common tips:

Using comments in your query as spaces to break a


firewall regex or word combination. For example:
2/*dhab
bc*/OR/*dahdshka*/2/*sd*/LIKE/*da*/"2"/**/%23
translates to: 2 OR 2=2%23 .
Use LIKE instead of =, 2 instead of 1 and " instead of ' as
the example shows above. Many people are lazy and so
are firewalls, walking the path less traveled will catch
many firewalls off guard.
Like I said above use Google to find niche functions. I
found for example that MID() works the same as
SUBSTRING() , however the latter was banned the first
one wasn't. Same goes for variables CURRENT_USER()
is banned and CURRENT_USER wasn't.

Putting it all together


Out of the SQL injections found this was probably my favorite
since the exploitation was fairly hard. So I'll describe it in
detail and hope that you guys can learn something from it.

I came across this URL:

https://www.example.com/php/analyticsExcel.php?
action=res_unique_analytics&resid=2100935&start_date=2016-
https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 4/6
5/3/22, 12:55 PM Manual SQL injection discovery tips

07-11 00:00:00&end_date=2017-08-11
23:59:59&action=res_unique_analytics&entity_type=restaurant

Here I have legitimate access to 2100935 and requesting


2100934 would result in an unauthenticated error. The weird
thing was that adding a single quote after 2100935 would
result in a 500 status error and adding two would make the
URL work again. Here to make exploitation easier I used my
www.example.com. bypass (described in the Firewall
section to get rid of the Akamai WAF). From there I tried to
find a place to inject my own SQL commands in the input,
however I didn't manage to inject a comment in the string,
thus I concluded the query was quite complex. Seeing this I
decided to focus on a simpler OR statement which can be
injected almost anywhere. Here I noticed that ' OR 1='1
would return a 200 status, ' OR 1='2 would be exactly the
same, ' AND 1='1 the same, ' AND 1='2 the same and
finally none of the sleep() commands seem to have any effect.

Super weird I can basically confirm the syntax I injected is


correct but none of the techniques allowed to extract data.
Here I tried ' OR @@version=5 which resulted in a 200
status and ' OR @@versionz=5 resulted in a 500 error. This
at least confirmed I was working with MySQL and showed
that the injection was really there. This pointed me towards
the MySQL IF function. My thought was that if I was able to
return an invalid function based on whether the if statement
was true or false I could proof data extraction. This didn't go
quite as planned since MySQL seems to validate command
before executing the IF statement, but the IF statement
ended up being part of the solution. Feeding a valid SLEEP
command in the IF statement with a positive integer would
result in the server timing out, while return a simple integer
from the IF statement would return in a fast 200 status code.
From here I developed the following POC:

TRUE: if @@version starts with a 5:

2100935' OR
IF(MID(@@version,1,1)='5',sleep(1),1)='2

Response:

HTTP/1.1 500 Internal Server Error

False: if @@version starts with a 4:

2100935' OR

https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 5/6
5/3/22, 12:55 PM Manual SQL injection discovery tips

IF(MID(@@version,1,1)='4',sleep(1),1)='2

Response:

HTTP/1.1 200 OK

Summary
If injecting a single quote leads to different output in the
response try the different techniques outlined in this blog to
see if you are dealing with a SQLi. After you have determined
in which SQL context you are working develop a POC that
either shows sensitive data (error and union based) or shows
a difference in output depending on whether the question
asked is true or false (boolean and time based).

⇠ Recon Android apps to The race to the top of a bug


widen scope bounty program ⇢

https://gerbenjavado.com/manual-sql-injection-discovery-tips/ 6/6

You might also like