Reputation: 406
I have received a pentest report several years ago reporting one of the modules we have was vulnerable to SQL Injection. I am trying to verify this with limited knowledge. The code below shows the SQL statement
takes in where
and where
variable may be subject to SQL injection as it can be manipulated. The recommendation is to use parameterised queries. The question I have is, does queryParser
sufficiently sanitise it to prevent sql.eachRow
from executing a potential malicious payload?
where = where + " AND " + queryParser(query)
switch (objectClass) {
case ObjectClass.ACCOUNT:
def where = "" ;
def whereParams = []
def fieldMap = [
"__ACCOUNT__" : [
"__UID__" : "USER_CONTEXT_KEY",
"__NAME__": "USER_CONTEXT_KEY"
]
]
if (filter != null) {
def query = filter.accept(MapFilterVisitor.INSTANCE, null)
log.info("Filter query:"+ query);
// this closure function recurses through the (potentially complex) query object in order to build an equivalent
// SQL 'where' expression
def queryParser
queryParser = { queryObj ->
if (queryObj.operation == "OR" || queryObj.operation == "AND") {
return "(" + queryParser(queryObj.right) + " " + queryObj.operation + " " + queryParser(queryObj.left) + ")"
} else {
if (fieldMap[objectClass.objectClassValue] && fieldMap[objectClass.objectClassValue][queryObj.get("left")]) {
queryObj.put("left", fieldMap[objectClass.objectClassValue][queryObj.get("left")])
}
def left = queryObj.get('left')
def not = queryObj.get('not')
def template
switch (queryObj.get('operation')) {
case 'CONTAINS':
template = "$left ${not ? "NOT " : ""}LIKE ?"
whereParams.add("%" + queryObj.get("right") + "%")
break
case 'ENDSWITH':
template = "$left ${not ? "NOT " : ""}LIKE ?"
whereParams.add("%" + queryObj.get("right"))
break
case 'STARTSWITH':
template = "$left ${not ? "NOT " : ""}LIKE ?"
whereParams.add(queryObj.get("right") + "%")
break
case 'EQUALS':
template = "$left ${not ? "<>" : "="} ?"
whereParams.add(queryObj.get("right"))
break
case 'GREATERTHAN':
template = "$left ${not ? "<=" : ">"} ?"
whereParams.add(queryObj.get("right"))
break
case 'GREATERTHANOREQUAL':
template = "$left ${not ? "<" : ">="} ?"
whereParams.add(queryObj.get("right"))
break
case 'LESSTHAN':
template = "$left ${not ? ">=" : "<"} ?"
whereParams.add(queryObj.get("right"))
break
case 'LESSTHANOREQUAL':
template = "$left ${not ? ">" : "<="} ?"
whereParams.add(queryObj.get("right"))
}
return template.toString()
}
}
where = where + " AND " + queryParser(query)
log.info("Search WHERE clause is: " + where)
}
def statement = """
select
a.USERUID||'^'||b.OCRCNMBR as USER_CONTEXT_KEY
,b.USERUID,b.OCRCNMBR,b.AUTHRCNTXTTYPE,b.AUTHRCNTXTSTATUS,b.CNTXTSTATUSREAS,b.REVIEWDATE,b.CNTXTSTRTDATE
,b.CNTXTEXPDATE,b.DOFPROFILEID,b.DESC, b.DATAAUTHRREF,b.APPROVERNAME,b.AC_TIMESTMP,b.APPROVER_EMAIL_ADDRESS,b.APPROVER_PHONE_NO
,c.AGENTLEVEL
,CASE
WHEN a.USERTYPE = 'AD' then '1'
WHEN a.USERTYPE in ('AA' , 'AB') and c.AGENCYACCNO is NULL then '1'
ELSE c.AGENCYACCNO
END as AGENCYACCNO,
c.RINO,c.COMPANYSIBNO,c.AAC_TIMESTMP,c.GI_AGENCY_NO,c.GI_AGENT_LEVEL,c.COMPANY_NAME,c.IRN_NO
from
ESEC.TIAUSER a,
ESEC.TIAAUTHRCNTXT b
LEFT JOIN ESEC.TIAAGNTAUTHR c ON b.useruid = c.useruid AND b.OCRCNMBR = c.OCRCNMBR
where a.USERTYPE in ('AA', 'AB' , 'AD')
and a.useruid = b.useruid
${where}
order by a.USERUID, b.OCRCNMBR WITH UR
"""
log.info("Statement is: {0}", statement);
log.info("Statement params : {0}", whereParams);
Upvotes: 0
Views: 208
Reputation: 799
My groovy is weak - but there are a at least a couple of potential issues with this:
If you do resolve the above issues, you should also ensure the "untrusted" where fragment is in in it's own parenthesis (to avoid bypassing parts of the existing query with "OR" clauses).
The only way to be safe in this is to validate all elements of the SQL via positive / whitelist validation. Each parsed line should be
AND/OR <column name> <operation> :<param>
all of which are positively validated against a list.
And you need to validate that everything that can pass this validation is semantically valid for the user.
Upvotes: 1