Skip to content

Commit a193ec3

Browse files
authored
Merge pull request #555 from AikidoSec/patch-is-private-ip
Improve isPrivateIP function
2 parents 0e76347 + 4051df4 commit a193ec3

File tree

4 files changed

+66
-27
lines changed

4 files changed

+66
-27
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as t from "tap";
2+
import mapIPv4ToIPv6 from "./mapIPv4ToIPv6";
3+
4+
t.test("it works", async (t) => {
5+
t.equal(mapIPv4ToIPv6("127.0.0.0"), "::ffff:127.0.0.0/128");
6+
t.equal(mapIPv4ToIPv6("127.0.0.0/8"), "::ffff:127.0.0.0/104");
7+
t.equal(mapIPv4ToIPv6("10.0.0.0"), "::ffff:10.0.0.0/128");
8+
t.equal(mapIPv4ToIPv6("10.0.0.0/8"), "::ffff:10.0.0.0/104");
9+
t.equal(mapIPv4ToIPv6("10.0.0.1"), "::ffff:10.0.0.1/128");
10+
t.equal(mapIPv4ToIPv6("10.0.0.1/8"), "::ffff:10.0.0.1/104");
11+
t.equal(mapIPv4ToIPv6("192.168.0.0/16"), "::ffff:192.168.0.0/112");
12+
t.equal(mapIPv4ToIPv6("172.16.0.0/12"), "::ffff:172.16.0.0/108");
13+
});

library/helpers/mapIPv4ToIPv6.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Maps an IPv4 address to an IPv6 address.
3+
* e.g. 127.0.0.0/8 -> ::ffff:127.0.0.0/104
4+
*/
5+
export default function mapIPv4ToIPv6(ip: string): string {
6+
if (!ip.includes("/")) {
7+
// No CIDR suffix, assume /32
8+
return `::ffff:${ip}/128`;
9+
}
10+
11+
const parts = ip.split("/");
12+
const suffix = Number.parseInt(parts[1], 10);
13+
// we add 96 to the suffix, since ::ffff: already is 96 bits, so the 32 remaining bits are decided by the IPv4 address
14+
return `::ffff:${parts[0]}/${suffix + 96}`;
15+
}

library/vulnerabilities/ssrf/containsPrivateIPAddress.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const publicIPs = [
3131
"fb00::",
3232
"fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
3333
"fec0::",
34+
"::ffff:1.2.3.4",
35+
"::ffff:172.1.2.3",
36+
"::ffff:192.145.0.0",
3437
];
3538

3639
const privateIPs = [
@@ -139,6 +142,10 @@ const privateIPs = [
139142
"::1",
140143
"::ffff:0.0.0.0",
141144
"::ffff:127.0.0.1",
145+
"::ffff:127.0.0.2",
146+
"::ffff:10.0.0.1",
147+
"::ffff:172.16.1.2",
148+
"::ffff:192.168.2.2",
142149
"fe80::",
143150
"fe80::1",
144151
"fe80::abc:1",

library/vulnerabilities/ssrf/isPrivateIP.ts

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
import { IPMatcher } from "../../helpers/ip-matcher/IPMatcher";
2+
import mapIPv4ToIPv6 from "../../helpers/mapIPv4ToIPv6";
23

3-
// Taken from https://github.com/frenchbread/private-ip/blob/master/src/index.ts
44
const PRIVATE_IP_RANGES = [
5-
"0.0.0.0/8",
6-
"10.0.0.0/8",
7-
"100.64.0.0/10",
8-
"127.0.0.0/8",
9-
"169.254.0.0/16",
10-
"172.16.0.0/12",
11-
"192.0.0.0/24",
12-
"192.0.2.0/24",
13-
"192.31.196.0/24",
14-
"192.52.193.0/24",
15-
"192.88.99.0/24",
16-
"192.168.0.0/16",
17-
"192.175.48.0/24",
18-
"198.18.0.0/15",
19-
"198.51.100.0/24",
20-
"203.0.113.0/24",
21-
"240.0.0.0/4",
22-
"224.0.0.0/4",
23-
"255.255.255.255/32",
5+
"0.0.0.0/8", // "This" network (RFC 1122)
6+
"10.0.0.0/8", // Private-Use Networks (RFC 1918)
7+
"100.64.0.0/10", // Shared Address Space (RFC 6598)
8+
"127.0.0.0/8", // Loopback (RFC 1122)
9+
"169.254.0.0/16", // Link Local (RFC 3927)
10+
"172.16.0.0/12", // Private-Use Networks (RFC 1918)
11+
"192.0.0.0/24", // IETF Protocol Assignments (RFC 5736)
12+
"192.0.2.0/24", // TEST-NET-1 (RFC 5737)
13+
"192.31.196.0/24", // AS112 Redirection Anycast (RFC 7535)
14+
"192.52.193.0/24", // Automatic Multicast Tunneling (RFC 7450)
15+
"192.88.99.0/24", // 6to4 Relay Anycast (RFC 3068)
16+
"192.168.0.0/16", // Private-Use Networks (RFC 1918)
17+
"192.175.48.0/24", // AS112 Redirection Anycast (RFC 7535)
18+
"198.18.0.0/15", // Network Interconnect Device Benchmark Testing (RFC 2544)
19+
"198.51.100.0/24", // TEST-NET-2 (RFC 5737)
20+
"203.0.113.0/24", // TEST-NET-3 (RFC 5737)
21+
"224.0.0.0/4", // Multicast (RFC 3171)
22+
"240.0.0.0/4", // Reserved for Future Use (RFC 1112)
23+
"255.255.255.255/32", // Limited Broadcast (RFC 919)
2424
];
2525

2626
const PRIVATE_IPV6_RANGES = [
27-
"::/128", // Unspecified address
28-
"::1/128", // Loopback address
29-
"fc00::/7", // Unique local address (ULA)
30-
"fe80::/10", // Link-local address (LLA)
31-
"::ffff:127.0.0.1/128", // IPv4-mapped address
32-
"::ffff:0:0",
33-
];
27+
"::/128", // Unspecified address (RFC 4291)
28+
"::1/128", // Loopback address (RFC 4291)
29+
"fc00::/7", // Unique local address (ULA) (RFC 4193)
30+
"fe80::/10", // Link-local address (LLA) (RFC 4291)
31+
"100::/64", // Discard prefix (RFC 6666)
32+
"2001:db8::/32", // Documentation prefix (RFC 3849)
33+
"3fff::/20", // Documentation prefix (RFC 9637)
34+
].concat(
35+
// Add the IPv4-mapped IPv6 addresses
36+
PRIVATE_IP_RANGES.map(mapIPv4ToIPv6)
37+
);
3438

3539
const privateIp = new IPMatcher();
3640

0 commit comments

Comments
 (0)