前台反序列化代码审计
本文最后更新于 72 天前,其中的信息可能已经有所发展或是发生改变。

一直在忙毕设,很久没看安全了,看个PHP代码审计练练手,参考自苏安的博客

基础框架依然是MVC,控制器都在framework/下,路由方式是/admin.php?c=login&f=index,对应framework/admin/login_control.php下的index_f方法。

思路

漏洞点在admin.php?c=login&f=update

	public function update_f()
	{
		$login_time = $this->get('login_time');
		if(!$login_time){
			$login_time = 1440;
		}
		$fid = $this->get('fid');
		$fcode = $this->get('fcode');
		if(!$fid && !$fcode){
			$this->error(P_Lang('登录数据不完整'));
		}
		$quickcode = $this->get('quickcode','html');
		if($quickcode){
			$file = $this->dir_cache.$fid.'.php';
			if(!file_exists($file)){
				$this->error(P_Lang('验证文件丢失,请重新扫码'));
			}
			$keyid = $this->lib('file')->cat($file);
			$this->lib('token')->keyid($keyid);
			$msg = $this->lib('token')->decode($quickcode);
			if(!$msg || !is_array($msg) || !$msg['id'] || !$msg['user'] || !$msg['time'] || !$msg['domain']){
				$this->error(P_Lang('数据解码失败'));
			}
			//超过30天,告知无效
			$time = $this->time - $msg['time'];
			if($time>(30*24*60*60)){
				$this->error(P_Lang('数据超过30天,请重新登录'));
			}
			$domain = $this->_domain();
			if($msg['domain'] != $domain){
				$this->error(P_Lang('数据来源不准确'));
			}
			$rs = $this->model('admin')->get_one($msg['id']);
			if(!$rs || $rs['account'] != $msg['user']){
				$this->error(P_Lang('账号不一致'));
			}
		}else{
			$user = $this->get('user');
			$pass = $this->get('pass');
			if(!$user || !$pass){
				$this->error(P_Lang('账号/密码不能为空'));
			}
			$rs = $this->model('admin')->get_one_from_name($user);
			if(!$rs){
				$this->error(P_Lang('管理员信息不存在'));
			}
			if(!$rs["status"]){
				$this->error(P_Lang("管理员账号已被锁定,请联系超管"));
			}
			if(!password_check($pass,$rs["pass"])){
				$this->error(P_Lang('管理员密码输入不正确'));
			}
		}
		$domain = $this->_domain();
		$data = array('id'=>$rs['id'],'user'=>$rs['account'],'time'=>$this->time);
		$data['domain'] = $domain;
		$content = '';
		if($this->site['api_code']){
			$this->lib('token')->keyid($this->site['api_code']);
			$this->lib('token')->expiry(30*24*60*60);
			$content = $this->lib('token')->encode($data);
		}
		//删除checking文件,创建登录文件
		$this->lib('file')->rm($this->dir_cache.$fid.'-checking.php');
		$data['online'] = $login_time;
		$this->lib('file')->vim($this->lib('json')->encode($data),$this->dir_cache.$fid.'-'.$fcode.'.php');
		$this->success($content);
	}

首先需要传入$fid以及$fcode两个参数,且$fid文件必须存在在cache目录下,这里可以用目录穿越绕过。

之后要提到一个很重要的函数就是lib(),跟进后是在全局变量$app,调用_init_phpok.php下的_init_phpok类中的lib()函数,我们分析一下在update_f()中的$keyid赋值这里。

$lib中,对$config进行赋值

最后返回:

随后进入file.php中的cat()函数,当我们传入的是index.php文件时,这里的处理是获得文件内容并做一定的处理后(当为index.php时无处理)返回。

之后的keyid()对传入的文件内容进行处理,获得md5值,由于选择的文件是一定的,所以获得的md5值也是一样的。

跟进decode,这里存在unserialize()反序列化点,逆向过程可以调用token.phpencode()函数。

	/**
	 * 解密
	 * @参数 $string 要解密的字串
	**/
	public function decode($string)
	{
		if($this->encode_type == 'public_key'){
			return $this->decode_rsa($string);
		}
		if(!$this->keyid){
			return false;
		}
		$string = str_replace(' ','+',$string);
		$keyc = substr($string, 0, $this->keyc_length);
		$string = base64_decode(substr($string, $this->keyc_length));
		$cryptkey = $this->keya.md5($this->keya.$keyc);
		$rs = $this->core($string,$cryptkey);
		$chkb = substr(md5(substr($rs,26).$this->keyb),0,16);
		if((substr($rs, 0, 10) - $this->time > 0) && substr($rs, 10, 16) == $chkb){
			$info = substr($rs, 26);
			return unserialize($info);
		}
		return false;
	}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