|
1 | 1 | /**
|
2 | 2 | * @name Python LDAP Improper Authentication
|
3 |
| - * @description Check if a user-controlled query carry no authentication |
| 3 | + * @description Check if a user-controlled query carries no authentication |
4 | 4 | * @kind path-problem
|
5 | 5 | * @problem.severity warning
|
6 |
| - * @id python/ldap-improper-auth |
| 6 | + * @id python/ldap-improper-authentication |
7 | 7 | * @tags experimental
|
8 | 8 | * security
|
9 | 9 | * external/cwe/cwe-287
|
10 | 10 | */
|
11 | 11 |
|
12 | 12 | // Determine precision above
|
13 | 13 | import python
|
14 |
| -import semmle.python.dataflow.new.RemoteFlowSources |
15 |
| -import semmle.python.dataflow.new.DataFlow |
16 |
| -import semmle.python.dataflow.new.TaintTracking |
| 14 | +import experimental.semmle.python.security.LDAPImproperAuth |
17 | 15 | import DataFlow::PathGraph
|
18 | 16 |
|
19 |
| -// LDAP2 |
20 |
| -class BindSink extends DataFlow::Node { |
21 |
| - BindSink() { |
22 |
| - exists(SsaVariable bindVar, CallNode bindCall, CallNode searchCall | |
23 |
| - // get variable initializing the connection |
24 |
| - bindVar.getDefinition().getImmediateDominator() = Value::named("ldap.initialize").getACall() and |
25 |
| - // get a call using that variable |
26 |
| - bindVar.getAUse().getImmediateDominator() = bindCall and |
27 |
| - // restrict call to any bind method |
28 |
| - bindCall.getNode().getFunc().(Attribute).getName().matches("%bind%") and |
29 |
| - ( |
30 |
| - // check second argument (password) |
31 |
| - bindCall.getArg(1).getNode() instanceof None or |
32 |
| - count(bindCall.getAnArg()) = 1 |
33 |
| - ) and |
34 |
| - // get another call using that variable |
35 |
| - bindVar.getAUse().getNode() = searchCall.getNode().getFunc().(Attribute).getObject() and |
36 |
| - // restrict call to any search method |
37 |
| - searchCall.getNode().getFunc().(Attribute).getName().matches("%search%") and |
38 |
| - // set the third argument as sink |
39 |
| - this.asExpr() = searchCall.getArg(2).getNode() |
40 |
| - ) |
41 |
| - } |
42 |
| -} |
43 |
| - |
44 |
| -// LDAP3 |
45 |
| -class ConnectionSink extends DataFlow::Node { |
46 |
| - ConnectionSink() { |
47 |
| - exists(SsaVariable connectionVar, CallNode connectionCall, CallNode searchCall | |
48 |
| - // get call initializing the connection |
49 |
| - connectionCall = Value::named("ldap3.Connection").getACall() and |
50 |
| - ( |
51 |
| - // check password argument |
52 |
| - not exists(connectionCall.getArgByName("password")) or |
53 |
| - connectionCall.getArgByName("password").pointsTo(Value::named("None")) |
54 |
| - ) and |
55 |
| - // get the variable initializing the connection |
56 |
| - connectionVar.getDefinition().getImmediateDominator() = connectionCall and |
57 |
| - // get a call using that variable |
58 |
| - connectionVar.getAUse().getNode() = searchCall.getNode().getFunc().(Attribute).getObject() and |
59 |
| - // restrict call to any search method |
60 |
| - searchCall.getNode().getFunc().(Attribute).getName().matches("%search%") and |
61 |
| - // set the second argument as sink |
62 |
| - this.asExpr() = searchCall.getArg(1).getNode() |
63 |
| - ) |
64 |
| - } |
65 |
| -} |
66 |
| - |
67 |
| -class LDAPImproperAuthSink extends DataFlow::Node { |
68 |
| - LDAPImproperAuthSink() { |
69 |
| - this instanceof BindSink or |
70 |
| - this instanceof ConnectionSink |
71 |
| - } |
72 |
| -} |
73 |
| - |
74 |
| -class LDAPImproperAuthConfig extends TaintTracking::Configuration { |
75 |
| - LDAPImproperAuthConfig() { this = "LDAPImproperAuthConfig" } |
76 |
| - |
77 |
| - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } |
78 |
| - |
79 |
| - override predicate isSink(DataFlow::Node sink) { sink instanceof LDAPImproperAuthSink } |
80 |
| -} |
81 |
| - |
82 |
| -from LDAPImproperAuthConfig config, DataFlow::PathNode source, DataFlow::PathNode sink |
| 17 | +from LDAPImproperAuthenticationConfig config, DataFlow::PathNode source, DataFlow::PathNode sink |
83 | 18 | where config.hasFlowPath(source, sink)
|
84 |
| -select sink.getNode(), source, sink, "$@ LDAP query executes $@.", sink.getNode(), "This", |
85 |
| - source.getNode(), "a user-provided value without authentication." |
| 19 | +select sink.getNode(), source, sink, |
| 20 | + "$@ LDAP query parameter contains $@ and is executed without authentication.", sink.getNode(), |
| 21 | + "This", source.getNode(), "a user-provided value" |
0 commit comments