如何正确的读网上的web漏洞分享文章(报告)

网上的漏洞分享报告很多,不管是文章也好报告也好,公开以后都是给人读的,最终目的都是让人受益。去了解,分析,研究,修复这个漏洞。但是读者群中不仅仅包括有厂商和漏洞研究者们,还有数目庞大的安全初学者和门外汉。

但是,在真正的拿起一篇文章开始读时,这些安全初学者往往会愕然,因为很多人会感觉无从读起,不好下手。为什么会有这种感觉呢?其实我猜应该是有以下几种原因导致的。

1. 安全研究者在发布漏洞时,往往只会注重技术细节,不会瞻前顾后。如果代码功底不强的读者看到了,肯定会云里雾里。

2. 漏洞公布平台版面/厂商要求? 不知道存在不存在这种情况,往往很多人喜欢一针见血, 不喜欢啰里八嗦的人,我曾经就被外甥训斥为:不要再啰嗦了。

3. 漏洞发布者是一个注重效率的人。

4. 初学者认为自己的问题太基础羞于下问,研究者认为问题太过基础耻于回答。(死循环)

于是这就导致了一个问题, 大多安全研究者认为此技术我已掌握不需要去过多了解,本来不会想去了解的人还是不会。 这样造成的结果就是,技术文章在有限的条件下偏离了造福一方的初衷。失去了安全的真正意义。

那么,问题来了, 如何正确的去读一篇web漏洞文章呢?

一:在读web漏洞文章前,首先要做到以下几点

1. 自己要有对应语言的基础,至少也要做到会读。

2. 应该本地搭建一个环境出来,运行存在漏洞的对应程序,不能只看不练,这样是没法进行深入研究的。

做到以上几点后, 就可以进入读书环节了, 那么来看一个实例

DEDECMS V5.7 SP2 后台Getshell

看到标题就是dedecms5.7 sp2版本, 那咱们就要下载回来, 在本地安装上,然后继续看。 可以先大概的扫完全文,然后再重头开始看。这个时候,我们知道了, 造成漏洞的文件在 dede/sys_info.php路径。

打开该文件,展现出来的就是php代码了, 其实能从文件的命名规则里猜出这个文件的含义, system information settings嘛。 那么,继续看代码。其实我建议不要按照漏洞作者的提醒直接去读对应存在漏洞的类或者函数最好, 如果代码量不大的话,读完整段代码也是个不错的选择,可以有效的培养自己的阅读量。

这里咱们按照提醒直接去看存在漏洞的片段

//保存配置的改动
if($dopost=="save")
{
    if(!isset($token)){
        echo 'No token found!';
        exit;
    }

    if(strcasecmp($token, $_SESSION['token']) != 0){
        echo 'Token mismatch!';
        exit;
    }
    foreach($_POST as $k=>$v)
    {
        if(preg_match("#^edit___#", $k))
        {
            $v = cn_substrR(${$k}, 1024);
        }
        else
        {
            continue;
        }
        $k = preg_replace("#^edit___#", "", $k);
        $dsql->ExecuteNoneQuery("UPDATE `#@__sysconfig` SET `value`='$v' WHERE varname='$k' ");
    }
    ReWriteConfig();
    ShowMsg("成功更改站点配置!", "sys_info.php");
    exit();
}

这段代码的大概意思是, 如果检测到了save动作, 就判断token是否设置, 如果token已设置, 就跳出进入下一个判断, 如果表单传到的token和session中的token一致,就再跳出进入foreach循环取出post过来的数据, foreach中又进入了一个if判断, 如果在get参数中找到了edit_格式的名字,就进行赋值,这里有个函数cn_substrR,要搞清楚这个的含义就要看它在哪封装的,咱们可以先在文件中进行搜索, 如果文件中没有就去include里找..最后,最后居然没有搜索到?! 我也不知道为什么,所以这里又用了另外一个方法, 编辑器都有在目录文件夹中搜索关键字的功能,我用这个最后找到了封装的cn_substrR函数。

if ( ! function_exists('cn_substrR'))
{
    function cn_substrR($str, $slen, $startdd=0)
    {
        $str = cn_substr(stripslashes($str), $slen, $startdd);
        return addslashes($str);
    }
}

