正题开始:
首先从wap.php文件中看到这里的内容,winmail是伪全局,我们现在走进index.php
前面的判断完全可以直接忽略,我们直接看后面
$logofile = ''; if ($logoimage != '') { if (strncasecmp($logoimage, 'jpg:', 4) == 0 || strncasecmp($logoimage, 'gif:', 4) == 0 || strncasecmp($logoimage, 'png:', 4) == 0) { $arrImage = explode(':', $logoimage); if (count($arrImage) == 3) { $logofile = $customizepath.$f_domain.'_logo.'.$arrImage[0]; if (!file_exists($logofile) || filemtime($logofile) <= floatval($arrImage[1])) { $fullfile = $webmailhome_directory.$logofile; file_put_contents($fullfile, base64_decode($arrImage[2])); } } } }
几乎全部变量都是可控的,所以无需质疑的这里 就存在一个文件写入的的操作,但我们绕不过后缀这里的验证,而且这套cms是一体安装的,并不是什么iis所以解析漏洞都GG了。这里其实我头疼了很久,我该怎么让这么一个无害的漏洞扩大伤害直达getshell?麻痹的继续挖:
viewsharenetdisk.php if (isset($f)) { $f = str_replace(' ', '+', $f); $f = base64_decode($f); parse_str($f); }
伪全局+变量覆盖漏洞又将会碰撞出如何的火花?
getlanguagetext($selected_common_language, 'NetDisk'); $domaininfo = load_domaininfo($domain); $userinfo = load_userinfo($userid);
Load_userinfo和domaininfo都是执行sql的地方
function load_domaininfo($domain) { global $domain_dbfile; $db = new SqliteDB($domain_dbfile); $strSql = 'SELECT * FROM domain'; if ($domain == '') $strSql .= ' WHERE type=1'; else $strSql .= ' WHERE domain='.$db->Escape($domain, true); $result = $db->Query($strSql);
先想想我们现在掌握的条件,一个变量覆盖和domain可控,但这里domain明显是经过sql防护。那么先继续往下面看
if ($domaininfo == false || $userinfo == false){ $smarty->assign('errCode', 1); $smarty->display($selected_theme.'/netdisk-viewshare.htm'); exit; }
if ($userinfo['netdiskcontrol'] != 1){ $smarty->assign('errCode', 1); $smarty->display($selected_theme.'/netdisk-viewshare.htm'); exit; } $share_check_userid = true; if ($share_check_userid) { if ($usercode != md5($userid.'|'.$userinfo['userid'].'|'.$userinfo['createtime'])) { echo 222; $smarty->assign('errCode', 1); $smarty->display($selected_theme.'/netdisk-viewshare.htm'); exit; }
if ($chksun != '' || $filename != '') { $item = ($chksum != '') ? $chksum : str_replace(' ', '+', $filename); //echo md5($item.'|'.$userinfo['userid'].'|'.$userinfo['createtime']); if ($itemcode != md5($item.'|'.$userinfo['userid'].'|'.$userinfo['createtime'])) { $smarty->assign('errCode', 1); $smarty->display($selected_theme.'/netdisk-viewshare.htm'); exit; } } }
下面有一个从sql中查询出来的md5效验,这样就很头疼了,所以绕不过的话那就没法利用?
这里突然想到刚刚sql中有new sqlite带入一个变量?而我们又有变量覆盖,那么???去看看
if (extension_loaded('sqlite3')) { class SqliteDB { var $dbhandle = null; var $dbfile = ''; function __construct($file) { $this->dbfile = $file; $this->Open(); } function __destruct() { $this->Close(); } function Open() { if ($this->dbfile == '') return false; if ($this->dbhandle) return true; $this->dbhandle = new SQLite3($this->dbfile); if (!$this->dbhandle) return false;
这里的file是可控的,也就是后面的$this->dbfile。那么这里我就想到了一个假设,sqlite是轻型类似access的数据库,这里access位置可以被我们恶意覆盖了。那么这个时候我们传一个我们自己的数据库然后变量覆盖指向这里是不是代表?于是想到怎么传呀?我们目前唯一可以写内容的就是之前那个漏洞,但只能写图片呀!!!等等 图片?轻型数据库?类似access?
大家都知道access可以修改任意后缀,那么sqlite可以??理论不然实操复现
这个是我们的数据库,去试试?
Go
事实证明是成功的
那么这个时候如何来利用喃?
本地先新建一个sqlite的数据库用二进制的方式读出来然后base64加密,最后写入jpg中。
在本地中测试时可以操作
正常从数据库中查询出内容。至于如何getshell?不多说了,数据库都已经被你控制了,你还不搞下…
【via@91ri-team Joseph】 本文系91ri团队原创文章,禁止第三方未经授权转载。