Some IT communities have special sections of their discussion areas where people can ask for feedback on their newly developed sites. Many of these are simply someone who put some stylish theme on a WordPress or Joomla install, however the real interesting sites is the ones who is self developed and custom made.
One day I found a someone posting a feedback request on a seemingly content heavy gaming site. I asked the developer via personal message on the forum if he would mind if I did a security test of his site. He found it interesting and valuable and after fixing the legal stuff, that is how the this story begins…
This was from my younger days of hacking so once I arrived at the page I did not have a good plan on what to look for or how to properly assess the entire site. Nowadays I have a defined plan on how to attack a penetration test in order to cover as much ground as possible on the target.
Once I arrived on the site I start casually browsing it, looking for something that catches my attention and can be pounce on. All over the site I saw custom ads for this game called “Super Quiz”, so this game became my staging point. I open up the game and I am presented with a flash based register/login function, completely separated from the surrounding CMS systems login system. This tells me that they have most likely hooked this game up to some kind of storage, probably a database, but could easily be file based as well.
Now, I am here to play games, however not the games they expect an ordinary user to play…
Decompiling the game
What many developers fail to realize is that anything, and I stress anything, that is sent to the client should not be trusted until it has been properly cleaned. Here is a few examples:
- HTTP headers (referer, mimetype, etc.)
- POST and GET requests
- Dropdown/check boxes and similar “static” HTML elements
- Plugins like Flash, Silverlight and so on
Since this application was using Flash, I decided to download the source and take a closer look at it.
Using the Firebug add-on for Firefox I use the “inspect element” right click to see where the Flash resides. This leads me to an URI which points to a SWF file I want to download. Pointing my browser to the URL of the file I get a choice to download it.
With the file stored on my local disk I use a tool called Flasm to do the decompiling. The following command solves the problem: ‘
flasm -d quizGame.swf‘. Today I would much rather recommend HP’s SWFScan, which is a pretty awesome tool for investigating flash files.
“SwfScan decompiles SWF files and locates security vulnerabilities directly in source code. You can decompile files from your local system or from the Internet by typing an URL. Both ActionScript versions 2 and 3 are supported
My next step was just to simply manually process the source code for interesting tidbits. What I found most interesting was all the different HTTP calls to various scripts on the site. I extracted all of them and marked them for manual probing for vulnerabilities. The URL’s look like any other URL’s you would expect to see in the source code of an HTML element. A quick look at two of them:
Testing for SQL injection
Most of this story is about SQL injection and how to leverage it manually. There is many good tools around make the entire SQL Injection fully automated. Tools like SQLMap is perfect for probing and exploiting SQL injection vulnerabilities. Doing it manually is a much better way to learn, and it is also quite fun.
The first basic step I do to test for SQL injection is simply just inject a quote mark into my username and see if the database returns any error messages. The GET request I send to the server ends up like this:
The result from sending this to server was an error similar to:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the
character string ''.
/login.asp, line 22
This reveals some important facts:
- The presence of possible injection
- Database type is SQL Server
- OS is Microsoft Windows
Considering that the error message is this verbose it will most definitively help me a whole deal when trying to do further injection to the database. SQL Injections with no returning error messages are usually called blind injections. In those circumstances I usually have to rely on either timing attack or other differences in the returning result from the webserver, like result size or difference in text or similar.
The next request I do is to try extract more data from the error messages. I append the SQL query I am making with two dashes so I will comment out any trailing SQL code that could potentially ruin the query I want to build. I end up with the following request:
/inc/quiz/login.asp?username=karrax' UNION SELECT 1 FROM test--
This resulted in this error message, still way too verbose!
Column 'QuizUser.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
What do we see here? We see that just by querying an probably non existent table, the database complains about us not putting QuizUser.id into the group by clause. This reveled that there exists a table called QuizUser with a table called id. Now lets see how we can enumerate the rest of the database. Be advised that there is other ways of doing this enumerating as well.
Enumerating tables and columns
Using the information from the previous messages, I can now craft a request that goes into the default SQL Server database tables and extract meta information about the rest of the database. The table containing this information is stored in a database called information_schema in a table conveniently called tables. The request I make look like this:
/inc/quiz/login.asp?username=karrax' or 1 in (select top 1 table_name from information_schema.tables where table_name not in ('QuizUser'))--
Just like the other requests this gives me an error message from the database revealing a new table called ‘about’. I added the table name to the ‘not in’ clause and this reveled more tables. After some repetitions I am left with with this request:
/inc/quiz/login.asp?username=karrax' or 1 in (select top 1 table_name from information_schema.tables where table_name not in ('about','ads','cards','card_en','category','category_en','cpostcards','cpostcards_en',
Look at that! I got all the tables in the database! This should make it easy to extract all the data from them, but first I need to know the column names in these tables. This technique is called enumeration.
For the columns we use an almost similar query. Instead of select top 1 from table_name we select top 1 from column_name where table_name=’
/inc/quiz/login.asp?username=karrax' or 1 in (select top 1 column_name from information_schema.columns where table_name='QuizUser')
With this method we can quickly map the entire structure of the database.
Extracting and inserting data
In order to prove how serious this kinds of vulnerabilities is I decided to extract the administrators data from the database. I crafted the following request:
/inc/quiz/login.asp?username=karrax' or 1 in (select password from QuizUser where username='admin')--
As expected it gave me the follow error message (thank you database):
Microsoft OLE DB Provider for SQL Server error '80040e07'
Syntax error converting the nvarchar value '<administrators password>' to a column of data type int.
/inc/quiz/login.asp, line 22
What I did not expect was that I now had the adminstrators password in CLEAR TEXT! I cannot stress how brutal and disrespecting this is for the users, however I am glad we found this in such an early phase of the site. I am glad that the user I created for this site I used in no way my real password.
Another, not so common, feature is the ability to inject stacking queries. The following example proves this and injects a new row in the database:
/inc/quiz/login.asp?username=k4rrax'; insert into QuizUser values('sqlinjection','firstname.lastname@example.org','foobar',1000,1000,0,0,1,1,2)--
This actually logged me into the game with no error messages. It also injected an user into the database with 1000 points in the game, allowing it to be first place.
The next step is going for the kill…testing to see if I can inject commands to the OS!
Testing for execution
Execution means the ability to run code and commands on the server you are attacking. This can often be the best way to attack as control of the OS, even if limited, can be extremely dangerous. As good as all DBMS have some form of allowing queries to run OS commands on the system. For this to work the user of the database must have the sufficient privileges, however due to wide spread system misconfiguration administrators often run their databases with the highest privileged users, in SQL Servers case the SA user. To read more about misconfiguration see OWASP’s top 10 vulnerabilities.
For SQL Server the syntax to do command execution is called xp_cmdshell. For example the following query would output a directory listing:
EXEC xp_cmdshell 'dir';
In my case I crafted a query like this:
/inc/quiz/login.asp?username=Olsen’;EXEC master.xp_cmdshell ‘dir’;–
If this had worked I would have got the contents of the directory either in the form of an error message or any other way depending on how the script work. In some injection vulnerabilities the job is really easy if there is an recursive function iterating and printing out the entire result from the query. In my example I was not that lucky though, which is a good thing for the developer! The result from the request was this error message:
Microsoft OLE DB Provider for SQL Server error '80040e09'
SELECT permission denied on object 'sysxlogins', database 'master', owner 'dbo'.
/inc/quiz/login.asp, line 22
I am glad that the database user was in fact not running with the highest privileges. Applause to the developer for this!
I took my findings straight away to the developer of the page so he could fix it immediately. Especially with the username and passwords being stored in clear-text there was no doubt in my mind that this had to be fixed ASAP!
The developer went straight to fixing the bugs and asked me if I could do some more testing of the functions on the page. I had no problem with this, as long as he wipes the username and password table immediately and implements a better solution where the passwords cannot be reversed.
Hijacking the newsletter function
This next exploit also involves SQL injection and more specifically login bypassing. This injection would’ve worked in the previous examples as well, but the difference here is that this is introduced into the system with an off the shelf product called myNewsletter (no links to this one! Go Google it at your own risk 🙂 ). Based on the previous reading I’ll explain this vulnerability with just a single picture. Enjoy!
The text is in Norwegian, but should be understandable. Also after logging into this function I went into the newsletter function and sent him a direct email from it letting him know. He ended up being quite mind blown of all the security he had to be thinking of when developing and running a website.
- Code sanitation – Do it, everywhere!
- Patching. Dont forget it. Keep track.