文章总结: 本文披露用友某产品前台RCE漏洞完整利用链。攻击者通过EntryController转发绕过鉴权,定位HRPubBusinessInternalAction,利用其类初始化能力调用RtfDownloadFactory,结合文件上传功能上传恶意模板,最终经Velocity引擎解析触发SSTI实现远程代码执行。文章详细分析了数据流与参数获取方式,并给出实战利用思路,对红队评估具有较高参考价值。 综合评分: 88 文章分类: 漏洞分析,红队,代码审计,渗透测试
用友某产品最新版前台RCE
原创
ptr ptr
UpRoot
2026年10月6日 18:36 江苏
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
入口断点,发现*.do结尾的路由会经过nccloud.framework.web.action.entry.EntryController#doPost转发并且不会进行鉴权。
进一步跟进来到nccloud.framework.web.action.entry.Dispatcher#doAction,可以了解到最原始的一个请求/nccloud/platform/total/switch.do其是由/platform/total/switch三个部分组成的,其动作的实现类是nccloud.web.platform.gzip.action.QueryTotalSwitchAction。
通过类定位jar包,我们可以找到action的配置文件,由此,我们对于基本的路由形式心里便有了基本的认知了。
如果是正在进行红队评估,追求效率,不妨以此入口,寻找破局的办法。
我们重点关注可以通过EntryController进行转发的action并且该action的具体实现办法不会做强鉴权(如session、token等),从中寻找我们想要的sink点。
通过大量时间的寻找,我们可以定位到nccloud.web.hr.login.action.HRPubBusinessInternalAction#doAction鉴权较弱可被绕过。
并且该类具备对类初始化和调用类方法的能力。但前提是被初始化的类需要是AbstractInternalDataFactory的子类。
不妨以该点进行展开,发散,寻找哪些类是AbstractInternalDataFactory的子类,并且具备可以用来rce的能力。
由此,我们定位到了nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory。
nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#dataOperate方法内部可调用如下两个方法。
对于nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#downLoad方法。
这里先从字面上理解rtf后缀的文件是什么?bing搜索后了解到是富文本。
那downLoad方法大概想表达的意思是把doc转成rtf这种富文本的形式。我们继续跟进nc.itf.hr.tools.rtf.IGenerateRTFDocument#createRtfFile看看有没有操作空间。
来到nc.impl.hr.tools.rtf.RtfCommonGenerator#createRtfFile,继续跟进nc.impl.hr.tools.rtf.RtfCommonGenerator#buildRtfFile看看是怎么build这个rtf的。
来到nc.impl.hr.tools.rtf.RtfCommonGenerator#buildRtfFile,我们豁然开朗。
标准的Velocity_SSTI。(具体能不能r,我们后续debug分析就好了,此处是我们看到了破局的点。)
回到nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#downLoad这个入口,我们看看这个数据流从哪可以填进去。
重点关注vo这个JavaBean,它承载了我们想要的主要数据。
bytes = ((IGenerateRTFDocument)ServiceLocator.find(IGenerateRTFDocument.class)).createRtfFile(context, pk_psnjob, "psndoc", vo, (String[])null);
vo是通过bai.queryByPk(pk_rpt_def)赋值的,重点分析nc.itf.hi.IRptQueryService#queryByPk做了什么事情。
那这里,我随便输入了个pk_rpt_def的值,最后得到的结果是null。由此,我们有了个初步的结论,vo是由查询并赋值得到的。
进而,我们的思路转变为:外部可控的pk_rpt_def参数,它是什么?其值如何获得?是否可以伪造?
带着这个疑问,来分析该类中的另一个方法:nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#upLoad,它也引用了pk_rpt_def参数。
外部传入该参数后同样是进入nc.itf.hi.IRptQueryService#queryByPk查询,那由此我们可以推断出pk_rpt_def参数是表中的字段的值。
这次我们仔细分析一下这个查询逻辑,看看是去哪个表里面查的,pk_rpt_def是固定的还是动态生成的。
此处,拿数据源,datasource外部传参而来,由此,我们这里需要知道一个点:需要一个接口可以返回系统的数据源(前台是有这样的接口,本文不会提及)。
随后,参数被送入hr_rpt_def表进行查询,取值判断是否存在。
我们去数据库中查看hr_rpt_def表中的键值情况。
找到了我们想要的pk_rpt_def。(注意,此处出厂配置如下,我验证过别的目标值也是如此。如果不一致,我们借助一个前台sql注入,即可拿到表中的值的,这里也可以透露一点,是存在这样的注入的,本文不再提及。)
由此,我们获得了一批rk_rpt_def。
1001Z710000000000JB3
1001Z710000000000R7Q
1001Z710000000000R9D
1001Z710000000000RA5
1001Z710000000000RB5
1001Z710000000000RBP
1001Z710000000000RCA
1001Z710000000000RCW
1001Z71000000000DNII
从前文中,我们已经了解到nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#downLoad是用来消费vo这个javabean的,那我们这里完全可以大胆的去猜,十步之内必有解药,那nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#upLoad是用来生产vo这个javabean的。
大胆猜想,细心求证。我们带着正确的rk_rpt_def去走完整个nccloud.web.hrhi.rptdef.factory.RtfDownloadFactory#upLoad逻辑。
方法的开始是从请求中拿到文件并转为流。注意这里的request.readFiles(),其内部实现是接收文件上传表单。
由此,得到一个点:构造的数据包需要是文件上传表单的形式。
随后就是根据传入的rk_rpt_def参数去给vo赋值了。
接着,针对上传的文件流进行保存,我们来看看这一块的逻辑是怎么样的。
将文件写入到用友产品的临时目录下,其实这里也可以认为是一个鸡肋的任意文件上传,没法解析。
从磁盘中读取文件并转为字节数组存起来,这里就存到vo这个javabean中了。
前文我们了解到了vo是javabean同数据库相联系起来,在这个方法的结尾,我们来看看vo的值如何。
至此,我们搞清了vo的数据流情况。回到Velocity_SSTI这个破局点,其具体是怎么消费vo的呢?
跟进nc.itf.hr.tools.rtf.IGenerateRTFDocument#createRtfFile,最后发现通过velocity引擎解析了我们上传的文件。
由此,我们已经可以下结论了,文件上传模板,velocity解析模板形成SSTI。
最后武器化打内存马来完结撒花吧。
这里考验java安全功底的是用友定制JDK17+开启JavaSecurity+unsafe阉割。不过既然有了代码执行的能力,那结果必然还是“有志者、事竟成”。
– END –
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:UpRoot ptr ptr《用友某产品最新版前台RCE》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论