0x01 漏洞原理
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
0x02 漏洞危害
Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行过滤,则会带来意想不到的后果。
Sql 注入带来的威胁主要有如下几点
攻击者未经授权可以访问数据库中的数据,盗取用户的隐私以及个人信息,造成用户的信息泄露。 通过操作数据库对某些网页进行篡改; 修改数据库一些字段的值,嵌入网马链接,进行挂马攻击;攻击者进而可以对网页进行篡改,发布一些违法信息等。 服务器被远程控制,被安装后门。可以对数据库的数据进行增加或删除操作,例如私自添加或删除管理员账号。 数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员帐户被窜改。 破坏硬盘数据,导致全系统瘫痪;
0x03 SQL注入类型
1.SQL注入按照注入点类型来分分为:
数值型注入,字符型注入,搜索型注入
数值型:当输入的参数为整形时,如果存在注入漏洞,可以认为是数值型注入,例如:
加单引号,URL:www.text.com/text.php?id=3’ 对应的sql:select * from table where id=3’ 这时sql语句出错,程序无法正常从数据库中查询出数据,就会抛出异常; 加and 1=1 ,URL:www.text.com/text.php?id=3 and 1=1 对应的sql:select * from table where id=3’ and 1=1 语句执行正常,与原始页面如任何差异; 加and 1=2,URL:www.text.com/text.php?id=3 and 1=2 对应的sql:select * from table where id=3 and 1=2 语句可以正常执行,但是无法查询出结果,所以返回数据与原始网页存在差异 如果满足以上三点,则可以判断该URL存在数字型注入。
字符型:当输入的参数为字符串时,称为字符型。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的,例如:
加单引号:select * from table where name=’admin’’ 由于加单引号后变成三个单引号,则无法执行,程序会报错; 加 ’and 1=1 此时sql 语句为:select * from table where name=’admin’ and 1=1’ ,也无法进行注入,还需要通过注释符号将其绕过; Mysql 有三种常用注释符: -- 注意,这种注释符后边有一个空格 # 通过#进行注释 /* */ 注释掉符号内的内容 因此,构造语句为:select * from table where name =’admin’ and 1=1—’ 可成功执行返回结果正确; 加and 1=2— 此时sql语句为:select * from table where name=’admin’ and 1=2 –’则会报错 如果满足以上三点,可以判断该url为字符型注入。
搜索型简介
在搭建网站的时候为了方便用户搜索该网站中的资源,程序员在写网站脚本的时候加入了搜索功能,但是忽略了对搜索变量的过滤,造成了搜索型注入漏洞,又称文本框注入。其中又分为POST/GET,GET型的一般是用在网站上的搜索,而POST则用在用户名的登录,可以从form表单的method="get"属性来区分是get还是post。搜索型注入又称为文本框注入,例如:
%’ and 1=1 and ‘%’=’ %’ and exists (select * from admin) and ‘%’=’ %’ and exists(select id from admin where id=1) and ‘%’=’ %’ and exists (select id from admin where len(username)<10 and id=1) and ‘%’=’ %’ and exists (select id from admin where len(password)=7 and id=1) and ‘%’=’ %’ and (select top 1 asc(mid(username,1,1)) from admin)=97 and ‘%’=’ 搜索型注入也无他,前加%’ 后加 and ‘%’=’ 对于MSSQL数据库,后面可以吧 and ‘%’='换成–
2.根据请求方式的不同,可分为:
GET型注入、POST型注入、HEADER型注入 、Cookie注入
GET型注入:
GET 是 HTTP 协议的传输方式。它的特点就是可以直接以 URL 的形式传输数据。而GET型注入漏洞就是利用这一特点,对数据库进行注入测试。
POST型注入:
在 HTTP 常用方法中,POST 方法提交的实体不存储在 URL 中,而是存储在 HTTP 协议实体内容中,在大多过程中,用户时无法感知的。而我们的注入信息是存储与 HTTP 实体内容中而不是 URL,通过改造实体内容,达到实际执行 SQL 语句获取到更多信息的目的。
http头注入:
后台开发人员为了验证客户端头信息,比如常用的 cookie 验证,或者通过 http 请求头信息获取客户端的一些信息,比如 useragent 、accept 字段等等,会对客户端的 http 请求头信息获取并使用 sql 进行处理,如果此时没有足够的安全考虑,则可能会导致基于 http 头的 sql 注入漏洞。
Cookie注入:
(1)程序对get和post方式提交的数据进行了过滤,但未对cookie提交的数据库进行过滤。(2)在条件1的基础上还需要程序对提交数据获取方式是直接request("xxx")的方式,未指明使用request对象的具体方法进行获取,也就是说用request这个方法的时候获取的参数可以是是在URL后面的参数也可以是cookie里面的参数这里没有做筛选,之后的原理就像我们的sql注入一样了。
3.按照注入技巧来分类
联合注入、盲注、堆叠注入、二次注入、无列名注入、宽字节注入、其他
联合注入:联合查询注入是联合两个查询语句进行注入攻击,使用关键词 union select 对两个表进行联合查询。两个表的字段数要相同,不然会出现报错。
盲注简介
盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
盲注原理
盲注的本质就是猜解,在没有回显数据的情况下,我们只能靠‘感觉’来体会每次查询时一点点细微的差异,而这差异包括运行时间的差异和页面返回结果的差异。
对于基于布尔的盲注来说,我们可以构造一条注入语句来测试我们输入的布尔表达式,而这布尔表达式结果的真假,决定了每次页面有不同的反应。
对于基于时间的盲注来说,我们构造的语句中,包含了能否影响系统运行时间的函数,根据每次页面返回的时间,判断注入的语句是否被成功执行。
盲注分类
•基于布尔SQL盲注 •基于时间的SQL盲注 •基于报错的SQL盲注
盲注的流程:
找寻并确认sql盲注点 强制产生通用错误界面 注入带有副作用的查询 根据布尔表达式的真假结果,结合不同的返回结果确认注入是否成功
布尔盲注:布尔盲注一般适用于页面没有回显字段(不支持联合查询),且web页面返回True 或者 false,
构造SQL语句,
利用and,or等关键字来其后的语句 true 、 false使web页面返回true或者false,
从而达到注入的目的来获取信息的一种方法
没有错误提示 也没有回显 但是输入错误的话页面会有反应 也就是说 只有 true 和false
例如 :sql-labs /less-7 它只有两种提示 所以可以用布尔盲注 playload:and length(database()) =8 --+ /判断数据库名长度
时间盲注:通过一个页面加载的时间延时来判断但是这和网络,性能,设置的延时长短有关系当对数据库进行查询操作,如果查询的条件不存在,语句执行的速度非常快,执行时间基本可以认为是0,通过控制sql语句的执行时间来判断
判断语句
1’ and length(database())>3# 1’ and length(database())=5 # 1’ and mid(database(),1,1)=‘d’ # 判断单个字符 1’ and substr(database(),1,1)=‘d’ # 判断单个字符 1’ and ord(substr((select database()),1,1))=98 # 使用ascii码判断单个字符 1’ and ascii(substr((select database()),1,1))=98 # 使用ascii判断单个字符 1’ and left(database(),4)=‘dvwa’ # 判断一个字符串,即多个字符
报错盲注:众所周知,盲注并不会返回错误信息,使得sql注入的难度提高。而报错型注入则是利用了MySQL的第8652号bug :Bug #8652 group by part of rand() returns duplicate key error来进行的盲注,使得MySQL由于函数的特性返回错误信息,进而我们可以显示我们想要的信息,从而达到注入的效果,语句
?id=1' union Select 1,count(*),concat(你希望的查询语句,floor(rand(0)*2))a from information_schema.columns group by a
堆叠注入: 在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。
二次注入:在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
无列名注入:顾名思义,就是在不知道列明的情况下进行sql注入。在mysql => 5的版本中存在一个名为 information_schema 的库,里面记录着 mysql 中所有表的结构。通常,在 mysql sqli 中,我们会通过此库中的表去获取其他表的结构,也就是表名、列名等。但是这个库经常被 WAF 过滤。
0x04 工具&插件推荐
SQLMAP-项目地址:https://github.com/sqlmapproject/sqlmap MDUT-项目地址:https://github.com/SafeGroceryStore/MDUT 超级SQL注入工具 穿山甲、胡萝卜、啊D、明小子 HackBar、Max HackBar(浏览器插件自行获取)