Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"
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"
]
}
Original file line number Diff line number Diff line change
@@ -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: "<html><head><title>Android Test Station</title></head><body><mtt></mtt><script>window.APP_DATA = {isOmniLabBased: \"False\" === \"True\",};</script></body></html>"
},
{
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: "<html><head><title>401 Authorization Required</title></head><body></body></html>"
}
]
}
}