Sunday, January 25, 2015

Detective story about SQL injection, sometimes blind

Good day!

Would not have thought to write an article about it, because thought that the theme is pretty jaded. But, judging by this article, the audience interested. Finally convinced me that this one should write a comment.

This story happened to "friends of friends of my friend," but for the sake of brevity, I will write citations in his words, to use just the "I". It was a week ago. Let's go.

It took me learn a European language, in the light of a possible move to a European country. And I found a wonderful website, which was proposed to learn a language via podcast. Podcasts themselves are free, but you can buy a PDF recordings of lessons and exercises. I write this not really need, but my wife, unlike me, do not audial and language teaching it is also necessary. Before to buy something online, I've been studying the merchant's website - do not want my data somewhere flowed. And in this case, everything was more than bad. Desire to buy something immediately disappeared. But left without PDF unsportsmanlike. As a result, I decided to try to take advantage of one of the found vulnerabilities. I must say that I basically do not use any automated vulnerability scanner and essentially does no harm to users of the resource - they are not to blame, that the owner of the resource clumsily wrote it. Therefore, my tools are soobrazhalka and theoretical knowledge on the causes and the use of vulnerabilities.

beginning

The first thing I looked at a few examples of the demo available to download PDF. First, the user sent to:

/guide.php?id=lesson_id

At this point, checks if the current user is given the right to download the PDF. If so - is redirected to:

/download.php?f=filename.pdf

Immediately it turned out that the script gives the specified file does not check out. Because available for example lesson №1 had filename 001.pdf I decided to try to get all the files bust. If only it were that simple, then it would be to write about. But in this way managed to get only the first 100 files. The rest were in the name timestamp creation time and through them became impossible, since creation time differed for several months.

Rotate an SQL injection

Pretty soon discovered banal SQL injection in the GET parameter:

/some_script.php?id=123

It seems to be on its use is constructed very simply:
Determine the number of parameters in the query
Choose the table and field names (in the case of MySQL 5.0 and above - select them from information_schema)
Get the desired file names
Download files themselves

But problems began with the first point - to determine the number of fields in the query failed. With any number of fields in the UNION SELECT and any room in the ORDER BY n I get the message «You have error in your syntax ...»

In fact, I accidentally realized what exactly the problem - trying to make GROUP BY 1. To this I received an error «can not group by cnt». It turned out that the vulnerable parameter is used twice (well, at least that's the assumption I was unable to refute).

First select the number of records with the specified id:

SELECT count (*) FROM table where id = 123

If the number of records 0, it is considered that the page could not be found and there is a redirect to the home page. If the records are not 0, pulls information:

SELECT * FROM table where id = 123

Now it becomes clear why it was not possible to find out the number of fields in the query - their 2 and in one of them will always be the wrong number of fields in the UNION. Think of a way that would insert a different number of fields in the UNION in the first and second request, I could not. At this point, SQL injection has become blind. I could not find the table name with the file paths, but managed to find a table name with the user data (MySQL 4.1).

Dear developers, do not do 2 request, where you can make one! In this case, you could instead SELECT count (*) to check the number of records returned by the query SELECT *

Now it remains to find a way to get useful information. I did so:

/script.php?id=123 limit 0,0 union all select length (username)> 4 from tablename limit 0,1--

What we see here:
123 limit 0,0 - because count (*) will always return to us exactly one record, and we know that it has been returned to our part of the request, you need to remove it from the result
union all select length (username)> 4 from tablename limit 0,1-- - if the user name length is greater than 4, then the condition is true, MySQL will return the unit, and then an error when trying to execute the second query. If the condition is false - returns 0 and will redirect. Well, '-' for comment at the end of

Thus for HTTP headers can understand the true condition if we passed. We first determine the length of the user name, and then take out the binary search spelled the name itself (lower (substr (username, 1,1)) in ('a', 'b', 'c')). Then take out letter by letter password. But it turns out that the hashed password in md5. Although hashing without salt, but the passwords site administrators still could not pick up (in no rainbow tables and brute force on the netbook did not want to deal with, and besides, it's unsportsmanlike).

After some deliberation, it was decided to go another way. Because in the base turned out more than 60,000 users, I suggested that many of these popular passwords. And then just had to get user names alphabetically which is the password hash md5 ('password') - they turned out to be more than 100, and among them were people who bought the desired PDF. And they were kind enough to share them with me.

All this was done with a very simple script that sent HEAD-request (and why do we need the body of the page?) And watched the response header. If the 200 - the condition is true if the 302 - not true.

conclusion

Why all this written? To show that it is necessary to know the nature and causes of vulnerability rather than to learn how to use them. All uses of SQL injection, which I saw on the internet, asked to determine the number of fields through 5 or ORDER BY UNION SELECT 1,2,3 ... And the man who did not want to think I would go with a site with nothing.

In addition, I am a bit proud of my workaround instead of breaking hash. Well, not so long ago expressed skepticism about the existence of such vulnerabilities in today's Internet and on the practical application of blind SQL injection.

No comments:

Post a Comment