本文来自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