When not even SQLMap’ --eval
can help :)
There are some SQL injections that exploiting them are not as straightforward as what you see in the ethical hacking courses. like when the value of the vulnerable parameter is base64 encoded. what do you do in that cases?
well, you maybe use the --base64
flag of sqlmap
.
Or for more twisted scenarios maybe you want to play cool and use the scripting engine of sqlmap
and ask for help from --eval
flag.
But what if not even the powerful --eval
functionality can help?
that’s when you need to level up you knowledge. ⏫
Part One: Vulnerable Functionality
during a pentest, I was testing an application that was used for sending official emails and documents.
in the inbox section, there was functionality for filtering the emails. by using a drop-down you could tell the application which mails to show you:
unread mails
high-priority mails
mails with attachments
etc.
upon choosing any of the options a POST request would be sent.
the POST body was strange, it was a JSON which in one of its parameters it contained XML data and the attributes of one of the XML tags were the inputs for the vulnerable SQL query.
simplified POST body:
{
"param1": "<Search Filter='GIBBERISH HERE' Order='DESC' Sort='priority'/>",
"param2": "something..",
...
}
methodology:
what do we have here? input for a SQL query
which parts of the query do we have control over?
1. WHERE (Filter)
2. ORDER BY (Sort, Order)
how the query structure can be?
SELECT
*
FROM
letters
WHERE
userid = 12345
AND injection
ORDER BY
injection injection
is it vulnerable?
as there are several injection points in the query a simple way is to confirm the injection is to comment a part of the query.
NOTE: we can’t inject in the WHERE section because the value of the Filter
parameter is base64 encoded of an encrypted value (better to say obfuscated). and this is the main point of this article which I’ll show you how I bypass the security mechanisms implemented. 😉
let’s start injecting:
{
"param1": "<Search Filter='GIBBERISH HERE' Order='DESC*/' Sort='priority/*'/>",
"param2": "something..",
...
}
the way this injection affects the query on the backend:
SELECT
*
FROM
letters
WHERE
userid = 12345
AND injection
ORDER BY
injection/* injection*/ <-- (commented part)
the response server returned was the same data as before but with a different ordering, this means the injection was successful!
good, sqlmap
time?
I used sqlmap
but it couldn’t confirm the vulnerability. so I started to test manually again but still no chance.
so what now? giving up? No, that’s forbidden for me. ⛔
I decided to work on the gibberish value of the Filter
parameter and break the encryption. that’s cooler anyway, isn’t it? 😌
but is it possible to decrypt a string that is encrypted server-side?
PRO TIP
whenever you see an encrypted value in the requests to the server but you can’t find that value in the previous response from the server, that means the value most probably gets encrypted client-side.
so dig into the JS files and break the code 💣
P.S.:use Grep Values
tab of Logger++
, uncheck the Search Requests
.
Part Two: Reverse Engineering JS Code
I searched for the encrypted value in the server’s previous response and didn’t find any instance of that value, so I could be pretty sure the encryption happens client-side in the js code.
alright, how to find the js code in charge of encrypting the query?
the first clue can be the request itself:
{
"param1": "<Search Filter='GIBBERISH HERE' Order='DESC' Sort='priority'/>",
"param2": "something..",
...
}
I searched for the name of the parameter containing the gibberish data and found the code which built the XML data.
nice, a good starting point. now it’s time to analyze the code.
how? using the best js debugging tool ever: chrome devtools 😏
PRO TIP
read this document entirely:
https://developer.chrome.com/docs/devtools/javascript/
long story short, by use of devtools
and setting some breakpoints I found out the workflow behind that obfuscated value:
1. based-on the dropdown option user selects, an SQL query would be selected:
function SelectFilter(selectedFilter) {
switch (selectedFilter) {
case "unread messages":
filter = "mailType = 1"
break; case "high priority":
filter = "mailType = 1"
break; case "having attachment":
filter = "mailType = 1"
break;
}
return filter;
}
2. then encryption of the query happens:
function encrypt(Filter){
// grep session token// mix the query with session token
// base64 encode the result of previous step
// obfouscate the result of previous step// base64 encode again
return Filter;
}
3. after that js query builds the XML data
4. and at the end, puts the XML in JSON and sends the request
At this moment I was pretty sure that if I find a way to encrypt my SQL payload the way the js code does and send it to the server, there would be an injection in the backend code. why?
Simple,
because when the developer has tried this hard to hide the query being transmitted and has done all of this client-side, he thinks his shield is impenetrable and… there is no protection server-side 😏
ok, now we know the workflow. how to use this knowledge to inject our own query? writing a script to do the same encryption ??
no, much simpler than that…
use devtools
…
put a breakpoint on the first line of the encryption function,
change the value of function’s argument to your own query,
hit the resume button and let code does its job, but in a malicious way 😉
I told you to read the devtools
documentation, didn’t I? :)
I used a simple boolean-based injection to confirm the vulnerability. and after that using the string concatenation technique I found out that the backend DBMS was SQL Server
.
you can find this technique at the beginning of portswigger’s SQL Injection cheat sheet
:
https://portswigger.net/web-security/sql-injection/cheat-sheet
after executing a couple of queries I realise that the injection was boolean-based.
As you remember the job of the vulnerable query was returning the received mails data, right?
then if it returns data, why the injection is blind?
read this article to learn how to turn your blind injections to union-based ones: ✌️
https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f
ok, at this stage I needed to use SQLMap
for automation.
but how to use SQLMap
when the vulnerable parameter is being this hard obfuscated… ?
Part Three: Automation, The Hard Way
in this section, I want to show you how to use tools improperly 😊
let me fast forward the story… 2X
I need to use SQLMap
for automation…
but the input gets obfuscated…
use --eval
flag and write a script to do the obfuscation…
what language --eval
accepts… ?
python…
should I write the entire python script myself… ?
not when you already have the code for that…
but it’s in JS…
find a way to convert JS to Python…
google it…
oh, there is a Python module called js2py
that does the exact job…
cool now I have a script that obfuscates the payload…
should I write the entire script in the terminal as input of --eval
…?
no, save it as a .py
file and import it: --eval="import mycode;..."
how to insert the script’s output into the request’s body… ?
⛔BLOCKED⛔
I can’t get it to work… ?
why… ?
the eval
flag does not support JSON
data the way it does form-based
data…
what if I be able to modify the request using burp
on the fly… ?
to do so, I need to execute Python code in burp…
is there a way…?
google this one too…
nice, there is an extension called python scripter
for that…
✅PASSED✅
how to use it… ?
it has implemented a part of burp’s API for python… (API itself is for JAVA)
where to find the API documentation… ?
here: burp suite -> extender tab -> API tab
using the API’s functions, add the code needed to modify the request’s body…
past your script into python scripter
not working… 😕
it doesn’t recognize js2py
module…
try to fix it…
⛔BLOCKED⛔
how to fix it…?
your code doesn't work in burp but it works in your terminal, isn’t it… ?
use os.popen()
to run it from your terminal 😉
✅PASSED✅
cool, all fine. now how to bring the SQLMap
to the play… ?
first, tell me how SQLMapp
works… ?
it sends a query and analyzes the response based on the injected payload (did you expect anything else? 😐)
it doesn’t care where or how the query is injected…
it just analyzed the response…
so…
I remove the entire POST body and put a *
there
this way, the request my script receives contains only the SQLMap
's payload…
I get the payload, modify it, and then I put it in the proper body that the server expects…
I mean, I put it in the XML and put the XML in the JSON…
send the request, receive its response, and give the response to SQLMap
and let it does its job, analyzing the response…
✨DONE✨SQLMap
confirmed the boolean-based injection…
boolean-base? I prefer union-based: 😏
https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f
was it helpful?
I don’t ask you to buy me a cup of coffee,
teach me something…
Discord: REDN#9702