0x01 前言
多米cms的源码可能部分会有所加密,我直接取巧拿了其他版本的做了测试,当然可以去看看网上有大佬的解密方法。当然本文用到的源码没有任何加密。
0x02 思路
使用变量覆盖漏洞,赋予管理员session,登录后台,getshell
0x03 实战
1、审计
我们可以利用的点就出现在common.php,在这里说明一下:一般文件名为function或者common等关键词的文件通常为我们经常要调用的文件,所以在代码审计的时候也注意一下这类文件。
//检查和注册外部提交的变量
foreach($_REQUEST as $_k=>$_v)
{
if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
{
exit('Request var not allow!');
}
}
这段代码的意思就是将$_REQUEST获取到的值进行键值分离,举个例子就是:你传了8=phpinfo()
其中的$_k就是8,$_v就是phpinfo(),当然这是个循环往复的过程,传入多个参数,就循环执行上面的操作。
接下来进入if的判断语句当中,strlen()看字面意思应该能够看的出来,是判断字符串长度,m_eregi()应该是个自定义函数(这里不确定的话可以去百度上面搜索一下,搜索不到一般就是自定义函数),定位函数后我们可以发现来到了common.fun.php,其函数如下
function m_eregi($reg,$p)
{
$nreg=chgreg($reg)."i";
return preg_match(chgreg($reg),$p);
}
其实也不难读懂,接受两个参数:$reg与$p,其中chgreg函数调用了$reg后面连接了 i 这里我猜测可能与正则表达式有关,最后返回的时候以chgreg($reg)里面的正则规则来返回匹配$p当中的内容chgreg()也一样,百度上面搜索不到就去定位函数试试,它的函数是这样的
function chgreg($reg)
{
$nreg=str_replace("/","\\/",$reg);
return "/".$nreg."/";
}
很明显是将$reg当中的“/”替换为“\\/”,然后以正则表达式的形式返回。接下来我们回到起点,只要我们传入的参数当中开头不是cfg_或者GLOBALS就行,当然这里要求的是$_k,不是$_v
//检查和注册外部提交的变量
foreach($_REQUEST as $_k=>$_v)
{
if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
{
exit('Request var not allow!');
}
}
2、利用
相信大家应该看过不少,关于变量覆盖漏洞的文章,其中有一部分是写到了,去赋值session来登录后台,在这里我们来复现一下。
要登录就要有相对应的session,就算有session,我们也需要找到能够写入session的地方,在PHP当中session_start()函数能够展开会话,要是此文件当中使用到了session,我们就可以实现登录($_SESSION为全局变量,只要为我们使用了session,相当于我们就有了这个session)(这里的措辞与逻辑可能不会欢迎各位大佬批评指正),所以我们要找到的文件必须满足两个条件:1、有session_start()函数,2、全文中有$_SESSION字样,代码必须运行到此。那么我们就能够找到很多这样的文件。
这时有了利用方式,就还缺少session这个值了,那么我们肯定是想登录成功,所以找到登录成功的代码,我们来到admin目录下的login.php文件,使用die打断点,就能拿到session
if($res==1)
{
$cuserLogin->keepUser();
die(var_dump($_SESSION));
if(!empty($gotopage))
{
ShowMsg('成功登录,正在转向管理管理主页!',$gotopage);
exit();
}
else
{
ShowMsg('成功登录,正在转向管理管理主页!',"index.php");
exit();
}
}
这里有一个知识点:die只能输出字符串,对于数组类型的,就要使用var_dump/print_f
最后我们传入参数,拿下管理员权限,至于后面gethell的内容我下一篇文章会有写到
0x04 总结
本文章我借鉴了代码审计实战 - FreeBuf网络安全行业门户的文章,文章写的比较详细,大家也可以看看他写的文章。