etw tampering pipeline rule and registery setting in agent.conf (#273)
taylor_socfortress committed
Jul 12, 2024 at 14:22 UTC
e76fc72fed406cde4803dbb416879177f82e9a91
6 files changed
+93
-1
backend/app/connectors/graylog/schema/pipelines.py
+5
@@ -69,3 +69,8 @@ class CreatePipeline(BaseModel):
69
title: str
70
description: str
71
source: str
72
+
73
+
74
+class ModifyPipeline(BaseModel):
75
+ pipeline_id: str
76
+ source: str
backend/app/connectors/graylog/services/pipelines.py
+13
@@ -4,11 +4,13 @@ from loguru import logger
4
from app.connectors.graylog.schema.pipelines import CreatePipeline
5
from app.connectors.graylog.schema.pipelines import CreatePipelineRule
6
from app.connectors.graylog.schema.pipelines import GraylogPipelinesResponse
7
+from app.connectors.graylog.schema.pipelines import ModifyPipeline
8
from app.connectors.graylog.schema.pipelines import Pipeline
9
from app.connectors.graylog.schema.pipelines import PipelineRule
10
from app.connectors.graylog.schema.pipelines import PipelineRulesResponse
11
from app.connectors.graylog.utils.universal import send_get_request
12
from app.connectors.graylog.utils.universal import send_post_request
13
+from app.connectors.graylog.utils.universal import send_put_request
14
from app.customer_provisioning.schema.graylog import StreamConnectionToPipelineRequest
15
from app.customer_provisioning.schema.graylog import StreamConnectionToPipelineResponse
16
@@ -144,6 +146,17 @@ async def create_pipeline_graylog(pipeline: CreatePipeline) -> None:
146
await send_post_request(endpoint=endpoint, data=data)
147
148
149
+async def modify_pipeline_graylog(pipeline: ModifyPipeline) -> None:
150
+ """
151
+ Modifies a pipeline with the given title in Graylog.
152
+ """
153
+ endpoint = f"/api/system/pipelines/pipeline/{pipeline.pipeline_id}"
154
+ data = {
155
+ "source": pipeline.source,
156
+ }
157
+ await send_put_request(endpoint=endpoint, data=data)
158
+
159
+
160
async def get_pipeline_id(subscription: str) -> str:
161
"""
162
Retrieves the pipeline ID for a given subscription.
backend/app/connectors/graylog/utils/universal.py
+1
-1
@@ -271,7 +271,7 @@ async def send_put_request(
271
Returns:
272
Dict[str, Any]: The response from the PUT request.
273
"""
274
- logger.info(f"Sending PUT request to {endpoint}")
274
+ logger.info(f"Sending PUT request to {endpoint} with payload {data}")
275
async with get_db_session() as session: # This will correctly enter the context manager
276
attributes = await get_connector_info_from_db(connector_name, session)
277
if attributes is None:
backend/app/customer_provisioning/templates/windows_agent.conf
+5
@@ -68,6 +68,11 @@
68
<windows_registry arch="both">HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows</windows_registry>
69
<windows_registry arch="both">HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon</windows_registry>
70
<windows_registry arch="both">HKEY_LOCAL_MACHINE\Software\Microsoft\Active Setup\Installed Components</windows_registry>
71
+ <!-- Added by SOCFortress For ETW Tampering -->
72
+ <windows_registry arch="both">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-Security</windows_registry>
73
+ <windows_registry arch="both">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-Application</windows_registry>
74
+ <windows_registry arch="both">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-System</windows_registry>
75
+ <windows_registry arch="both">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-Microsoft-Windows-Sysmon-Operational</windows_registry>
76
<!-- Windows registry entries to ignore. -->
77
<registry_ignore>HKEY_LOCAL_MACHINE\Security\Policy\Secrets</registry_ignore>
78
<registry_ignore>HKEY_LOCAL_MACHINE\Security\SAM\Domains\Account\Users</registry_ignore>
backend/app/stack_provisioning/graylog/routes/provision.py
+2
@@ -9,6 +9,7 @@ from app.stack_provisioning.graylog.schema.provision import (
9
from app.stack_provisioning.graylog.schema.provision import AvailbleContentPacksOverview
10
from app.stack_provisioning.graylog.schema.provision import ProvisionContentPackRequest
11
from app.stack_provisioning.graylog.schema.provision import ProvisionGraylogResponse
12
+from app.stack_provisioning.graylog.services.provision import check_pipeline_rules
13
from app.stack_provisioning.graylog.services.provision import provision_content_pack
14
from app.stack_provisioning.graylog.services.utils import does_content_pack_exist
15
from app.stack_provisioning.graylog.services.utils import system_version_check
@@ -50,6 +51,7 @@ async def provision_content_pack_route(
51
await system_version_check(compatible_version="5.0.13+083613e")
52
await does_content_pack_exist(content_pack_name=content_pack_request.content_pack_name.name)
53
await provision_content_pack(content_pack_request)
54
+ await check_pipeline_rules()
55
return ProvisionGraylogResponse(
56
success=True,
57
message=f"{content_pack_request.content_pack_name.name} Content Pack provisioned successfully",
backend/app/stack_provisioning/graylog/services/provision.py
+67
@@ -1,12 +1,18 @@
1
import json
2
+from enum import Enum
3
from pathlib import Path
4
+from typing import List
5
from uuid import uuid4
6
7
from fastapi import HTTPException
8
from loguru import logger
9
10
+from app.connectors.graylog.schema.pipelines import CreatePipelineRule
11
+from app.connectors.graylog.schema.pipelines import PipelineRulesResponse
12
from app.connectors.graylog.services.content_packs import insert_content_pack
13
from app.connectors.graylog.services.content_packs import install_content_pack
14
+from app.connectors.graylog.services.pipelines import create_pipeline_rule
15
+from app.connectors.graylog.services.pipelines import get_pipeline_rules
16
from app.stack_provisioning.graylog.schema.provision import AvailableContentPacks
17
from app.stack_provisioning.graylog.schema.provision import ProvisionContentPackRequest
18
from app.stack_provisioning.graylog.schema.provision import ProvisionGraylogResponse
@@ -173,6 +179,67 @@ async def provision_content_pack(content_pack_request: ProvisionContentPackReque
179
)
180
181
182
+class PipelineRuleTitles(Enum):
183
+ ETW = "Set Syslog Level to ALERT for ETW Registry"
184
+
185
+
186
+async def check_pipeline_rules() -> None:
187
+ """
188
+ Checks if the pipeline rules exist in Graylog. If they don't, create them.
189
+ """
190
+ pipeline_rules = await get_pipeline_rules()
191
+ non_existing_rules = await pipeline_rules_exists(pipeline_rules)
192
+ if non_existing_rules:
193
+ logger.info(f"Creating pipeline rules: {non_existing_rules}")
194
+ await create_pipeline_rules(non_existing_rules)
195
+
196
+
197
+async def pipeline_rules_exists(pipeline_rules: PipelineRulesResponse) -> List[str]:
198
+ """
199
+ Checks if the pipeline rules exist in Graylog and returns a list of non-existing pipeline rules.
200
+ """
201
+ return [
202
+ rule_title.value
203
+ for rule_title in PipelineRuleTitles
204
+ if not any(rule.title == rule_title.value for rule in pipeline_rules.pipeline_rules)
205
+ ]
206
+
207
+
208
+async def create_pipeline_rules(non_existing_rules: List[str]) -> None:
209
+ """
210
+ Creates the given pipeline rules.
211
+ """
212
+ rule_creators = {
213
+ "Set Syslog Level to ALERT for ETW Registry": create_etw_rule,
214
+ }
215
+
216
+ for rule_title in non_existing_rules:
217
+ logger.info(f"Creating pipeline rule {rule_title}.")
218
+ await rule_creators[rule_title](rule_title)
219
+
220
+
221
+async def create_etw_rule(rule_title: str) -> None:
222
+ """
223
+ Creates the 'Set Syslog Level to ALERT for ETW Registry' pipeline rule.
224
+ """
225
+ rule_source = (
226
+ f'rule "{rule_title}"\n'
227
+ "when\n"
228
+ ' has_field("syscheck_path") &&\n'
229
+ ' starts_with(to_string($message.syscheck_path), "HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\WMI\\\\Autologger\\\\EventLog")\n'
230
+ "then\n"
231
+ ' set_field("syslog_level", "ALERT");\n'
232
+ "end"
233
+ )
234
+ await create_pipeline_rule(
235
+ CreatePipelineRule(
236
+ title=rule_title,
237
+ description=rule_title,
238
+ source=rule_source,
239
+ ),
240
+ )
241
+
242
+
243
# ! NETWORK CONNECTOR CONTENT PACKS PROVISIONING ! #
244
async def filter_content_packs(content_packs, protocol_type):
245
if protocol_type == "TCP":