1
0

Add the ssrf module

This commit is contained in:
2026-08-29 09:31:09 +05:30
parent 0fceb2cd4e
commit 4e37a54e92
28 changed files with 1391 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
address under test: 104.20.23.154 (inside 104.16.0.0/12, outside 172.64.0.0/13)
of("104.16.0.0/12") -> true
of("104.16.0.0/12", "172.64.0.0/13") -> true
externalAddresses().and("104.16.0.0/12") -> true
externalAddresses().and("104.16.0.0/12", "172.64.0.0/13") -> false
externalAddresses().and(of("104.16.0.0/12", "172.64.0.0/13")) -> true
The fourth line is the trap. One address is one filter; two addresses
are two filters ANDed, and no address is inside two disjoint ranges.

View File

@@ -0,0 +1,55 @@
===================================================================================
PROFILE: (none) - no InetAddressFilter bean
===================================================================================
target outcome
-----------------------------------------------------------------------------------------
http://127.0.0.1:8080/internal/credentials FETCHED | {"SecretAccessKey":"wJalrXUtnFEMI-EXAMPLE-NOT-REAL","AccessKeyId":"ASIA-EXAMPLE-NOT-REAL","Expir
http://localhost:8080/internal/credentials FETCHED | {"SecretAccessKey":"wJalrXUtnFEMI-EXAMPLE-NOT-REAL","AccessKeyId":"ASIA-EXAMPLE-NOT-REAL","Expir
http://[::1]:8080/internal/credentials FETCHED | {"SecretAccessKey":"wJalrXUtnFEMI-EXAMPLE-NOT-REAL","AccessKeyId":"ASIA-EXAMPLE-NOT-REAL","Expir
http://172.16.10.3:8080/internal/credentials FETCHED | {"SecretAccessKey":"wJalrXUtnFEMI-EXAMPLE-NOT-REAL","AccessKeyId":"ASIA-EXAMPLE-NOT-REAL","Expir
http://example.com/ FETCHED | <!doctype html><html lang="en"><head><title>Example Domain</title><link rel="icon" href="data:,"
===================================================================================
PROFILE: docsfilter
===================================================================================
target outcome
-----------------------------------------------------------------------------------------
http://127.0.0.1:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '127.0.0.1'
http://localhost:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host 'localhost'
http://[::1]:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '[::1]'
http://172.16.10.3:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '172.16.10.3'
http://example.com/ FETCHED | <!doctype html><html lang="en"><head><title>Example Domain</title><link rel="icon" href="data:,"
===================================================================================
PROFILE: blocklist
===================================================================================
target outcome
-----------------------------------------------------------------------------------------
http://127.0.0.1:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '127.0.0.1'
http://localhost:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host 'localhost'
http://[::1]:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '[::1]'
http://172.16.10.3:8080/internal/credentials FETCHED | {"Expiration":"2026-08-29T23:59:59Z","AccessKeyId":"ASIA-EXAMPLE-NOT-REAL","SecretAccessKey":"wJ
http://example.com/ BLOCKED_BY_FILTER | Filtered host 'example.com'
===================================================================================
PROFILE: negated
===================================================================================
target outcome
-----------------------------------------------------------------------------------------
http://127.0.0.1:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '127.0.0.1'
http://localhost:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host 'localhost'
http://[::1]:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '[::1]'
http://172.16.10.3:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '172.16.10.3'
http://example.com/ FETCHED | <!doctype html><html lang="en"><head><title>Example Domain</title><link rel="icon" href="data:,"
===================================================================================
PROFILE: allowlist
===================================================================================
target outcome
-----------------------------------------------------------------------------------------
http://127.0.0.1:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '127.0.0.1'
http://localhost:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host 'localhost'
http://[::1]:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '[::1]'
http://172.16.10.3:8080/internal/credentials BLOCKED_BY_FILTER | Filtered host '172.16.10.3'
http://example.com/ FETCHED | <!doctype html><html lang="en"><head><title>Example Domain</title><link rel="icon" href="data:,"

View File

@@ -0,0 +1,20 @@
true = the filter MATCHES the address = the call is ALLOWED through.
A row that is false in the active filter's column throws FilteredHostException.
address | all() | none() | routable() | multicast() | specialPurpose() | internalAddresses() | externalAddresses() | internalAddresses().negate()| of(RFC1918) [the inversion]
----------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------
127.0.0.1 | true | false | true | false | true | true | false | false | false
169.254.169.254 | true | false | true | false | true | true | false | false | false
10.0.0.1 | true | false | true | false | true | true | false | false | true
172.16.10.3 | true | false | true | false | true | true | false | false | true
192.168.1.1 | true | false | true | false | true | true | false | false | true
100.64.0.1 | true | false | true | false | true | false | false | true | false
0.0.0.0 | true | false | false | false | true | false | false | true | false
192.0.2.1 | true | false | true | false | true | false | false | true | false
224.0.0.1 | true | false | true | true | false | false | false | true | false
93.184.216.34 | true | false | true | false | false | false | true | true | false
::1 | true | false | true | false | true | true | false | false | false
fc00::1 | true | false | true | false | true | true | false | false | false
fe80::1 | true | false | true | false | true | true | false | false | false
64:ff9b::a00:1 | true | false | true | false | true | true | false | false | false
2606:2800:220:1::1 | true | false | true | false | false | false | true | true | false

View File

@@ -0,0 +1,3 @@
[INFO] Running org.springframework.boot.http.client.WhereTheFilterRunsTests
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.221 s -- in org.springframework.boot.http.client.WhereTheFilterRunsTests
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

View File

@@ -0,0 +1,6 @@
$ java -cp ... SsrfDemoApplication --spring.profiles.active=twofilters
2026-08-29T09:28:27.206+05:30 WARN 445 --- [ssrf-inet-address-filter] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'linkPreviewController' defined in file [/tmp/work/ssd/ssrf/target/classes/com/ankurm/ssrf/LinkPreviewController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'restClientBuilder' defined in class path resource [org/springframework/boot/restclient/autoconfigure/RestClientAutoConfiguration.class]: Unsatisfied dependency expressed through method 'restClientBuilder' parameter 0: Error creating bean with name 'restClientBuilderConfigurer' defined in class path resource [org/springframework/boot/restclient/autoconfigure/RestClientAutoConfiguration.class]: Failed to instantiate [org.springframework.boot.restclient.autoconfigure.RestClientBuilderConfigurer]: Factory method 'restClientBuilderConfigurer' threw exception with message: Error creating bean with name 'httpClientSettings' defined in class path resource [org/springframework/boot/http/client/autoconfigure/HttpClientAutoConfiguration.class]: Failed to instantiate [org.springframework.boot.http.client.HttpClientSettings]: Factory method 'httpClientSettings' threw exception with message: No qualifying bean of type 'org.springframework.boot.http.client.InetAddressFilter' available: expected single matching bean but found 2: firstFilter,secondFilter
APPLICATION FAILED TO START
Description:
Parameter 0 of method restClientBuilder in org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration required a single bean, but 2 were found:
Action: