Skip to content

Commit f67d3d2

Browse files
Fix rare private ip address bypass SSRF issue (#1070) (#1081)
* Change connector access control creation allow empty list Signed-off-by: zane-neo <[email protected]> * Fix rare private ip address bypass SSRF issue Signed-off-by: zane-neo <[email protected]> --------- Signed-off-by: zane-neo <[email protected]> (cherry picked from commit e3cb2e3) Co-authored-by: zane-neo <[email protected]>
1 parent c6aa8d9 commit f67d3d2

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

ml-algorithms/src/main/java/org/opensearch/ml/engine/httpclient/MLHttpClientFactory.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.http.protocol.HttpContext;
2020
import org.apache.logging.log4j.util.Strings;
2121

22+
import java.net.Inet4Address;
2223
import java.net.InetAddress;
2324
import java.net.UnknownHostException;
2425
import java.util.Arrays;
@@ -42,10 +43,7 @@ public int resolve(HttpHost host) throws UnsupportedSchemeException {
4243
}
4344
});
4445

45-
builder.setDnsResolver(hostName -> {
46-
validateIp(hostName);
47-
return InetAddress.getAllByName(hostName);
48-
});
46+
builder.setDnsResolver(MLHttpClientFactory::validateIp);
4947

5048
builder.setRedirectStrategy(new LaxRedirectStrategy() {
5149
@Override
@@ -79,15 +77,51 @@ protected static void validateSchemaAndPort(HttpHost host) {
7977
}
8078
}
8179

82-
protected static void validateIp(String hostName) throws UnknownHostException {
80+
protected static InetAddress[] validateIp(String hostName) throws UnknownHostException {
8381
InetAddress[] addresses = InetAddress.getAllByName(hostName);
8482
if (hasPrivateIpAddress(addresses)) {
8583
log.error("Remote inference host name has private ip address: " + hostName);
8684
throw new IllegalArgumentException(hostName);
8785
}
86+
return addresses;
8887
}
8988

9089
private static boolean hasPrivateIpAddress(InetAddress[] ipAddress) {
90+
for (InetAddress ip : ipAddress) {
91+
if (ip instanceof Inet4Address) {
92+
byte[] bytes = ip.getAddress();
93+
if (bytes.length != 4) {
94+
return true;
95+
} else {
96+
int firstOctets = bytes[0] & 0xff;
97+
int firstInOctal = parseWithOctal(String.valueOf(firstOctets));
98+
int firstInHex = Integer.parseInt(String.valueOf(firstOctets), 16);
99+
if (firstInOctal == 127 || firstInHex == 127) {
100+
return bytes[1] == 0 && bytes[2] == 0 && bytes[3] == 1;
101+
} else if (firstInOctal == 10 || firstInHex == 10) {
102+
return true;
103+
} else if (firstInOctal == 172 || firstInHex == 172) {
104+
int secondOctets = bytes[1] & 0xff;
105+
int secondInOctal = parseWithOctal(String.valueOf(secondOctets));
106+
int secondInHex = Integer.parseInt(String.valueOf(secondOctets), 16);
107+
return (secondInOctal >= 16 && secondInOctal <= 32) || (secondInHex >= 16 && secondInHex <= 32);
108+
} else if (firstInOctal == 192 || firstInHex == 192) {
109+
int secondOctets = bytes[1] & 0xff;
110+
int secondInOctal = parseWithOctal(String.valueOf(secondOctets));
111+
int secondInHex = Integer.parseInt(String.valueOf(secondOctets), 16);
112+
return secondInOctal == 168 || secondInHex == 168;
113+
}
114+
}
115+
}
116+
}
91117
return Arrays.stream(ipAddress).anyMatch(x -> x.isSiteLocalAddress() || x.isLoopbackAddress() || x.isAnyLocalAddress());
92118
}
119+
120+
private static int parseWithOctal(String input) {
121+
try {
122+
return Integer.parseInt(input, 8);
123+
} catch (NumberFormatException e) {
124+
return Integer.parseInt(input);
125+
}
126+
}
93127
}

ml-algorithms/src/test/java/org/opensearch/ml/engine/httpclient/MLHttpClientFactoryTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
import org.junit.Test;
1212
import org.junit.rules.ExpectedException;
1313

14+
import java.net.InetAddress;
1415
import java.net.UnknownHostException;
1516

1617
import static org.junit.Assert.assertNotNull;
18+
import static org.junit.Assert.fail;
1719

1820
public class MLHttpClientFactoryTests {
1921

@@ -43,6 +45,45 @@ public void test_validateIp_privateIp_throwException() throws UnknownHostExcepti
4345
MLHttpClientFactory.validateIp("localhost");
4446
}
4547

48+
@Test
49+
public void test_validateIp_rarePrivateIp_throwException() throws UnknownHostException {
50+
try {
51+
MLHttpClientFactory.validateIp("0254.020.00.01");
52+
} catch (IllegalArgumentException e) {
53+
assertNotNull(e);
54+
}
55+
56+
try {
57+
MLHttpClientFactory.validateIp("172.1048577");
58+
} catch (IllegalArgumentException e) {
59+
assertNotNull(e);
60+
}
61+
62+
try {
63+
MLHttpClientFactory.validateIp("2886729729");
64+
} catch (IllegalArgumentException e) {
65+
assertNotNull(e);
66+
}
67+
68+
try {
69+
MLHttpClientFactory.validateIp("192.11010049");
70+
} catch (IllegalArgumentException e) {
71+
assertNotNull(e);
72+
}
73+
74+
try {
75+
MLHttpClientFactory.validateIp("3232300545");
76+
} catch (IllegalArgumentException e) {
77+
assertNotNull(e);
78+
}
79+
80+
try {
81+
MLHttpClientFactory.validateIp("0:0:0:0:0:ffff:127.0.0.1");
82+
} catch (IllegalArgumentException e) {
83+
assertNotNull(e);
84+
}
85+
}
86+
4687
@Test
4788
public void test_validateSchemaAndPort_success() {
4889
HttpHost httpHost = new HttpHost("api.openai.com", 8080, "https");

0 commit comments

Comments
 (0)