CodeQL query to detect JNDI injections#3288
Conversation
|
|
||
| Hashtable<String, String> env = new Hashtable<String, String>(); | ||
| env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); | ||
| env.put(Context.PROVIDER_URL, "rmi://trusted-server:1099"); |
There was a problem hiding this comment.
should we have a sink for user-controlled URLs?
There was a problem hiding this comment.
Makes sense. I'll add it.
|
|
||
| /** The class `javax.naming.CompositeName`. */ | ||
| class TypeCompositeName extends Class { | ||
| TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") } |
There was a problem hiding this comment.
Should account for javax.naming.Name interface instead? Not sure if CompositeName is the only one that can hold a JNDI inj payload or if it can be hold in a Name object at all (maybe only String params to lookup are valid for injection purposes)
There was a problem hiding this comment.
Name interface has 3 implementations in JDK: CompositeName, CompoundName and LdapName. CompositeName and CompoundName can hold JNDI payload:
ctx.lookup(new CompositeName("rmi:\\/\\/127.0.0.1:12345/abc"));
ctx.lookup(new CompoundName("rmi://127.0.0.1:12345/abc", new Properties()));LdapName, most likely, can't.
I'll add support for CompoundName in the query, but if you think that handling all javax.naming.Name implementations is better, I can change it.
There was a problem hiding this comment.
If LdapName cant, I think its enough with adding CompoundName, thanks!
| * method from Spring's `LdapTemplate`. | ||
| */ | ||
| predicate springLdapTemplateSinkMethod(Method m, int index) { | ||
| m.getDeclaringType() instanceof TypeSpringLdapTemplate and |
There was a problem hiding this comment.
Cant find TypeSpringLdapTempalte definition. Make sure it also accounts for LdapOperations
There was a problem hiding this comment.
In older versions of the API, these clases were in org.springframework.ldap namespace (without core), see https://docs.spring.io/spring-ldap/docs/1.1.2/api/
There was a problem hiding this comment.
TypeSpringLdapTemplate is defined in java/ql/src/semmle/code/java/frameworks/SpringLdap.qll:
class TypeSpringLdapTemplate extends Class {
TypeSpringLdapTemplate() {
this.hasQualifiedName("org.springframework.ldap.core", "LdapTemplate")
}
}But it makes sense to account for any implementation of LdapOperations interface - I'll change it. I'll also add support for org.springframework.ldap package (without core).
| */ | ||
| predicate springLdapTemplateSinkMethod(Method m, int index) { | ||
| m.getDeclaringType() instanceof TypeSpringLdapTemplate and | ||
| (m.hasName("lookup") or m.hasName("lookupContext")) and |
There was a problem hiding this comment.
Please review if other methods may end up calling lookup operations. For example:
- https://github.com/spring-projects/spring-ldap/blob/master/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java#L1695
- https://github.com/spring-projects/spring-ldap/blob/master/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java#L718
Also the searchForObject methods (using RETURN_OBJ_FLAG) are vulnerable as well
There was a problem hiding this comment.
Thanks for pointing this out. I'll add findByDn, rename, list, listBindings, unbind (if recursive is true).
It looks like all search and searchForObject methods where the last parameter is ContextMapper and there's no SearchControls parameter are vulnerable as well (in all these cases, search with RETURN_OBJ_FLAG is called eventually). I'll add them all.
|
@pwntester, I updated the query according to your comments (I hope that I didn't miss anything). |
aschackmull
left a comment
There was a problem hiding this comment.
Overall the QL code looks solid, but I've left a few inline comments.
….qll Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
|
@aschackmull Thanks for reviewing the query. I've updated it according to your comments. Please check if everything is fine now. |
This PR adds a query to detect JNDI injections. It flags the code where user-provided input is used in JNDI lookup:
It also supports Spring's and Apache Shiro's
JndiTemplate.If the name being used to look up the data is controlled by the user, it can point to a
malicious server, which can return an arbitrary object. In the worst case, this can allow remote
code execution.
The tests and required
qlpack.ymlinsrc/experimentalandtest/experimentalare also included.