Skip to content

Commit 734d444

Browse files
committed
Fix codes for the reviews
1 parent 236008d commit 734d444

File tree

3 files changed

+112
-73
lines changed

3 files changed

+112
-73
lines changed

Diff for: community/detectors/intel_neural_compressor_cve_2024_22476/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202422476/Cve202422476DetectorBootstrapModule.java

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package com.google.tsunami.plugins.detectors.cves.cve202422476;
1718

1819
import com.google.tsunami.plugin.PluginBootstrapModule;

Diff for: community/detectors/intel_neural_compressor_cve_2024_22476/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202422476/Cve202422476VulnDetector.java

+52-40
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package com.google.tsunami.plugins.detectors.cves.cve202422476;
1718

1819
import static com.google.common.base.Preconditions.checkNotNull;
@@ -32,6 +33,7 @@
3233
import com.google.tsunami.common.data.NetworkServiceUtils;
3334
import com.google.tsunami.common.net.http.HttpClient;
3435
import com.google.tsunami.common.net.http.HttpHeaders;
36+
import com.google.tsunami.common.net.http.HttpRequest;
3537
import com.google.tsunami.common.net.http.HttpResponse;
3638
import com.google.tsunami.common.time.UtcClock;
3739
import com.google.tsunami.plugin.PluginType;
@@ -68,12 +70,12 @@ public final class Cve202422476VulnDetector implements VulnDetector {
6870
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
6971

7072
private final Clock utcClock;
71-
private final HttpClient httpClient;
7273
private final PayloadGenerator payloadGenerator;
7374

7475
private static final String VUL_PATH = "task/submit/";
7576
private static final int BATCH_REQUEST_WAIT_AFTER_TIMEOUT = 10;
7677
private final String taskRequestTemplate;
78+
private static HttpClient httpClient;
7779

7880
@Inject
7981
Cve202422476VulnDetector(
@@ -104,10 +106,26 @@ public DetectionReportList detect(
104106
.build();
105107
}
106108

109+
private static boolean checkNeuralSolutionFingerprint(NetworkService networkService) {
110+
String targetWebAddress = buildTarget(networkService).toString();
111+
var request = HttpRequest.get(targetWebAddress).withEmptyHeaders().build();
112+
113+
try {
114+
HttpResponse response = httpClient.send(request, networkService);
115+
return response.status().isSuccess()
116+
&& response
117+
.bodyString()
118+
.map(body -> body.contains("{\"message\":\"Welcome to Neural Solution!\"}"))
119+
.orElse(false);
120+
} catch (IOException e) {
121+
logger.atWarning().withCause(e).log("Failed to send request.");
122+
return false;
123+
}
124+
}
125+
107126
private static boolean isWebServiceOrUnknownService(NetworkService networkService) {
108-
return networkService.getServiceName().isEmpty()
109-
|| NetworkServiceUtils.isWebService(networkService)
110-
|| NetworkServiceUtils.getServiceName(networkService).equals("unknown");
127+
return NetworkServiceUtils.isWebService(networkService)
128+
&& checkNeuralSolutionFingerprint(networkService);
111129
}
112130

113131
private static StringBuilder buildTarget(NetworkService networkService) {
@@ -124,43 +142,37 @@ private static StringBuilder buildTarget(NetworkService networkService) {
124142
}
125143

126144
private boolean isServiceVulnerable(NetworkService networkService) {
127-
return isRceExecutable(networkService);
128-
}
129-
130-
private boolean isRceExecutable(NetworkService networkService) {
131-
if (payloadGenerator.isCallbackServerEnabled()) {
132-
String taskRequestBody = taskRequestTemplate;
133-
// Check callback server is enabled
134-
logger.atInfo().log("Callback server is available!");
135-
Payload payload = generateCallbackServerPayload();
136-
taskRequestBody =
137-
taskRequestBody.replace(
138-
"{{CALLBACK_PAYLOAD}}",
139-
BaseEncoding.base64().encode(payload.getPayload().getBytes(UTF_8)));
140-
String targetVulnerabilityUrl = buildTarget(networkService).append(VUL_PATH).toString();
141-
logger.atInfo().log(taskRequestBody);
142-
try {
143-
HttpResponse httpResponse =
144-
httpClient.send(
145-
post(targetVulnerabilityUrl)
146-
.setHeaders(
147-
HttpHeaders.builder().addHeader(CONTENT_TYPE, "application/json").build())
148-
.setRequestBody(ByteString.copyFromUtf8(taskRequestBody))
149-
.build(),
150-
networkService);
151-
logger.atInfo().log(
152-
"Callback Server Payload Response: %s", httpResponse.bodyString().get());
153-
Uninterruptibles.sleepUninterruptibly(Duration.ofSeconds(BATCH_REQUEST_WAIT_AFTER_TIMEOUT));
154-
return payload.checkIfExecuted();
155-
156-
} catch (IOException e) {
157-
logger.atWarning().withCause(e).log("Failed to send request.");
158-
return false;
159-
}
160-
} else {
145+
Payload payload = generateCallbackServerPayload();
146+
if (!payload.getPayloadAttributes().getUsesCallbackServer()) {
161147
logger.atInfo().log(
162-
"Callback server is not available! This vulnerability cannot be detected without a"
163-
+ " callback server!");
148+
"The Tsunami callback server is not setup for this environment, so we cannot confirm the"
149+
+ " RCE callback");
150+
return false;
151+
}
152+
String taskRequestBody = taskRequestTemplate;
153+
// Check callback server is enabled
154+
logger.atInfo().log("Callback server is available!");
155+
taskRequestBody =
156+
taskRequestBody.replace(
157+
"{{CALLBACK_PAYLOAD}}",
158+
BaseEncoding.base64().encode(payload.getPayload().getBytes(UTF_8)));
159+
String targetVulnerabilityUrl = buildTarget(networkService).append(VUL_PATH).toString();
160+
logger.atInfo().log(taskRequestBody);
161+
try {
162+
HttpResponse httpResponse =
163+
httpClient.send(
164+
post(targetVulnerabilityUrl)
165+
.setHeaders(
166+
HttpHeaders.builder().addHeader(CONTENT_TYPE, "application/json").build())
167+
.setRequestBody(ByteString.copyFromUtf8(taskRequestBody))
168+
.build(),
169+
networkService);
170+
logger.atInfo().log("Callback Server Payload Response: %s", httpResponse.bodyString().get());
171+
Uninterruptibles.sleepUninterruptibly(Duration.ofSeconds(BATCH_REQUEST_WAIT_AFTER_TIMEOUT));
172+
return payload.checkIfExecuted();
173+
174+
} catch (IOException e) {
175+
logger.atWarning().withCause(e).log("Failed to send request.");
164176
return false;
165177
}
166178
}

Diff for: community/detectors/intel_neural_compressor_cve_2024_22476/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202422476/Cve202422476VulnDetectorTest.java

+59-33
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package com.google.tsunami.plugins.detectors.cves.cve202422476;
1718

1819
import static com.google.common.truth.Truth.assertThat;
1920
import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
20-
import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostname;
2121
import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort;
2222

2323
import com.google.common.collect.ImmutableList;
2424
import com.google.inject.Guice;
2525
import com.google.protobuf.util.Timestamps;
2626
import com.google.tsunami.common.net.http.HttpClientModule;
27-
import com.google.tsunami.common.net.http.HttpStatus;
2827
import com.google.tsunami.common.time.testing.FakeUtcClock;
2928
import com.google.tsunami.common.time.testing.FakeUtcClockModule;
3029
import com.google.tsunami.plugin.payload.testing.FakePayloadGeneratorModule;
@@ -34,16 +33,16 @@
3433
import com.google.tsunami.proto.DetectionStatus;
3534
import com.google.tsunami.proto.NetworkService;
3635
import com.google.tsunami.proto.Severity;
37-
import com.google.tsunami.proto.Software;
3836
import com.google.tsunami.proto.TargetInfo;
39-
import com.google.tsunami.proto.TransportProtocol;
4037
import com.google.tsunami.proto.Vulnerability;
4138
import com.google.tsunami.proto.VulnerabilityId;
4239
import java.io.IOException;
4340
import java.time.Instant;
4441
import javax.inject.Inject;
42+
import okhttp3.mockwebserver.Dispatcher;
4543
import okhttp3.mockwebserver.MockResponse;
4644
import okhttp3.mockwebserver.MockWebServer;
45+
import okhttp3.mockwebserver.RecordedRequest;
4746
import org.junit.After;
4847
import org.junit.Before;
4948
import org.junit.Test;
@@ -57,7 +56,7 @@ public class Cve202422476VulnDetectorTest {
5756
FakeUtcClock.create().setNow(Instant.parse("2022-05-23T00:00:00.00Z"));
5857
private MockWebServer mockWebServer;
5958
private MockWebServer mockCallbackServer;
60-
private NetworkService service;
59+
private NetworkService targetNetworkService;
6160
private TargetInfo targetInfo;
6261

6362
@Inject private Cve202422476VulnDetector detector;
@@ -74,20 +73,6 @@ public void setUp() throws IOException {
7473
FakePayloadGeneratorModule.builder().setCallbackServer(mockCallbackServer).build(),
7574
new Cve202422476DetectorBootstrapModule())
7675
.injectMembers(this);
77-
78-
service =
79-
NetworkService.newBuilder()
80-
.setNetworkEndpoint(
81-
forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
82-
.setTransportProtocol(TransportProtocol.TCP)
83-
.setSoftware(Software.newBuilder().setName("http"))
84-
.setServiceName("http")
85-
.build();
86-
87-
targetInfo =
88-
TargetInfo.newBuilder()
89-
.addNetworkEndpoints(forHostname(mockWebServer.getHostName()))
90-
.build();
9176
}
9277

9378
@After
@@ -99,21 +84,16 @@ public void tearDown() throws IOException {
9984
@Test
10085
public void detect_whenVulnerable_returnsVulnerability() throws IOException {
10186
// It is a blind RCE, body is not important. This is a part of a valid response.
102-
mockWebServer.enqueue(
103-
new MockResponse()
104-
.setResponseCode(200)
105-
.setBody(
106-
"{\"status\":\"successfully\",\"task_id\":\"065d95dd70524cb2baa743def3ff7036\",\"msg\":\"Task"
107-
+ " submitted successfully\"}"));
108-
87+
startMockWebServer(true);
10988
mockCallbackServer.enqueue(PayloadTestHelper.generateMockSuccessfulCallbackResponse());
110-
DetectionReportList detectionReports = detector.detect(targetInfo, ImmutableList.of(service));
89+
DetectionReportList detectionReports =
90+
detector.detect(targetInfo, ImmutableList.of(targetNetworkService));
11191

11292
assertThat(detectionReports.getDetectionReportsList())
11393
.containsExactly(
11494
DetectionReport.newBuilder()
11595
.setTargetInfo(targetInfo)
116-
.setNetworkService(service)
96+
.setNetworkService(targetNetworkService)
11797
.setDetectionTimestamp(
11898
Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli()))
11999
.setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED)
@@ -138,17 +118,63 @@ public void detect_whenVulnerable_returnsVulnerability() throws IOException {
138118
+ " result, attackers can manipulate this parameter to remotely"
139119
+ " execute arbitrary commands."))
140120
.build());
141-
assertThat(mockWebServer.getRequestCount()).isEqualTo(1);
121+
assertThat(mockWebServer.getRequestCount()).isEqualTo(2);
142122
assertThat(mockCallbackServer.getRequestCount()).isEqualTo(1);
143123
}
144124

145125
@Test
146126
public void detect_ifNotVulnerable_doesNotReportVuln() throws IOException {
147-
mockWebServer.enqueue(
148-
new MockResponse().setResponseCode(HttpStatus.OK.code()).setBody("Hello world!"));
127+
startMockWebServer(false);
149128

150-
DetectionReportList detectionReports = detector.detect(targetInfo, ImmutableList.of(service));
129+
DetectionReportList detectionReports =
130+
detector.detect(targetInfo, ImmutableList.of(targetNetworkService));
151131
assertThat(detectionReports.getDetectionReportsList()).isEmpty();
152-
assertThat(mockWebServer.getRequestCount()).isEqualTo(1);
132+
assertThat(mockWebServer.getRequestCount()).isEqualTo(2);
133+
}
134+
135+
private void startMockWebServer(boolean isVulnerableServer) throws IOException {
136+
final Dispatcher dispatcher =
137+
new Dispatcher() {
138+
139+
@Override
140+
public MockResponse dispatch(RecordedRequest request) {
141+
switch (request.getPath()) {
142+
case "/":
143+
return new MockResponse()
144+
.setResponseCode(200)
145+
.setBody("{\"message\":\"Welcome to Neural Solution!\"}");
146+
case "/task/submit/":
147+
if (isVulnerableServer) {
148+
return new MockResponse()
149+
.setResponseCode(200)
150+
.setBody(
151+
"{\"status\":\"successfully\",\"task_id\":\"065d95dd70524cb2baa743def3ff7036\",\"msg\":\"Task"
152+
+ " submitted successfully\"}");
153+
} else {
154+
return new MockResponse()
155+
.setResponseCode(422)
156+
.setBody("{\"detail\":\"Invalid task\"}");
157+
}
158+
default:
159+
return new MockResponse()
160+
.setResponseCode(404)
161+
.setBody("{\"detail\":\"Not Found\"}");
162+
}
163+
}
164+
};
165+
mockWebServer.setDispatcher(dispatcher);
166+
mockWebServer.start();
167+
mockWebServer.url("/");
168+
targetNetworkService =
169+
NetworkService.newBuilder()
170+
.setNetworkEndpoint(
171+
forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort()))
172+
.addSupportedHttpMethods("POST")
173+
.addSupportedHttpMethods("GET")
174+
.build();
175+
targetInfo =
176+
TargetInfo.newBuilder()
177+
.addNetworkEndpoints(targetNetworkService.getNetworkEndpoint())
178+
.build();
153179
}
154180
}

0 commit comments

Comments
 (0)