Edit on 2021-03-29 21:40(ish) UTC: Added Net-Subnet (appears unaffected) and reordered the details to match the list at the top of the post.
Edit on 2021-03-30 14:50(ish) UTC: Added Net-Works (appears unaffected).
Edit on 2021-03-30 15:40(ish) UTC: Added Net-CIDR (some functions are affected).
Edit on 2021-03-31 01:05(ish) UTC: Added Net-IPv4Addr (affected).
Edit on 2021-04-05 01:21(ish) UTC: Net-CIDR-Lite 0.22 contains a remediation.
Edit on 2021-04-05 19:30(ish) UTC: Net-IPAddress-Util 5.000 contains a remediation.
TLDR: Some Perl modules for working with IP addresses and netmasks have bugs with potential security applications. See below for more details on the bug and which modules are affected.
- Net-IPv4Addr: Affected.
- Net-CIDR-Lite: Vulnerable before the 0.22 release. Upgrade now.
- Net-Netmask: Vulnerable before the 2.00000 release. Upgrade now.
- Net-IPAddress-Util: Vulnerable before the 5.000 release. Upgrade now.
- Data-Validate-IP: Depends on exactly how it’s used. See below for details.
- Net-CIDR: Depends on exactly how it’s used. See below for details.
- Socket: Appears unaffected.
- Net-DNS: Appears unaffected.
- NetAddr-IP: Appears unaffected.
- Net-Works: Appears unaffected.
- Net-Subnet: Appears unaffected.
- Net-Patricia: Appears unaffected.
Yesterday,
a security issue with the NPM package netmask
was published1.
The issue itself is pretty straightforward. Your OS will allow an IP address like 010.0.0.1
or a
netmask like 010.0.0.0/8
. That 010
is treated as an octal number, not a base-10 number with a
leading zero! That means that 010.0.0.1
is actually 8.0.0.1
. We can confirm this with ping
:
|
|
But the NPM netmask
package would treat this as 10.0.0.1
. This confusion means that an
application could be tricked into thinking a public IP - 8.0.0.1
- was part of a private subnet -
10.0.0.0/8
. And conversely, you could trick it into thinking a private IP - 10.0.0.1
written as
012.0.0.1
- was part of a public subnet - 12.0.0.1
.
This has security implications for any application that is trying to distinguish between public and private IP addresses or networks for access control, firewalling, etc.
As I was reading about this I checked out
the Git repo for the netmask
package. Its README says “This
module is highly inspired by Perl Net::Netmask module.”
And at that point I realized that it was quite possible that this affected Perl code as well! So I started digging into this by looking at various CPAN modules for working with IP addresses, networks, and netmasks.
Here’s the current state of CPAN modules, ordered roughly by their position in The River of CPAN (which basically means how many modules depend on them).
Net-IPv4Addr
This distribution has 4 direct dependents and 12 total dependents.
|
|
Net-CIDR-Lite
This distribution has 24 direct dependents and 36 total dependents.
|
|
Net-Netmask
This distribution has 22 direct dependents and 30 total dependents.
So for versions before 2.0000 we see this:
|
|
Note the use of the new2
constructor. The old new
constructor cannot be changed to return
undef
for backwards compatibility reasons. Fortunately, it’s probably not vulnerable in any
exploitable way, as it returns a 0-length subnet:
|
|
Net-IPAddress-Util
This distribution has no dependents.
|
|
Data-Validate-IP
This distribution has 21 direct dependents and 60 total dependents.
This distribution returns false for any is_*_ipv4
method that includes an octal number. So both
is_private_ipv4('010.0.0.1')
and is_public_ipv4('010.0.0.1')
return false. Depending on how
you’re using this module, it’s possible that this could lead to bugs, including bugs with security
implications.
I
updated the documentation
to explicitly recommend that you always call is_ipv4()
in addition to calling a method like
is_private_ipv4()
. The is_ipv4()
method will always return false for IP addresses with octal
numbers.
While this isn’t strictly POSIX-correct, this seems like the safest behavior for a module like this. It’s better to be too strict if this eliminates a potential footgun.
If you are using this distribution, I highly encourage you to audit your use of it in a security context!
Net-CIDR
This distribution has 17 direct dependents and 25 total dependents.
The distribution provides a number of functions for working with networks and IP addresses. Most of these are not affected. However, two are:
|
|
However, this distribution also contains a cidrvalidate
function that will return false for any
CIDR string with a leading 0 in an octet. The documentation explicitly tells you to use this before
passing the data to other functions.
If you are using this distribution, I highly encourage you to audit your use of it in a security context!
Socket
This distribution has 275 direct dependents and 9,936 total dependents.
|
|
The inet_pton()
function is just returning undef
for this octal-formatted address.
Net-DNS
This distribution has 104 direct dependents and 561 total dependents.
If you try to resolve an IP address, it turns this into a reverse lookup, but it treats the IP as text:
|
|
So it’s not a useful answer, but it’s not looking up the wrong address.
NetAddr-IP
This distribution has 36 direct dependents and 110 total dependents.
|
|
Net-Works
This distribution has 3 direct dependents and 7 total dependents.
|
|
Thanks to Stig Palmquist for checking this one and letting me know.
Net-Subnet
This distribution has 3 direct dependents and 7 total dependents.
|
|
Net-Patricia
This distribution has 1 direct dependent and 1 total dependent.
|
|
One of the most ridiculous URL paths I’ve ever seen. ↩︎