diff --git a/plugin/src/main/java/com/google/tsunami/plugin/payload/PayloadGenerator.java b/plugin/src/main/java/com/google/tsunami/plugin/payload/PayloadGenerator.java index ff365b5a..75fdc5b6 100644 --- a/plugin/src/main/java/com/google/tsunami/plugin/payload/PayloadGenerator.java +++ b/plugin/src/main/java/com/google/tsunami/plugin/payload/PayloadGenerator.java @@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.protobuf.ByteString; import com.google.tsunami.plugin.TcsClient; @@ -32,11 +31,8 @@ /** Holds the generate function to get a detection payload given config parameters */ public final class PayloadGenerator { - @VisibleForTesting static final String UNDEF_VAL = "${TCS_UNDEF}"; private static final int SECRET_LENGTH = 8; private static final String TOKEN_CALLBACK_SERVER_URL = "$TSUNAMI_PAYLOAD_TOKEN_URL"; - private static final String TOKEN_CALLBACK_SERVER_URL_LINUX_RCE = - "$TSUNAMI_PAYLOAD_TOKEN_URL_LINUX_RCE"; private static final String TOKEN_RANDOM_STRING = "$TSUNAMI_PAYLOAD_TOKEN_RANDOM"; private final TcsClient tcsClient; @@ -116,42 +112,34 @@ private boolean isMatchingPayload(PayloadDefinition p, PayloadGeneratorConfig c) private Payload convertParsedPayload(PayloadDefinition p, PayloadGeneratorConfig c) { String secret = secretGenerator.generate(SECRET_LENGTH); if (p.getUsesCallbackServer().getValue()) { - String callbackUri = tcsClient.getCallbackUri(secret); return new Payload( p.getPayloadString() .getValue() - .replace( - TOKEN_CALLBACK_SERVER_URL_LINUX_RCE, generateLinuxRceCallbackUri(callbackUri)) - .replace(TOKEN_CALLBACK_SERVER_URL, callbackUri), + .replace(TOKEN_CALLBACK_SERVER_URL, tcsClient.getCallbackUri(secret)), (Validator) (unused) -> tcsClient.hasOobLog(secret), PayloadAttributes.newBuilder().setUsesCallbackServer(true).build(), c); + } else { + String payloadString = p.getPayloadString().getValue().replace(TOKEN_RANDOM_STRING, secret); + Validator v; + switch (p.getValidationType()) { + case VALIDATION_REGEX: + String processedRegex = + p.getValidationRegex().getValue().replace(TOKEN_RANDOM_STRING, secret); + v = + (Validator) + (Optional input) -> + input.map(i -> i.toStringUtf8().matches(processedRegex)).orElse(false); + return new Payload( + payloadString, + v, + PayloadAttributes.newBuilder().setUsesCallbackServer(false).build(), + c); + default: + throw new NotImplementedException( + "Validation type %s not implemented.", p.getValidationType()); + } } - String payloadString = p.getPayloadString().getValue().replace(TOKEN_RANDOM_STRING, secret); - Validator v; - switch (p.getValidationType()) { - case VALIDATION_REGEX: - String processedRegex = - p.getValidationRegex().getValue().replace(TOKEN_RANDOM_STRING, secret); - v = - (Validator) - (Optional input) -> - input.map(i -> i.toStringUtf8().matches(processedRegex)).orElse(false); - return new Payload( - payloadString, - v, - PayloadAttributes.newBuilder().setUsesCallbackServer(false).build(), - c); - default: - throw new NotImplementedException( - "Validation type %s not implemented.", p.getValidationType()); - } - } - - private static String generateLinuxRceCallbackUri(String callbackUri) { - return callbackUri.substring(0, callbackUri.length() / 2) - + UNDEF_VAL - + callbackUri.substring(callbackUri.length() / 2); } /** Guice interface for injecting parsed payloads from payload_definitions.yaml */ diff --git a/plugin/src/main/resources/com/google/tsunami/plugin/payload/payload_definitions.yaml b/plugin/src/main/resources/com/google/tsunami/plugin/payload/payload_definitions.yaml index 9f6034f8..8cba4175 100644 --- a/plugin/src/main/resources/com/google/tsunami/plugin/payload/payload_definitions.yaml +++ b/plugin/src/main/resources/com/google/tsunami/plugin/payload/payload_definitions.yaml @@ -36,7 +36,7 @@ payloads: interpretation_environment: LINUX_SHELL execution_environment: EXEC_INTERPRETATION_ENVIRONMENT uses_callback_server: true - payload_string: curl $TSUNAMI_PAYLOAD_TOKEN_URL_LINUX_RCE + payload_string: curl $TSUNAMI_PAYLOAD_TOKEN_URL vulnerability_type: - REFLECTIVE_RCE - BLIND_RCE diff --git a/plugin/src/test/java/com/google/tsunami/plugin/payload/PayloadGeneratorWithCallbackServerTest.java b/plugin/src/test/java/com/google/tsunami/plugin/payload/PayloadGeneratorWithCallbackServerTest.java index af58dfe8..efdd3353 100644 --- a/plugin/src/test/java/com/google/tsunami/plugin/payload/PayloadGeneratorWithCallbackServerTest.java +++ b/plugin/src/test/java/com/google/tsunami/plugin/payload/PayloadGeneratorWithCallbackServerTest.java @@ -16,7 +16,6 @@ package com.google.tsunami.plugin.payload; import static com.google.common.truth.Truth.assertThat; -import static com.google.tsunami.plugin.payload.PayloadGenerator.UNDEF_VAL; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -91,7 +90,6 @@ public void generate_withLinuxConfiguration_returnsCurlPayload() { Payload payload = payloadGenerator.generate(LINUX_REFLECTIVE_RCE_CONFIG); assertThat(payload.getPayload()).contains("curl"); - assertThat(payload.getPayload()).contains(UNDEF_VAL); assertThat(payload.getPayload()).contains(mockCallbackServer.getHostName()); assertThat(payload.getPayload()).contains(Integer.toString(mockCallbackServer.getPort(), 10)); assertTrue(payload.getPayloadAttributes().getUsesCallbackServer()); @@ -102,7 +100,6 @@ public void generate_withLinuxConfiguration_returnsPrintfPayload() { Payload payload = payloadGenerator.generateNoCallback(LINUX_REFLECTIVE_RCE_CONFIG); assertThat(payload.getPayload()).isEqualTo(CORRECT_PRINTF); - assertThat(payload.getPayload()).doesNotContain(UNDEF_VAL); assertFalse(payload.getPayloadAttributes().getUsesCallbackServer()); } diff --git a/plugin_server/py/plugin/payload/payload_generator.py b/plugin_server/py/plugin/payload/payload_generator.py index a63054ca..79f3cd9c 100644 --- a/plugin_server/py/plugin/payload/payload_generator.py +++ b/plugin_server/py/plugin/payload/payload_generator.py @@ -15,9 +15,7 @@ class PayloadGenerator: SECRET_LENGTH = 8 TOKEN_CALLBACK_SERVER_URL = '$TSUNAMI_PAYLOAD_TOKEN_URL' - TOKEN_CALLBACK_SERVER_URL_LINUX_RCE = '$TSUNAMI_PAYLOAD_TOKEN_URL_LINUX_RCE' TOKEN_RANDOM_STRING = '$TSUNAMI_PAYLOAD_TOKEN_RANDOM' - UNDEF_VAL = '${TCS_UNDEF}' def __init__( self, @@ -112,13 +110,9 @@ def _parse_payload( """Create payload from the selected payload definition.""" secret = self.payload_secret_generator.generate(self.SECRET_LENGTH) if bool(payload.uses_callback_server.ByteSize()): - callback_uri = self.tcs_client.get_callback_uri(secret) payload_string = payload.payload_string.value.replace( - self.TOKEN_CALLBACK_SERVER_URL_LINUX_RCE, - _generate_linux_rce_callback_uri(callback_uri), - ).replace( self.TOKEN_CALLBACK_SERVER_URL, - callback_uri, + self.tcs_client.get_callback_uri(secret), ) validator = type( 'PayloadValidator', @@ -131,32 +125,32 @@ def _parse_payload( pg.PayloadAttributes(uses_callback_server=True), config, ) - - payload_string = payload.payload_string.value.replace( - self.TOKEN_RANDOM_STRING, secret - ) - if payload.validation_type != pg.PayloadValidationType.Value( - 'VALIDATION_REGEX' - ): - raise NotImplementedError( - 'Validation type %s not supported.' - % pg.PayloadGeneratorConfig.VulnerabilityType.Name( - config.vulnerability_type) - ) - regex = payload.validation_regex.value.replace( - self.TOKEN_RANDOM_STRING, secret - ) - validator = type( - 'PayloadValidator', - (Validator,), - {'is_executed': _is_executed(regex)}, - )() - return Payload( - payload_string, - validator, - pg.PayloadAttributes(uses_callback_server=False), - config, - ) + else: + payload_string = payload.payload_string.value.replace( + self.TOKEN_RANDOM_STRING, secret + ) + if payload.validation_type != pg.PayloadValidationType.Value( + 'VALIDATION_REGEX' + ): + raise NotImplementedError( + 'Validation type %s not supported.' + % pg.PayloadGeneratorConfig.VulnerabilityType.Name( + config.vulnerability_type) + ) + regex = payload.validation_regex.value.replace( + self.TOKEN_RANDOM_STRING, secret + ) + validator = type( + 'PayloadValidator', + (Validator,), + {'is_executed': _is_executed(regex)}, + )() + return Payload( + payload_string, + validator, + pg.PayloadAttributes(uses_callback_server=False), + config, + ) def _payload_matches_config( self, @@ -183,11 +177,3 @@ def check_payload_execution(_, data: Optional[bytes]) -> bool: return bool(re.compile(regex).search(string)) or False return check_payload_execution - - -def _generate_linux_rce_callback_uri(callback_uri: str) -> str: - return ( - callback_uri[0 : len(callback_uri) // 2] - + PayloadGenerator.UNDEF_VAL - + callback_uri[len(callback_uri) // 2 :] - ) diff --git a/plugin_server/py/plugin/payload/payload_generator_test.py b/plugin_server/py/plugin/payload/payload_generator_test.py index fd2bd1a4..6a474785 100644 --- a/plugin_server/py/plugin/payload/payload_generator_test.py +++ b/plugin_server/py/plugin/payload/payload_generator_test.py @@ -43,11 +43,7 @@ def test_is_callback_server_enabled_returns_true(self): self.assertTrue(self.payload_generator.is_callback_server_enabled()) @parameterized.named_parameters( - ( - 'linux_config', - LINUX_REFLECTIVE_RCE_CONFIG, - 'curl', - ), + ('linux_config', LINUX_REFLECTIVE_RCE_CONFIG, 'curl'), ( 'ssrf_config', ANY_SSRF_CONFIG, @@ -59,16 +55,10 @@ def test_generate_with_callback_returns_payload( ): payload = self.payload_generator.generate(config) self.assertIn(expected_payload, payload.payload) - self.assertIn( - _IP_ADDRESS, payload.payload.replace(PayloadGenerator.UNDEF_VAL, '') - ) + self.assertIn(_IP_ADDRESS, payload.payload) self.assertIn(str(_PORT), payload.payload) self.assertTrue(payload.get_payload_attributes().uses_callback_server) - def test_generate_with_callback_returns_undef_val_placeholder(self): - payload = self.payload_generator.generate(LINUX_REFLECTIVE_RCE_CONFIG) - self.assertIn(PayloadGenerator.UNDEF_VAL, payload.payload) - @parameterized.named_parameters( ( 'linux_config',