-
Notifications
You must be signed in to change notification settings - Fork 299
Development
WatchAD Root directory
├─libs Referenced libraries
├─models Data objects
├─modules Main modules
│ ├─alert Alarm handle
│ ├─detect Threat detections
│ │ ├─event_log Detections based on event log
│ │ │ ├─ ... ... Detection files
│ │ │ └─record Record the activities of entries
│ │ └─traffic_kerberos Detections based on kerberos traffic (not open source)
│ └─record_handle Other Information Object Handle
├─scripts Scripts used for installation, crontab and etc.
├─settings Project profile
├─tools Tool functions
├─start.py Detection Engine Start
├─WatchAD.py Project main program, installation, start, stop, etc.
└─supervisor.conf Supervisor settings
WatchAD allows users to write their own add-on detection modules. The following is an example of the Modification of sensitive group
module to explain how to write a custom module.
In the directory {project_home}/modules/detect/event_log
,there are six directories classified by threat types. The record
directory, which is used to record related activities of entities in AD.
Depending on the current threat type,the Modification of sensitive group module,which is generally used to persistence and should be stored in the {project_home}/modules/detect/event_log/persistence
directory. Now, let’s create a file called ModifySensitiveGroup.py
in this directory.
After creating the new file, we need to define the event log ID list
, threat type code
, title
and description template
that the current module needs to analyze. By testing the attack in the test environment and querying related documentation, we know that adding users to the security group triggers three events: 4728
, 4732
, and 4756
.
Next, We need to determine the threat type code and it must not be duplicated with existing code. You can classify by threat type. For example, persistence starts with 5.
Finally, the description template is used to outline the status of threat activity. The field name wrapped by []
corresponds to the following alarm content field, and is automatically replaced when displayed on the web platform.
EVENT_ID = [4728, 4732, 4756]
ALERT_CODE = "506"
TITLE = "Modification of sensitive group"
DESC_TEMPLATE = "From [source_ip]([source_workstation]) added the target user [target_user_name] to the sensitive group [group_name] using the identity [source_user_name]"
After that, import DetectBase class, create a class with the same name as the file name, inherit DetectBase, implement the _generate_alert_doc
and _get_level
methods.
from settings.config import main_config
from models.Log import Log
from modules.detect.DetectBase import DetectBase, HIGH_LEVEL
from tools.common.common import get_cn_from_dn
EVENT_ID = [4728, 4732, 4756]
ALERT_CODE = "506"
TITLE = "Modification of sensitive group"
DESC_TEMPLATE = "From [source_ip]([source_workstation]) added the target user [target_user_name] to the sensitive group [group_name] using the identity [source_user_name]"
class ModifySensitiveGroup(DetectBase):
def __init__(self):
super().__init__(code=ALERT_CODE, title=TITLE, desc=DESC_TEMPLATE)
def run(self, log: Log):
# init the module, necessary
self.init(log=log)
group_name = log.target_info.user_name
# Dynamically configured list of sensitive groups
sensitive_groups = list(map(lambda x: x["name"], main_config.sensitive_groups))
# If the modified group exists in the sensitive group, the alarm is generated.
if group_name in sensitive_groups:
return self._generate_alert_doc()
def _generate_alert_doc(self, **kwargs) -> dict:
# Find the IP address at login by login name and login ID
source_ip = self._get_source_ip_by_logon_id(self.log.subject_info.logon_id,
self.log.subject_info.full_user_name)
form_data = {
# Recommended necessary field
"source_ip": source_ip,
"source_workstation": self._get_workstation_by_source_ip(source_ip),
"source_user_name": self.log.subject_info.user_name,
"group_name": self.log.target_info.user_name,
"target_user_name": get_cn_from_dn(self.log.event_data["MemberName"]),
# The following fields are optional
... ...
}
doc = self._get_base_doc(
level=self._get_level(),
# Uniquely identify an alert based on threat activity code and source username
unique_id=self._get_unique_id(self.code, self.log.subject_info.user_name),
form_data=form_data
)
return doc
def _get_level(self) -> str:
return HIGH_LEVEL
Briefly explain the above code,
-
from models.Log import Log
:This is a simple encapsulated log object that turns the dictionary object into an object property to access, reducing spelling errors. You can view the code content of theLog
class. -
_get_level
:level of current threat activity,_generate_alert_doc
return the document of the alarm content. -
_generate_alert_doc
:-
form_data
:Used to customize save information about current threat activity,Such as source ip address(source_ip), source workstation name(source_workstation), source user name(source_user_name), target user name(target_user_name and so on. You can save different fields for each threat activity, but the field names that express the same meaning must be the same. For example, you can't set the field name of the source user name:source_user. However, some content is required. You can use the following ideas to decide which fields to set: "Who sourced from which IP and host, what did it do, who is the target", you can refer to the content of other detection modules. -
unique_id
: Used to merge duplicate alarms, usually threat activity code + source user name or source IP -
level
: threat level
-
-
run
: Main function to run the module. The parameter log is the current need to analyze the log. Because we have specified 4728, 4732, 4756 three kinds of logs, so the logs appear here will only have these three types.-
self.init(log=log)
:This line of code must be at the beginning of the function and for initializing the current detection module environment. Each new log will be re-run therun
function. -
return value:If there are no threat activities, return Null. If a threat is found, return the
self._generate_alert_doc()
alert document and the engine will automatically perform the next operations.
-