Skip to content

Commit 9391058

Browse files
committed
Java: Add unit test for ldap injection.
1 parent bbcfbd7 commit 9391058

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+859
-0
lines changed

java/ql/test/query-tests/security/CWE-090/LdapInjection.expected

Lines changed: 231 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
import java.util.List;
2+
3+
import javax.naming.Name;
4+
import javax.naming.NamingException;
5+
import javax.naming.directory.BasicAttributes;
6+
import javax.naming.directory.DirContext;
7+
import javax.naming.directory.InitialDirContext;
8+
import javax.naming.directory.SearchControls;
9+
import javax.naming.ldap.InitialLdapContext;
10+
import javax.naming.ldap.LdapContext;
11+
import javax.naming.ldap.LdapName;
12+
import javax.naming.ldap.Rdn;
13+
14+
import com.unboundid.ldap.sdk.Filter;
15+
import com.unboundid.ldap.sdk.LDAPConnection;
16+
import com.unboundid.ldap.sdk.LDAPException;
17+
import com.unboundid.ldap.sdk.LDAPSearchException;
18+
import com.unboundid.ldap.sdk.ReadOnlySearchRequest;
19+
import com.unboundid.ldap.sdk.SearchRequest;
20+
21+
import org.apache.directory.api.ldap.model.exception.LdapException;
22+
import org.apache.directory.api.ldap.model.filter.EqualityNode;
23+
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
24+
import org.apache.directory.api.ldap.model.name.Dn;
25+
import org.apache.directory.ldap.client.api.LdapConnection;
26+
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
27+
import org.owasp.esapi.Encoder;
28+
import org.owasp.esapi.reference.DefaultEncoder;
29+
import org.springframework.ldap.core.LdapTemplate;
30+
import org.springframework.ldap.filter.EqualsFilter;
31+
import org.springframework.ldap.filter.HardcodedFilter;
32+
import org.springframework.ldap.query.LdapQuery;
33+
import org.springframework.ldap.query.LdapQueryBuilder;
34+
import org.springframework.ldap.support.LdapEncoder;
35+
import org.springframework.ldap.support.LdapNameBuilder;
36+
import org.springframework.ldap.support.LdapUtils;
37+
import org.springframework.web.bind.annotation.RequestParam;
38+
39+
public class LdapInjection {
40+
// JNDI
41+
public void testJndiBad1(@RequestParam String jBad, @RequestParam String jBadDN, DirContext ctx)
42+
throws NamingException {
43+
ctx.search("ou=system" + jBadDN, "(uid=" + jBad + ")", new SearchControls());
44+
}
45+
46+
public void testJndiBad2(@RequestParam String jBad, @RequestParam String jBadDNName, InitialDirContext ctx)
47+
throws NamingException {
48+
ctx.search(new LdapName("ou=system" + jBadDNName), "(uid=" + jBad + ")", new SearchControls());
49+
}
50+
51+
public void testJndiBad3(@RequestParam String jBad, @RequestParam String jOkDN, LdapContext ctx)
52+
throws NamingException {
53+
ctx.search(new LdapName(List.of(new Rdn("ou=" + jOkDN))), "(uid=" + jBad + ")", new SearchControls());
54+
}
55+
56+
public void testJndiBad4(@RequestParam String jBadInitial, InitialLdapContext ctx)
57+
throws NamingException {
58+
ctx.search("ou=system", "(uid=" + jBadInitial + ")", new SearchControls());
59+
}
60+
61+
public void testJndiBad5(@RequestParam String jBad, @RequestParam String jBadDNNameAdd, InitialDirContext ctx)
62+
throws NamingException {
63+
ctx.search(new LdapName("").addAll(new LdapName("ou=system" + jBadDNNameAdd)), "(uid=" + jBad + ")", new SearchControls());
64+
}
65+
66+
public void testJndiBad6(@RequestParam String jBad, @RequestParam String jBadDNNameAdd2, InitialDirContext ctx)
67+
throws NamingException {
68+
LdapName name = new LdapName("");
69+
name.addAll(new LdapName("ou=system" + jBadDNNameAdd2).getRdns());
70+
ctx.search(new LdapName("").addAll(name), "(uid=" + jBad + ")", new SearchControls());
71+
}
72+
73+
public void testJndiBad7(@RequestParam String jBad, @RequestParam String jBadDNNameToString, InitialDirContext ctx)
74+
throws NamingException {
75+
ctx.search(new LdapName("ou=system" + jBadDNNameToString).toString(), "(uid=" + jBad + ")", new SearchControls());
76+
}
77+
78+
public void testJndiBad8(@RequestParam String jBad, @RequestParam String jBadDNNameClone, InitialDirContext ctx)
79+
throws NamingException {
80+
ctx.search((Name) new LdapName("ou=system" + jBadDNNameClone).clone(), "(uid=" + jBad + ")", new SearchControls());
81+
}
82+
83+
public void testJndiOk1(@RequestParam String jOkFilterExpr, DirContext ctx) throws NamingException {
84+
ctx.search("ou=system", "(uid={0})", new String[] { jOkFilterExpr }, new SearchControls());
85+
}
86+
87+
public void testJndiOk2(@RequestParam String jOkAttribute, DirContext ctx) throws NamingException {
88+
ctx.search("ou=system", new BasicAttributes(jOkAttribute, jOkAttribute));
89+
}
90+
91+
// UnboundID
92+
public void testUnboundBad1(@RequestParam String uBad, @RequestParam String uBadDN, LDAPConnection c)
93+
throws LDAPSearchException {
94+
c.search(null, "ou=system" + uBadDN, null, null, 1, 1, false, "(uid=" + uBad + ")");
95+
}
96+
97+
public void testUnboundBad2(@RequestParam String uBadFilterCreate, LDAPConnection c) throws LDAPException {
98+
c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreate));
99+
}
100+
101+
public void testUnboundBad3(@RequestParam String uBadROSearchRequest, @RequestParam String uBadROSRDN,
102+
LDAPConnection c) throws LDAPException {
103+
ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDN, null, null, 1, 1, false,
104+
"(uid=" + uBadROSearchRequest + ")");
105+
c.search(s);
106+
}
107+
108+
public void testUnboundBad4(@RequestParam String uBadSearchRequest, @RequestParam String uBadSRDN, LDAPConnection c)
109+
throws LDAPException {
110+
SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDN, null, null, 1, 1, false,
111+
"(uid=" + uBadSearchRequest + ")");
112+
c.search(s);
113+
}
114+
115+
public void testUnboundBad5(@RequestParam String uBad, @RequestParam String uBadDNSFR, LDAPConnection c)
116+
throws LDAPSearchException {
117+
c.searchForEntry("ou=system" + uBadDNSFR, null, null, 1, false, "(uid=" + uBad + ")");
118+
}
119+
120+
public void testUnboundBad6(@RequestParam String uBadROSearchRequestAsync, @RequestParam String uBadROSRDNAsync,
121+
LDAPConnection c) throws LDAPException {
122+
ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDNAsync, null, null, 1, 1, false,
123+
"(uid=" + uBadROSearchRequestAsync + ")");
124+
c.asyncSearch(s);
125+
}
126+
127+
public void testUnboundBad7(@RequestParam String uBadSearchRequestAsync, @RequestParam String uBadSRDNAsync, LDAPConnection c)
128+
throws LDAPException {
129+
SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDNAsync, null, null, 1, 1, false,
130+
"(uid=" + uBadSearchRequestAsync + ")");
131+
c.asyncSearch(s);
132+
}
133+
134+
public void testUnboundBad8(@RequestParam String uBadFilterCreateNOT, LDAPConnection c) throws LDAPException {
135+
c.search(null, "ou=system", null, null, 1, 1, false, Filter.createNOTFilter(Filter.create(uBadFilterCreateNOT)));
136+
}
137+
138+
public void testUnboundBad9(@RequestParam String uBadFilterCreateToString, LDAPConnection c) throws LDAPException {
139+
c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreateToString).toString()); // False Negative
140+
}
141+
142+
public void testUnboundBad10(@RequestParam String uBadFilterCreateToStringBuffer, LDAPConnection c) throws LDAPException {
143+
StringBuilder b = new StringBuilder();
144+
Filter.create(uBadFilterCreateToStringBuffer).toNormalizedString(b);
145+
c.search(null, "ou=system", null, null, 1, 1, false, b.toString());
146+
}
147+
148+
public void testUnboundBad11(@RequestParam String uBadSearchRequestDuplicate, LDAPConnection c)
149+
throws LDAPException {
150+
SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false,
151+
"(uid=" + uBadSearchRequestDuplicate + ")");
152+
c.search(s.duplicate());
153+
}
154+
155+
public void testUnboundBad12(@RequestParam String uBadROSearchRequestDuplicate, LDAPConnection c)
156+
throws LDAPException {
157+
ReadOnlySearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false,
158+
"(uid=" + uBadROSearchRequestDuplicate + ")");
159+
c.search(s.duplicate());
160+
}
161+
162+
public void testUnboundBad13(@RequestParam String uBadSearchRequestSetDN, LDAPConnection c)
163+
throws LDAPException {
164+
SearchRequest s = new SearchRequest(null, "", null, null, 1, 1, false, "");
165+
s.setBaseDN(uBadSearchRequestSetDN);
166+
c.search(s);
167+
}
168+
169+
public void testUnboundBad14(@RequestParam String uBadSearchRequestSetFilter, LDAPConnection c)
170+
throws LDAPException {
171+
SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, "");
172+
s.setFilter(uBadSearchRequestSetFilter);
173+
c.search(s);
174+
}
175+
176+
public void testUnboundOk1(@RequestParam String uOkEqualityFilter, LDAPConnection c) throws LDAPSearchException {
177+
c.search(null, "ou=system", null, null, 1, 1, false, Filter.createEqualityFilter("uid", uOkEqualityFilter));
178+
}
179+
180+
public void testUnboundOk2(@RequestParam String uOkVaragsAttr, LDAPConnection c) throws LDAPSearchException {
181+
c.search("ou=system", null, null, 1, 1, false, "(uid=fixed)", "a" + uOkVaragsAttr);
182+
}
183+
184+
public void testUnboundOk3(@RequestParam String uOkFilterSearchRequest, LDAPConnection c) throws LDAPException {
185+
SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false,
186+
Filter.createEqualityFilter("uid", uOkFilterSearchRequest));
187+
c.search(s);
188+
}
189+
190+
public void testUnboundOk4(@RequestParam String uOkSearchRequestVarargs, LDAPConnection c) throws LDAPException {
191+
SearchRequest s = new SearchRequest("ou=system", null, "(uid=fixed)", "va1", "va2", "va3",
192+
"a" + uOkSearchRequestVarargs);
193+
c.search(s);
194+
}
195+
196+
// Spring LDAP
197+
public void testSpringBad1(@RequestParam String sBad, @RequestParam String sBadDN, LdapTemplate c) {
198+
c.search("ou=system" + sBadDN, "(uid=" + sBad + ")", 1, false, null);
199+
}
200+
201+
public void testSpringBad2(@RequestParam String sBad, @RequestParam String sBadDNLNBuilder, LdapTemplate c) {
202+
c.authenticate(LdapNameBuilder.newInstance("ou=system" + sBadDNLNBuilder).build(), "(uid=" + sBad + ")", "pass");
203+
}
204+
205+
public void testSpringBad3(@RequestParam String sBad, @RequestParam String sBadDNLNBuilderAdd, LdapTemplate c) {
206+
c.searchForObject(LdapNameBuilder.newInstance().add("ou=system" + sBadDNLNBuilderAdd).build(), "(uid=" + sBad + ")", null);
207+
}
208+
209+
public void testSpringBad4(@RequestParam String sBadLdapQuery, LdapTemplate c) {
210+
c.findOne(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"), null);
211+
}
212+
213+
public void testSpringBad5(@RequestParam String sBadFilter, @RequestParam String sBadDNLdapUtils, LdapTemplate c) {
214+
c.find(LdapUtils.newLdapName("ou=system" + sBadDNLdapUtils), new HardcodedFilter("(uid=" + sBadFilter + ")"), null, null);
215+
}
216+
217+
public void testSpringBad6(@RequestParam String sBadLdapQuery, LdapTemplate c) {
218+
c.searchForContext(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"));
219+
}
220+
221+
public void testSpringBad7(@RequestParam String sBadLdapQuery2, LdapTemplate c) {
222+
LdapQuery q = LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery2 + ")");
223+
c.searchForContext(q);
224+
}
225+
226+
public void testSpringBad8(@RequestParam String sBadLdapQueryWithFilter, LdapTemplate c) {
227+
c.searchForContext(LdapQueryBuilder.query().filter(new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter + ")")));
228+
}
229+
230+
public void testSpringBad9(@RequestParam String sBadLdapQueryWithFilter2, LdapTemplate c) {
231+
org.springframework.ldap.filter.Filter f = new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter2 + ")");
232+
c.searchForContext(LdapQueryBuilder.query().filter(f));
233+
}
234+
235+
public void testSpringBad10(@RequestParam String sBadLdapQueryBase, LdapTemplate c) {
236+
c.find(LdapQueryBuilder.query().base(sBadLdapQueryBase).base(), null, null, null);
237+
}
238+
239+
public void testSpringBad11(@RequestParam String sBadLdapQueryComplex, LdapTemplate c) {
240+
c.searchForContext(LdapQueryBuilder.query().base(sBadLdapQueryComplex).where("uid").is("test"));
241+
}
242+
243+
public void testSpringBad12(@RequestParam String sBadFilterToString, LdapTemplate c) {
244+
c.search("", new HardcodedFilter("(uid=" + sBadFilterToString + ")").toString(), 1, false, null); // False Negative
245+
}
246+
247+
public void testSpringBad13(@RequestParam String sBadFilterEncode, LdapTemplate c) {
248+
StringBuffer s = new StringBuffer();
249+
new HardcodedFilter("(uid=" + sBadFilterEncode + ")").encode(s);
250+
c.search("", s.toString(), 1, false, null);
251+
}
252+
253+
public void testSpringOk1(@RequestParam String sOkLdapQuery, LdapTemplate c) {
254+
c.find(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), null);
255+
}
256+
257+
public void testSpringOk2(@RequestParam String sOkFilter, @RequestParam String sOkDN, LdapTemplate c) {
258+
c.find(LdapNameBuilder.newInstance().add("ou", sOkDN).build(), new EqualsFilter("uid", sOkFilter), null, null);
259+
}
260+
261+
public void testSpringOk3(@RequestParam String sOkLdapQuery, @RequestParam String sOkPassword, LdapTemplate c) {
262+
c.authenticate(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), sOkPassword);
263+
}
264+
265+
// Apache LDAP API
266+
public void testApacheBad1(@RequestParam String aBad, @RequestParam String aBadDN, LdapConnection c)
267+
throws LdapException {
268+
c.search("ou=system" + aBadDN, "(uid=" + aBad + ")", null);
269+
}
270+
271+
public void testApacheBad2(@RequestParam String aBad, @RequestParam String aBadDNObjToString, LdapNetworkConnection c)
272+
throws LdapException {
273+
c.search(new Dn("ou=system" + aBadDNObjToString).getName(), "(uid=" + aBad + ")", null); // False Negative
274+
}
275+
276+
public void testApacheBad3(@RequestParam String aBadSearchRequest, LdapConnection c)
277+
throws LdapException {
278+
org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl();
279+
s.setFilter("(uid=" + aBadSearchRequest + ")");
280+
c.search(s);
281+
}
282+
283+
public void testApacheBad4(@RequestParam String aBadSearchRequestImpl, @RequestParam String aBadDNObj, LdapConnection c)
284+
throws LdapException {
285+
SearchRequestImpl s = new SearchRequestImpl();
286+
s.setBase(new Dn("ou=system" + aBadDNObj));
287+
c.search(s);
288+
}
289+
290+
public void testApacheBad5(@RequestParam String aBadDNSearchRequestGet, LdapConnection c)
291+
throws LdapException {
292+
org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl();
293+
s.setBase(new Dn("ou=system" + aBadDNSearchRequestGet));
294+
c.search(s.getBase(), "(uid=test", null);
295+
}
296+
297+
public void testApacheOk1(@RequestParam String aOk, LdapConnection c)
298+
throws LdapException {
299+
org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl();
300+
s.setFilter(new EqualityNode<String>("uid", aOk));
301+
c.search(s);
302+
}
303+
304+
public void testApacheOk2(@RequestParam String aOk, LdapConnection c)
305+
throws LdapException {
306+
SearchRequestImpl s = new SearchRequestImpl();
307+
s.setFilter(new EqualityNode<String>("uid", aOk));
308+
c.search(s);
309+
}
310+
311+
// ESAPI encoder sanitizer
312+
public void testOk3(@RequestParam String okEncodeForLDAP, DirContext ctx) throws NamingException {
313+
Encoder encoder = DefaultEncoder.getInstance();
314+
ctx.search("ou=system", "(uid=" + encoder.encodeForLDAP(okEncodeForLDAP) + ")", new SearchControls()); // False Positive
315+
}
316+
317+
// Spring LdapEncoder sanitizer
318+
public void testOk4(@RequestParam String okFilterEncode, DirContext ctx) throws NamingException {
319+
ctx.search("ou=system", "(uid=" + LdapEncoder.filterEncode(okFilterEncode) + ")", new SearchControls()); // False Positive
320+
}
321+
322+
// UnboundID Filter.encodeValue sanitizer
323+
public void testOk5(@RequestParam String okUnboundEncodeValue, DirContext ctx) throws NamingException {
324+
ctx.search("ou=system", "(uid=" + Filter.encodeValue(okUnboundEncodeValue) + ")", new SearchControls());
325+
}
326+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-90/LdapInjection.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/unboundid-ldap-4.0.14:${testdir}/../../../stubs/esapi-2.0.1:${testdir}/../../../stubs/apache-ldap-1.0.2
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.apache.directory.api.ldap.model.cursor;
2+
3+
public interface EntryCursor {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.apache.directory.api.ldap.model.cursor;
2+
3+
public interface SearchCursor {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.apache.directory.api.ldap.model.entry;
2+
3+
public interface Value<T> {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.apache.directory.api.ldap.model.exception;
2+
3+
public class LdapException extends Exception {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.apache.directory.api.ldap.model.exception;
2+
3+
public class LdapInvalidDnException extends LdapException {
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.apache.directory.api.ldap.model.filter;
2+
3+
import org.apache.directory.api.ldap.model.entry.Value;
4+
5+
public class EqualityNode<T> implements ExprNode {
6+
public EqualityNode(String attribute, Value<T> value) { }
7+
public EqualityNode(String attribute, String value) { }
8+
}

0 commit comments

Comments
 (0)