海豚cms(cookie欺骗可被绕过登录)

漏洞分析

public function signout()
......此处代码省略
session(null);
cookie('uid', null);
cookie('signin_token', null);
$this->redirect('signin');
}

主要我们看在执⾏signout退出操作的时候对session以及cookie中对uid与signin_token进⾏了清
空,⽬前猜测signin_token可能⽤于控制登陆,搜⼀下都有哪些地⽅使⽤

function is_signin()
{
$user = session('user_auth');
if (empty($user)) {
// 判断是否记住登录
if (cookie('?uid') && cookie('?signin_token')) {
$UserModel = new User();
$user = $UserModel::get(cookie('uid'));
if ($user) {
$signin_token = data_auth_sign($user['username'].$user['id'].$user['last_login_time']);
if (cookie('signin_token') == $signin_token) {
// ⾃动登录
$UserModel->autoLogin($user);
return $user['id'];
}
}
};
return 0;
}else{
return session('user_auth_sign') == data_auth_sign($user) ? $user['uid'] : 0;
}
}

检测是否登陆 ,当session的user_auth为空时则⾛cookie验证流程,通过cookie中的uid获取具体
的user信息,再通过data_auth_sign⽣成sign值

function data_auth_sign($data = [])
{
// 数据类型检测
if(!is_array($data)){
$data = (array)$data;
}
// 排序
ksort($data);
// url编码并⽣成query字符串
$code = http_build_query($data);
// ⽣成签名
$sign = sha1($code);
return $sign;
}

就是很常规的拼接sha1⽣成签名

if (cookie('signin_token') == $signin_token) {
// ⾃动登录
$UserModel->autoLogin($user);
return $user['id'];
}

这是很重要的⼀段,当cookie的值与⽣成出的签名符合时。则进⼊autoLogin⾃动登陆

public function autoLogin($user, $rememberme = false)
{
// 记录登录SESSION和COOKIES
$auth = array(
'uid' => $user->id,
'group' => $user->group,
'role' => $user->role,
'role_name' => Db::name('admin_role')->where('id', $user->role)->value('name'),
'avatar' => $user->avatar,
'username' => $user->username,
'nickname' => $user->nickname,
'last_login_time' => $user->last_login_time,
'last_login_ip' => get_client_ip(1),
);
session('user_auth', $auth);
session('user_auth_sign', data_auth_sign($auth));
// 保存⽤户节点权限
if ($user->role != 1) {
$menu_auth = Db::name('admin_role')->where('id', session('user_auth.role'))->value('menu_auth');
$menu_auth = json_decode($menu_auth, true);
if (!$menu_auth) {
session('user_auth', null);
session('user_auth_sign', null);
$this->error = '未分配任何节点权限!';
return false;
}
}
// 记住登录
if ($rememberme) {
$signin_token = $user->username.$user->id.$user->last_login_time;
cookie('uid', $user->id, 24 * 3600 * 7);
cookie('signin_token', data_auth_sign($signin_token), 24 * 3600 * 7);
}
return $user->id;
}

直接将通过uid查询出来的user信息传⼊并启⽤有效的session,导致⽤户可在cookie许可的情况下直
接登陆。再回顾看看技术的难点在哪⾥

$user = $UserModel::get(cookie('uid'));
if ($user) {
$signin_token = data_auth_sign($user['username'].$user['id'].$user['last_login_time']);

uid可控,username以及id不可控,但是我们知道数据库排序是递增的,所以⼀般我们uid为1⼤多数的
id都是为1,⽽username很好解决,因为海豚拥有⾃身的⼀个问题
image
当输⼊不存在当⽤户名时会进⾏友好提示,默认安装时admin最默认管理员⽤户名并且id为1以及uid为1
所以当admin存在的时候,我们的uid以及id以及username均已知。未知的则是last_login_time。
我们跟⼀下login看last_login_time如何⽣成

$user['last_login_time'] = request()->time();
$user['last_login_ip'] = request()->ip(1);
if ($user->save()) {
// ⾃动登录
return $this->autoLogin($this::get($uid), $rememberme);
}

跟⼊reques下的time

public function time($float = false)
{
return $float ? $this->server('REQUEST_TIME_FLOAT') : $this->server('REQUEST_TIME');
}

获取登陆成功时请求时间并且执⾏save进⾏user表登陆⽤户last_login_time值更新。

3 个赞

这个时间戳就很难受,利用感觉有点困难啊

是有点难受的!不过这种点的利用还是得看目标站是什么类型的,如果是那种经常维护的站!就爆破当天的时间就行了!还是有希望的!

哈哈,佛系日站

差不多吧!一般特殊情况特殊对待,真没点可以突破的时候,这种点还是会考虑上