mirror of
https://github.com/github/codeql.git
synced 2026-05-03 12:45:27 +02:00
Merge pull request #596 from pupiles/feature/cwe-090
CWE-090: Ldap Injection
This commit is contained in:
44
ql/src/experimental/CWE-090/LDAPInjection.qhelp
Normal file
44
ql/src/experimental/CWE-090/LDAPInjection.qhelp
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>If an LDAP query or DN is built using string concatenation or string formatting, and the
|
||||
components of the concatenation include user input without any proper sanitization, a user
|
||||
is likely to be able to run malicious LDAP queries.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>If user input must be included in an LDAP query or DN, it should be escaped to
|
||||
avoid a malicious user providing special characters that change the meaning
|
||||
of the query. In Go, user input should be escaped with <code>EscapeFilter</code>.
|
||||
A good practice is to escape filter characters
|
||||
that could change the meaning of the query (https://tools.ietf.org/search/rfc4515#section-3).</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following examples, the code accepts both <code>filter</code> and <code>attr</code> from the user,
|
||||
which it then uses to build a LDAP query and DN.</p>
|
||||
|
||||
<p>The following example uses the unsanitized user input directly
|
||||
in the search filter and DN for the LDAP query.
|
||||
A malicious user could provide special characters to change the meaning of these
|
||||
components, and search for a completely different set of values.</p>
|
||||
|
||||
<sample src="example/example_bad.go" />
|
||||
|
||||
<p>In the following example, the input provided by the user is sanitized before it is included in the search filter or DN.
|
||||
This ensures the meaning of the query cannot be changed by a malicious user.</p>
|
||||
|
||||
<sample src="example/example_good.go" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html">LDAP Injection Prevention Cheat Sheet</a>.</li>
|
||||
<li>OWASP: <a href="https://owasp.org/www-community/attacks/LDAP_Injection">LDAP Injection</a>.</li>
|
||||
<li>Go: <a href="https://github.com/go-ldap/ldap">LDAP Documentation</a>.</li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/LDAP_injection">LDAP injection</a>.</li>
|
||||
<li>BlackHat: <a href="https://www.blackhat.com/presentations/bh-europe-08/Alonso-Parada/Whitepaper/bh-eu-08-alonso-parada-WP.pdf">LDAP Injection and Blind LDAP Injection</a>.</li>
|
||||
<li>LDAP: <a href="https://ldap.com/2018/05/04/understanding-and-defending-against-ldap-injection-attacks/">Understanding and Defending Against LDAP Injection Attacks</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
19
ql/src/experimental/CWE-090/LDAPInjection.ql
Normal file
19
ql/src/experimental/CWE-090/LDAPInjection.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name LDAP query built from user-controlled sources
|
||||
* @description Building an LDAP query from user-controlled sources is vulnerable to insertion of
|
||||
* malicious LDAP code by the user.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id go/ldap-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-90
|
||||
*/
|
||||
|
||||
import go
|
||||
import LDAPInjection
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from LdapInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "LDAP query parameter is derived from $@.", source.getNode(),
|
||||
"a user-provided value"
|
||||
111
ql/src/experimental/CWE-090/LDAPInjection.qll
Normal file
111
ql/src/experimental/CWE-090/LDAPInjection.qll
Normal file
@@ -0,0 +1,111 @@
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A sanitizer function that prevents LDAP injection attacks.
|
||||
*/
|
||||
abstract class LdapSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A common sanitizer function. These are name-based heuristics only.
|
||||
*/
|
||||
private class CommonLdapEscape extends LdapSanitizer {
|
||||
CommonLdapEscape() {
|
||||
exists(DataFlow::MethodCallNode m |
|
||||
m.getTarget().getName() in [
|
||||
"sanitizedUserQuery", "sanitizedUserDN", "sanitizedGroupFilter", "sanitizedGroupDN"
|
||||
]
|
||||
|
|
||||
this = m.getResult(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `EscapeFilter` function from the `go-ldap` or `ldap` packages.
|
||||
*/
|
||||
private class EscapeFilterCall extends LdapSanitizer {
|
||||
EscapeFilterCall() {
|
||||
exists(Function f |
|
||||
f.hasQualifiedName([
|
||||
"github.com/go-ldap/ldap", "github.com/go-ldap/ldap/v3", "gopkg.in/ldap.v2",
|
||||
"gopkg.in/ldap.v3"
|
||||
], "EscapeFilter")
|
||||
|
|
||||
this = f.getACall()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink that is vulnerable to LDAP injection vulnerabilities.
|
||||
*/
|
||||
abstract class LdapSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A vulnerable argument to `go-ldap` or `ldap`'s `NewSearchRequest` function.
|
||||
*/
|
||||
private class GoLdapSink extends LdapSink {
|
||||
GoLdapSink() {
|
||||
exists(Function f |
|
||||
f.hasQualifiedName([
|
||||
"github.com/go-ldap/ldap", "github.com/go-ldap/ldap/v3", "gopkg.in/ldap.v2",
|
||||
"gopkg.in/ldap.v3"
|
||||
], "NewSearchRequest")
|
||||
|
|
||||
this = f.getACall().getArgument([0, 6, 7])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value written to the `ldap` package's `SearchRequest.BaseDN` field.
|
||||
*/
|
||||
private class LdapV2DNSink extends LdapSink {
|
||||
LdapV2DNSink() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(["gopkg.in/ldap.v2", "gopkg.in/ldap.v3"], "SearchRequest", "BaseDN") and
|
||||
w.writesField(_, f, this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument to `go-ldap-client`'s `LDAPClient.Authenticate` or `.GetGroupsOfUser` function.
|
||||
*/
|
||||
private class LdapClientSink extends LdapSink {
|
||||
LdapClientSink() {
|
||||
exists(Method m |
|
||||
m.hasQualifiedName("github.com/jtblin/go-ldap-client", "LDAPClient",
|
||||
["Authenticate", "GetGroupsOfUser"])
|
||||
|
|
||||
this = m.getACall().getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value written to `go-ldap-client`'s `LDAPClient.Base` field.
|
||||
*/
|
||||
private class LdapClientDNSink extends LdapSink {
|
||||
LdapClientDNSink() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName("github.com/jtblin/go-ldap-client", "LDAPClient", "Base") and
|
||||
w.writesField(_, f, this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when an `UntrustedFlowSource`
|
||||
* flows into an argument or field that is vulnerable to LDAP injection.
|
||||
*/
|
||||
class LdapInjectionConfiguration extends TaintTracking::Configuration {
|
||||
LdapInjectionConfiguration() { this = "Ldap injection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof LdapSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof LdapSanitizer }
|
||||
}
|
||||
13
ql/src/experimental/CWE-090/example/example_bad.go
Normal file
13
ql/src/experimental/CWE-090/example/example_bad.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func LDAPInjectionVulnerable(untrusted string) {
|
||||
// ...
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
"dc=example,dc=com", // The base dn to search
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson)) + untrusted", // BAD: untrusted filter
|
||||
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
|
||||
nil,
|
||||
)
|
||||
// ...
|
||||
}
|
||||
15
ql/src/experimental/CWE-090/example/example_good.go
Normal file
15
ql/src/experimental/CWE-090/example/example_good.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func LDAPInjectionVulnerable(untrusted string) {
|
||||
// ...
|
||||
safe := ldap.EscapeFilter(untrusted)
|
||||
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
"dc=example,dc=com", // The base dn to search
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+safe, // GOOD: sanitized filter
|
||||
[]string{"dn", "cn", safe}, // GOOD: sanitized attribute
|
||||
nil,
|
||||
)
|
||||
// ...
|
||||
}
|
||||
37
ql/test/experimental/CWE-090/LDAPInjection.expected
Normal file
37
ql/test/experimental/CWE-090/LDAPInjection.expected
Normal file
@@ -0,0 +1,37 @@
|
||||
edges
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:59:3:59:11 | untrusted |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:61:3:61:51 | ...+... |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:62:3:62:33 | slice literal |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:66:3:66:11 | untrusted |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:68:3:68:51 | ...+... |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:69:3:69:33 | slice literal |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:73:3:73:11 | untrusted |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:75:3:75:51 | ...+... |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:76:3:76:33 | slice literal |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:80:22:80:30 | untrusted |
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:81:25:81:33 | untrusted |
|
||||
nodes
|
||||
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | semmle.label | call to UserAgent : string |
|
||||
| LDAPInjection.go:59:3:59:11 | untrusted | semmle.label | untrusted |
|
||||
| LDAPInjection.go:61:3:61:51 | ...+... | semmle.label | ...+... |
|
||||
| LDAPInjection.go:62:3:62:33 | slice literal | semmle.label | slice literal |
|
||||
| LDAPInjection.go:66:3:66:11 | untrusted | semmle.label | untrusted |
|
||||
| LDAPInjection.go:68:3:68:51 | ...+... | semmle.label | ...+... |
|
||||
| LDAPInjection.go:69:3:69:33 | slice literal | semmle.label | slice literal |
|
||||
| LDAPInjection.go:73:3:73:11 | untrusted | semmle.label | untrusted |
|
||||
| LDAPInjection.go:75:3:75:51 | ...+... | semmle.label | ...+... |
|
||||
| LDAPInjection.go:76:3:76:33 | slice literal | semmle.label | slice literal |
|
||||
| LDAPInjection.go:80:22:80:30 | untrusted | semmle.label | untrusted |
|
||||
| LDAPInjection.go:81:25:81:33 | untrusted | semmle.label | untrusted |
|
||||
#select
|
||||
| LDAPInjection.go:59:3:59:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:59:3:59:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:61:3:61:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:61:3:61:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:62:3:62:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:62:3:62:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:66:3:66:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:66:3:66:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:68:3:68:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:68:3:68:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:69:3:69:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:69:3:69:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:73:3:73:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:73:3:73:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:75:3:75:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:75:3:75:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:76:3:76:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:76:3:76:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:80:22:80:30 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:80:22:80:30 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
| LDAPInjection.go:81:25:81:33 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:81:25:81:33 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
|
||||
135
ql/test/experimental/CWE-090/LDAPInjection.go
Normal file
135
ql/test/experimental/CWE-090/LDAPInjection.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package main
|
||||
|
||||
//go:generate depstubber -vendor github.com/go-ldap/ldap "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
|
||||
//go:generate depstubber -vendor github.com/go-ldap/ldap/v3 "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
|
||||
//go:generate depstubber -vendor github.com/jtblin/go-ldap-client LDAPClient
|
||||
//go:generate depstubber -vendor gopkg.in/ldap.v2 "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
goldap "github.com/go-ldap/ldap"
|
||||
goldapv3 "github.com/go-ldap/ldap/v3"
|
||||
ldapclient "github.com/jtblin/go-ldap-client"
|
||||
gopkgldapv2 "gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
type Ldap struct{}
|
||||
|
||||
func (*Ldap) sanitizedUserQuery(username string) (string, bool) {
|
||||
badCharacters := "\x00()*\\"
|
||||
if strings.ContainsAny(username, badCharacters) {
|
||||
return "", false
|
||||
}
|
||||
return username, true
|
||||
}
|
||||
|
||||
func (*Ldap) sanitizedUserDN(username string) (string, bool) {
|
||||
badCharacters := "\x00()*\\"
|
||||
if strings.ContainsAny(username, badCharacters) {
|
||||
return "", false
|
||||
}
|
||||
return username, true
|
||||
}
|
||||
|
||||
func (*Ldap) sanitizedGroupFilter(username string) (string, bool) {
|
||||
badCharacters := "\x00()*\\"
|
||||
if strings.ContainsAny(username, badCharacters) {
|
||||
return "", false
|
||||
}
|
||||
return username, true
|
||||
}
|
||||
|
||||
func (*Ldap) sanitizedGroupDN(username string) (string, bool) {
|
||||
badCharacters := "\x00()*\\"
|
||||
if strings.ContainsAny(username, badCharacters) {
|
||||
return "", false
|
||||
}
|
||||
return username, true
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
||||
// bad is an example of a bad implementation
|
||||
func (ld *Ldap) bad(req *http.Request) {
|
||||
// ...
|
||||
untrusted := req.UserAgent()
|
||||
goldap.NewSearchRequest(
|
||||
untrusted, // BAD: untrusted dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
|
||||
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
|
||||
nil,
|
||||
)
|
||||
goldapv3.NewSearchRequest(
|
||||
untrusted, // BAD: untrusted dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
|
||||
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
|
||||
nil,
|
||||
)
|
||||
gopkgldapv2.NewSearchRequest(
|
||||
untrusted, // BAD: untrusted dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
|
||||
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
|
||||
nil,
|
||||
)
|
||||
client := &ldapclient.LDAPClient{}
|
||||
client.Authenticate(untrusted, "123456") // BAD: untrusted filter
|
||||
client.GetGroupsOfUser(untrusted) // BAD: untrusted filter
|
||||
// ...
|
||||
}
|
||||
|
||||
// good is an example of a good implementation
|
||||
func (ld *Ldap) good(req *http.Request) {
|
||||
// ...
|
||||
untrusted := req.UserAgent()
|
||||
escapegoldap := goldap.EscapeFilter(untrusted)
|
||||
goldap.NewSearchRequest(
|
||||
escapegoldap, // GOOD: sanitized dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+escapegoldap, // GOOD: sanitized filter
|
||||
[]string{"dn", "cn", escapegoldap}, // GOOD: sanitized attribute
|
||||
nil,
|
||||
)
|
||||
escapegoldapv3 := goldapv3.EscapeFilter(untrusted)
|
||||
goldapv3.NewSearchRequest(
|
||||
escapegoldapv3, // GOOD: sanitized dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+escapegoldapv3, // GOOD: sanitized filter
|
||||
[]string{"dn", "cn", escapegoldapv3}, // GOOD: sanitized attribute
|
||||
nil,
|
||||
)
|
||||
escapegopkgv2 := gopkgldapv2.EscapeFilter(untrusted)
|
||||
gopkgldapv2.NewSearchRequest(
|
||||
escapegopkgv2, // GOOD: sanitized dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+escapegopkgv2, // GOOD: sanitized filter
|
||||
[]string{"dn", "cn", escapegopkgv2}, // GOOD: sanitized attribute
|
||||
nil,
|
||||
)
|
||||
escapedusercustom, _ := ld.sanitizedUserQuery(untrusted) // GOOD: custom sanitized filter
|
||||
escapedgroupcustom, _ := ld.sanitizedGroupFilter(untrusted) // GOOD: custom sanitized filter
|
||||
escapeduserdncustom, _ := ld.sanitizedUserDN(untrusted) // GOOD: custom sanitized filter
|
||||
escapedgroupdncustom, _ := ld.sanitizedGroupDN(untrusted) // GOOD: custom sanitized filter
|
||||
client := &ldapclient.LDAPClient{}
|
||||
client.Authenticate(escapedusercustom, "123456") // GOOD: sanitized filter
|
||||
client.GetGroupsOfUser(escapedgroupcustom) // GOOD: sanitized filter
|
||||
gopkgldapv2.NewSearchRequest(
|
||||
escapeduserdncustom, // GOOD: sanitized dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+"(uid=1)",
|
||||
[]string{"dn", "cn"},
|
||||
nil,
|
||||
)
|
||||
gopkgldapv2.NewSearchRequest(
|
||||
escapedgroupdncustom, // GOOD: sanitized dn
|
||||
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=organizationalPerson))"+"(uid=1)",
|
||||
[]string{"dn", "cn"},
|
||||
nil,
|
||||
)
|
||||
// ...
|
||||
}
|
||||
1
ql/test/experimental/CWE-090/LDAPInjection.qlref
Normal file
1
ql/test/experimental/CWE-090/LDAPInjection.qlref
Normal file
@@ -0,0 +1 @@
|
||||
experimental/CWE-090/LDAPInjection.ql
|
||||
11
ql/test/experimental/CWE-090/go.mod
Normal file
11
ql/test/experimental/CWE-090/go.mod
Normal file
@@ -0,0 +1,11 @@
|
||||
module example.com/ldap
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
github.com/go-ldap/ldap/v3 v3.4.1
|
||||
github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/ldap.v2 v2.5.1
|
||||
)
|
||||
38
ql/test/experimental/CWE-090/vendor/github.com/go-ldap/ldap/stub.go
generated
vendored
Normal file
38
ql/test/experimental/CWE-090/vendor/github.com/go-ldap/ldap/stub.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for github.com/go-ldap/ldap, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/go-ldap/ldap (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
|
||||
|
||||
// Package ldap is a stub of github.com/go-ldap/ldap, generated by depstubber.
|
||||
package ldap
|
||||
|
||||
type Control interface {
|
||||
Encode() interface{}
|
||||
GetControlType() string
|
||||
String() string
|
||||
}
|
||||
|
||||
func EscapeFilter(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
var NeverDerefAliases int = 0
|
||||
|
||||
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ScopeWholeSubtree int = 0
|
||||
|
||||
type SearchRequest struct {
|
||||
BaseDN string
|
||||
Scope int
|
||||
DerefAliases int
|
||||
SizeLimit int
|
||||
TimeLimit int
|
||||
TypesOnly bool
|
||||
Filter string
|
||||
Attributes []string
|
||||
Controls []Control
|
||||
}
|
||||
38
ql/test/experimental/CWE-090/vendor/github.com/go-ldap/ldap/v3/stub.go
generated
vendored
Normal file
38
ql/test/experimental/CWE-090/vendor/github.com/go-ldap/ldap/v3/stub.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for github.com/go-ldap/ldap/v3, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/go-ldap/ldap/v3 (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
|
||||
|
||||
// Package ldap is a stub of github.com/go-ldap/ldap/v3, generated by depstubber.
|
||||
package ldap
|
||||
|
||||
type Control interface {
|
||||
Encode() interface{}
|
||||
GetControlType() string
|
||||
String() string
|
||||
}
|
||||
|
||||
func EscapeFilter(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
var NeverDerefAliases int = 0
|
||||
|
||||
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ScopeWholeSubtree int = 0
|
||||
|
||||
type SearchRequest struct {
|
||||
BaseDN string
|
||||
Scope int
|
||||
DerefAliases int
|
||||
SizeLimit int
|
||||
TimeLimit int
|
||||
TypesOnly bool
|
||||
Filter string
|
||||
Attributes []string
|
||||
Controls []Control
|
||||
}
|
||||
43
ql/test/experimental/CWE-090/vendor/github.com/jtblin/go-ldap-client/stub.go
generated
vendored
Normal file
43
ql/test/experimental/CWE-090/vendor/github.com/jtblin/go-ldap-client/stub.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for github.com/jtblin/go-ldap-client, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/jtblin/go-ldap-client (exports: LDAPClient; functions: )
|
||||
|
||||
// Package go_pkg is a stub of github.com/jtblin/go-ldap-client, generated by depstubber.
|
||||
package go_pkg
|
||||
|
||||
import (
|
||||
tls "crypto/tls"
|
||||
)
|
||||
|
||||
type LDAPClient struct {
|
||||
Attributes []string
|
||||
Base string
|
||||
BindDN string
|
||||
BindPassword string
|
||||
GroupFilter string
|
||||
Host string
|
||||
ServerName string
|
||||
UserFilter string
|
||||
Conn interface{}
|
||||
Port int
|
||||
InsecureSkipVerify bool
|
||||
UseSSL bool
|
||||
SkipTLS bool
|
||||
ClientCertificates []tls.Certificate
|
||||
}
|
||||
|
||||
func (_ *LDAPClient) Authenticate(_ string, _ string) (bool, map[string]string, error) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
func (_ *LDAPClient) Close() {}
|
||||
|
||||
func (_ *LDAPClient) Connect() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *LDAPClient) GetGroupsOfUser(_ string) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
11
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/depstubber_reflect_635541987/go.mod
generated
vendored
Normal file
11
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/depstubber_reflect_635541987/go.mod
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
module example.com/ldap
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
github.com/go-ldap/ldap/v3 v3.4.1
|
||||
github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/ldap.v2 v2.5.1
|
||||
)
|
||||
79
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/depstubber_reflect_635541987/prog.go
generated
vendored
Normal file
79
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/depstubber_reflect_635541987/prog.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/github/depstubber/model"
|
||||
|
||||
pkg_ "gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
var output = flag.String("output", "", "The output file name, or empty to use stdout.")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
types := []struct{
|
||||
sym string
|
||||
typ reflect.Type
|
||||
}{
|
||||
|
||||
}
|
||||
|
||||
values := []struct{
|
||||
sym string
|
||||
val reflect.Value
|
||||
}{
|
||||
|
||||
{ "Authenticate", reflect.ValueOf(pkg_.Authenticate) },
|
||||
|
||||
{ "GetGroupsOfUser", reflect.ValueOf(pkg_.GetGroupsOfUser) },
|
||||
|
||||
}
|
||||
|
||||
// NOTE: This behaves contrary to documented behaviour if the
|
||||
// package name is not the final component of the import path.
|
||||
// The reflect package doesn't expose the package name, though.
|
||||
pkg := model.NewPackage("gopkg.in/ldap.v2", false)
|
||||
|
||||
for _, t := range types {
|
||||
err := pkg.AddType(t.sym, t.typ)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range values {
|
||||
err := pkg.AddValue(v.sym, v.val)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
outfile := os.Stdout
|
||||
if len(*output) != 0 {
|
||||
var err error
|
||||
outfile, err = os.Create(*output)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to open output file %q", *output)
|
||||
}
|
||||
defer func() {
|
||||
if err := outfile.Close(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to close output file %q", *output)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := gob.NewEncoder(outfile).Encode(model.PackPkg(pkg)); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "gob encode: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
38
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/stub.go
generated
vendored
Normal file
38
ql/test/experimental/CWE-090/vendor/gopkg.in/ldap.v2/stub.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for gopkg.in/ldap.v2, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: gopkg.in/ldap.v2 (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
|
||||
|
||||
// Package ldap is a stub of gopkg.in/ldap.v2, generated by depstubber.
|
||||
package ldap
|
||||
|
||||
type Control interface {
|
||||
Encode() interface{}
|
||||
GetControlType() string
|
||||
String() string
|
||||
}
|
||||
|
||||
func EscapeFilter(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
var NeverDerefAliases int = 0
|
||||
|
||||
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ScopeWholeSubtree int = 0
|
||||
|
||||
type SearchRequest struct {
|
||||
BaseDN string
|
||||
Scope int
|
||||
DerefAliases int
|
||||
SizeLimit int
|
||||
TimeLimit int
|
||||
TypesOnly bool
|
||||
Filter string
|
||||
Attributes []string
|
||||
Controls []Control
|
||||
}
|
||||
15
ql/test/experimental/CWE-090/vendor/modules.txt
vendored
Normal file
15
ql/test/experimental/CWE-090/vendor/modules.txt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
## explicit
|
||||
github.com/go-ldap/ldap
|
||||
# github.com/go-ldap/ldap/v3 v3.4.1
|
||||
## explicit
|
||||
github.com/go-ldap/ldap/v3
|
||||
# github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
|
||||
## explicit
|
||||
github.com/jtblin/go-ldap-client
|
||||
# gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d
|
||||
## explicit
|
||||
gopkg.in/asn1-ber.v1
|
||||
# gopkg.in/ldap.v2 v2.5.1
|
||||
## explicit
|
||||
gopkg.in/ldap.v2
|
||||
Reference in New Issue
Block a user