本文来自i春秋作者:索马里的海贼

前言

一篇说了一般审计中的流程,有的时候我们的目的并不是完整的审计一套系统,而是在搞事的过程中发现目标站或者旁站或者关联站点为开源cms,这时候的目的是尽快拿到可利用的漏洞。这时候当然也可以按部就班慢慢从框架流程看起,不过估计大伙都没这个心思,那么再来说说一些快速发现的漏洞挖掘方法。

一、关注重点

为了搞事,所以当然是从比较严重的问题开始看,xss csrf这些留到最后,先看命令执行,文件操作,sql这3块。这次主要说sql(因为发现的就是sql注入) sql注入快速挖掘,第一步先看有没有全局的防御机制 比如很多cms都会在全局配置文件里有这么一块

foreach(array('_GET','_POST','_COOKIE') as $key=>$value){
        $key = daddslashes($value);//daddslashes是addslashes函数的扩展版 增加了对数组的循环转义
}

比如这次目标Mlecms的代码 inc/include/globals.php行24

foreach(array('_GET','_POST','_COOKIE') as $_request){
        foreach($_request as $i => &$n){
                ${$i} = daddslashes($n);
        }
}

类似这样的代码,把GPC的内容都转义了一遍 碰上这样的情况 就不要再去想简单的跟踪请求参数来注入了 直接去找能重新引入单引号或者反斜杠的地方 比如下面的一些例子

> substr() //取到转义处,留下反斜杠
> $sth['xx'] //当变量为字符串时 取的是xx位置的一个字符
> stripslashes() //这三个就不解释了
> urldecode() //这三个就不解释了
> base64_decode() //这三个就不解释了
> parse_str() //parse_str之前会先urldecode

或者直接找除了GPC之外的能提交的内容 比如常见的X-Forwarded-For的注入 referer的注入 它们都来自$_SERVER数组 而且经常被认为是安全的而不进行处理。当然现在大伙儿(码农)意识都高了(其实是被搞怕了) 再不济也知道从X-Forwarded-For取到IP之后做个转义,更多的是拿到IP之后用正则校验一下是不是正常的IP 比如目标CMS

function get_ip(){
        if(!empty($_SERVER["HTTP_CLIENT_IP"])){
                $cip = $_SERVER["HTTP_CLIENT_IP"];
        }else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"])){
                $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        }else if(!empty($_SERVER["REMOTE_ADDR"])){
                $cip = $_SERVER["REMOTE_ADDR"];
        }else{
                $cip = '';
        }
        preg_match("/[\d\.]{7,15}/",$cip,$cips);
        $cip = isset($cips[0]) ? $cips[0] : 'unknown';
        unset($cips);
        return $cip;
}

可以看到最后用/[\d\.]{7,15}/这条正则匹配了一下 这里不说这样判断IP是否正确,至少除了数字和点之外 混不进其他字符了  没有了单引号也就几乎没有了注入的可能。

二、实战

上一段说了不少能引入单引号或者绕过全局转义的地方,那么就来实战一下 这里从$_SERVER开始,为了快速发现问题 一些搜索技巧必须熟练 比如这里我用的一条正则

(SELECT|INSERT|UPDATE|DELETE).*\$_SERVER

简单给不懂正则的童鞋解释一下这条正则的意思是 有(SELECT|INSERT|UPDATE|DELETE)其中之一且后面出现了$_SERVER 如果能在sql语句拼接中出现不会被转义的$_SERVER内容的话,很有可能就是一个注入了 不得不说,审代码 运气也很重要,还真被我搜到一处

inc/lib/admin.lib.php 行46

public static function logs($type,$info){
            global $db,$admin_config,$gmt_time;
            if($admin_config['logs_open'] == 1){
                    $sql = "INSERT INTO `{$db->prefix}logs` (`type`,`info`,`pageurl`,`lang`,`username`,`ip`,`ipaddress`,`addtime`) VALUES ('{$type}','{$info}','http://{$_SERVER['SERVER_NAME']}".substr(get_url(),0,200)."','".LANG."','{$_SESSION['admin']['login']['username']}','".get_ip()."','".ip::get_address(get_ip())."','".$gmt_time."');";
                    $db->execute($sql);
                }

$_SERVER['SERVER_NAME']被拼进了sql语句,$_SERVER['SERVER_NAME']是什么鬼,能吃么?能伪造么? 答案是肯定的 来看看php官方对SERVER_NAME的定义

中文版

'SERVER_NAME' 当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。

英文版

'SERVER_NAME' The name of the server host under which the current script is executing. If the script is running on a virtual host, this will be the value defined for that virtual host.

Note: Under Apache 2, you must set UseCanonicalName = On and ServerName. Otherwise, this value reflects the hostname supplied by the client, which can be spoofed. It is not safe to rely on this value in security-dependent contexts.

有没有发现 英文版多了点东西 简单翻译一下: 在apache2 下 如果你没有设置ServerName或者没有把UseCanonicalName 设置为 On的话,这个值就会是客户端提供的hostname  不安全哟

所以老师说英语学得好 爸爸回家早 噢不 渗透搞得好

那么这个客户端提供的hostname是什么鬼呢,其实就是http包中的Host: 字段的值

那么又有人说了,如果修改了Host字段的值,那配置了ServerName的web容器怎么判断是哪个虚拟主机呢

这里就要说另一个有意思的事了,如果我们的http包中有两个或者多个Host值 会是什么情况呢

对于apache来说,不管你有多少个 它只取第一个

对于php来说,不管你有多少个,它全要了 是的 全要了。。 比如

Host:a.com Host:b.com

php的$_SERVER['SERVER_NAME']会取到 a.com, b.com 用逗号分隔的两个host值 这下就好办了

三、利用

logs函数在后台登陆的时候会被调用,不管登录成功与否,都会调用logs()函数写入登录记录,利用的话  随便填账号密码   burp或者fiddler拦下来 添加一个Host头 然后查看结果就好了

如图

总结

写文章好累。。。

快速漏洞挖掘需要积累常见漏洞触发点,函数,语言特性等等。 顺便建议不会正则的看看正则表达式入门,提高搜索效率、挖漏洞也能碰上不少正则,到时候看不懂错失0day就亏了。

原文地址:http://bbs.ichunqiu.com/thread-13714-1-1.html?from=seebug


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:http://paper.seebug.org/78/