discuz漏洞重现--函数缺陷导致的xss
in 漏洞分析 with 0 comment

discuz漏洞重现--函数缺陷导致的xss

in 漏洞分析 with 0 comment

手里有个后台脱裤的洞,本来想捡一个discuz的xss的弄成前台脱裤,但是渣渣捡不到啊,于是就在乌云上看看discuz的xss,有个xss的洞引起我的注意《Disucz X3.2 多处反射型XSS漏洞(函数缺陷导致)
》这个,但是!!!!等我看到下面

QQ20170520-170957@2x.png
我擦,还要wb,我这种爱wb如命的怎么可能支付呢,于是我认真看了这个洞,重现了一下这个漏洞
QQ20170519-235357@2x.png
首先是知道了输入点和输出点,那我们就拿第一个链接分析一下
通过member.php?mod=logging&action=login我们先看到member.php中,最后有这样一句
QQ20170519-235454@2x.png
包含了一下member_logging这个页面,我们跟进去看看
QQ20170519-235530@2x.png
可以看这个里面就是执行了logging_ctl类中的on_login方法
我们搜索到这个类看看这个方法
QQ20170519-235607@2x.png
我们可以看到referer直接被输出了.
referer是通过dreferer()这个函数来的,我们搜索一下这个函数,看看referer到底是什么东西
在这里把这个函数贴出来

function dreferer($default = '') {
    global $_G;

    $default = empty($default) && $_ENV['curapp'] ? $_ENV['curapp'].'.php' : '';
    $_G['referer'] = !empty($_GET['referer']) ? $_GET['referer'] : $_SERVER['HTTP_REFERER'];
    $_G['referer'] = substr($_G['referer'], -1) == '?' ? substr($_G['referer'], 0, -1) : $_G['referer'];

    

    $reurl = parse_url($_G['referer']);


    if(!empty($reurl['host']) && !in_array($reurl['host'], array($_SERVER['HTTP_HOST'], 'www.'.$_SERVER['HTTP_HOST'])) && !in_array($_SERVER['HTTP_HOST'], array($reurl['host'], 'www.'.$reurl['host']))) {
        if(!in_array($reurl['host'], $_G['setting']['domain']['app']) && !isset($_G['setting']['domain']['list'][$reurl['host']])) {
            $domainroot = substr($reurl['host'], strpos($reurl['host'], '.')+1);
            if(empty($_G['setting']['domain']['root']) || (is_array($_G['setting']['domain']['root']) && !in_array($domainroot, $_G['setting']['domain']['root']))) {
                $_G['referer'] = $_G['setting']['domain']['defaultindex'] ? $_G['setting']['domain']['defaultindex'] : 'index.php';
            }
        }
    } elseif(empty($reurl['host'])) {
        $_G['referer'] = $_G['siteurl'].'./'.$_G['referer'];
    }

    $_G['referer'] = durlencode($_G['referer']);
    return $_G['referer'];

我们先看到这一段
QQ20170519-235737@2x.png
这里就是在获取我们传递进去的referer,也就是说referer是我们可控的,继续往下看
QQ20170519-235806@2x.png
这里用了parse_url对referer解析了,先介绍一下parse_url这个函数:直接用例子解释:

parse_url(“http://127.0.0.01/discuz/news/data?id=0&name=haha#hei”);

这个输出的是:

array (size=5)
  'scheme' => string 'http' (length=4)
  'host' => string '127.0.0.01' (length=10)
  'path' => string '/discuz/news/data' (length=17)
  'query' => string 'id=0&name=haha' (length=14)
  'fragment' => string 'hei' (length=3)

就是把url的各个部分解析到数组里,我们接着看
QQ20170519-235937@2x.png
这一部分很麻烦,但是我们看标记的地方
如果走进这个if里面我们的referer就会重新构造,就不受我们控制了
也就是说一定不能走进这个if里面,那我们重点看看这个条件

if(!empty($reurl['host']) && !in_array($reurl['host'], array($_SERVER['HTTP_HOST'], 'www.'.$_SERVER['HTTP_HOST'])) && !in_array($_SERVER['HTTP_HOST'], array($reurl['host'], 'www.'.$reurl['host'])))

这里是对host进行了判断
我们知道数组中的host就是刚刚的127.0.0.1
这个判断就是说,如果数组里没有host或者host跟http头里面host不一样(加www后一样也行)
那么就会进入到这个if中
也就是说我们必须要让数组中的host等于http头中的host
在本地测试的话就是必须是127.0.0.1,接着往下看
QQ20170520-000132@2x.png
可以看到host也不能为空,不然也会重新拼接,然后用url编码一下就返回了我们的referer
然后我们关注一下输出点是在
xxxx
也就是在a标签中的href中,那么我们思路就来了,href中不仅能是http开头的网址,也能执行js代码,例如
xxxx
这样也是可以的,那我们的referer应该怎么构造
这里还要讲parse_url的一个特性,就是它只管解析,不管验证
也就是不管你输入的是不是http请求,都会解析
举个例子:

parse_url(“javascript://127.0.0.1/data?id=1;”);

会解析成这样

array (size=4)
  'scheme' => string 'javascript' (length=10)
  'host' => string '127.0.0.1' (length=9)
  'path' => string '/data' (length=5)
  'query' => string 'id=1;' (length=5)

那么我们的思路就有了,我们输入的referer应该是:
referer=javascript:alert(1)
但是这样的话host就不是127.0.0.1了呀,也就是前面必须是
referer=javascript://127.0.0.1/
但是这样referer=javascript://127.0.0.1/alert(1)这样也不能执行js啊
但是我们知道在js中//表示注释符,而且是单行注释.
也就是说,我们可以让我们的js代码放在第二行,还是属于js的执行范围之内,就相当于

<script>
//127.0.0.1/
alert(1);
</script>

QQ20170520-000549@2x.png
我们点击之后
QQ20170520-000620@2x.png
由于discuz会对url进行解码,看有没有敏感字符
所以我们输入的还要对%进行url编码,也就是%250d这样
最后我们的攻击代码就是

    member.php?mod=logging&action=login&referer=javascript://127.0.0.1/%250dalert(1);

这样就能成功弹窗啦!!!!

Comments are closed.