作者:来自 Elastic Kevin Umsted
安全团队面临着无休止的警报、复杂的调查以及资源有限的艰巨挑战。这不仅是要发现威胁,还要快速且高效地应对。Elastic Security 一直提供用于检测、调查和响应的预构建能力。但真正让 Elastic 脱颖而出的是其开放、以 API 为先的方式,使你能够在安全运营中心(SOC)构建并自动化特定的工作流程。
在这篇博客中,我们将展示 Elastic 可扩展 API 如何通过一个常见的 “实例” 解锁 AI 驱动的安全编排、自动化与响应(security orchestration, automation, and response - SOAR)新可能性。你将学习如何结合 Elastic 的安全平台、AI 以及像 Slack 这样的协作工具来设计、自动化并持续完善你自己的响应剧本。
利用 Elastic API 强化你的工作流程
在这个场景中,SOC 的检测工程团队正面临一个熟悉的难题:未能满足关键警报的服务水平目标。尽管团队已部署了强大的工具来提高平均响应时间(mean time to respond - MTTR),但仍在努力应对庞大而紧迫的警报量。因此,一些关键警报有时会被延迟处理,甚至未能在预期时间内解决。为了解决这一问题,团队希望借助自动化、AI 以及 Elastic 强大的 API 进一步优化工作流程。
现在,想象这样一个工作流程:每个关键警报都能被一致地检测、分类并响应,分析人员能全程引导并监督每一步。以下是如何使用 Elastic 灵活的 API 和像 Slack 这样的常用协作工具实现这一解决方案。
我们来分解这个项目的步骤:
-
使用 Elasticsearch Python 客户端监控一个 Elastic 集群。
-
监控任何被标记为关键的警报。
-
将警报 JSON 通过 API 发送给 Elastic AI Assistant for Security。
-
获取 AI 响应。
-
将 AI 响应发布到 Slack 频道。
-
在 Slack 消息中标记相关安全分析人员,以通知他们并在 Slack 中直接进行操作。
事件时间线
让我们来梳理一下事件的时间线。首先,Elastic Security 收到一个关键警报,涉及一台受端点检测与响应(Elastic Defend)保护的重要 Windows 服务器。在这个案例中,Elastic 检测到 Windows Management Instrumentation (WMI) 被用来创建注册表项,从而实现对该关键服务器的持久访问。
Elastic Security 警报:
Python 可以每分钟查询一次 Elastic,以获取任何关键警报。当发现此类警报时,将提取警报的完整 JSON 有效负载以进行处理。下面是一个可用于实时监控 Elastic 中关键警报的 Python 示例:
es = Elasticsearch(
os.getenv("ELASTICSEARCH_URL"),
api_key=ELASTICSEARCH_API_KEY
)
def monitor_alerts():
from datetime import datetime, timedelta, timezone
import time
polling_interval = 60 # Poll every 60 seconds
index_patterns = {
"endpoint": {
"pattern": ".ds-logs-endpoint.alerts*",
"timestamp_field": "Responses.@timestamp"
},
"security": {
"pattern": ".internal.alerts-security.alerts-default-*",
"timestamp_field": "@timestamp"
}
}
last_timestamps = {
key: datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
for key in index_patterns
}
while True:
for key, config in index_patterns.items():
pattern = config["pattern"]
ts_field = config["timestamp_field"]
query = {
"query": {
"bool": {
"filter": [
{"range": {ts_field: {"gt": last_timestamps[key]}}},
{"term": {"kibana.alert.severity": "critical"}}
]
}
},
"sort": [{ts_field: {"order": "asc"}}]
}
try:
response = es.search(index=pattern, body=query)
alerts = response['hits']['hits']
if alerts:
print(f"Found {len(alerts)} critical alert(s) for {key} since {last_timestamps[key]}")
max_ts = last_timestamps[key]
for alert in alerts:
alert_id = alert.get('_id')
if alert_id in processed_alert_ids:
continue
processed_alert_ids.add(alert_id)
alert_json = alert['_source']
process_alert(alert_json)
alert_ts = get_custom_alert_timestamp(alert_json, ts_field)
if alert_ts and alert_ts > max_ts:
max_ts = alert_ts
dt = datetime.fromisoformat(max_ts.replace("Z", "+00:00"))
dt += timedelta(seconds=1)
last_timestamps[key] = dt.isoformat().replace("+00:00", "Z")
except Exception as e:
print(f"Error fetching critical alerts for {key}: {str(e)}")
time.sleep(polling_interval)
捕获的 JSON 然后通过 API 请求发送到 Elastic AI Assistant for Security。一个 prompt 会附加到该 JSON,以为 AI Assistant 提供生成适当响应所需的上下文。
Python prompt 代码:
def process_alert(alert_json):
alert_str = json.dumps(alert_json, indent=2)
prompt = (
f"Please look at this JSON:\n{alert_str}\n\n"
"You are a security analyst and you want to run commands to start a forensic investigation for this alert. "
"Make sure you summarize the alert in one paragraph. "
"Summarize the alert and then give 5 commands that you would run to start your IR investigation. "
"The next 3 commands should be dedicated to commands that would remediate the malware or malicious activity. "
"The total commands should be 8. Make sure you include the affected host via the IP address in the alert summary. "
"The commands should be in a list format and clearly separated into Investigation Commands and Remediation Commands. For example: \n"
"Investigation Commands:\n1. command\n2. command\n... \nRemediation Commands:\n1. command\n2. command\n..."
) print("Alert Received")
response = chat_complete(prompt)
print("AI Responded")
Python API 调用:
def chat_complete(question, thread_ts=None, use_existing_conversation=False):
url = f"{KIBANA_URL}/api/security_ai_assistant/chat/complete"
headers = {
"kbn-xsrf": "true",
"Content-Type": "application/json",
}
payload = {
"messages": [{"role": "user", "content": question}],
"connectorId": CONNECTOR_ID,
"persist": True
}
if use_existing_conversation and thread_ts and thread_ts in conversation_map:
payload["conversationId"] = conversation_map[thread_ts]
response = requests.post(
url,
auth=(USERNAME, PASSWORD),
headers=headers,
json=payload,
stream=True
)
response.raise_for_status()
full_response = ""
for line in response.iter_lines():
if line:
decoded_line = line.decode('utf-8')
try:
event = json.loads(decoded_line)
if "data" in event:
full_response += event["data"]
if "conversationId" in event and thread_ts:
conversation_map[thread_ts] = event["conversationId"]
except json.JSONDecodeError:
continue
return full_response.strip()
AI 助手接收 API 请求并使用大型语言模型(LLM)生成响应。这个响应包括一个可操作的警报摘要以及推荐的调查和缓解命令。
AI 助手还可以确定应该在 Slack 消息中标记哪位分析师。它通过查询一个包含 SOC 中分析师信息的自定义知识库来实现这一点。这个自定义知识功能非常强大,大幅提升了 AI 助手的有效性。
通过在自定义知识库中集中机构知识,AI 助手最大限度地减少了获取关键信息的延迟。这提升了整个 SOC 的操作工作流程的速度和一致性。
了解如何设置自定义 AI 助手知识库。
一旦 AI 助手返回其响应,使用 Python 将消息及相应的分析人员 @ 提及发送到指定的 Slack 频道。
将响应发送到 Slack:
response = chat_complete(prompt)
print("AI Responded")
if response:
clean_response = response.replace("**", "")
inv_match = re.search(r"(?i)\s*Investigation Commands:\s*", clean_response)
rem_match = re.search(r"(?i)\s*Remediation Commands:\s*", clean_response)
if not inv_match or not rem_match:
print("Could not find both 'Investigation Commands:' and 'Remediation Commands:' in the response.")
return
summary = clean_response[:inv_match.start()].strip()
inv_commands_part = clean_response[inv_match.end():rem_match.start()].strip()
rem_commands_part = clean_response[rem_match.end():].strip()
inv_commands = re.findall(r"^\s*\d+\.\s+(.+)$", inv_commands_part, re.MULTILINE)
rem_commands = re.findall(r"^\s*\d+\.\s+(.+)$", rem_commands_part, re.MULTILINE)
# Extract the handler from AI (e.g., "Who handles critical windows alerts?")
handler_question = f"Who handles {operating_system.lower()} alerts? Respond with just their name."
handler_response = chat_complete(handler_question).strip()
handler_id = get_user_id_by_name(handler_response)
handler_mention = f"<@{handler_id}>" if handler_id else handler_response
full_message = (
f"New Alert Detected\n\n{clean_response}\n\n"
f"Alert assigned to:\n{handler_mention}\n\n"
"Do you want me to run the investigation and remediation commands?"
)
blocks = [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": full_message
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Yes"},
"action_id": "run_commands",
"value": "run"
},
{
"type": "button",
"text": {"type": "plain_text", "text": "No"},
"action_id": "do_not_run",
"value": "do_not_run"
}
]
}
]
result = app.client.chat_postMessage(
channel=ALERT_CHANNEL,
blocks=blocks,
text="New Alert Detected"
)
alert_data_map[result['ts']] = {
"alert_json": alert_json,
"investigation_commands": inv_commands,
"remediation_commands": rem_commands,
"host_ip": host_ip,
"ai_summary": summary
}
Slack 消息:
此阶段,Slack 消息会生成,包含警报的有意义摘要、受影响的主机,以及建议的调查和修复命令列表。分配给该警报的分析人员会在消息中被 @ 提及,并且会看到“是/否”选项,用于批准在主机上执行命令。
在此场景中,分析人员点击“是”并批准自动响应。
为了执行命令,使用 Python 和 Windows 远程管理(WinRM)。受影响主机的 IP 地址和命令列表会从 AI 助手的响应中提取,并按顺序在目标机器上执行。
Python 命令执行:
import winrm
def execute_winrm_command(host_ip: str, command: str, winrm_domain: str, winrm_username: str, winrm_password: str) -> str:
session = winrm.Session(
host_ip,
auth=(f"{winrm_domain}\\{winrm_username}", winrm_password),
transport='ntlm'
)
full_cmd = (
"$ProgressPreference = 'SilentlyContinue'; "
"$VerbosePreference = 'SilentlyContinue'; "
"$WarningPreference = 'SilentlyContinue'; "
f"try {{ {command} | Format-List | Out-String -Width 120 }} "
"catch {{ 'Error: ' + $_.Exception.Message }}"
)
result = session.run_ps(full_cmd)
output = result.std_out.decode('utf-8', errors='ignore').strip()
return output if output else "No output returned."
def execute_winrm_commands(host_ip: str, commands: list, winrm_domain: str, winrm_username: str, winrm_password: str) -> dict:
outputs = {}
session = winrm.Session(
host_ip,
auth=(f"{winrm_domain}\\{winrm_username}", winrm_password),
transport='ntlm'
)
for command in commands:
full_cmd = (
"$ProgressPreference = 'SilentlyContinue'; "
"$VerbosePreference = 'SilentlyContinue'; "
"$WarningPreference = 'SilentlyContinue'; "
f"try {{ {command} | Format-List | Out-String -Width 120 }} "
"catch {{ 'Error: ' + $_.Exception.Message }}"
)
result = session.run_ps(full_cmd)
output = result.std_out.decode('utf-8', errors='ignore').strip()
outputs[command] = output if output else "No output returned."
return outputs
分析人员执行的命令:
每个操作都被完整跟踪和可审计。应用程序为每个事件在 Elastic Security 中创建一个新案例,并附上所有 AI 摘要、执行的命令以及响应过程中生成的所有输出,确保所有证据都被保存以备将来参考或合规需求。
Python 创建案例代码:
def create_case(alert_json, command_output, ai_summary):
description = ai_summary + "\n\n"
if command_output:
description += "Commands Executed:\n\n"
for cmd, output in command_output.items():
truncated_output = output[:500] + "..." if len(output) > 500 else output
description += f"Command: `{cmd}`\n\nOutput:\n```\n{truncated_output}\n```\n\n"
if len(description) > 30000:
description = description[:29997] + "..."
title = "Investigation for Alert"
case_payload = {
"title": title,
"description": description,
"tags": ["auto-generated", "investigation"],
"connector": {"id": "none", "name": "none", "type": ".none", "fields": None},
"owner": "securitySolution",
"settings": {"syncAlerts": True},
"severity": "medium"
}
url = f"{KIBANA_URL}/api/cases"
headers = {"kbn-xsrf": "true", "Content-Type": "application/json"}
try:
response = requests.post(
url,
auth=(USERNAME, PASSWORD),
headers=headers,
json=case_payload
)
if response.status_code == 200:
case_id = response.json().get('id')
print(f"Successfully created case: {case_id}")
return case_id
else:
print(f"Failed to create case: {response.status_code} - {response.text}")
return None
except requests.RequestException as e:
print(f"Request failed: {str(e)}")
return None
Kibana 安全案例:
Elastic 提供无与伦比的灵活性
Elastic Security 不仅限于开箱即用的检测和响应,还支持无缝集成企业 AI 和协作工具(如 Slack)的定制自动化流程。
利用 Elastic 强大的 APIs 和开源基础,我们能够:
-
编程式监控关键警报
-
使用 Elastic AI Assistant for Security 生成富有上下文的可操作响应
-
以可控、可审计的方式自动化分类和补救
-
直接集成到分析师每天使用的协作工具中
Elastic 开放、API 优先的架构为安全团队提供了无与伦比的灵活性,可以构建最适合他们的工作流程。这就是基于 Elastic 构建的力量。无论你是通过 AI 扩展响应能力,自定义警报工作流程,还是将 Elastic 嵌入现有的 SecOps 堆栈,平台都设计成以你需要的方式工作。
Elastic 为 AI 驱动的 SOAR 提供无与伦比的灵活性
准备好自己动手了吗?
开始使用 Elastic AI Assistant API 文档构建你的工作流,或者联系我们深入了解 Elastic 开放平台如何满足你独特的 SOC 需求。
本文中描述的任何功能或特性的发布时间和内容,完全由 Elastic 自行决定。任何当前不可用的功能可能无法按时或根本不会发布。
本文中可能使用或提及了第三方生成式 AI 工具,这些工具由各自所有者拥有和运营。Elastic 无法控制这些第三方工具,对其内容、操作或使用不承担任何责任,也不对你使用这些工具可能导致的任何损失或损害负责。使用 AI 工具处理个人、敏感或机密信息时请谨慎。你提交的任何数据可能会被用于 AI 训练或其他目的。无法保证你提供的信息会被安全或保密地保存。你应在使用前熟悉任何生成式 AI 工具的隐私政策和使用条款。
Elastic、Elasticsearch 及相关标志是 Elasticsearch N.V. 在美国及其他国家的商标、徽标或注册商标。所有其他公司和产品名称均为其各自所有者的商标、徽标或注册商标。
原文:Harnessing Elastic APIs for custom AI-driven SOAR | Elastic Blog