用户
搜索
  • TA的每日心情

    昨天 09:45
  • 签到天数: 24 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋-见习白帽

    DYBOY

    Rank: 3Rank: 3

    7

    主题

    41

    帖子

    435

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2017-8-7
    发表于 2018-8-19 22:17:36 117589

    相信很多人都看过“输入内容存在危险字符,安全起见,已被本站拦截”这句话,这是360webscan脚本搞得鬼,当然也不排除360主机卫士,之前在很多的网站都看到了360webscan的攻击拦截脚本,正好分析并学习一下。

    下载地址:http://webscan.360.cn/protect/down?domain=blog.dyboy.cn

    最后一个 domain 参数改为自己的线上网站域名

    为了本地测试:我下载http://webscan.360.cn/protect/down?domain=www.test.com

    0x01 安装

    将下载的 360webscan.zip 解压后,得到360safe文件夹,并上传至网站根目录

    在全局加载的文件中(示例网站根目录下:index.php),加入如下代码:

    if(is_file($_SERVER['DOCUMENT_ROOT'].'/360safe/360webscan.php')){
        require_once($_SERVER['DOCUMENT_ROOT'].'/360safe/360webscan.php');
    } //注意文件路径

    访问:http://www.test.com/360safe/360webscan.php post-data: webscan_act=ckinstall

    但是并没有出现安装信息,原因是:http://safe.webscan.360.cn

    该域名已经无法访问(后面涉及到这个网址的函数都不无法正常执行),因此着重分析拦截过滤的一个过程。

    看到这个脚本文件的最后编辑时间为2014年...

    0x02 结构分析

    webscan_cache.php

    webscan_cache.php

    默认拦截,POST/GET/COOKIE/REFERER 这四个参数

    同时还有白名单功能

    //url白名单,可以自定义添加url白名单,默认是对phpcms的后台url放行
    //写法:比如phpcms 后台操作url index.php?m=admin php168的文章提交链接post.php?job=postnew&step=post ,dedecms 空间设置edit_space_info.php
    $webscan_white_url = array('index.php' => 'm=admin','post.php' => 'job=postnew&step=post','edit_space_info.php'=>'');

    很清晰的解释了

    再看 360webscan.php

    360webscan.php

    所有的过滤规则以及函数实现都在此文件

    0x03 功能测试

    在按照上述安装方法安装后,测试访问:http://www.test.com/index.php?test=<script>alert(1)</script>

    XSS拦截显示:

    XSS被拦截

    比如注入等都会被拦截

    0x04 拦截规则

    //get拦截规则
    $getfilter = "\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
    //post拦截规则
    $postfilter = "<.*=(&#\\d+?;?)+?>|<.*data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
    //cookie拦截规则
    $cookiefilter = "benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\(|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
    //获取指令
    $webscan_action  = isset($_POST['webscan_act'])&&webscan_cheack() ? trim($_POST['webscan_act']) : '';
    //referer获取
    $webscan_referer = empty($_SERVER['HTTP_REFERER']) ? array() : array('HTTP_REFERER'=>$_SERVER['HTTP_REFERER']);

    0x05 运行分析

    在程序的底部调用函数,过滤判断四种参数是否存在非法攻击字符串,如果是在白名单目录下(webscan_white()函数 ),就不会调用第二层的判断(四种拦截方式)

    拦截四种

    继续跟进:webscan_white()

    /**
     *  拦截目录白名单
     */
    function webscan_white($webscan_white_name,$webscan_white_url=array()) {
      $url_path=$_SERVER['SCRIPT_NAME'];  //修复之前是PHP_SELF
      $url_var=$_SERVER['QUERY_STRING'];
      if (preg_match("/".$webscan_white_name."/is",$url_path)==1&&!empty($webscan_white_name)) {
        return false;
      }
      foreach ($webscan_white_url as $key => $value) {
        if(!empty($url_var)&&!empty($value)){
          if (stristr($url_path,$key)&&stristr($url_var,$value)) {
            return false;
          }
        }
        elseif (empty($url_var)&&empty($value)) {
          if (stristr($url_path,$key)) {
            return false;
          }
        }
      }
      return true;
    }

    1.如果你输入 /test.php/123456 的话 $_SERVER['SCRIPT_NAME']结果是/test.php 。所以为了安全起见,为了指向自身,应该用$_SERVER['SCRIPT_NAME']

    2.$_SERVER['QUERY_STRING']获取 ? 后面的字符串,例如:index.php?action=login&username=123&pass=123,那么获取的结果就是:action=login&username=123&pass=123

    3.preg_mactch函数: 搜索subjectpattern给定的正则表达式的一个匹配.

    reference: http://php.net/manual/zh/function.preg-match.php
    int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
    

    正则语法:http://php.net/manual/zh/reference.pcre.pattern.syntax.php

    翻译了一下

    Regex quick reference
    [abc]     A single character: a, b or c          单独的字符
    [^abc]     Any single character but a, b, or c          匹配字符除了abc
    [a-z]     Any single character in the range a-z                匹配a到z的字符
    [a-zA-Z]     Any single character in the range a-z or A-Z        匹配a到z或A到Z的字符
    ^     Start of line                        一行的开始
    $     End of line                        一行的结束
    \A     Start of string                字符串开头
    \z     End of string                字符串结尾
    .     Any single character                任何字符
    \s     Any whitespace character                        任何空白字符
    \S     Any non-whitespace character                任何非空白字符
    \d     Any digit                任何数字
    \D     Any non-digit                任何非数字
    \w     Any word character (letter, number, underscore)                任何的单词字符(字母,数字,下划线)
    \W     Any non-word character                        任何非单词字符
    \b     Any word boundary character                任何单词边界字符
    (...)     Capture everything enclosed        捕获所未包裹有内容
    (a|b)     a or b                a或b
    a?     Zero or one of a                  有0个或1个字符a
    a*     Zero or more of a                有0个或多个字符a
    a+     One or more of a                        有1个或多个字符a
    a{3}     Exactly 3 of a                        有3个字符a
    a{3,}     3 or more of a                有3个或多个字符a
    a{3,6}     Between 3 and 6 of a                        有3到6个字符a
    
    options: i case insensitive m make dot match newlines x ignore whitespace in regex o perform #{...} substitutions only once
    
    可选设置:i不区分大小写,m使得.(点符号)匹配换行符,x忽略正则表达式中的空格,o只执行一次#{...}中内容替换

    其中的\\等价于\

    \\\\等价于\\等价于/

    4.strsti()函数:返回 haystack 字符串从 needle 第一次出现的位置开始到结尾的字符串。

    reference: http://php.net/manual/zh/function.stristr.php
    string stristr ( string $haystack , mixed $needle [, bool $before_needle = FALSE ] )

    在整个白名单判断函数中,如果匹配上了,那么就返回false,就不做拦截检测,针对白名单这一点其实是有漏洞可绕过的,传递的第一个参数$webscan_white_name是一个全局参数在webscan_cache.php文件中

    //后台白名单,后台操作将不会拦截,添加"|"隔开白名单目录下面默认是网址带 `admin`  `/dede/` 放行
    `$webscan_white_directory='admin|\/dede\/'`;

    这样的话,那么我们只要在admin 或者 dede目录下的任何操作都不会被拦截。如果存在后台注入的话,同时在后台添加了白名单,那么拦截就不再有效果了。

    同时提一点:如上代码,注释了一下 $url_path=$_SERVER['SCRIPT_NAME'];  //修复之前是PHP_SELF,这里存在一个安全问题,直接引用一下离别歌大佬的博文:

    然后再给大家说明一下$_SERVER['PHP_SELF']是什么:
    PHP_SELF指当前的页面绝对地址,比如我们的网站:
    https://www.leavesongs.com/hehe/index.php
    那么PHP_SELF就是/hehe/index.php。
    但有个小问题很多人没有注意到,当url是PATH_INFO的时候,比如
    https://www.leavesongs.com/hehe/index.php/phithon
    那么PHP_SELF就是/hehe/index.php/phithon
    也就是说,其实PHP_SELF有一部分是我们可以控制的。

    ok,那么如果目录不在白名单中,那么就会下一步匹配参数是否在白名单中,如果能够匹配上也返回false

    进入过滤检测手中,比如xss过滤:

    这样的:http://www.test.com/index.php?id=123%3Ciframe%20src=http://www.xxx.com/1.js%3E 是不会被过滤的

    然后调用webscan_StopAttack()函数将拦截规则与当前的GET/POST/COOKIE/REFERER参数匹配!

    那么直接看GET请求中的过滤规则吧!

    //get拦截规则
    $getfilter = "\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

    简单解读,只要规则中出现的单词或连续字符,那么在访问链接URL中就不能存在这些关键词,否则就会被拦截。

    为什么要简单解读呐?因为这TM的规则太复杂了...

    可以把 | 分割开的看成一个小规则,这样子来分别分析

    在上面我们看到iframe关键词没被过滤,那么改为如下的:

    //添加一个iframe关键词 iframe|
    
    $getfilter = "iframe|\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

    规则修改

    这样就起到了拦截效果

    其他的请求都是类似的,正则语法真难!真香!

    如果匹配到了需要拦截过滤的关键词,就会调用webscan_pape()函数,及调用拦截结果显示页面,如上图所示。

    0x06 总结

    正则语法看得心力憔悴,更多的匹配规则得自己下来写一写,然后在本地环境输出查看!

    脚本防火墙真方便!正则匹配就好了,在这个360webscan的过滤插件中,还是看到了函数封装的美感,Do you like these?

    听说评论回复有惊喜,不知真假?

    [/md]
    专注网络安全与程序开发,博客:https://blog.dyboy.cn
    发表于 2018-8-20 11:07:39
    提示: 作者被禁止或删除 内容自动屏蔽
    使用道具 举报 回复
    嘿嘿
    使用道具 举报 回复
    学习一下~
    使用道具 举报 回复
    发表于 2018-8-20 13:51:56
    惊不惊喜,意不意外
    使用道具 举报 回复
    发表于 2018-8-20 14:18:18
    初来乍到01 发表于 2018-8-20 11:07
    惊不惊喜,意不意外

    明知这是一场意外,你会不会来~
    专注网络安全与程序开发,博客:https://blog.dyboy.cn
    使用道具 举报 回复
    发表于 2018-8-20 14:34:51
    学习学习。。。。
    http://www.anonymou5.com
    使用道具 举报 回复
    惊喜?  不存在的
    使用道具 举报 回复
    哈啊哈,惊喜在哪儿啊
    使用道具 举报 回复
    发表于 2018-8-22 10:36:20
    666666666666666666
    q 36222404 一起嗨啊
    使用道具 举报 回复
    感谢分享
    使用道具 举报 回复
    发表于 2018-8-23 10:25:33
    感谢分享。。。这年头站子都带墙,小白不好过了
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册