Execution (TA0002)(external, opens in a new tab or window)
Command and Control (TA0011)(external, opens in a new tab or window)
text code block:FROM logs-aws.cloudtrail*, logs-endpoint.events.process-* METADATA _id, _version, _index | WHERE // CloudTrail SSM SendCommand with AWS-RunShellScript ( event.dataset == "aws.cloudtrail" AND event.action == "SendCommand" AND aws.cloudtrail.request_parameters LIKE "*documentName=AWS-RunShellScript*" ) // Linux endpoint process events, prefiltered to SSM shell runner OR LOLBins/GTFOBins OR ( event.dataset == "endpoint.events.process" AND host.os.type == "linux" AND ( // SSM shell (_script.sh) runner process.command_line LIKE "%/document/orchestration/%/awsrunShellScript/%/_script.sh" // LOLBins / GTFOBins OR process.name IN ( "base64", "curl", "wget", "openssl", "nc", "ncat", "netcat", "socat", "python", "python3", "perl", "php", "ruby", "ssh", "scp", "sftp", "rsync" ) ) ) // Endpoint leg: extract SSM command ID from parent command line | DISSECT process.parent.command_line "%{}/document/orchestration/%{Esql.process_parent_command_line_ssm_command_id}/%{}" // CloudTrail leg: extract SSM command ID from response_elements | DISSECT aws.cloudtrail.response_elements "%{}commandId=%{Esql.aws_cloudtrail_response_elements_ssm_command_id},%{}" // Coalesce SSM command ID from both data sources | EVAL Esql.aws_ssm_command_id = COALESCE( Esql.aws_cloudtrail_response_elements_ssm_command_id, Esql.process_parent_command_line_ssm_command_id ) | WHERE Esql.aws_ssm_command_id IS NOT NULL // Role flags | EVAL Esql.is_cloud_event = event.dataset == "aws.cloudtrail" | EVAL Esql.is_endpoint_event = event.dataset == "endpoint.events.process" // Identify the SSM shell processes (the _script.sh runners) | EVAL Esql.is_ssm_shell_process = Esql.is_endpoint_event AND process.command_line LIKE "%/document/orchestration/%/awsrunShellScript/%/_script.sh" // LOLBins / GTFOBins on Linux | EVAL Esql.is_lolbin_process = Esql.is_endpoint_event AND NOT Esql.is_ssm_shell_process // Aggregate per SSM command ID | STATS // Core correlation counts & timing Esql.aws_cloudtrail_event_count = SUM(CASE(Esql.is_cloud_event, 1, 0)), Esql.endpoint_events_process_lolbin_count = SUM(CASE(Esql.is_lolbin_process, 1, 0)), Esql.endpoint_events_process_ssm_shell_count = SUM(CASE(Esql.is_ssm_shell_process, 1, 0)), Esql.aws_cloudtrail_first_event_ts = MIN(CASE(Esql.is_cloud_event, @timestamp, null)), Esql.endpoint_events_process_first_lolbin_ts = MIN(CASE(Esql.is_lolbin_process, @timestamp, null)), // AWS / CloudTrail identity & request context Esql_priv.aws_cloudtrail_user_identity_arn_values = VALUES(CASE(Esql.is_cloud_event, aws.cloudtrail.user_identity.arn, null)), Esql_priv.aws_cloudtrail_user_identity_access_key_id_values = VALUES(CASE(Esql.is_cloud_event, aws.cloudtrail.user_identity.access_key_id, null)), Esql_priv.user_name_values = VALUES(CASE(Esql.is_cloud_event, user.name, null)), // AWS environment / request metadata Esql.cloud_region_values = VALUES(CASE(Esql.is_cloud_event, cloud.region, null)), Esql.source_ip_values = VALUES(CASE(Esql.is_cloud_event, source.ip, null)), Esql.user_agent_original_values = VALUES(CASE(Esql.is_cloud_event, user_agent.original, null)), // Endpoint host & user context Esql.host_name_values = VALUES(CASE(Esql.is_endpoint_event, host.name, null)), Esql_priv.endpoint_user_name_values = VALUES(CASE(Esql.is_endpoint_event, user.name, null)), // SSM shell processes on endpoint Esql.process_command_line_ssm_shell_values = VALUES(CASE(Esql.is_ssm_shell_process, process.command_line, null)), Esql.process_pid_ssm_shell_values = VALUES(CASE(Esql.is_ssm_shell_process, process.pid, null)), // LOLBin processes on endpoint Esql.process_name_lolbin_values = VALUES(CASE(Esql.is_lolbin_process, process.name, null)), Esql.process_executable_lolbin_values = VALUES(CASE(Esql.is_lolbin_process, process.executable, null)), Esql.process_command_line_lolbin_values = VALUES(CASE(Esql.is_lolbin_process, process.command_line, null)), Esql.process_pid_lolbin_values = VALUES(CASE(Esql.is_lolbin_process, process.pid, null)), Esql.process_parent_command_line_lolbin_values = VALUES(CASE(Esql.is_lolbin_process, process.parent.command_line, null)), Esql.data_stream_namespace_values = VALUES(data_stream.namespace) BY Esql.aws_ssm_command_id // Detection condition: SSM SendCommand + AWS-RunShellScript + LOLBin on endpoint | WHERE Esql.aws_cloudtrail_event_count > 0 AND Esql.endpoint_events_process_lolbin_count > 0 AND DATE_DIFF( "minutes", Esql.endpoint_events_process_first_lolbin_ts, Esql.aws_cloudtrail_first_event_ts ) <= 5 | SORT Esql.aws_cloudtrail_first_event_ts ASC | KEEP Esql.*, Esql_priv.*
Install detection rules in Elastic Security
Detect AWS EC2 LOLBin Execution via SSM SendCommand in the Elastic Security detection engine by installing this rule into your Elastic Stack.
To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).