diff --git a/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI.textproto new file mode 100644 index 000000000..c8c780897 --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI.textproto @@ -0,0 +1,113 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "OmnilabATS_ExposedUI" + author: "Giacomo Coluccelli " + version: "0.1" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "OMNILAB_ATS_EXPOSED_UI" + } + title: "Exposed Omnilab Android Test Station instance" + description: "OmniLab ATS (Android Test Station) is publicly accessible without authentication. This exposes device management, test execution capabilities, and potentially sensitive configuration data. Attackers can access connected Android devices, execute arbitrary tests, view test results, and manage the testing infrastructure." + recommendation: + "1. Implement authentication using a reverse proxy (nginx/Apache) with HTTP Basic Auth or OAuth" + "2. Restrict network access using firewall rules to trusted IP ranges only" + "3. Deploy behind VPN for remote access" + "4. Use SSH tunneling for administrative access" + "5. Enable TLS/HTTPS with valid certificates" + severity: CRITICAL +} + +########### +# ACTIONS # +########### + +actions { + name: "omnilab_ats_exposed_ui_fingerprint" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_all: { + conditions: [ + { body {} contains: "Android Test Station" }, + { body {} contains: "OmniLab" } + ] + } + } + } +} + +actions { + name: "omnilab_ats_exposed_ui_create_build" + http_request: { + method: POST + uri: "/_ah/api/mtt/v1/builds" + headers: [ + { name: "Content-Type" value: "application/json" } + ] + data: "{\"name\":\"Tsunami Build\",\"fingerprint\":\"Tsunami Fingerprint\",\"file_url\":\"\",\"size\":0,\"labels\":[]}" + response: { + http_status: 200 + expect_all: { + conditions: { body {} contains: "\"id\":"} + } + extract_all: { + patterns: { from_body: {} regexp: "\"id\": \"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\"" variable_name: "BUILD_ID" } + } + } + } + cleanup_actions: "omnilab_ats_exposed_ui_delete_build" +} + +actions { + name: "omnilab_ats_exposed_ui_delete_build" + http_request: { + method: DELETE + uri: "/_ah/api/mtt/v1/builds?build_ids={{ BUILD_ID }}" + response: { + http_status: 204 + } + } +} + +actions { + name: "omnilab_ats_exposed_ui_verify_build_creation" + http_request: { + method: GET + uri: "/_ah/api/mtt/v1/builds/{{ BUILD_ID }}" + response: { + http_status: 200 + expect_all: { + conditions: [ + { body {} contains: "\"fingerprint\": \"Tsunami Fingerprint\"" }, + { body {} contains: "\"id\": \"{{ BUILD_ID }}\"" }, + { body {} contains: "\"name\": \"Tsunami Build\"" } + ] + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + actions: [ + "omnilab_ats_exposed_ui_fingerprint", + "omnilab_ats_exposed_ui_create_build", + "omnilab_ats_exposed_ui_verify_build_creation" + ] +} diff --git a/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI_test.textproto b/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI_test.textproto new file mode 100644 index 000000000..80a429f15 --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/OmnilabATS_ExposedUI_test.textproto @@ -0,0 +1,64 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "OmnilabATS_ExposedUI" +} + +tests: { + name: "whenNotATS_returnsFalse" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + } + ] + } +} + +tests: { + name: "whenATSAndVulnerable_returnsTrue" + expect_vulnerability: true + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: "Android Test Station" + }, + { + uri: "/_ah/api/mtt/v1/builds" + status: 200 + body_content: "{\"fingerprint\": \"Tsunami Fingerprint\",\"id\": \"0a0fd6f0-8241-4f76-abfc-493a245b37fd\",\"name\": \"Tsunami Build\"}" + }, + { + uri: "/_ah/api/mtt/v1/builds/0a0fd6f0-8241-4f76-abfc-493a245b37fd" + status: 200 + body_content:"{\"fingerprint\": \"Tsunami Fingerprint\",\"id\": \"0a0fd6f0-8241-4f76-abfc-493a245b37fd\",\"name\": \"Tsunami Build\"}" + }, + { + uri: "/_ah/api/mtt/v1/builds?build_ids=0a0fd6f0-8241-4f76-abfc-493a245b37fd" + status: 204 + } + ] + } +} + +tests: { + name: "whenATSAndNotVulnerable_returnsFalse" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 401 + body_content: "401 Authorization Required" + } + ] + } +}