mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Add bind-socket-all-network-interfaces Python query (#2048)
Add bind-socket-all-network-interfaces Python query
This commit is contained in:
13
python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py
Normal file
13
python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import socket
|
||||
|
||||
# binds to all interfaces, insecure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('0.0.0.0', 31137))
|
||||
|
||||
# binds to all interfaces, insecure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('', 4040))
|
||||
|
||||
# binds only to a dedicated interface, secure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('84.68.10.12', 8080))
|
||||
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Sockets can be used to communicate
|
||||
with other machines on a network.
|
||||
You can use the (IP address, port) pair
|
||||
to define the access restrictions for the socket you create.
|
||||
When using the built-in Python <code>socket</code> module
|
||||
(for instance, when building a message sender service
|
||||
or an FTP server data transmitter),
|
||||
one has to bind the port to some interface.
|
||||
When you bind the port to all interfaces
|
||||
using <code>0.0.0.0</code> as the IP address,
|
||||
you essentially allow it to accept connections from any IPv4 address
|
||||
provided that it can get to the socket via routing.
|
||||
Binding to all interfaces is therefore associated with security risks.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Bind your service incoming traffic only to a dedicated interface.
|
||||
If you need to bind more than one interface
|
||||
using the built-in <code>socket</code> module,
|
||||
create multiple sockets (instead of binding to one socket to all interfaces).</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In this example, two sockets are insecure because they are bound to all interfaces;
|
||||
one through the <code>0.0.0.0</code> notation
|
||||
and another one through an empty string <code>''</code>.
|
||||
</p>
|
||||
<sample src="BindToAllInterfaces.py" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Python reference: <a href="https://docs.python.org/3/library/socket.html#socket-families">
|
||||
Socket families</a>.</li>
|
||||
<li>Python reference: <a href="https://docs.python.org/3.7/howto/sockets.html">
|
||||
Socket Programming HOWTO</a>.</li>
|
||||
<li>Common Vulnerabilities and Exposures: <a href="https://nvd.nist.gov/vuln/detail/CVE-2018-1281">
|
||||
CVE-2018-1281 Detail</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
38
python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql
Normal file
38
python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @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
|
||||
* @problem.severity error
|
||||
* @sub-severity low
|
||||
* @precision high
|
||||
* @id py/bind-socket-all-network-interfaces
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
Value aSocket() { result.getClass() = Value::named("socket.socket") }
|
||||
|
||||
CallNode socketBindCall() {
|
||||
result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3
|
||||
or
|
||||
result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and
|
||||
major_version() = 2
|
||||
}
|
||||
|
||||
string allInterfaces() { result = "0.0.0.0" or result = "" }
|
||||
|
||||
Value getTextValue(string address) {
|
||||
result = Value::forUnicode(address) and major_version() = 3
|
||||
or
|
||||
result = Value::forString(address) and major_version() = 2
|
||||
}
|
||||
|
||||
from CallNode call, TupleValue args, string address
|
||||
where
|
||||
call = socketBindCall() and
|
||||
call.getArg(0).pointsTo(args) and
|
||||
args.getItem(0) = getTextValue(address) and
|
||||
address = allInterfaces()
|
||||
select call.getNode(), "'" + address + "' binds a socket to all interfaces."
|
||||
@@ -0,0 +1,3 @@
|
||||
| BindToAllInterfaces_test.py:5:1:5:26 | Attribute() | '0.0.0.0' binds a socket to all interfaces. |
|
||||
| BindToAllInterfaces_test.py:9:1:9:18 | Attribute() | '' binds a socket to all interfaces. |
|
||||
| BindToAllInterfaces_test.py:17:1:17:26 | Attribute() | '0.0.0.0' binds a socket to all interfaces. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CVE-2018-1281/BindToAllInterfaces.ql
|
||||
@@ -0,0 +1,17 @@
|
||||
import socket
|
||||
|
||||
# binds to all interfaces, insecure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('0.0.0.0', 31137))
|
||||
|
||||
# binds to all interfaces, insecure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('', 4040))
|
||||
|
||||
# binds only to a dedicated interface, secure
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('84.68.10.12', 8080))
|
||||
|
||||
# binds to all interfaces, insecure
|
||||
ALL_LOCALS = "0.0.0.0"
|
||||
s.bind((ALL_LOCALS, 9090))
|
||||
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --max-import-depth=3
|
||||
Reference in New Issue
Block a user