看到stripslashes和addslashes, 不自然的噢了一声在心里, 原来是安全功能函数啊,防止注入的,给了一个默认字节长度是1024字节。进行循环取值过滤,过滤完后进入下一个replace, 去空格后使用pdo的形式对指定varname的k value值进行更新,最后通过调用rewriteconfig函数写入配置文件完成更新, 这里看到有个writeconfig,那咱们跳过去,搜索了一下发现在文件中。

//更新配置函数
function ReWriteConfig()
{
    global $dsql,$configfile;
    if(!is_writeable($configfile))
    {
        echo "配置文件'{$configfile}'不支持写入,无法修改系统配置参数!";
        exit();
    }
    $fp = fopen($configfile,'w');
    flock($fp,3);
    fwrite($fp,"<"."?php\r\n");
    $dsql->SetQuery("SELECT `varname`,`type`,`value`,`groupid` FROM `#@__sysconfig` ORDER BY aid ASC ");
    $dsql->Execute();
    while($row = $dsql->GetArray())
    {
        if($row['type']=='number')
        {
            if($row['value']=='') $row['value'] = 0;
            fwrite($fp,"\${$row['varname']} = ".$row['value'].";\r\n");
        }
        else
        {
            fwrite($fp,"\${$row['varname']} = '".str_replace("'",'',$row['value'])."';\r\n");
        }
    }
    fwrite($fp,"?".">");
    fclose($fp);
}

看到它调用了fwrite就大致知道是什么漏洞了, 读了一下代码, 大概意思是, 如果有权限就进入写文件流程, 然后执行一个select查询出配置信息里面的东西。 再往下进入一个while, 执行getarray()函数获取存入数据库的信息,然后给一个数组名row,这里有两个判断, 类型是number和非number, 漏洞作者这里采用的是true分支里的信息, 因为少了一个replace避免麻烦(这真是极好的。)最后未经过任何处理就把取出的信息存入了文件中,这里的varname实际就是通过post过来的参数信息,value就是值不用说了。 最后作者用21;phpinfo的含义是,数字可以符合进入true的条件,;闭合一段代码,最后把包含phpinfo的代码写入到了文件中造成了意外结果。

这里怎么修复呢? 因为带入了数据库, 所以直接is_numeric肯定是不行的, 也有可能会造成16进制注入, 可以进行嵌套判断, 先判断是否为数字, 如果为数字, 再对数字进行判断, 进行一个preg去掉 a-A-z-Z。也可以采用白名单形式。这样就会安全的多了。

比如在不考虑其它前提的情况下,这样就会安全很多

while($row = $dsql->GetArray())
{
if($row[‘type’]==’number’  && preg_match("/[^a-zA-Z]\S/",$row['value']) && is_numeric($row['value']))
{
if($row[‘value’]==”) $row[‘value’] = 0;
fwrite($fp,”\${$row[‘varname’]} = ‘”.str_replace(array('\'',';','.'),”,$row[‘value’]).”‘;\r\n”);
}
else
{
$row['value'] = intval($row['value']);
fwrite($fp,”\${$row[‘varname’]} = ‘”.str_replace(array('\'',';','.'),”,$row[‘value’]).”‘;\r\n”);
}
}
fwrite($fp,”?”.”>”);
fclose($fp);
}

好的建议是把preg放到最外层,其实有很多种办法, 看具体环境怎么写。 慎用单条件过滤。

if($row[‘type’]==’number’  && preg_match("/[^a-zA-Z]\S/",$row['value']) && is_numeric($row['value']))

这个条件不能单独用到sql增删改查环境下, 是可以被绕过的。原因是还有一个前面说过的十六进制注入。 可以使用函数过滤+正则+pdo查询+给服务器运行环境设置一个低权限账号+给不同数据库设置不同的账号禁止读取information_schema表,就会更安全一些。

各位同志如果没有那么多时间从头学起的话, 可以先重点从结构体,函数, 变量, 循环语句去了解。 再去结合一些敏感函数和动作,慢慢去发现更多未知的世界。

我曾经用多个id在包括乌云网在内的多个zone发表过类似的文章。收到了很好的评价。

如何正确的读网上的web漏洞分享文章(报告)》有1个想法

评论已关闭。