Java: CWE-798: Query to detect hard-coded SHIRO key#5907
Java: CWE-798: Query to detect hard-coded SHIRO key#5907smowton merged 7 commits intogithub:mainfrom
Conversation
|
|
||
| override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { | ||
| node1.asExpr().getType() instanceof TypeString and | ||
| exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) | |
There was a problem hiding this comment.
| override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { | ||
| node1.asExpr().getType() instanceof TypeString and | ||
| exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) | | ||
| exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray","decode"]) | |
There was a problem hiding this comment.
Be specific: what type's decode method are you referring to here? (the existing getBytes and toCharArray should be specific too in fairness, though no need to fiddle with that in this PR)
There was a problem hiding this comment.
when i test cookieRememberMeManager.setCipherKey(Base64.decode("1234")) by the query without decode , it do not work. so i add 'decode' method as additional data flow. Other queries used to detect hard-coded may also encounter similar situations.
There was a problem hiding this comment.
OK, in that case you should check if ma.getMethod().hasQualifiedName("java.util", "Base64$Decoder", "decode")
The existing getBytes and toCharArray methods should also be qualified that way; it isn't mandatory for you to fix that here though.
There was a problem hiding this comment.
Shouldn't this work out-of-the-box?
codeql/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
Lines 244 to 251 in 9b0e3b1
There was a problem hiding this comment.
Good spot, yes it should. Can you show a test case that requires this extra decode method to be modelled this way?
There was a problem hiding this comment.
nice. but in some case, java.util.Base64$Decoder is not be used. for instance, org.apache.shiro.codec.Base64 in https://github.com/yinna/wjproject/blob/master/wj/src/main/java/com/example/wj/config/ShiroConfiguration.java,cn.hutool.core.codec.Base64 in https://github.com/ph-sir/usermg/blob/master/src/main/java/com/pengh/usermg/shiro/ShiroConfig.java, how to detect that?
There was a problem hiding this comment.
Either we would welcome a PR to model Shiro and/or Hutool, providing model specifications similar to those that @intrigus-lgtm linked to, or if you just want to provide enough support for this query, write something like
ma.getMethod().hasQualifiedName(["org.apache.shiro.codec", "cn.hutool.core.codec"], "Base64", "decode")
The important thing is to specify particular methods you want to model, rather than guessing that any future method encountered that is named decode will behave the same way.
| s = "sun.security.tools.keytool.Main;getKeyPasswd(String, String, char[]);2" or | ||
| s = "sun.security.x509.X509Key;decode(byte[]);0" | ||
| s = "sun.security.x509.X509Key;decode(byte[]);0" or | ||
| s = "org.apache.shiro.mgt.AbstractRememberMeManager;setCipherKey(byte[]);0" |
There was a problem hiding this comment.
This should get moved to the otherApiCallableCredentialParam method, because the javaApiCallableCryptoKeyParam method is auto-generated.
|
You should also add a change note, similar to #5852 which is making very similar changes. |
| ma.getQualifier() = node1.asExpr() | ||
| ) | ||
| or | ||
| FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, false) |
There was a problem hiding this comment.
OOI: Why is this needed?
There was a problem hiding this comment.
I modelled the decode methods of shiro and Hutool in ExternalFlow.qll and FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, false) is for using that
There was a problem hiding this comment.
As far as I know this should work by default, so you don't have to manually call it.
There was a problem hiding this comment.
This doesn't work by default, because
codeql/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
Lines 251 to 252 in 4ac91ea
TaintTracking::Configurations but not DataFlow::Configurations.
I'm not sure whether changing this to a TaintTracking::Configuration would be the right action.
There was a problem hiding this comment.
I think it would: dataflow configs track things with the same object identity, while taint tracking also allows related but different objects. Base64 decoding clearly produces a different object but is relevant to the query. Therefore taint tracking seems appropriate (cc @aschackmull to double check you're happy with this)
There was a problem hiding this comment.
It depends on whether you want the complete set of default taint steps to apply to your configuration or whether you just want object identity tracking plus a few select steps. In the former case, use a TaintTracking::Configuration, in the latter case, use a DataFlow::Configuration and add steps as needed. In either case, you shouldn't reference internal libraries directly (e.g. FlowSummaryImpl).
In this case, as we're likely mostly dealing with strings, consider whether steps like string concatenation are valid taint steps, if they are, then a TaintTracking::Configuration is likely the right choice, but if string concatenation doesn't make sense for this flow config, then a DataFlow::Configuration must be used.
| @@ -0,0 +1,3 @@ | |||
| lgtm,codescanning | |||
| * The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) | |||
| This query finds hard-coded cipher key for shiro. This vulnerability can lead to arbitrary code execution. No newline at end of file | |||
There was a problem hiding this comment.
How does this lead to arbitrary code execution?
There was a problem hiding this comment.
if you know the cipher key for the remember me feature,you can deserialize any class on the server environment by the key to achieve Remote Code Execution.
actually,This vulnerability is very similar to CVE-2016-4437. The difference is that CVE-2016-4437 is hard-coded by the shiro framework, this vulnerability is hard-coded by the developer,
(In order to fix CVE-2016-4437, shiro used a random key, but still retains "setCipherKey" method to set the key)
| * The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) | ||
| This query finds hard-coded cipher key for shiro. This vulnerability can lead to arbitrary code execution. No newline at end of file |
There was a problem hiding this comment.
| * The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) | |
| This query finds hard-coded cipher key for shiro. This vulnerability can lead to arbitrary code execution. | |
| * The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) can now detect a hard-coded Apache Shiro cipher key. |
| ma.getQualifier() = node1.asExpr() | ||
| ) | ||
| or | ||
| FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, false) |
There was a problem hiding this comment.
I think it would: dataflow configs track things with the same object identity, while taint tracking also allows related but different objects. Base64 decoding clearly produces a different object but is relevant to the query. Therefore taint tracking seems appropriate (cc @aschackmull to double check you're happy with this)
4ac91ea to
b0983cb
Compare
|
Updated this and will merge on green |
javaGenerated file changes for java
- Others,"``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,26,151,,,,14,18,,
+ Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,28,151,,,,14,18,,
- Totals,,143,4984,408,13,6,10,107,33,1,66
+ Totals,,143,4986,408,13,6,10,107,33,1,66
+ cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,1,
+ org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,1, |
Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management.
shiro allows user to set default cipher key for the “remember me” feature,
when a cipher key can be guessed , allows remote attackers to execute arbitrary code or bypass intended access restrictions via an unspecified request parameter.
The query detects a hard-coded cipher key for shiro.