From 33669f833826697eea95535a466c189805a1b0a8 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Mon, 1 Dec 2025 15:09:00 +0100 Subject: [PATCH 1/4] Switch BlockList class in favour of IPList --- .../vulnerabilities/ssrf/imds/BlockList.java | 37 ------- .../ssrf/imds/IMDSAddresses.java | 12 ++- .../vulnerabilities/ssrf/BlockListTest.java | 100 ------------------ 3 files changed, 7 insertions(+), 142 deletions(-) delete mode 100644 agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/BlockList.java delete mode 100644 agent_api/src/test/java/vulnerabilities/ssrf/BlockListTest.java diff --git a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/BlockList.java b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/BlockList.java deleted file mode 100644 index f56d90438..000000000 --- a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/BlockList.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.aikido.agent_api.vulnerabilities.ssrf.imds; - - -import java.util.HashSet; -import java.util.Set; - -public class BlockList { - /** A list of IPs that shouldn't be accessed */ - private final Set blockedIPv4Addresses; - private final Set blockedIPv6Addresses; - - public BlockList() { - this.blockedIPv4Addresses = new HashSet<>(); - this.blockedIPv6Addresses = new HashSet<>(); - } - - /** Add an address to this list */ - public void addAddress(String address, String addressType) { - if ("ipv4".equals(addressType)) { - blockedIPv4Addresses.add(address); - } else if ("ipv6".equals(addressType)) { - blockedIPv6Addresses.add(address); - } - } - - /** Check if the IP is on the list */ - public boolean check(String address, String addressType) { - if (addressType != null) { - if ("ipv4".equals(addressType)) { - return blockedIPv4Addresses.contains(address); - } else if ("ipv6".equals(addressType)) { - return blockedIPv6Addresses.contains(address); - } - } - return blockedIPv4Addresses.contains(address) || blockedIPv6Addresses.contains(address); - } -} \ No newline at end of file diff --git a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java index d9cf0bd5d..f89bb82a6 100644 --- a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java +++ b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java @@ -1,20 +1,22 @@ package dev.aikido.agent_api.vulnerabilities.ssrf.imds; +import dev.aikido.agent_api.helpers.net.IPList; + public final class IMDSAddresses { private IMDSAddresses() {} - private static final BlockList imdsAddresses = new BlockList(); + private static final IPList imdsAddresses = new IPList(); static { // Add the IP addresses used by AWS EC2 instances for IMDS - imdsAddresses.addAddress("169.254.169.254", "ipv4"); - imdsAddresses.addAddress("fd00:ec2::254", "ipv6"); + imdsAddresses.add("169.254.169.254"); + imdsAddresses.add("fd00:ec2::254"); // Add the IP addresses used for Alibaba Cloud - imdsAddresses.addAddress("100.100.100.200", "ipv4"); + imdsAddresses.add("100.100.100.200"); } /** Checks if the IP is an IMDS IP */ public static boolean isImdsIpAddress(String ip) { - return imdsAddresses.check(ip, "ipv4") || imdsAddresses.check(ip, "ipv6"); + return imdsAddresses.matches(ip); } } diff --git a/agent_api/src/test/java/vulnerabilities/ssrf/BlockListTest.java b/agent_api/src/test/java/vulnerabilities/ssrf/BlockListTest.java deleted file mode 100644 index 5ee905463..000000000 --- a/agent_api/src/test/java/vulnerabilities/ssrf/BlockListTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package vulnerabilities.ssrf; - - -import dev.aikido.agent_api.vulnerabilities.ssrf.imds.BlockList; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class BlockListTest { - - private BlockList blockList; - - @BeforeEach - void setUp() { - blockList = new BlockList(); - } - - @Test - void testAddIPv4Address() { - blockList.addAddress("192.168.1.1", "ipv4"); - assertTrue(blockList.check("192.168.1.1", "ipv4"), "IPv4 address should be blocked"); - assertTrue(blockList.check("192.168.1.1", "unknown"), "IPv4 address should be blocked"); - } - - @Test - void testAddIPv6Address() { - blockList.addAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"); - assertTrue(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"), "IPv6 address should be blocked"); - assertTrue(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "unknown"), "IPv6 address should be blocked"); - - } - - @Test - void testAddIPv8AddressDoesNotWork() { - blockList.addAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv8"); - assertFalse(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv4")); - assertFalse(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6")); - assertFalse(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv8")); - } - - @Test - void testCheckBlockedIPv4Address() { - blockList.addAddress("10.0.0.1", "ipv4"); - assertTrue(blockList.check("10.0.0.1", "ipv4"), "IPv4 address should be blocked"); - } - - @Test - void testCheckBlockedIPv6Address() { - blockList.addAddress("::1", "ipv6"); - assertTrue(blockList.check("::1", "ipv6"), "IPv6 address should be blocked"); - } - - @Test - void testCheckUnblockedIPv4Address() { - blockList.addAddress("192.168.1.1", "ipv4"); - assertFalse(blockList.check("192.168.1.2", "ipv4"), "IPv4 address should not be blocked"); - } - - @Test - void testCheckUnblockedIPv6Address() { - blockList.addAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"); - assertFalse(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7335", "ipv6"), "IPv6 address should not be blocked"); - } - - @Test - void testCheckNullAddressType() { - blockList.addAddress("192.168.1.1", "ipv4"); - assertTrue(blockList.check("192.168.1.1", null), "IPv4 address should be blocked when checking with null type"); - } - - @Test - void testCheckEmptyAddress() { - assertFalse(blockList.check("", "ipv4"), "Empty address should not be blocked"); - assertFalse(blockList.check("", "ipv6"), "Empty address should not be blocked"); - } - - @Test - void testAddDuplicateIPv4Address() { - blockList.addAddress("192.168.1.1", "ipv4"); - blockList.addAddress("192.168.1.1", "ipv4"); // Adding duplicate - assertTrue(blockList.check("192.168.1.1", "ipv4"), "IPv4 address should still be blocked"); - } - - @Test - void testAddDuplicateIPv6Address() { - blockList.addAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"); - blockList.addAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"); // Adding duplicate - assertTrue(blockList.check("2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ipv6"), "IPv6 address should still be blocked"); - } - - @Test - void testCheckBlockedIPv4AndIPv6() { - blockList.addAddress("192.168.1.1", "ipv4"); - blockList.addAddress("::1", "ipv6"); - assertTrue(blockList.check("192.168.1.1", "ipv4"), "IPv4 address should be blocked"); - assertTrue(blockList.check("::1", "ipv6"), "IPv6 address should be blocked"); - } -} \ No newline at end of file From 9c986d994bcc14724b9bf1c3e8c3721c4639f00d Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Mon, 1 Dec 2025 15:10:06 +0100 Subject: [PATCH 2/4] remove test_stored_ssrf from skip list in qa tests --- .github/workflows/qa-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa-tests.yml b/.github/workflows/qa-tests.yml index 90ce57168..ce01cadd6 100644 --- a/.github/workflows/qa-tests.yml +++ b/.github/workflows/qa-tests.yml @@ -49,4 +49,4 @@ jobs: dockerfile_path: ./zen-demo-java/Dockerfile app_port: 8080 sleep_before_test: 30 - skip_tests: test_ssrf,test_stored_ssrf,test_demo_apps_generic_tests + skip_tests: test_ssrf,test_demo_apps_generic_tests From 1bb452c833d3a8ac84851ddd599d74d8e5614263 Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Mon, 1 Dec 2025 15:13:59 +0100 Subject: [PATCH 3/4] Add ipv4-mapped ipv6 addresses for IMDS --- .../vulnerabilities/ssrf/imds/IMDSAddresses.java | 3 +++ .../java/vulnerabilities/ssrf/ResolverTest.java | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java index f89bb82a6..3981ec4a4 100644 --- a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java +++ b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java @@ -1,6 +1,7 @@ package dev.aikido.agent_api.vulnerabilities.ssrf.imds; import dev.aikido.agent_api.helpers.net.IPList; +import static dev.aikido.agent_api.vulnerabilities.ssrf.IsPrivateIP.mapIPv4ToIPv6; public final class IMDSAddresses { private IMDSAddresses() {} @@ -10,9 +11,11 @@ private IMDSAddresses() {} // Add the IP addresses used by AWS EC2 instances for IMDS imdsAddresses.add("169.254.169.254"); imdsAddresses.add("fd00:ec2::254"); + imdsAddresses.add(mapIPv4ToIPv6("169.254.169.254")); // Add the IP addresses used for Alibaba Cloud imdsAddresses.add("100.100.100.200"); + imdsAddresses.add(mapIPv4ToIPv6("169.254.169.254")); } /** Checks if the IP is an IMDS IP */ diff --git a/agent_api/src/test/java/vulnerabilities/ssrf/ResolverTest.java b/agent_api/src/test/java/vulnerabilities/ssrf/ResolverTest.java index 98e58ab82..363ae06b7 100644 --- a/agent_api/src/test/java/vulnerabilities/ssrf/ResolverTest.java +++ b/agent_api/src/test/java/vulnerabilities/ssrf/ResolverTest.java @@ -27,6 +27,22 @@ void testResolvesToImdsIp_WithImdsIp() { assertEquals("169.254.169.254", Resolver.resolvesToImdsIp(resolvedIps, "example.com")); } + @Test + void testResolvesToImdsIp_WithIpv4MappedIP() { + Set resolvedIps = new HashSet<>(); + resolvedIps.add("::ffff:169.254.169.254"); // IMDS IP + + assertEquals("::ffff:169.254.169.254", Resolver.resolvesToImdsIp(resolvedIps, "example.com")); + } + + @Test + void testResolvesToImdsIp_WithIpv4MappedIP2() { + Set resolvedIps = new HashSet<>(); + resolvedIps.add("::ffff:100.100.100.200"); // IMDS IP + + assertEquals("::ffff:100.100.100.200", Resolver.resolvesToImdsIp(resolvedIps, "example.com")); + } + @Test void testDoesntResolveToImdsIp_WithHostnameImdsIp() { Set resolvedIps = new HashSet<>(); From 5f6bd6699778260944cc1a10f1ead29e04f601bc Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Mon, 1 Dec 2025 15:14:42 +0100 Subject: [PATCH 4/4] Fix alibaba cloud case --- .../agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java index 3981ec4a4..225a6e7c3 100644 --- a/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java +++ b/agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/ssrf/imds/IMDSAddresses.java @@ -15,7 +15,7 @@ private IMDSAddresses() {} // Add the IP addresses used for Alibaba Cloud imdsAddresses.add("100.100.100.200"); - imdsAddresses.add(mapIPv4ToIPv6("169.254.169.254")); + imdsAddresses.add(mapIPv4ToIPv6("100.100.100.200")); } /** Checks if the IP is an IMDS IP */