文章总结: 文章详细记录了对某EIS办公平台的安全审计过程,包括环境搭建、产品授权绕过、配置分析和漏洞挖掘。作者通过逆向破解授权算法和注释鉴权代码两种方式绕过了产品授权限制,随后发现了多个高危漏洞:前台SSRF漏洞、前台down.aspx和Notify.asmx的SQL注入漏洞、前台任意用户添加漏洞以及后台任意文件上传漏洞。文章提供了详细的技术细节和漏洞利用方法,展示了企业办公平台可能存在的安全风险。 综合评分: 89 文章分类: 漏洞分析,代码审计,WEB安全,渗透测试,漏洞POC
记一次某EIS办公平台0day挖掘审计过程
原创
hyrrent
亿人安全
2025年12月18日 11:18 北京
| | | — | | 声明:该公众号大部分文章来自作者日常学习笔记,也有部分文章是经过作者授权和其他公众号白名单转载,未经授权,严禁转载,如需转载,联系开白。 请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与文章作者和本公众号无关。 |
现在只对常读和星标的公众号才展示大图推送,建议大家把“亿人安全”设为星标,否则可能看不到了!
原文首发在:先知社区:
https://xz.aliyun.com/news/90808
环境搭建
机缘巧合下从好兄弟那拿套源码,好久没审计有点生疏了,搭个环境练练手
虚拟机选择win2012,在Internet信息服务(IIS)上新建网站,设置站点名称和安装路径
在应用程序池中找到对应站点程序池,托管管道模式默认为集成,将其修改为经典模式.NET
新建数据库,与web.config连接保持一致即可
| |
| — |
| set DBNAME=EIS set SQLUSER=sa set SQLPWD=password01! set SQLSERVER=127.0.0.1,1433 <connectionStrings> <add name="" connectionString="Data Source=.\SQLEXPRESS;User ID=sa;Password=password01!;Initial Catalog=EIS;Connection Timeout=30;Connect Retry Count=3;Connect Retry Interval=10;Pooling=true;Min Pool Size=0;Max Pool Size=100" providerName="System.Data.SqlClient" /> </connectionStrings> |
按顺序依次导入sql文件
Patch产品授权
该产品是需要产品授权的,访问login.aspx会提示无效或过期
逆向破解算法,模拟生成授权licsense
应用启动时验证(CheckLicense)
位置:EkpBaseGlobal.Application_Start()→EkpGlobal.CheckLicense()
流程:
- 读取文件授权(
Checker.p_GetLicense())
- 读取
Bin/Landray.lic文件 - 获取CPU ID和MAC地址
- 解密授权文件
- 解析授权信息(10个字段)
- 提取FullName
- 读取数据库授权
- 从
Mekp_EISProductInfo表读取LicenseKey - 使用相同的密钥和IV解密
- 解析授权信息(2个字段:过期时间;FullName)
- 验证授权
- 比较文件授权和数据库授权中的FullName是否一致
- 如果是试用版,检查过期时间(逻辑:
DateTime.Now < expiration→ 返回false) - 如果验证通过,将授权信息存储到
Application对象中
- 更新数据库授权(如果是试用版)
- 将数据库授权更新为当前时间 + FullName
采用加密算法:3DES (TripleDES)
- 文件授权lic:
读取文件并解密(密钥:CPU + "xxxxxxx20800",IV:MAC地址)
解析10个字段,关键字段:array[3] = "DeptName|FullName存入lisenceInfo.FullName
-
时间校验:
if (DateTime.Now < result) return false,如果当前时间 < 过期时间,返回false(验证失败) -
FullName匹配:
lisenceInfo.FullName必须与数据库完全一致
根据 CPU MAC 生成
注释鉴权代码重编译
如果觉得第一种方法比较复杂,也可以选择第二种简单粗暴的方法,直接注释掉核心鉴权代码
根据报错的关键字定位相关的文件,发现有以下这些文件参与鉴权,这些方法都来源于yard.Framework.dll
- EkpGlobal.CheckLicense() – 核心授权检查
- EkpPage.OnInit() – 页面初始化检查
- EkpPage.Page_Load() – 页面加载检查
- EkpUserControl.Page_Load() – 用户控件检查
因此我们可以使用dnspy导入dll,再导出工程到vs里面进行重编译
成功通过授权校验,访问系统首页
web.config配置分析
根据web.config分析,以下路径配置为允许所有用户访问(<allow users="*" />)
(部分接口关键字替换了)整理如下:
| | | |
| — | — | — |
| 配置路径 | 访问路径 | 说明 |
| <location path="XX"> | /XX/*.asmx | WebService接口目录,所有ASMX文件可匿名访问 |
| <location path="aaa"> | /aaa/*.aspx | 该模块目录下所有aspx文件可匿名访问 |
| <location path="third"> | /third/*.aspx | 第三方集成目录 |
| <location path="Global/Pages/CheckPage"> | /Global/Pages/CheckPage/*.aspx | 检查页面目录 |
| <location path="Services/MobileDown.aspx"> | /Services/MobileDown.aspx | 移动端下载接口 |
漏洞分析
前台SSRF
-
文件路径:
-
bin/yard.UI.Integration/yard.UI.Integration.third.template/Service.cs -
方法:
PostResponsethird目录配置允许匿名访问 -
link参数直接拼接:
base.Request["link"]直接拼接到URL中,未进行任何验证 -
无URL白名单: 未限制可访问的URL范围,虽然固定使用
http://,但可以通过传入link参数控制造成SSRF
前台down.aspx SQL注入
前台Notify.asmx SQL注入
- 文件路径
- :
bin/yard.WebService/yard.WebService.WS.Notify/Notify.cs - LoginName参数直接拼接:
person.LoginName直接拼接到SQL查询中
| |
| — |
| [WebMethod] public NotifyResult getTodo(string targets, int type, string otherCond, int rowSize, int pageNo) { Person person = JsonConvert.DeserializeObject<Person>(targets); if (!string.IsNullOrEmpty(person.LoginName)) { // SQL注入点: LoginName参数直接拼接 string oneStrValue = yard.DataAccess.DataAccess.GetOneStrValue( $"SELECT id FROM FI_ORG_EMP where account=N'{person.LoginName}'"); // ... } } |
构造请求,通过xp_cmdshell写入文件1.txt
前台任意用户添加
- 文件路
- 径:
bin/yard.WebService/yard.WebService.WS/UserInfo.cs User方法使用[WebMethod]标记,WS目录被配置为允许所有用户访问,该方法无权限校验可直接执行数据库插入操作- 继承于WebService可直接传入账号密码等信息新建用户,首先在数据库中查询是否存在该⽤户, 如果不存在就创建
FI_ORG_EMP为员工主表,可看到成功新建用户
后台UploadLogImg.aspx任意文件上传
文件bin\yard.Admin.UI\yard.Admin.UIUploadLogImg.cs提供了saveBg()和saveLogo()两个上传的方法
string text = base.Server.MapPath这个地方路径不可控,默认会写到/App_Themes/Login下面,文件名为日期命名
构造方法上传
/App_Themes/Login不允许,因此这个上传无法shell
后台 bulkinsert_data.aspx任意文件上传
但是不要灰心,这个点找不到就找下一个,继续搜SaveAs(filename)
- 这里还有两个值是必须的,
__VIEWSTATE和__VIEWSTATEGENERATOR - 当用户首次访问
/XX/bulkinsert_data.aspx?id=1时,页面加载 –Page_Load方法执行,所有服务器控件初始化,使用 Base64 编码,生成__VIEWSTATE和__VIEWSTATEGENERATOR值,ASP.NET 会验证,没有ViewState会导致Invalid ViewState错误,控件状态无法恢复
| |
| — |
| string text = "/files/"; // 固定基础路径 string fileName = tpfile.PostedFile.FileName; // 用户输入 int num = fileName.LastIndexOf("\\"); // 查找最后一个反斜杠 string empty = string.Empty; empty = ((num <= 0) ? ("\\" + fileName) : fileName.Substring(num)); tpfile.PostedFile.SaveAs(base.Server.MapPath(text + empty)); |
可进行目录穿越,代码会取最后一个\之后的部分,但是正斜杠可以正常绕过
..\third\shell.aspx→empty = "shell.aspx"❌../third/shell.aspx→empty = "third/shell.aspx"✅️
结合web.config,可写到third路径下
查看原文:《记一次某EIS办公平台0day挖掘审计过程》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论