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. ↩︎