Skip to content

Commit a34d6d3

Browse files
committed
Port to ApiGraphs and finish the query
1 parent edb273a commit a34d6d3

File tree

11 files changed

+246
-193
lines changed

11 files changed

+246
-193
lines changed

python/ql/src/experimental/Security/CWE-090/LDAPInsecureAuth.ql

Lines changed: 0 additions & 192 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @name Python Insecure LDAP Authentication
3+
* @description Python LDAP Insecure LDAP Authentication
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @id python/insecure-ldap-auth
7+
* @tags experimental
8+
* security
9+
* external/cwe/cwe-522
10+
*/
11+
12+
// determine precision above
13+
import python
14+
import DataFlow::PathGraph
15+
import experimental.semmle.python.security.LDAPInsecureAuth
16+
17+
from LDAPInsecureAuthConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
18+
where config.hasFlowPath(source, sink)
19+
select sink.getNode(), source, sink, "$@ is authenticated insecurely.", sink.getNode(),
20+
"This LDAP host"

python/ql/src/experimental/semmle/python/Concepts.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,20 @@ module LDAPBind {
156156
* extend `LDAPBind` instead.
157157
*/
158158
abstract class Range extends DataFlow::Node {
159+
/**
160+
* Gets the argument containing the binding host.
161+
*/
162+
abstract DataFlow::Node getHost();
163+
159164
/**
160165
* Gets the argument containing the binding expression.
161166
*/
162167
abstract DataFlow::Node getPassword();
168+
169+
/**
170+
* Checks if the binding process use SSL.
171+
*/
172+
abstract predicate useSSL();
163173
}
164174
}
165175

@@ -174,5 +184,18 @@ class LDAPBind extends DataFlow::Node {
174184

175185
LDAPBind() { this = range }
176186

187+
/**
188+
* Gets the argument containing the binding host.
189+
*/
190+
DataFlow::Node getHost() { result = range.getHost() }
191+
192+
/**
193+
* Gets the argument containing the binding expression.
194+
*/
177195
DataFlow::Node getPassword() { result = range.getPassword() }
196+
197+
/**
198+
* Checks if the binding process use SSL.
199+
*/
200+
predicate useSSL() { range.useSSL() }
178201
}

python/ql/src/experimental/semmle/python/frameworks/LDAP.qll

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,42 @@ private module LDAP {
9999
override DataFlow::Node getPassword() {
100100
result in [this.getArg(1), this.getArgByName("cred")]
101101
}
102+
103+
override DataFlow::Node getHost() {
104+
exists(DataFlow::CallCfgNode initialize |
105+
this.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() = initialize and
106+
initialize = ldapInitialize().getACall() and
107+
result = initialize.getArg(0)
108+
)
109+
}
110+
111+
override predicate useSSL() {
112+
// use initialize to correlate `this` and so avoid FP in several instances
113+
exists(DataFlow::CallCfgNode initialize |
114+
this.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() = initialize and
115+
initialize = ldapInitialize().getACall() and
116+
(
117+
// ldap_connection.start_tls_s()
118+
exists(DataFlow::AttrRead startTLS |
119+
startTLS.getObject().getALocalSource() = initialize and
120+
startTLS.getAttributeName().matches("%start_tls%")
121+
)
122+
or
123+
// ldap_connection.set_option(ldap.OPT_X_TLS_%s, True)
124+
// ldap_connection.set_option(ldap.OPT_X_TLS_%s)
125+
exists(DataFlow::CallCfgNode setOption |
126+
setOption.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() =
127+
initialize and
128+
setOption.getFunction().(DataFlow::AttrRead).getAttributeName() = "set_option" and
129+
setOption.getArg(0) =
130+
ldap().getMember("OPT_X_TLS_" + ["ALLOW", "TRY", "DEMAND", "HARD"]).getAUse() and
131+
not DataFlow::exprNode(any(False falseExpr))
132+
.(DataFlow::LocalSourceNode)
133+
.flowsTo(setOption.getArg(1))
134+
)
135+
)
136+
)
137+
}
102138
}
103139

104140
/**
@@ -166,6 +202,24 @@ private module LDAP {
166202
override DataFlow::Node getPassword() {
167203
result in [this.getArg(2), this.getArgByName("password")]
168204
}
205+
206+
override DataFlow::Node getHost() {
207+
exists(DataFlow::CallCfgNode serverCall |
208+
serverCall = ldap3Server().getACall() and
209+
this.getArg(0).getALocalSource() = serverCall and
210+
result = serverCall.getArg(0)
211+
)
212+
}
213+
214+
override predicate useSSL() {
215+
exists(DataFlow::CallCfgNode serverCall |
216+
serverCall = ldap3Server().getACall() and
217+
this.getArg(0).getALocalSource() = serverCall and
218+
DataFlow::exprNode(any(True trueExpr))
219+
.(DataFlow::LocalSourceNode)
220+
.flowsTo([serverCall.getArg(2), serverCall.getArgByName("use_ssl")])
221+
)
222+
}
169223
}
170224

171225
/**

0 commit comments

Comments
 (0)