Day One: In Which The Heavens Part, But Only Slightly
A few weeks ago while performing a web application test for
$CLIENT, I happened to run into search functionality. As one of the very first standard tests I inserted a single quote ' into the search field and clicked the search button.
The SQL error message that was returned was the stuff dreams are made of (ie: a lot of info, slightly vague, not everything there, but enough in that moment to make you really, really believe). After a few quick tests to see if anything easy could be obtained (nope, no such luck), and confirming that I wouldn't be negatively impacting
$CLIENT's systems if I did so, I turned it over to automated tools and went about testing other parts of the application.
Time passed, and a few other issues were discovered and documented (it doesn't exist if no one else can reproduce it from your official description), and I went back to view the progress of automated tools, eager to see the keys to the kingdom laid down before me.
Okay, maybe I made a mistake or two setting the automated tools up? Investigations disproved that line of thinking, as the recorded request/response pairs showed the attacks were being properly sent with all the appropriate data.
It is probably my imagination, but I think I can hear
$CLIENT's webapp laughing at me.
Hmmmm . . . this may be a bit more complex than I had hoped.
Day Two: In Which The Heavens Laugh At Our Beleaguered Tester
Alright, a new day, I've had a good night's sleep, I'm properly caffeinated, and I'm ready to tackle the world!^h^h^h^h^h^h
Looking over my sitemap, there are a few more places I need to dig into before I return to that beautiful SQL error message. On the off-chance that something strange happened overnight, I reread the automated tools' documentation, tweak a few options, and let them start poking again. I return to manually testing parts of the application while other automated tools continue scan the site.
After a bit of testing, I return to the automated tools.
The feeling that I get telling me that I can hear
$CLIENT's webapp laughing at me is getting stronger.
Okay, maybe this isn't an actual SQL Injection, but rather some error message that automagically shows up just to frustrate me. Manual testing begins again.
I'm getting different SQL error messages for different types of injections, all of which really, really strongly indicate that I'm interacting with the underlying SQL statement, but other than another item to mark down as an informational item, I don't actually have anything. I can't really PROVE that this is a SQL Injection finding. Error messages are nice, and may indicate a SQL Injection vulnerability, but without solid proof, I may end up wasting
$CLIENT's time and resources (and money) as they have people chasing down an issue that doesn't exist.
This is more than a little bit frustrating.
My mind must be playing tricks on me, as in the distance I can hear
$CLIENT's webapp laughing at me.
Think, Carlos, Think!
Hmmmm . . . okay, I'm going to step back a bit. What are some really, really, really simple things I can test that would let me know if I'm on the right path or not. How about String Concatenation?
So I know the type of SQL database (thank you SQL error message), so I can look up how string concatenation is performed on that platform. I take a quick trip to review readily available documentation, and then I'm back at work.
Alright, so one of the available search results is
"Wendy", so can I do a search for
"Wen' + 'dy" and have it return
"Wendy"? Yes, okay that works, but is it really concatenating strings, or is something strange happening that only LOOKS like string concatenation, but is really only . . . well, something strange?
How about I try
"We' + CHAR(110) + 'dy"?
Okay, calm down, calm down, maybe something strange is happening. I'll try
"We' + CHAR(111) + 'dy" . . . and it fails! (insert mental happy dance here) Hooray for Failure!
Excellent! Now I have a plan of attack. I'll combine string concatenation with the
SUBSTRING() function to grab data from the database by seeing if I get back search results or not (the Blind SQL Injection we all know and love/hate).
"We' + SUBSTRING(<thing>,X,1) + 'dy" should allow me to see if any of the data I want has the letter
"n" at the
And I can move the string concatenation sections around a bit to get
"y", and . . . Hmmmm . . . I'm seeing a problem here.
I can only test characters that return in the search results.
Okay, first things first, what are all the search results? If I do an open search to get every possible search result, what characters do I have to work with?
Not many. This is a problem. I have
"Albert" as my search results. I have no numbers, no special characters, . . I don't even have the full English alphabet.
I can hear
$CLIENT's webapp laughing at me.
Day Three: In Which Our Tester Blasts The "TEAM AMERICA: WORLD POLICE" Theme Song At Full Volume . . . But Only In His Own Mind, Because He Is Considerate Of Others
$CLIENT's webapp is laughing at me.
Okay, think, Carlos, THINK! What can be done to turn this from a very, very, very limited exploitability finding to something that might be worthy of the SpiderLabs name?
Argh . . . well, I have time, and according to my sitemap, I have other places to test. I'll put this aside for now.
And so other testing proceeds, and I find a few things, document them, and the webapp continues to laugh at me. I know it is laughing at me. I can hear it laughing at me.
Webapp, stop laughing at me.
/*sigh*/, I'm just not finding the really juicy bits I want to find. Persistent XSS is good, URL Redirection is nice, and I never turn away a non-HTTPOnly session cookie, but I really set myself up for disappointment with the SQL error message.
Perhaps today is the day where the webapp wins.
. . .
Okay, so what if--slow down, slow down, deep breaths here, deeeeeeeep breaths--so what if:
. . . what if I take a single character of the thing I want:
. . . and then convert that to its numeric ASCII value:
ASCII( SUBSTRING(<thing>,X,1) )
. . . and then either increment or decrement that numeric value to the ASCII value of a character I CAN get a result from:
ASCII( SUBSTRING(<thing>,X,1) ) +/- Y
. . . and then take that numeric ASCII value and convert THAT back to a character:
CHAR( ASCII( SUBSTRING(<thing>,X,1) ) +/- Y )
. . . and then perform string concatenation on that entire thing:
"We' + CHAR( ASCII( SUBSTRING(<thing>,X,1) ) +/- Y ) + 'dy"
. . . and then see if I get
"Wendy" back as my search result or nothing at all. Does that work???
A quick scripting job to run through the printable ASCII character range establish if this works or not . . . and . . .
I can read data from the database, one character at a time.
(insert "TEAM AMERICA: WORLD POLICE" theme song here)
I quickly have the script run through and grab the database banner in order to firmly establish that I have something actionable to report. Documentation takes a bit longer, but it will be worth it.
Legitimate, validated, exploitable SQL Injection is a very, very serious issue, so I reach out and make sure that
$CLIENT gets notified as soon as possible.
I relax a little bit and continue on with the rest of my testing, content in the knowledge that today the webapp didn't win (and the "TEAM AMERICA: WORLD POLICE" theme song continues to play).
Days Four And Beyond: In Which Life Goes On
There was a call with
$CLIENT, in which
$CLIENT was glad the Blind SQL Injection was found, but not glad that it existed. During the call I noted a second location where the same Blind SQL Injection process worked, but that I haven't finished documenting it, so it wasn't available in the preliminary findings report just yet (not too long after the call it was ready).
$CLIENT begins processes to get things fixed.
There's still time available before
$CLIENT's hard end of testing date, so my work on
$CLIENT's webapp continues.
Not much else is found, a few new reflected XSS, another CSRF, nothing exciting, just a bit more work documenting things,
. . . but $CLIENT's webapp is no longer laughing at me,
. . . and I'm okay with that.