mirror of
https://github.com/github/codeql.git
synced 2026-07-21 11:18:20 +02:00
Splits `ModuleVariableNode` away from `LocalSourceNode`, instead creating a class `TypeTrackingNode` that encapsulates both of these. This means we no longer have module variable nodes as part of `LocalSourceNode` (which is good, since they have no "local" aspect to them), and hence we can have `LocalSourceNode` inherit directly from `ExprNode` (which makes the API a bit nicer). Unfortunately these are breaking changes, so we can't actually fulfil the above two desiderata until the `track` and `backtrack` methods on `LocalSourceNode` have been fully deprecated. For this reason, we preserve the present implementation of `LocalSourceNode`, and instead lay the foundation for switching over in the future, by deprecating `track` and `backtrack` on `LocalSourceNode`.
71 lines
2.6 KiB
Plaintext
71 lines
2.6 KiB
Plaintext
/**
|
|
* @name Binding a socket to all network interfaces
|
|
* @description Binding a socket to all interfaces opens it up to traffic from any IPv4 address
|
|
* and is therefore associated with security risks.
|
|
* @kind problem
|
|
* @tags security
|
|
* external/cwe/cwe-200
|
|
* @problem.severity error
|
|
* @security-severity 6.5
|
|
* @sub-severity low
|
|
* @precision high
|
|
* @id py/bind-socket-all-network-interfaces
|
|
*/
|
|
|
|
import python
|
|
import semmle.python.dataflow.new.DataFlow
|
|
import semmle.python.ApiGraphs
|
|
|
|
/** Gets a hostname that can be used to bind to all interfaces. */
|
|
private string vulnerableHostname() {
|
|
result in [
|
|
// IPv4
|
|
"0.0.0.0", "",
|
|
// IPv6
|
|
"::", "::0"
|
|
]
|
|
}
|
|
|
|
/** Gets a reference to a hostname that can be used to bind to all interfaces. */
|
|
private DataFlow::TypeTrackingNode vulnerableHostnameRef(DataFlow::TypeTracker t, string hostname) {
|
|
t.start() and
|
|
exists(StrConst allInterfacesStrConst | hostname = vulnerableHostname() |
|
|
allInterfacesStrConst.getText() = hostname and
|
|
result.asExpr() = allInterfacesStrConst
|
|
)
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = vulnerableHostnameRef(t2, hostname).track(t2, t))
|
|
}
|
|
|
|
/** Gets a reference to a hostname that can be used to bind to all interfaces. */
|
|
DataFlow::Node vulnerableHostnameRef(string hostname) {
|
|
vulnerableHostnameRef(DataFlow::TypeTracker::end(), hostname).flowsTo(result)
|
|
}
|
|
|
|
/** Gets a reference to a tuple for which the first element is a hostname that can be used to bind to all interfaces. */
|
|
private DataFlow::TypeTrackingNode vulnerableAddressTuple(DataFlow::TypeTracker t, string hostname) {
|
|
t.start() and
|
|
result.asExpr() = any(Tuple tup | tup.getElt(0) = vulnerableHostnameRef(hostname).asExpr())
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = vulnerableAddressTuple(t2, hostname).track(t2, t))
|
|
}
|
|
|
|
/** Gets a reference to a tuple for which the first element is a hostname that can be used to bind to all interfaces. */
|
|
DataFlow::Node vulnerableAddressTuple(string hostname) {
|
|
vulnerableAddressTuple(DataFlow::TypeTracker::end(), hostname).flowsTo(result)
|
|
}
|
|
|
|
/**
|
|
* Gets an instance of `socket.socket` using _some_ address family.
|
|
*
|
|
* See https://docs.python.org/3/library/socket.html
|
|
*/
|
|
API::Node socketInstance() { result = API::moduleImport("socket").getMember("socket").getReturn() }
|
|
|
|
from DataFlow::CallCfgNode bindCall, DataFlow::Node addressArg, string hostname
|
|
where
|
|
bindCall = socketInstance().getMember("bind").getACall() and
|
|
addressArg = bindCall.getArg(0) and
|
|
addressArg = vulnerableAddressTuple(hostname)
|
|
select bindCall.asExpr(), "'" + hostname + "' binds a socket to all interfaces."
|