Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions library/helpers/mapIPv4ToIPv6.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as t from "tap";
import mapIPv4ToIPv6 from "./mapIPv4ToIPv6";

t.test("it works", async (t) => {
t.equal(mapIPv4ToIPv6("127.0.0.0"), "::ffff:127.0.0.0/128");
t.equal(mapIPv4ToIPv6("127.0.0.0/8"), "::ffff:127.0.0.0/104");
t.equal(mapIPv4ToIPv6("10.0.0.0"), "::ffff:10.0.0.0/128");
t.equal(mapIPv4ToIPv6("10.0.0.0/8"), "::ffff:10.0.0.0/104");
t.equal(mapIPv4ToIPv6("10.0.0.1"), "::ffff:10.0.0.1/128");
t.equal(mapIPv4ToIPv6("10.0.0.1/8"), "::ffff:10.0.0.1/104");
t.equal(mapIPv4ToIPv6("192.168.0.0/16"), "::ffff:192.168.0.0/112");
t.equal(mapIPv4ToIPv6("172.16.0.0/12"), "::ffff:172.16.0.0/108");
});
15 changes: 15 additions & 0 deletions library/helpers/mapIPv4ToIPv6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Maps an IPv4 address to an IPv6 address.
* e.g. 127.0.0.0/8 -> ::ffff:127.0.0.0/104
*/
export default function mapIPv4ToIPv6(ip: string): string {
if (!ip.includes("/")) {
// No CIDR suffix, assume /32
return `::ffff:${ip}/128`;
}

const parts = ip.split("/");
const suffix = Number.parseInt(parts[1], 10);
// we add 96 to the suffix, since ::ffff: already is 96 bits, so the 32 remaining bits are decided by the IPv4 address
return `::ffff:${parts[0]}/${suffix + 96}`;
}
7 changes: 7 additions & 0 deletions library/vulnerabilities/ssrf/containsPrivateIPAddress.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const publicIPs = [
"fb00::",
"fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
"fec0::",
"::ffff:1.2.3.4",
"::ffff:172.1.2.3",
"::ffff:192.145.0.0",
];

const privateIPs = [
Expand Down Expand Up @@ -139,6 +142,10 @@ const privateIPs = [
"::1",
"::ffff:0.0.0.0",
"::ffff:127.0.0.1",
"::ffff:127.0.0.2",
"::ffff:10.0.0.1",
"::ffff:172.16.1.2",
"::ffff:192.168.2.2",
"fe80::",
"fe80::1",
"fe80::abc:1",
Expand Down
58 changes: 31 additions & 27 deletions library/vulnerabilities/ssrf/isPrivateIP.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
import { IPMatcher } from "../../helpers/ip-matcher/IPMatcher";
import mapIPv4ToIPv6 from "../../helpers/mapIPv4ToIPv6";

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

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

const privateIp = new IPMatcher();

Expand Down
Loading