SOLDR modules first release

This commit is contained in:
Dmitry Ng
2022-11-22 02:21:28 +03:00
commit 2668031e7f
528 changed files with 61224 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
return {
_all = {
coverage = false
},
default = {
verbose = true
},
}
+22
View File
@@ -0,0 +1,22 @@
.DS_Store
dump.sql
dump_global.sql
dump_global_sec_cfg.sql
env.sh
docker_env.list
tools/sysmon.xml
.idea/
.venv/
.vscode/
tmpcwd/*
tmpdir/*
!.gitkeep
luacov-html
luacov.*
coverage-report
junit.xml
+3
View File
@@ -0,0 +1,3 @@
[submodule "luapower"]
path = luapower
url = git@github.com:capr/multigit.git
+111
View File
@@ -0,0 +1,111 @@
-- Get rid of "unused argument self"-warnings
self = false
-- The unit tests can use busted
files["**/*_spec.lua"].std = "+busted"
files["**/tests/*_spec.lua"].std = "+busted"
max_line_length=160
max_string_line_length=250
max_comment_line_length=320
exclude_files = {"tests_framework/*"}
read_globals = {
-- table
"table.unpack",
-- package
"package.searchers",
-- assert
"assert.is_true",
"assert.is_false",
-- yaci API
"newclass",
-- lightningmdb global object
"lightningmdb",
-- luajit API
"newproxy",
-- winapi module
"winapi",
-- command line arguments
"arg",
}
globals = {
"__api",
"__imc",
"__sec",
"__agents",
"__config",
"__routes",
"__args",
"__tmpdir",
-- agent or server version string
"__version",
-- agent ID (hash) string
"__aid",
-- group ID (hash) string
"__gid",
-- policy ID (hash) string
"__pid",
-- server connection properties
"__sconn",
-- logging global table
"__log",
-- monitoring global table
"__metric",
-- system variable
"__files",
-- mock variable to test modules
"__mock",
-- utils classes
"CFileReader",
"CReader",
-- correlator classes
"CEventEngine",
"CActionEngine",
"CCorrEngine",
"CBaseEngine",
-- uploader classes
"CUploaderResp",
-- wineventlog module aux class
"CModule",
"CWinEventLog",
-- responder template classes
"CActsEngine",
-- YARA classes
"CYaraModule",
"CDatabaseEngine",
-- lua 5.2 compat
"bit",
"loadstring",
"setfenv",
-- busted API
"describe",
"teardown",
"setup",
"it",
}
+80
View File
@@ -0,0 +1,80 @@
return {
--- Filename to store collected stats. Default: "luacov.stats.out".
statsfile = "luacov.stats.out",
--- Filename to store report. Default: "luacov.report.out".
reportfile = "luacov.report.out",
--- Enable saving coverage data after every `savestepsize` lines?
-- Setting this flag to `true` in config is equivalent to running LuaCov
-- using `luacov.tick` module. Default: false.
tick = false,
--- Stats file updating frequency for `luacov.tick`.
-- The lower this value - the more frequently results will be written out to the stats file.
-- You may want to reduce this value (to, for example, 2) to avoid losing coverage data in
-- case your program may terminate without triggering luacov exit hooks that are supposed
-- to save the data. Default: 100.
savestepsize = 100,
-- - Run reporter on completion? Default: false.
runreport = true,
--- Delete stats file after reporting? Default: false.
deletestats = true,
--- Process Lua code loaded from raw strings?
-- That is, when the 'source' field in the debug info
-- does not start with '@'. Default: false.
-- codefromstrings = false,
--- Lua patterns for files to include when reporting.
-- All will be included if nothing is listed.
-- Do not include the '.lua' extension. Path separator is always '/'.
-- Overruled by `exclude`.
-- @usage
-- include = {
-- "mymodule$", -- the main module
-- "mymodule%/.+$", -- and everything namespaced underneath it
-- }
-- include = {
-- },
--- Lua patterns for files to exclude when reporting.
-- Nothing will be excluded if nothing is listed.
-- Do not include the '.lua' extension. Path separator is always '/'.
-- Overrules `include`.
exclude = {
"tests_framework/",
"utils/"
},
--- Table mapping names of modules to be included to their filenames.
-- Has no effect if empty.
-- Real filenames mentioned here will be used for reporting
-- even if the modules have been installed elsewhere.
-- Module name can contain '*' wildcard to match groups of modules,
-- in this case corresponding path will be used as a prefix directory
-- where modules from the group are located.
-- @usage
-- modules = {
-- ["some_rock"] = "src/some_rock.lua",
-- ["some_rock.*"] = "src"
-- }
-- modules = {},
--- Enable including untested files in report.
-- Default: false.
-- includeuntestedfiles = false,
reporter = "cobertura",
cobertura = {
}
-- html = {
-- outputDirectory = "coverage-report",
-- projectName = "example"
-- }
}
+58
View File
@@ -0,0 +1,58 @@
FROM minio/mc
FROM mysql:5.7-debian
COPY --from=0 /usr/bin/mc /usr/bin/mc
ARG VXVERSION=unknown
# Directory for Monitor service modules
RUN mkdir -p /opt/vxmodules/mon
# End User License Agreement for SOLDR modules
COPY LICENSE /opt/vxmodules/
# Entrypoint script
COPY startup.sh /opt/vxmodules/
# SQL file generator script
COPY gen_sql.py /opt/vxmodules/
# Content for test loading modules from S3
COPY syslog /opt/vxmodules/mon/syslog
COPY sysmon /opt/vxmodules/mon/sysmon
COPY file_remover /opt/vxmodules/mon/file_remover
COPY file_uploader /opt/vxmodules/mon/file_uploader
COPY proc_terminator /opt/vxmodules/mon/proc_terminator
COPY wineventlog /opt/vxmodules/mon/wineventlog
COPY file_reader /opt/vxmodules/mon/file_reader
COPY correlator /opt/vxmodules/mon/correlator
COPY correlator_linux /opt/vxmodules/mon/correlator_linux
COPY yara_scanner /opt/vxmodules/mon/yara_scanner
COPY lua_interpreter /opt/vxmodules/mon/lua_interpreter
COPY utils /opt/vxmodules/mon/utils
COPY config.json /opt/vxmodules/mon/
RUN chmod +x /opt/vxmodules/startup.sh
RUN chmod +x /opt/vxmodules/gen_sql.py
RUN \
apt update && \
apt install -y ca-certificates && \
apt install -y jq && \
apt install -y --no-install-recommends python3 python3-pip && \
apt clean -y && \
apt autoremove -y && \
rm -rf /tmp/* /var/tmp/* && \
rm -rf /var/lib/apt/lists/* && \
echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
RUN pip3 install pypika
WORKDIR /opt/vxmodules/mon/
# Generate new dump sql files
RUN python3 /opt/vxmodules/gen_sql.py /opt/vxmodules/
# Write version file
RUN echo ${VXVERSION} > /opt/vxmodules/version
ENTRYPOINT ["/opt/vxmodules/startup.sh"]
+100
View File
@@ -0,0 +1,100 @@
END USER LICENSE AGREEMENT FOR SOLDR MODULES
1. General provisions
1.1. This License License (hereinafter the License) represents an agreement between A-Lab FZE (hereinafter the Rightholder) and the end user (hereinafter the User) with regard to SOLDR modules (hereinafter the Software) made publicly available by the Rightholder at the repository address https://github.com/vxcontrol/soldr-modules (hereinafter referred to as the Software) and/or the Software Modifications as defined herebelow made available as SOLDR modules forks at other github repositories.
1.2. Whenever the Rigtholder provide any updates, fixes and/or patches to the Software (hereinafter Software update installation package) such Software update installation packages are considered a part of the Software and provided strictly under the License as well.
1.3. The Software can be used only under the terms of this License. By using the Software, the User undertakes to fulfill the terms and conditions of the License. If the User does not accept the terms and conditions of this License in full, the User shall not use the Software in any way, including keeping a copy of the Software on data storage devices.
2. Permitted use
2.1. Downloading, storage, execution, or any other use of the Software means the User accepts the terms of the License and agrees to abide by the terms hereof. If the User does not accept those no rights are granted to use the Software in any way, including, without limitation, downloading, storage, execution and/or modification of the Software.
2.2. The User agrees to use the Software only for personal, noncommercial purposes for its intended purpose, namely within SOLDR agent and server software environment (https://github.com/vxcontrol/soldr). It is expressly forbidden to use the Softwares functionality within any software other than SOLDR agent and server software environment or to include the Software into or distribute with any software other than EDR software.
2.3. The User is granted the right to use the Software as follows: to download an instance of the Software as distributed by the Rightholder, to install and to execute the Software. The User is also granted the right to modify the part of the Software which is made available by the Rightholder asa source code form written in LUA solely according to the terms specified in clause 4 of the License.
2.4 The license to use the Software under the License is granted free of charge.
2.5. The license to use the Software under the License is granted perpetually unless terminated in accordance with the License based on the Users breach of its terms and conditions.
2.6. The User shall not modify, adapt, localize, or decompile the part the Software which is made available by the Rightholder as compiled (binary) libraries, nor shall the User make any changes to the source code of the Software, except as expressly specified in the License.
2.7. The User shall not use the Software to provide services (including consulting) to third parties, including those provided on a free-of-charge basis.
2.8. The User shall not distribute, lease, replicate, or transfer the Software to third parties, or use it for fraudulent or other illegal purposes either separately, bundled together with or as a part of any other software.
2.9. The User shall not use the Software for fraudulent or other illegal purposes.
3. Copyright
3.1. The Rightholder of the Software is JSC Positive Technologies.
3.2. All rights (including the right for the content that can become available as a result of the Software use) are the property of the Rightholder.
3.3. The Software includes third-party software, which is not the subject of intellectual property rights or other rights of the Rightholder. The usage of such third-party software is governed by respective licenses (license Licenses) issued by the rightholders of such software. By accepting the terms and conditions of this License, the User therefore accepts the terms and conditions specified in the licenses (license Licenses) of the third-party software.
3.4. All rights that are not directly and explicitly granted by the License shall remain with the Rightholder.
3.5. The User may not change or remove the Rightholder's and third parties' copyright information from the Software.
4. The Software modification
4.1. The User may change, modify, or improve source code or object code of the Software thus creating modified Software (hereinafter - Modifications); this permission does not cover modifications aimed at change or removal of any term of the License or mention of the Rightholder.
4.2. Any Modifications created by the User shall be governed by the License and may only be used under the terms of the License or published together with it.
4.3. It is expressly forbidden to modify the Software in such way as to enable Modifications to be compatible with any software other than EDR software whereas it was not compatible before modification.
4.4. The User may distribute Modifications by the way of creating the Software fork on Github and making it available for others to access. If doing so, the User shall make sure that such Modifications are distributed under the terms of this License.
4.5. The User agrees that the Rightholder may use and improve Modifications.
5. Telemetry
5.1. The User acknowledges and agrees that in the process of using the Software according to its functional purpose, the Software may automatically transfer to the Rightholder the following information:
5.1.1. Statistics of Software use
5.1.2. Diagnostic information about Software installation
5.1.3. Statistics of product settings
5.2. The Rightholder guarantees that any data transferred by the Software in accordance with Clause 5.1 of the License will be used by the Rightholder only to improve the Software performance stability and efficiency.
5.3. The Rightholder guarantees that collection of data in accordance with clause 5.1 of the License under no circumstances is aimed at gathering the User's personal data. If transmitted data contains the User's personal data, the Rightholder guarantees that such data will be processed solely for the purposes of statistics and research, and processing will include only depersonalization and destruction. Under no circumstances will this data be used for any other purposes including promotion of goods, labor, and services in the market, or political agitation.
5.4. Automatic data transmission as per Clause 5.1 of the License can be enabled or disabled during the Software installation or operation.
5.5. The Rightholder has the right to disclose transmitted data to third parties only in anonymized form, that is, if it does not contain personal data or confidential information. The Rightholder guarantees that transmitted data will not be disclosed to third parties other than as specified in this clause.
5.6. The User accepts and agrees that the data transmitted by the Software as per Clause 5.1 of the License can potentially be secret, confidential or otherwise being limited or illegal to distribute. The User undertakes not to enable automatic information transmission when using the Software in systems for which the information covered by Clause 5.1 of the License can be a state secret. By using this software, you acknowledge that you are aware of this and take sole responsibility for any such data provided to the Rightholder through your use of the Software
6. Limited warranty
6.1. The Software is provided "as is." The Rightholder gives no warranties of uninterrupted or error-free operation of the Software, nor does it give warranties that the Software meets the User's requirements or expectations.. The Rightholder makes no warranties that the Software is error-free and is not liable for direct or indirect damages resulting from potential errors in the Software, as well as for damages that might result from using or impossibility to use the Software.
7. Liability
7.1. The User shall be liable for any breach of the terms of this License and for the illegal use of the Software in accordance with the terms of this License, applicable national law and international treaties.
7.2. The Rightholder reserves the right to terminate the User's license unilaterally in case of any breach of the terms and conditions of this License and in case of illegal usage of the Software.
8. Other provisions
8.1. The Rightholder reserves the right to amend the terms and conditions of this License and notify the User of such amendments. Information published at the Rightholder's website shall be considered due notice under this License. The User agrees that information about the current version of the License containing such amended License terms shall be considered due notice as per this clause if placed by the Rightholder as an element of the interface in the Software update installation package. If the User installs the Software update installation package containing amended License terms, this is considered an implicative action signifying that the User agrees to such amended License terms.
8.2. If the User disagrees with any terms of the License relayed to the User in the manner described in Clause 7.2 of the License, the User must abort installation and must not use the Software update installation package containing such amended License terms. The User has the right to continue using the Software and the Software update packages provided to the User by the Rightholder until the License terms are changed.
8.3. Should the User have any questions regarding the permitted use of the Software, the User may contact the Rightholder:
A-Lab FZE
AE, Dubai, Dubai World Trade Center, Dubai One Central The Offices 3, Level 3, Office 362-7
Tel.: +971 52 112 7367
Email: info@vxcontrol.com
+63
View File
@@ -0,0 +1,63 @@
# SOLDR modules repository
## Using
There is using next environment variables to run the container:
* `DB_HOST` - Global MySQL IP address or domain
* `DB_PORT` - Global MySQL TCP port to connect
* `DB_USER` - Global MySQL username to connect
* `DB_PASS` - Global MySQL password to connect
* `DB_NAME` - Global MySQL database name to connect
* `MINIO_ENDPOINT` - URL to connect to Minio S3 storage (including port and schema)
* `MINIO_ACCESS_KEY` - Access key to connect to Minio S3 storage
* `MINIO_SECRET_KEY` - Secret key to connect to Minio S3 storage
* `MINIO_BUCKET_NAME` - Global S3 bucket name to connect and copy modules files
Command to build image:
`docker build -t local/modules .`
## Simple docker_env file
Command to run container (to remote services):
`docker run --add-host mysql.local:10.0.0.1 --add-host minio.local:10.0.0.2 --rm --env-file docker_env.list -ti local/modules`
Or link to local running containers:
`docker run --link=vx_mysql:mysql.local --link=vx_minio:minio.local --net soldr_vx-stand --rm --env-file docker_env.list -ti local/modules`
File docker_env.list by default:
```
DB_HOST=mysql.local
DB_PORT=3306
DB_USER=vxcontrol
DB_PASS=password
DB_NAME=vx_global
MINIO_ENDPOINT=http://minio.local:9000
MINIO_ACCESS_KEY=accesskey
MINIO_SECRET_KEY=secretkey
MINIO_BUCKET_NAME=soldr-modules
```
## Simple script file export environment variables to current bash session
Command to run container:
`. ./env.sh`
File env.sh by default:
```
export DB_HOST=mysql.local
export DB_PORT=3306
export DB_USER=vxcontrol
export DB_PASS=password
export DB_NAME=vx_global
export MINIO_ENDPOINT=http://minio.local:9000
export MINIO_ACCESS_KEY=accesskey
export MINIO_SECRET_KEY=secretkey
export MINIO_BUCKET_NAME=soldr-modules
```
+919
View File
@@ -0,0 +1,919 @@
[
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "empty",
"os": {
"windows": [
"386",
"amd64"
]
},
"name": "sysmon",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [
"sysmon_already_installed",
"sysmon_already_started",
"sysmon_config_updated_error",
"sysmon_config_updated_success",
"sysmon_installed_error",
"sysmon_installed_success",
"sysmon_started_error",
"sysmon_started_success",
"sysmon_unexpected_stopped",
"sysmon_unexpected_uninstalled",
"sysmon_uninstalled_error",
"sysmon_uninstalled_success",
"sysmon_updated_error",
"sysmon_updated_success"
],
"fields": [
"reason",
"version"
],
"last_module_update": "2022-10-26 00:00:00",
"last_update": "2022-10-26 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "empty",
"os": {
"windows": [
"386",
"amd64"
]
},
"name": "wineventlog",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [
"wel_module_internal_error",
"wel_module_started",
"wel_module_stopped"
],
"fields": [
"reason"
],
"last_module_update": "2022-10-26 00:00:00",
"last_update": "2022-10-26 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "custom",
"os": {
"darwin": [
"amd64"
],
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "lua_interpreter",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [],
"fields": [],
"last_module_update": "2022-04-29 00:00:00",
"last_update": "2022-04-29 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"darwin": [
"amd64"
],
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "syslog",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [
"send_to_syslog"
],
"events": [
"syslog_module_started",
"syslog_module_stopped"
],
"fields": [],
"last_module_update": "2022-04-29 00:00:00",
"last_update": "2022-04-29 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"darwin": [
"amd64"
],
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "file_remover",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [
"fr_remove_object_file",
"fr_remove_object_proc_image",
"fr_remove_subject_proc_image"
],
"events": [
"fr_module_started",
"fr_module_stopped",
"fr_object_file_removed_failed",
"fr_object_file_removed_successful",
"fr_object_proc_image_removed_failed",
"fr_object_proc_image_removed_successful",
"fr_remove_internal_error",
"fr_subject_proc_image_removed_failed",
"fr_subject_proc_image_removed_successful"
],
"fields": [
"object.fullpath",
"object.process.fullpath",
"reason",
"subject.fullpath",
"subject.process.fullpath"
],
"last_module_update": "2022-04-29 00:00:00",
"last_update": "2022-04-29 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"darwin": [
"amd64"
],
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "proc_terminator",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [
"pt_kill_object_process_by_file_path",
"pt_kill_object_process_by_image",
"pt_kill_object_process_by_name",
"pt_kill_object_process_by_name_and_id",
"pt_kill_object_process_by_image_and_id",
"pt_kill_object_process_tree_by_file_path",
"pt_kill_object_process_tree_by_image",
"pt_kill_object_process_tree_by_name",
"pt_kill_object_process_tree_by_name_and_id",
"pt_kill_object_process_tree_by_image_and_id",
"pt_kill_subject_process_by_image",
"pt_kill_subject_process_by_name",
"pt_kill_subject_process_by_name_and_id",
"pt_kill_subject_process_by_image_and_id",
"pt_kill_subject_process_tree_by_image",
"pt_kill_subject_process_tree_by_name",
"pt_kill_subject_process_tree_by_name_and_id",
"pt_kill_subject_process_tree_by_image_and_id"
],
"events": [
"pt_module_started",
"pt_module_stopped",
"pt_object_process_killed_failed",
"pt_object_process_killed_successful",
"pt_object_process_skipped",
"pt_process_not_found",
"pt_subject_process_killed_failed",
"pt_subject_process_killed_successful",
"pt_subject_process_skipped"
],
"fields": [
"object.fullpath",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"reason",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"last_module_update": "2022-08-26 00:00:00",
"last_update": "2022-06-26 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "yara_scanner",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [
"yr_object_scan_proc",
"yr_object_task_scan_proc",
"yr_scan_fs",
"yr_subject_scan_proc",
"yr_subject_task_scan_proc",
"yr_task_fastscan_fs",
"yr_task_fastscan_proc",
"yr_task_fullscan_fs",
"yr_task_fullscan_proc",
"yr_task_scan_fs"
],
"events": [
"yr_file_matched_custom",
"yr_file_matched_high",
"yr_file_matched_low",
"yr_file_matched_medium",
"yr_module_started",
"yr_module_stopped",
"yr_object_process_matched_high",
"yr_object_process_matched_low",
"yr_object_process_matched_medium",
"yr_process_matched_custom",
"yr_subject_process_matched_high",
"yr_subject_process_matched_low",
"yr_subject_process_matched_medium"
],
"fields": [
"malware_class",
"object.fullpath",
"object.process.fullpath",
"object.process.id",
"object.sha256_hash",
"reason",
"rule_name",
"rule_precision",
"rule_type",
"rules",
"subject.process.fullpath",
"subject.process.id"
],
"last_module_update": "2022-11-07 09:11:39",
"last_update": "2022-11-07 09:11:39"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"darwin": [
"amd64"
],
"linux": [
"386",
"amd64"
],
"windows": [
"386",
"amd64"
]
},
"name": "file_uploader",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [
"fu_upload_object_file",
"fu_upload_object_proc_image",
"fu_upload_subject_proc_image"
],
"events": [
"fu_module_started",
"fu_module_stopped",
"fu_object_file_upload_failed",
"fu_object_file_upload_successful",
"fu_object_proc_image_upload_failed",
"fu_object_proc_image_upload_successful",
"fu_subject_proc_image_upload_failed",
"fu_subject_proc_image_upload_successful",
"fu_upload_internal_error"
],
"fields": [
"object.fullpath",
"object.process.fullpath",
"reason",
"subject.fullpath",
"subject.process.fullpath"
],
"last_module_update": "2022-09-30 00:00:00",
"last_update": "2022-09-30 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"linux": [
"amd64"
]
},
"name": "correlator_linux",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [
"Auxiliary_SuspiciousWeightsTrojan_Linux_subject_a",
"Local_Recon_by_Web_User",
"Malware_Exploit_Elf_CVE_2019_14287_a",
"Malware_Exploit_Elf_CVE_2021_4034_a",
"Malware_Trojan_Linux_Generic_a",
"Malware_Trojan_Spy_Linux_Generic_a",
"Raw_Socket",
"Reverse_Tunneling_via_SSH",
"Suspicious_Create_File_Attribute_Hidden",
"Suspicious_Create_File_Boot_Modification",
"Suspicious_Create_File_Boot_RCScripts",
"Suspicious_Create_File_Ldd_PreloadDynamicLibrary",
"Suspicious_Create_File_Scheduler_At",
"Suspicious_Create_File_Scheduler_Cron",
"Suspicious_Create_File_Scheduler_SystemdTimer",
"Suspicious_Create_File_Shell_Config",
"Suspicious_Create_File_Ssh_AuthorizedKeys",
"Suspicious_Create_File_Systemd_Service",
"Suspicious_Create_File_Xdg_Autostart",
"Suspicious_Create_Process_Chkconfig_DisableRCScripts",
"Suspicious_Create_Process_Iptables_ModifyFirewall",
"Suspicious_Create_Process_Service_Disable",
"Suspicious_Create_Process_Setenforce_ModifySELinux",
"Suspicious_Create_Process_Sudo_Bruteforce",
"Suspicious_Create_Process_WipeData_Destruction",
"Suspicious_Read_File_Email_Local",
"Suspicious_Read_File_Fstab_Configuration",
"Suspicious_Read_File_Passwd_CredentialsEnumeration",
"Suspicious_Read_File_Polkit_Policy",
"Suspicious_Read_File_Shadow_CredentialsDumping",
"Suspicious_Read_System_BIOS_Reconnaissance",
"Suspicious_Read_System_DMI_CheckVM",
"Suspicious_Read_System_Kernel_ASLR",
"Suspicious_Read_System_Kernel_PtraceScope",
"Suspicious_Read_System_KeyState_Keylogger",
"Suspicious_Read_System_PCI_GPU",
"Suspicious_Read_System_PCI_USB",
"Suspicious_Read_System_Proc_ARPSessions",
"Suspicious_Read_System_Proc_BootCmdline",
"Suspicious_Read_System_Proc_Modules",
"Suspicious_Read_System_Proc_Route",
"Suspicious_Read_System_Proc_SCSI",
"Suspicious_Read_System_Proc_TCPSessions",
"Suspicious_Write_Disk_Data_DirectAccess",
"Suspicious_Write_File_PAM_Persistence",
"Suspicious_Write_Process_Inject_Ptrace",
"Tunneling_via_SSH",
"Tunneling_via_SSHuttle_Client",
"Tunneling_via_SSHuttle_Server"
],
"fields": [
"action",
"alert.key",
"category.generic",
"category.high",
"category.low",
"correlation_name",
"correlation_type",
"event_src.asset",
"event_src.host",
"event_src.hostname",
"event_src.id",
"event_src.ip",
"event_src.subsys",
"event_src.title",
"event_src.vendor",
"importance",
"incident.aggregation.key",
"incident.aggregation.timeout",
"incident.category",
"incident.severity",
"labels",
"numfield1",
"numfield2",
"object",
"object.account.group",
"object.account.id",
"object.account.name",
"object.fullpath",
"object.name",
"object.path",
"object.process.cmdline",
"object.process.cwd",
"object.process.fullpath",
"object.process.id",
"object.process.meta",
"object.process.name",
"object.process.parent.id",
"object.process.path",
"object.state",
"object.value",
"status",
"subject",
"subject.account.id",
"subject.account.name",
"subject.account.privileges",
"subject.account.session_id",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path",
"subject.type"
],
"last_module_update": "2022-11-07 12:52:12",
"last_update": "2022-11-07 12:52:12"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "responder",
"os": {
"windows": [
"amd64"
]
},
"name": "correlator",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [
"Abnormal_Directory_for_Process",
"Abusing_CredSSP",
"Access_System_Credential_files_via_cmdline",
"Access_into_Sensitive_Files_via_Network_Share",
"Accessibility_Feature_Tool_Abuse",
"Account_Created_on_Local_System",
"Account_Discovery",
"Account_or_Group_discovery_via_SAM_R",
"Add_new_user_in_commandline",
"Alternate_Data_Stream",
"Audit_XP_params_change",
"Auxiliary_SuspiciousWeightsTrojan_Windows_subject_a",
"Auxiliary_SuspiciousWeightsTrojan_Windows_subject_b",
"BitsJob_Download_and_Run",
"COM_object_persistence",
"CVE_2021_41379_Subrule_Elevation_service_chain",
"CVE_2021_41379_Subrule_Start_elevation",
"CVE_2021_41379_exploitation",
"CVE_2022_26500_26501_exploitation",
"CVE_2022_26503_Subrule_1",
"CVE_2022_26503_Subrule_2",
"CVE_2022_26503_exploitation",
"Client_Side_Execution_via_DCOM",
"Clipboard_Access",
"Clipboard_Access_Powershell",
"Cmstp_AWL_Bypass",
"Cobalt_Strike_Assembly",
"Cobalt_Strike_Payload_Delivery_Check",
"Cobalt_Strike_Pipe_from_AdminShare",
"Cobalt_Strike_Process_Injection",
"Cobalt_Strike_Psexec_Jump",
"Cobalt_Strike_SMB_Beacon",
"Cobalt_Strike_Service_Move",
"Code_Execution_Via_JDK_Tools",
"Command_Processor_Autorun_Modify",
"Computer_object_ldap_request",
"ControlPanel_AWL_Bypass",
"Copy_Mimikatz_To_Share",
"Credential_Access_to_Passwords_Storage",
"Credential_Dump_in_Local_Registry",
"Csc_AWL_Bypass",
"DRSUAPI_User_Enumeration",
"DSInternals_Usage",
"Disable_Credential_Guard",
"Disable_LSA_Protection",
"Disable_Restricted_Admin_Mode",
"Dnscmd_AWL_Bypass",
"Domain_Controllers_Discovery",
"Domain_Trust_Discovery",
"Download_File_Through_Curl",
"Download_File_Through_Windows_Defender",
"Downloading_Remote_File_Via_Lolbas",
"Empire_Stager",
"Esentutil_Copy_File",
"Execute_Encoded_Powershell",
"Execute_Malicious_Command",
"Execute_Malicious_Powershell_Cmdlet",
"Execute_PSEXEC",
"Execute_Suspicious_Command_via_cmd",
"Failed_LSASS_Injection",
"Fast_Create_and_Delete_Account",
"Finger_AWL_Bypass",
"Groups_And_Users_Enumeration",
"Hidden_Scheduled_Task",
"Hidden_Service_Create",
"Hide_Account_from_Logon_Screen",
"IEExec_AWL_Bypass",
"Impacket_SMBEXEC",
"Impacket_Secretsdump",
"InstallUtil_AWL_Bypass",
"Intercept_Creds_from_MSTSC",
"Internal_Monologue_Attack",
"KeePass_Keys_Extraction",
"KeePass_Persistence",
"Koadic_MSHTA_Stager",
"Koadic_REGSVR32_Stager",
"Koadic_Rundll32_Stager",
"Koadic_WMIC_Stager",
"LAPS_Enumeration",
"LOLBin_Copying",
"LSA_SSP_Change",
"Lazagne_Usage",
"Local_Pass_the_Hash",
"Lsass_Dump_via_SilentProcessExit",
"Lsass_SilentProcessExit_Keys",
"MSBuild_AWL_Bypass",
"MSHTA_AWL_Bypass",
"MSXSL_AWL_Bypass",
"Malicious_CHM_File",
"Malicious_Office_Document",
"Malware_Backdoor_Win32_Evilnum_a",
"Malware_Backdoor_Win32_Havex_a",
"Malware_Backdoor_Win32_NetWire_b",
"Malware_Backdoor_Win32_Pteredo_a",
"Malware_Backdoor_Win64_Throwback_b",
"Malware_Exploit_Win32_CVE_2022_30190_a",
"Malware_Exploit_Win32_PrintSpooler_a",
"Malware_Hacktool_Win32_CrackMapExec_a",
"Malware_Trojan_Dropper_MSOffice_Launcher_a",
"Malware_Trojan_Dropper_Script_Generic_a",
"Malware_Trojan_Dropper_Win32_Generic_k",
"Malware_Trojan_Ransom_Win32_Generic_a",
"Malware_Trojan_Ransom_Win32_Generic_b",
"Malware_Trojan_Win32_Generic_a",
"Malware_Trojan_Win32_Generic_o",
"Malware_Trojan_Win32_Generic_s",
"Malware_Trojan_Win32_Generic_t",
"Mavinject_AWL_Bypass",
"Metasploit_Payload",
"Microsoft_Teams_AWL_Bypass",
"Mimikatz_Command",
"Msiexec_AWL_Bypass",
"NetCat_Usage",
"Network_Share_Discovery",
"Odbcconf_AWL_Bypass",
"Office_File_with_Macros",
"Office_Normal_dotm_modification",
"Office_XLL_modification",
"Password_Policy_Discovery",
"Pcalua_AWL_Bypass",
"Permission_Groups_Discovery",
"Persistence_Netsh_DLL",
"Port_Forwarding_or_Tunneling",
"Potential_Users_Or_Groups_Enumeration_Process",
"Potential_domain_groups_and_users_enumeration_handle",
"Potential_localgroups_and_administrators_enumeration_handle",
"Powershell_Remoting",
"Process_Discovery",
"Proxy_Tools_Usage",
"RDP_Session_Hijacking",
"Reading_Registry_Objects",
"RegAsm_or_RegSvcs_AWL_Bypass",
"Registry_Winlogon_Helper",
"Regsvr32_AWL_Bypass",
"Remote_Admin_Share_Access",
"Remote_Code_Execution_Via_AtSvc",
"Remote_Connection_through_SMBEXEC_WinXP",
"Remote_Copy_Credential_Dump_Artifact",
"Remote_Copying_Malicious_File",
"Remote_File_Download_Via_Certutil",
"Remote_Password_Dump",
"Remoting_Impacket_PsExec",
"Remoting_SysInternals_PsExec",
"Remoting_WMI",
"Remoting_WinExec",
"Remoting_Windows_Shell",
"Remove_Access_To_Sensitive_Account",
"Remove_Account_From_Sensitive_Group",
"Rubeus_Usage",
"RunAs_Subrule_Login",
"RunAs_System_or_External_tools",
"Run_Malicious_Msbuild_Project",
"Run_whoami_as_System",
"Rundll32_AWL_Bypass",
"SPN_LDAP_requests",
"Scheduled_Task_Was_Created_Or_Updated_Via_Schtasks",
"Search_Stored_Credentials",
"Service_Created_or_Modified",
"Shadow_Copies_Deletion_with_Builtin_Tools",
"Shadow_Key_Creation",
"Shadow_Screen_save",
"Shadow_Screen_saves_PowerShell",
"SharpSploit_Usage",
"SharpWMI_Usage",
"Sharphound_Client_Side",
"Sharphound_Server_Side",
"SilentTrinity_Stager",
"Sliver_Shell_Usage",
"Software_Discovery",
"Spoolsv_Priv_Escalation",
"Stop_Important_Service",
"Stop_Important_Service_registry",
"Subrule_Sharphound_Client_Side",
"Subrule_Sharphound_Server_Side",
"Suspicious_Access_To_Users_Folder",
"Suspicious_Child_from_Messenger_Process",
"Suspicious_Create_File_FromBrowser_SuspiciousExtension",
"Suspicious_Create_File_FromMessenger_SuspiciousExtension",
"Suspicious_Create_File_PartitionMaster_DirectAccess",
"Suspicious_Create_File_RawDisk_DirectAccess",
"Suspicious_Create_Object_Account_Persistence",
"Suspicious_Create_Process_At_Persistence",
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass",
"Suspicious_Create_Process_Debugger_Inject",
"Suspicious_Create_Process_DirectoryMock_UACBypass",
"Suspicious_Create_Process_NetSh_NetShell",
"Suspicious_Create_Process_Ping_SelfDelete",
"Suspicious_Create_Process_RunScript_WScript",
"Suspicious_Create_Process_Schtasks_Persistence",
"Suspicious_Create_Process_TaskKill_TerminateProcess",
"Suspicious_Create_Process_VSTOInstaller_OfficeAddIns",
"Suspicious_Create_Process_VirtualInstance_Evasion",
"Suspicious_Create_Process_WinDef_AddExclusion",
"Suspicious_Create_Process_WinDef_ChangeSettings",
"Suspicious_Create_Process_WithDebugger_Execution_Predetect_2_1",
"Suspicious_Create_Process_WusaExtract_UACBypass",
"Suspicious_Create_Registry_Key_SafeBoot",
"Suspicious_Delete_Registry_Key_ETWProvider",
"Suspicious_Delete_Registry_Key_RunAsPPL",
"Suspicious_Delete_Registry_Key_SafeBoot",
"Suspicious_Delete_Registry_Key_Service",
"Suspicious_Delete_Registry_Key_TaskSD",
"Suspicious_File_Created_by_Legal_Process",
"Suspicious_Windows_Kernel_creating",
"Suspicious_Wmic_Command",
"Suspicious_Write_File_EfiSystemPartition_Persistence",
"Suspicious_Write_File_USB_AirSpread",
"Suspicious_Write_Process_Inject_CreateRemoteThread",
"Suspicious_Write_Registry_Key_CPL",
"Suspicious_Write_Registry_Key_ChangeDefaultFileAssociation",
"Suspicious_Write_Registry_Key_ChangeFirewallPolicy",
"Suspicious_Write_Registry_Key_ChangeRdpPort",
"Suspicious_Write_Registry_Key_CredentialsDelegation",
"Suspicious_Write_Registry_Key_DisableAppLaunch",
"Suspicious_Write_Registry_Key_DisableTaskManager",
"Suspicious_Write_Registry_Key_DisableUAC",
"Suspicious_Write_Registry_Key_FlashConfigEnrollee",
"Suspicious_Write_Registry_Key_ImagePath",
"Suspicious_Write_Registry_Key_InjectAppCertDlls",
"Suspicious_Write_Registry_Key_InjectAppInitDLLs",
"Suspicious_Write_Registry_Key_InjectImageFileExecutionOptions",
"Suspicious_Write_Registry_Key_InjectLoadAppInitDLLs",
"Suspicious_Write_Registry_Key_InjectSilentProcessExit",
"Suspicious_Write_Registry_Key_KillAntivirus",
"Suspicious_Write_Registry_Key_LsaComponents",
"Suspicious_Write_Registry_Key_ModifyRdpSettings",
"Suspicious_Write_Registry_Key_OfficeTemplate",
"Suspicious_Write_Registry_Key_ProxyHijack",
"Suspicious_Write_Registry_Key_SafeBoot",
"Suspicious_Write_Registry_Key_ScreenSaver",
"Suspicious_Write_Registry_Key_SvchostContextService",
"Suspicious_Write_Registry_Key_TerminalContextService",
"Suspicious_Write_Registry_Key_TimeProviders",
"Suspicious_process_execution_sequence",
"Sysmon_Driver_Unload",
"System_Information_Discovery",
"System_Network_Configuration_Discovery",
"System_Network_Connections_Discovery",
"System_Service_Discovery",
"TikiTorch_Process_Injection",
"Universal_Windows_Platform_Apps_Modify",
"User_object_ldap_request",
"Userinitmprlogonscript_Modify",
"WDAC_Bypass_via_Dbgsrv",
"WDigest_Enable",
"WMI_Subscriptions",
"WinAPI_Access_from_Powershell",
"Windows_Accessibility_StickyKey_modification",
"Windows_Autorun_Modification",
"Windows_Defender_Disable",
"Windows_Eventlog_cleaning",
"Windows_Hacktool_Usage",
"Windows_Malicious_service_registration",
"Windows_Registry_sensitive_keys_modification",
"Windows_Service_Installed",
"Windows_Shadow_copy_removal",
"Windows_WMI_event_consumer_registration",
"Windows_WMI_event_subscription_removal",
"Windows_firewall_enable_local_RDP",
"XSL_Script_WMIC_Execution"
],
"fields": [
"action",
"alert.context",
"alert.key",
"category.generic",
"category.high",
"category.low",
"chain_id",
"correlation_name",
"correlation_type",
"dst.asset",
"dst.fqdn",
"dst.host",
"dst.hostname",
"dst.ip",
"dst.mac",
"dst.port",
"event_src.asset",
"event_src.category",
"event_src.fqdn",
"event_src.host",
"event_src.hostname",
"event_src.ip",
"event_src.rule",
"event_src.subsys",
"event_src.title",
"event_src.vendor",
"importance",
"incident.aggregation.key",
"incident.aggregation.time_window",
"incident.aggregation.timeout",
"incident.attacking_addresses",
"incident.category",
"incident.severity",
"labels",
"numfield1",
"object",
"object.account.domain",
"object.account.fullname",
"object.account.id",
"object.account.name",
"object.account.privileges",
"object.account.session_id",
"object.domain",
"object.fullpath",
"object.hash",
"object.id",
"object.name",
"object.new_value",
"object.path",
"object.process.cmdline",
"object.process.cwd",
"object.process.fullpath",
"object.process.guid",
"object.process.hash",
"object.process.id",
"object.process.meta",
"object.process.name",
"object.process.original_name",
"object.process.parent.cmdline",
"object.process.parent.fullpath",
"object.process.parent.guid",
"object.process.parent.id",
"object.process.parent.name",
"object.process.parent.path",
"object.process.path",
"object.process.version",
"object.property",
"object.query",
"object.state",
"object.storage.fullpath",
"object.storage.id",
"object.storage.name",
"object.storage.path",
"object.type",
"object.value",
"object.vendor",
"object.version",
"reason",
"src.asset",
"src.fqdn",
"src.host",
"src.hostname",
"src.ip",
"src.mac",
"src.port",
"status",
"subject",
"subject.account.domain",
"subject.account.fullname",
"subject.account.id",
"subject.account.name",
"subject.account.privileges",
"subject.account.session_id",
"subject.name",
"subject.process.cmdline",
"subject.process.cwd",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.hash",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.original_name",
"subject.process.parent.id",
"subject.process.path",
"subject.process.version",
"subject.type",
"subject.version"
],
"last_module_update": "2022-10-26 00:00:00",
"last_update": "2022-10-26 00:00:00"
},
{
"group_id": "",
"policy_id": "",
"state": "release",
"template": "empty",
"os": {
"linux": [
"amd64"
],
"windows": [
"amd64"
]
},
"name": "file_reader",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"actions": [],
"events": [
"frd_module_internal_error",
"frd_module_started",
"frd_module_stopped"
],
"fields": [
"reason"
],
"last_module_update": "2022-11-02 00:00:00",
"last_update": "2022-11-02 00:00:00"
}
]
+15
View File
@@ -0,0 +1,15 @@
<template>
<div>
</div>
</template>
<script>
const name = "empty";
module.exports = {
name,
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
data: () => ({
})
};
</script>
+4
View File
@@ -0,0 +1,4 @@
{
"debug_engines": ["false"],
"debug_correlator": ["false"]
}
Binary file not shown.
@@ -0,0 +1,188 @@
require("yaci")
require("strict")
require("engines.base_engine")
require("engines.corr_engine")
local json = require("cjson.safe")
CActsEngine = newclass("CActsEngine", CBaseEngine)
--[[
cfg top keys:
* config - module arguments (hard limits)
]]
function CActsEngine:init(cfg)
__log.debug("init CActsEngine object")
assert(type(cfg) == "table", "configuration object has invalid type")
cfg.engine = "acts_engine"
self.super:init(cfg)
self.correlator = CCorrEngine(
function(event)
self:push_result(event)
end
)
if not self.correlator.valid then
__log.info("try to restore correlator instance")
self.correlator = CCorrEngine(
function(event)
self:push_result(event)
end,
true
)
end
self.proc_id_fields = {
"object.process.id",
"object.process.parent.id",
"subject.process.id",
"subject.process.parent.id",
}
-- initialization of object after base class constructing
self:update_config_cb()
end
-- in: nil
-- out: nil
function CActsEngine:free()
__log.debug("finalize CActsEngine object")
-- here will be triggered after closing vxproto object (destructor of the state)
end
-- in: nil
-- out: number
-- amount of milliseconds timeout to wait next call of the timer_cb
function CActsEngine:timer_cb()
-- __log.debug("timer_cb CActsEngine")
local acts_engine = CActsEngine:cast(self)
acts_engine.correlator:pullEvents()
__metric.add_int_gauge_counter("corr_agent_mem_usage", collectgarbage("count")*1024)
return 500
end
-- in: nil
-- out: nil
function CActsEngine:quit_cb()
__log.debug("quit_cb CActsEngine")
-- here will be triggered before closing vxproto object and destroying the state
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CActsEngine:agent_connected_cb(dst)
__log.debugf("agent_connected_cb CActsEngine with token '%s'", dst)
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CActsEngine:agent_disconnected_cb(dst)
__log.debugf("agent_disconnected_cb CActsEngine with token '%s'", dst)
end
-- in: nil
-- out: nil
function CActsEngine:update_config_cb()
__log.debug("update_config_cb CActsEngine")
-- actual current configuration contains into next fields
-- self.config.actions
-- self.config.events
-- self.config.module
end
-- in: string, string
-- source token (string) of sender module side
-- data payload (string) as a custom string serialized struct object (json)
-- out: boolean
-- result of data processing from business logic
function CActsEngine:recv_data_cb(src, data)
__log.debugf("perform custom logic for data with payload len %d from '%s'", #data, src)
local acts_engine = CActsEngine:cast(self)
local odata, err = json.decode(data)
if not odata then
__log.errorf("failed to parse events packet: %s", err)
return true
end
if acts_engine.correlator then
__metric.add_int_counter("corr_agent_events_recv_count", #odata)
__metric.add_int_counter("corr_agent_events_recv_size", #data)
for _,v in ipairs(odata) do
v.body = json.encode(v.body)
while acts_engine.correlator:sendEvent(json.encode(v)) == false do
__api.await(50)
end
end
else
__metric.add_int_counter("corr_agent_events_drop", #odata)
end
return true
end
-- in: string, string, string
-- source token (string) of sender module side
-- file path (string) on local FS where received file was stored
-- file name (string) is a original file name which was set on sender side
-- out: boolean
-- result of file processing from business logic
function CActsEngine:recv_file_cb(src, path, name)
__log.debugf("perform custom logic for file with path '%s' and name '%s' from '%s'", path, name, src)
return true
end
-- in: string, string, table
-- source token (string) of sender module side
-- action name (string) to execute it into the acts_engine
-- action data (table) as a arguments to execute action via acts_engine
-- e.x. {"data": {"key": "val"}, "actions": ["mod1.act1"]}
-- out: boolean
-- result of action processing from business logic
function CActsEngine:recv_action_cb(src, data, name)
__log.debugf("perform custom logic for action '%s' from '%s'", name, src)
local acts_engine = CActsEngine:cast(self)
if name == "some_action" then
return acts_engine:dummy(data.data["arg"])
end
return false
end
-- in: table
-- out: nil
function CActsEngine:push_result(event)
local oevent = json.decode(event)
if type(oevent) ~= "table" then
__log.errorf("failed to parse event from correlator: %s", tostring(event))
return
end
local event_name = oevent["_rule"]
local result = oevent
if event_name == nil or event_name == "" then return end
local config_events = self.config["events"] or {events={}}
local config_event = config_events[event_name] or {fields={}}
local config_fields = self.config["fields"] or {properties={}}
local _fields = config_event["fields"] or {}
local defaults = {string = "", number = 0, integer = 0, object = {}, array = {}, boolean = false, null = nil}
for _, v in ipairs(self.proc_id_fields) do
result[v] = tonumber(result[v])
end
for _, v in ipairs(_fields) do
result[v] = result[v] or defaults[(config_fields.properties[v] or {}).type or "null"]
end
__log.debugf("perform logic to push result: '%s'", json.encode(result))
self:push_event(event_name,result)
end
@@ -0,0 +1,336 @@
require("yaci")
require("strict")
require("engine")
local glue = require("glue")
local crc32 = require("crc32")
local cjson = require("cjson.safe")
math.randomseed(crc32(tostring({})))
CBaseEngine = newclass("CBaseEngine")
--[[
cfg top keys:
* config - module arguments (hard limits)
]]
function CBaseEngine:init(cfg)
__log.debug("init CBaseEngine object")
assert(type(cfg) == "table", "configuration object has invalid type")
self.config = glue.merge(self.config or {}, cfg.config or {})
self.config.actions = cjson.decode(__config.get_current_action_config())
self.config.events = cjson.decode(__config.get_current_event_config())
self.config.module = cjson.decode(__config.get_current_config())
self.config.fields = cjson.decode(__config.get_fields_schema())
self.mod_name = __config.ctx.name
self.is_debug = __args["debug_engines"][1] == "true"
self.prefix_db = __gid .. "."
self.server_token = ""
self.action_engine = CActionEngine(
{},
__args["debug_correlator"][1] == "true"
)
self.event_engine = CEventEngine(
__config.get_fields_schema(),
__config.get_current_event_config(),
__config.get_module_info(),
self.prefix_db,
__args["debug_correlator"][1] == "true"
)
end
-- in: nil
-- out: nil
function CBaseEngine:free()
__log.debug("finalize CBaseEngine object")
if self.event_engine ~= nil then
self.event_engine:free()
self.event_engine = nil
end
if self.action_engine ~= nil then
self.action_engine:free()
self.action_engine = nil
end
collectgarbage("collect")
end
-- in: nil
-- out: nil
function CBaseEngine:run()
__log.debug("run CBaseEngine started")
while not __api.is_close() do
local timeout = self:timer_cb()
assert(type(timeout) == "number", "await timeout has invalid type")
__api.await(timeout)
end
__log.debug("run CBaseEngine stopped")
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CBaseEngine:agent_connected(dst)
__log.debugf("agent_connected CBaseEngine with token '%s'", dst)
self:agent_connected_cb(dst)
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CBaseEngine:agent_disconnected(dst)
__log.debugf("agent_disconnected CBaseEngine with token '%s'", dst)
self:agent_disconnected_cb(dst)
end
-- in: nil
-- out: nil
function CBaseEngine:quit()
__log.debug("quit CBaseEngine")
self:quit_cb()
end
-- in: nil
-- out: nil
function CBaseEngine:update_config()
__log.debug("update_config CBaseEngine")
-- renew actions and events config according by the module configuration
self.config.actions = cjson.decode(__config.get_current_action_config())
self.config.events = cjson.decode(__config.get_current_event_config())
self.config.module = cjson.decode(__config.get_current_config())
self.config.fields = cjson.decode(__config.get_fields_schema())
-- renew current event engine instance
if self.event_engine ~= nil then
self.event_engine:free()
self.event_engine = nil
collectgarbage("collect")
self.event_engine = CEventEngine(
__config.get_fields_schema(),
__config.get_current_event_config(),
__config.get_module_info(),
self.prefix_db,
__args["debug_correlator"][1] == "true"
)
end
-- notify engine about update config from the server
self:update_config_cb()
end
-- in: string, string, string, table
-- out: nil
function CBaseEngine:commit_event(src, event_name, action_name, action_data)
__log.debug("commit_event CBaseEngine")
if self.config.events[event_name] == nil then
__log.errorf("requested event '%s' does not exists in current event config", event_name)
return
end
local is_imc, mod_name, group_id = self:get_sender_info(src)
action_data.data.action = {
["name"] = action_name,
["source"] = {
["is_imc"] = is_imc,
["mod_name"] = mod_name,
["group_id"] = group_id,
},
}
self:push_event(event_name, action_data.data, action_data.actions)
end
-- in: string, string, table
-- out: nil
function CBaseEngine:commit_success(src, action_name, action_data)
__log.debug("commit_success CBaseEngine")
local event_name = tostring(self.mod_name) .. "_action_exec_success"
action_data.data.result = true
action_data.data.reason = "action_exec_success"
self:commit_event(src, event_name, action_name, action_data)
-- case to notify other side about action execution result
if type(action_data.retaddr) == "string" and action_data.retaddr ~= "" then
local data = cjson.encode(glue.merge({status = "success"}, action_data))
__api.send_data_to(src, data)
end
end
-- in: string, string, table
-- out: nil
function CBaseEngine:commit_failed(src, action_name, action_data)
__log.debug("commit_failed CBaseEngine")
local event_name = tostring(self.mod_name) .. "_action_exec_failed"
action_data.data.result = false
action_data.data.reason = "action_exec_failed"
self:commit_event(src, event_name, action_name, action_data)
-- case to notify other side about action execution result
if type(action_data.retaddr) == "string" and action_data.retaddr ~= "" then
local data = cjson.encode(glue.merge({status = "error"}, action_data))
__api.send_data_to(src, data)
end
end
-- in: string
-- source token (string) of sender module side
-- out: boolean, string, string
-- is it inter modules communication packet (boolean)
-- module name (string) which was a sender the packet
-- group id (string) which contained the sender module
function CBaseEngine:get_sender_info(src)
if __imc.is_exist(src) then
local mod_name, group_id = __imc.get_info(src)
__log.debugf("received internal from module '%s' and group '%s'", mod_name, group_id)
return true, mod_name, group_id
end
__log.debugf("message received from the server")
return false, self.mod_name, __gid
end
-- in: nil
-- out: string
-- destination token (string) it'll be empty if agent disconnected
function CBaseEngine:get_server_token()
local tablelength = function(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
if tablelength(__agents.get_by_dst(self.server_token)) == 0 then
self.server_token = ""
else
return self.server_token
end
for client_id, client_info in pairs(__agents.dump()) do
if tostring(client_info.Type) == "VXAgent" then
self.server_token = tostring(client_id)
return self.server_token
end
end
return ""
end
-- in: string, table, table or nil
-- event name (string) to execute it into event engine
-- event data (table) to store key-value struct into the event
-- previous actions array (table or nil) to avoid loop actions execution
-- out: boolean
-- result of event processing received from event engine (true if event exists)
function CBaseEngine:push_event(name, data, actions)
assert(type(name) == "string", "input event name type is invalid")
assert(type(data) == "table", "input event data type is invalid")
assert(not actions or type(actions) == "table", "input event data type is invalid")
assert(self.event_engine ~= nil, "event engine is not initialized")
assert(self.action_engine ~= nil, "action engine is not initialized")
__log.debugf("try push event '%s' with data json: %s", name, cjson.encode(data))
if self.config.events[name] == nil then
__log.errorf("requested event '%s' does not exists in current event config", name)
return false
end
-- build event info structure
local info = {
["name"] = name,
["data"] = data,
["actions"] = actions or {},
}
local event_result, action_list = self.event_engine:push_event(info)
__log.debugf("result of pushing event '%s' is %s", name, event_result)
-- check result return variable as marker is there need to execute actions
if event_result then
__log.debugf("try to exec event '%s' actions list %s", name, cjson.encode(action_list))
for action_id, action_result in ipairs(self.action_engine:exec(__aid, action_list)) do
__log.debugf("result of executing action '%s' is %s", action_id, action_result)
end
end
return event_result
end
-- in: string, string
-- source token (string) of sender module side
-- data payload (string) as a custom string serialized struct object (json)
-- out: boolean
-- result of data processing received from acts_engine
function CBaseEngine:recv_data(src, data)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(data) == "string", "input action data type is invalid")
__log.debugf("try process data with payload len %d from '%s'", #data, src)
return self:recv_data_cb(src, data)
end
-- in: string, string, string
-- source token (string) of sender module side
-- file path (string) on local FS where received file was stored
-- file name (string) is a original file name which was set on sender side
-- out: boolean
-- result of file processing received from acts_engine
function CBaseEngine:recv_file(src, path, name)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(path) == "string", "input file path type is invalid")
assert(type(name) == "string", "input file name type is invalid")
__log.debugf("try process file with path '%s' and name '%s' from '%s'", path, name, src)
return self:recv_file_cb(src, path, name)
end
-- in: string, string, string
-- source token (string) of sender module side
-- action data (string) json string as a arguments to execute action via acts_engine
-- action name (string) to execute it into the acts_engine
-- out: boolean
-- result of action processing received from acts_engine
function CBaseEngine:recv_action(src, data, name)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(data) == "string", "input action data type is invalid")
assert(type(name) == "string", "input action name type is invalid")
__log.debugf("try exec action '%s' with data json '%s' from '%s'", name, data, src)
if self.config.actions[name] == nil then
__log.errorf("requested action '%s' does not exists in current action config", name)
return false
end
-- normalize action data payload
local action_name, action_data = name, cjson.decode(data)
action_data.data = action_data.data or {}
action_data.actions = action_data.actions or {}
-- add the action name to executed actions list to avoid infinity recursive calls
local action_full_name = tostring(self.mod_name) .. "." .. action_name
if glue.indexof(action_full_name, action_data.actions) == nil then
table.insert(action_data.actions, action_full_name)
end
local action_result = self:recv_action_cb(src, action_data, action_name)
if action_result then
self:commit_success(src, action_name, action_data)
else
self:commit_failed(src, action_name, action_data)
end
return action_result
end
-- virtual methods
CBaseEngine:virtual("timer_cb")
CBaseEngine:virtual("quit_cb")
CBaseEngine:virtual("agent_connected_cb")
CBaseEngine:virtual("agent_disconnected_cb")
CBaseEngine:virtual("update_config_cb")
CBaseEngine:virtual("recv_data_cb")
CBaseEngine:virtual("recv_file_cb")
CBaseEngine:virtual("recv_action_cb")
@@ -0,0 +1,241 @@
require("module")
local ffi = require("ffi")
local lfs = require("lfs")
local md5 = require("md5")
local zip = require("minizip")
local glue = require("glue")
local json = require("cjson.safe")
local sprofile = [[
{
"wrapper": {
"timeout_thread":5000,
"steps":["normalizer", "correlator"],
"messages_limit":100
},
"modules": {
"normalizer": {
"filename":"normalizer-module.dll",
"formats": {
"input":"JSON",
"output":"OBJECT"
},
"graph_filename":"formulas_graph.json",
"timeout_pull":20,
"timeout_thread":10,
"keepalive_timeout":1000,
"transfer_count":100,
"messages_limit":500,
"failure_alert":false,
"workers": {
"count":1,
"timeout":10
}
},
"correlator": {
"filename":"correlator-module.dll",
"formats": {
"input":"OBJECT",
"output":"JSON"
},
"graph_filename":"rules_graph.json",
"enricher_graph_filename":"enrules_graph.json",
"timeout_thread":2,
"timeout_pull":1,
"keepalive_timeout":1000,
"messages_limit":1000,
"failure_transfer":false,
"workers": {
"count":1
},
"cache": {
"update_period":30,
"messages_limit":5000,
"soft_ttl":1800,
"hard_ttl":7200
},
"database_extensions": {
"fpta": {
"enabled":false,
"path":"fpta_db.db"
},
"enricher": {
"enabled":false,
"path":"fpta_db.db"
}
}
}
}
}
]]
CCorrEngine = newclass("CCorrEngine")
function CCorrEngine:free()
if self and self.valid == true then
self.mdl:unregister()
self.mdl = nil
self.statistics = nil
self.callbacks = nil
self.valid = nil
end
end
--init correlator [receiveEvents - callback result correlations, restore - restore database]
function CCorrEngine:init(receiveEvents, restore)
zip.unzip(__tmpdir .. "\\data\\graphs.zip", "-d", __tmpdir .. "\\data\\")
self.callbacks = {
receive = function(type, data, size)
if type == 1 and receiveEvents then
receiveEvents(ffi.string(data,size))
elseif type == 2 then
self.statistics = json.decode(ffi.string(data,size))
elseif type == 3 then
__log.errorf("caught error from corr lib: '%s'", ffi.string(data,size))
end
return size
end
}
self.statistics = {}
self.valid = false
local jprofile = json.decode(sprofile)
for key, val in pairs(jprofile["modules"]) do
jprofile["modules"][key]["filename"] = __tmpdir .. "\\" .. val["filename"]
jprofile["modules"][key]["graph_filename"] = __tmpdir .. "\\data\\" .. val["graph_filename"]
if val["enricher_graph_filename"] then
jprofile["modules"][key]["enricher_graph_filename"] = __tmpdir .. "\\data\\" .. val["enricher_graph_filename"]
end
end
local current_dir = lfs.currentdir()
local global_dir_correlator = current_dir .. "\\_global\\correlator"
for _, val in pairs(jprofile["modules"]["correlator"]["database_extensions"]) do
local origfile = __tmpdir .. "\\data\\" .. val["path"] .. ".default"
local orighash = self.get_file_hash_md5(origfile)
local filename = global_dir_correlator .. "\\" .. orighash .. "_" .. val["path"]
if lfs.attributes(filename, "size") == nil then
restore = true
break
end
end
if restore == true then
__log.infof("try to restore global database folder '%s'", global_dir_correlator)
if lfs.attributes(global_dir_correlator, "modification") then
__log.infof("clear global database folder '%s'", global_dir_correlator)
for file in lfs.dir(global_dir_correlator) do
if file ~= "." and file ~= ".." then
__log.infof("remove file '%s'", file)
os.remove(global_dir_correlator .. "\\" .. file)
end
end
end
lfs.mkdir(current_dir .. "\\_global")
lfs.mkdir(current_dir .. "\\_global\\correlator")
end
for key, val in pairs(jprofile["modules"]["correlator"]["database_extensions"]) do
local filename = val["path"]
local origfile = __tmpdir .. "\\data\\" .. filename .. ".default"
local orighash = self.get_file_hash_md5(origfile)
local localpath = global_dir_correlator .. "\\" .. orighash .. "_" .. filename
self.copyFile(origfile, localpath)
if lfs.attributes(localpath, "size") then
jprofile["modules"]["correlator"]["database_extensions"][key]["enabled"] = true
jprofile["modules"]["correlator"]["database_extensions"][key]["path"] = localpath
__log.infof("enable '%s' database extensions with path '%s'", key, localpath)
end
end
self.mdl = CModule(__tmpdir .. "/" .. "CorrelationInterface")
__log.debugf("self.mdl=%s module_dir=%s/CorrelationInterface", tostring(self.mdl), __tmpdir)
if self.mdl:register(json.encode(jprofile), self.callbacks) == true then
self.mdl:start()
self.valid = true
else
self:free()
end
end
function CCorrEngine.get_file_hash_md5(filepath)
local md5_digest = md5.digest()
local file = io.open(filepath, "rb")
if not file then
return ""
end
local read_num, content = 1024 * 1024 -- 1 MB as a chunk to read file
while true do
content = file:read(read_num)
if content == nil then break end
md5_digest(content)
end
file:close()
return glue.tohex(md5_digest())
end
function CCorrEngine.copyFile(src, dst, force)
local f, err = io.open(src, 'rb')
if not f then return nil, err end
local t, ok
if not force then
t = io.open(dst, 'rb')
if t then
f:close()
t:close()
return nil, "file alredy exists"
end
end
t, err = io.open(dst, 'w+b')
if not t then
f:close()
return nil, err
end
local CHUNK_SIZE = 4096
while true do
local chunk = f:read(CHUNK_SIZE)
if not chunk then break end
ok, err = t:write(chunk)
if not ok then
t:close()
f:close()
return nil, err or "can not write"
end
end
t:close()
f:close()
collectgarbage("collect")
return true
end
function CCorrEngine:isValid()
return self.valid ~= nil and self.valid
end
function CCorrEngine:updateStats()
if self:isValid() == false then return end
self.mdl:send(2, "") --get statistics
self.mdl:send(4, "") --pull events
end
function CCorrEngine:pullEvents()
if self:isValid() == false then return end
self.mdl:send(4, "") --pull events
end
function CCorrEngine:sendEvent(data)
if self:isValid() == false then return false end
if self.mdl:send(1, data) ~= #data then -- if push event failed
self:pullEvents()
return false
end
return true
end
+86
View File
@@ -0,0 +1,86 @@
require("engines.acts_engine")
-- base config to actions engine
local cfg = {
config = {}
}
-- actions engine initialize
local acts_engine = CActsEngine(cfg)
-- set default timeout to wait exit on blocking of recv_* functions
__api.set_recv_timeout(5000) -- 5s
__api.add_cbs({
data = function(src, data)
__log.debugf("receive data from '%s' with data", src)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
return acts_engine:recv_data(src, data)
end,
file = function(src, path, name)
__log.infof("receive file from '%s' with name '%s' path '%s'", src, name, path)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
return acts_engine:recv_file(src, path, name)
end,
-- text = function(src, text, name)
-- msg = function(src, msg, mtype)
action = function(src, data, name)
__log.infof("receive action '%s' from '%s' with data %s", name, src, data)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
local action_result = acts_engine:recv_action(src, data, name)
__log.infof("requested action '%s' was executed: %s", name, action_result)
return action_result
end,
control = function(cmtype, data)
__log.debugf("receive control msg '%s' with data %s", cmtype, data)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
if cmtype == "quit" then
acts_engine:quit()
end
if cmtype == "agent_connected" then
acts_engine:agent_connected(data)
end
if cmtype == "agent_disconnected" then
acts_engine:agent_disconnected(data)
end
if cmtype == "update_config" then
acts_engine:update_config()
end
return true
end,
})
__log.infof("module '%s' was started", __config.ctx.name)
acts_engine:run()
__log.infof("module '%s' was stopped", __config.ctx.name)
-- explicit destroy engine
__log.info("before destroy correlator phase")
if acts_engine.correlator ~= nil then
acts_engine.correlator:free()
acts_engine.correlator = nil
end
collectgarbage("collect")
__log.info("after destroy correlator phase")
if acts_engine.event_engine ~= nil then
acts_engine.event_engine:free()
acts_engine.event_engine = nil
end
if acts_engine.action_engine ~= nil then
acts_engine.action_engine:free()
acts_engine.action_engine = nil
end
acts_engine = nil
collectgarbage("collect")
return "success"
+145
View File
@@ -0,0 +1,145 @@
require("yaci")
require("strict")
require("waffi.windows.common")
local ffi = require("ffi")
local lk32 = require("waffi.windows.kernel32")
ffi.cdef [[
typedef long (*Module__transport_data_Ptr)(void *transport,
int type, void *data, long size);
typedef struct _api_module_transport {
Module__transport_data_Ptr to_module;
void *module_ptr;
Module__transport_data_Ptr to_client;
void *client_ptr;
} api_module_transport;
typedef bool (*Module__Init_Ptr)(api_module_transport *transport, const void *profile,
size_t profileSize);
typedef void (*Module__Void_Ptr)(api_module_transport *transport);
typedef struct _api_module_interface {
Module__Init_Ptr init;
Module__Void_Ptr start;
Module__Void_Ptr stop;
Module__Void_Ptr pause;
Module__Void_Ptr resume;
} api_module_interface;
typedef api_module_interface *(*Module_Create_Ptr)(api_module_transport *transport,
int argc, const char **argv);
typedef void(*Module_Destroy_Ptr)(api_module_transport *transport);
typedef int(*Module_Version_Ptr)();
api_module_interface* module_create(api_module_transport *transport, int argc, const char **argv);
void module_destroy(api_module_transport *transport);
int module_version();
]]
CModule = newclass("CModule")
function CModule:init(moduleName)
local ctmpdir = ffi.new("char[?]", 256)
lk32.GetDllDirectoryA(256, ctmpdir)
lk32.SetDllDirectoryA(__tmpdir)
self.module = ffi.load(moduleName)
lk32.SetDllDirectoryA(ctmpdir)
self.api = {
create = self.module.module_create,
destroy = self.module.module_destroy,
version = nil,--self.module.Module__Version,
is_inited = false
}
self.transport = ffi.new("api_module_transport[1]", {})
end
function CModule:free()
__log.info("call CModule:free")
self:unregister()
end
function CModule:unregister()
__log.info("call CModule:unregister")
if self.module_i then
self.module_i.stop(self.transport)
self.api.destroy(self.transport)
__log.info("destroy successful")
end
if self.functions then
self.functions["receive"] = nil
end
self.functions = nil
self.transport = nil
if self.api then
self.api.create = nil
self.api.destroy = nil
self.api.version = nil
self.api.is_inited = nil
end
self.api = nil
self.module_i = nil
self.module = nil
self.profile = nil
collectgarbage("collect")
end
function CModule:register(profile, callbacks)
__log.info("call CModule:register")
assert(type(profile) == "string", "module profile is invalid")
assert(type(callbacks) == "table", "callbacks is invalid")
if self.module == nil then
return false, "module not loaded"
end
self.functions = {}
self.functions["receive"] = function(transport, type, data, size)
if callbacks and transport == self.transport and callbacks["receive"] then
return callbacks["receive"](type, data, size)
end
return -1
end
self.transport[0].to_client = ffi.cast("Module__transport_data_Ptr", self.functions["receive"])
self.module_i = self.api.create(self.transport, 0, nil)
self.profile = ffi.new("const char[?]", #profile + 1, profile)
local ctmpdir = ffi.new("char[?]", 256)
lk32.GetDllDirectoryA(256, ctmpdir)
lk32.SetDllDirectoryA(__tmpdir)
self.api.is_inited = self.module_i.init(self.transport,self.profile, #profile)
lk32.SetDllDirectoryA(ctmpdir)
return self.api.is_inited, ""
end
function CModule:start()
__log.info("call CModule:start")
if self.api.is_inited == false then
return
end
self.module_i.start(self.transport)
end
function CModule:send(type,data)
if self.transport[0].to_module == nil then
return
end
local _data
if #data ~= 0 then
_data = ffi.cast("void*", data)
end
return self.transport[0].to_module(self.transport, type, _data, #data)
end
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
+14
View File
@@ -0,0 +1,14 @@
{
"1.0.0": {
"en": {
"date": "04-19-2022",
"title": "Base functionality",
"description": "Implemented normalization, aggregation, and correlation of raw events from sources."
},
"ru": {
"date": "19.04.2022",
"title": "Базовая функциональность",
"description": "Реализована нормализация, агрегация и корреляция потока необработанных событий от источников."
}
}
}
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,262 @@
{
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_NetSh_NetShell": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_Ping_SelfDelete": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_Schtasks_Persistence": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Write_File_USB_AirSpread": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_CreateRemoteThread": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_ProcessTampering": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"reason",
"subject.process.cmdline",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_LsaComponents": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_SafeBoot": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_ScreenSaver": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
}
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,262 @@
{
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_NetSh_NetShell": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_Ping_SelfDelete": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Create_Process_Schtasks_Persistence": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "atomic"
},
"Suspicious_Write_File_USB_AirSpread": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_CreateRemoteThread": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_ProcessTampering": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"reason",
"subject.process.cmdline",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_LsaComponents": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_SafeBoot": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "atomic"
},
"Suspicious_Write_Registry_Key_ScreenSaver": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
}
}
@@ -0,0 +1 @@
[]
@@ -0,0 +1,548 @@
{
"additionalProperties": false,
"properties": {
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_Process_NetSh_NetShell": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_Process_Ping_SelfDelete": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_Process_Schtasks_Persistence": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_File_USB_AirSpread": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Process_Inject_CreateRemoteThread": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 16,
"minItems": 16,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Process_Inject_ProcessTampering": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"reason",
"subject.process.cmdline",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.path",
"reason",
"subject.process.cmdline",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 17,
"minItems": 17,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Registry_Key_LsaComponents": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "string"
},
"maxItems": 14,
"minItems": 14,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Registry_Key_SafeBoot": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.type",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name"
],
"type": "string"
},
"maxItems": 14,
"minItems": 14,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Registry_Key_ScreenSaver": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.property",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 14,
"minItems": 14,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
}
},
"required": [
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass",
"Suspicious_Create_Process_NetSh_NetShell",
"Suspicious_Create_Process_Ping_SelfDelete",
"Suspicious_Create_Process_Schtasks_Persistence",
"Suspicious_Write_File_USB_AirSpread",
"Suspicious_Write_Process_Inject_CreateRemoteThread",
"Suspicious_Write_Process_Inject_ProcessTampering",
"Suspicious_Write_Registry_Key_LsaComponents",
"Suspicious_Write_Registry_Key_SafeBoot",
"Suspicious_Write_Registry_Key_ScreenSaver"
],
"type": "object"
}
+196
View File
@@ -0,0 +1,196 @@
{
"additionalProperties": true,
"properties": {
"category.generic": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"category.high": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"correlation_name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"numfield1": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.new_value": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.cmdline": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.guid": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.process.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.parent.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.parent.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.process.parent.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.property": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.type": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.value": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"reason": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.cmdline": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.guid": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"subject.process.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
}
},
"required": [],
"type": "object"
}
+61
View File
@@ -0,0 +1,61 @@
{
"actions": [],
"events": [
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass",
"Suspicious_Create_Process_NetSh_NetShell",
"Suspicious_Create_Process_Ping_SelfDelete",
"Suspicious_Create_Process_Schtasks_Persistence",
"Suspicious_Write_File_USB_AirSpread",
"Suspicious_Write_Process_Inject_CreateRemoteThread",
"Suspicious_Write_Process_Inject_ProcessTampering",
"Suspicious_Write_Registry_Key_LsaComponents",
"Suspicious_Write_Registry_Key_SafeBoot",
"Suspicious_Write_Registry_Key_ScreenSaver"
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.new_value",
"object.path",
"object.process.cmdline",
"object.process.fullpath",
"object.process.guid",
"object.process.id",
"object.process.name",
"object.process.parent.fullpath",
"object.process.parent.id",
"object.process.parent.name",
"object.process.path",
"object.property",
"object.type",
"object.value",
"reason",
"subject.process.cmdline",
"subject.process.fullpath",
"subject.process.guid",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"name": "correlator",
"os": {
"windows": [
"amd64"
]
},
"system": false,
"tags": [
"detector",
"responder"
],
"template": "responder",
"version": {
"major": 1,
"minor": 0,
"patch": 0
}
}
+424
View File
@@ -0,0 +1,424 @@
{
"action_config": {},
"actions": {},
"config": {},
"event_config": {
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass": {},
"Suspicious_Create_Process_NetSh_NetShell": {},
"Suspicious_Create_Process_Ping_SelfDelete": {},
"Suspicious_Create_Process_Schtasks_Persistence": {},
"Suspicious_Write_File_USB_AirSpread": {},
"Suspicious_Write_Process_Inject_CreateRemoteThread": {},
"Suspicious_Write_Process_Inject_ProcessTampering": {},
"Suspicious_Write_Registry_Key_LsaComponents": {},
"Suspicious_Write_Registry_Key_SafeBoot": {},
"Suspicious_Write_Registry_Key_ScreenSaver": {}
},
"events": {
"Suspicious_Create_Process_BitsAdmin_RestrictionBypass": {
"en": {
"description": "BitsAdmin process creation; \nSeverity medium; Precision high",
"title": "Suspicious Create Process BitsAdmin RestrictionBypass"
},
"ru": {
"description": "BitsAdmin process creation; \nСредняя критичность; Высокая точность",
"title": "Suspicious Create Process BitsAdmin RestrictionBypass"
}
},
"Suspicious_Create_Process_NetSh_NetShell": {
"en": {
"description": "Malicious program changes windows firewall settings; \nSeverity medium; Precision high",
"title": "Suspicious Create Process NetSh NetShell"
},
"ru": {
"description": "Malicious program changes windows firewall settings; \nСредняя критичность; Высокая точность",
"title": "Suspicious Create Process NetSh NetShell"
}
},
"Suspicious_Create_Process_Ping_SelfDelete": {
"en": {
"description": "Ping process creation for self-deletion wait; \nSeverity medium; Precision high",
"title": "Suspicious Create Process Ping SelfDelete"
},
"ru": {
"description": "Ping process creation for self-deletion wait; \nСредняя критичность; Высокая точность",
"title": "Suspicious Create Process Ping SelfDelete"
}
},
"Suspicious_Create_Process_Schtasks_Persistence": {
"en": {
"description": "schtasks.exe run for persistence; \nSeverity medium; Precision high",
"title": "Suspicious Create Process Schtasks Persistence"
},
"ru": {
"description": "schtasks.exe run for persistence; \nСредняя критичность; Высокая точность",
"title": "Suspicious Create Process Schtasks Persistence"
}
},
"Suspicious_Write_File_USB_AirSpread": {
"en": {
"description": "echo \"123\" > f:\\\\autorun.inf; \nSeverity high; Precision high; MITRE techniques: T1546",
"title": "Suspicious Write File USB AirSpread"
},
"ru": {
"description": "echo \"123\" > f:\\\\autorun.inf; \nВысокая критичность; Высокая точность; Техники MITRE: T1546",
"title": "Suspicious Write File USB AirSpread"
}
},
"Suspicious_Write_Process_Inject_CreateRemoteThread": {
"en": {
"description": "Suspicious_Write_Process_Inject_CreateRemoteThread\nSeverity high; Precision high; MITRE techniques: T1055",
"title": "Suspicious Write Process Inject CreateRemoteThread"
},
"ru": {
"description": "Suspicious_Write_Process_Inject_CreateRemoteThread\nВысокая критичность; Высокая точность; Техники MITRE: T1055",
"title": "Suspicious Write Process Inject CreateRemoteThread"
}
},
"Suspicious_Write_Process_Inject_ProcessTampering": {
"en": {
"description": "Suspicious_Write_Process_Inject_ProcessTampering\nSeverity high; Precision high; MITRE techniques: T1055",
"title": "Suspicious Write Process Inject ProcessTampering"
},
"ru": {
"description": "Suspicious_Write_Process_Inject_ProcessTampering\nВысокая критичность; Высокая точность; Техники MITRE: T1055",
"title": "Suspicious Write Process Inject ProcessTampering"
}
},
"Suspicious_Write_Registry_Key_LsaComponents": {
"en": {
"description": "Suspicious_Write_Registry_Key_LsaComponents\nSeverity high; Precision high; MITRE techniques: T1547",
"title": "Suspicious Write Registry Key LsaComponents"
},
"ru": {
"description": "Suspicious_Write_Registry_Key_LsaComponents\nВысокая критичность; Высокая точность; Техники MITRE: T1547",
"title": "Suspicious Write Registry Key LsaComponents"
}
},
"Suspicious_Write_Registry_Key_SafeBoot": {
"en": {
"description": "Suspicious_Write_Registry_Key_SafeBoot\nSeverity high; Precision high; MITRE techniques: T1562",
"title": "Suspicious Write Registry Key SafeBoot"
},
"ru": {
"description": "Suspicious_Write_Registry_Key_SafeBoot\nВысокая критичность; Высокая точность; Техники MITRE: T1562",
"title": "Suspicious Write Registry Key SafeBoot"
}
},
"Suspicious_Write_Registry_Key_ScreenSaver": {
"en": {
"description": "Suspicious_Write_Registry_Key_ScreenSaver\nSeverity medium; Precision high; MITRE techniques: T1546.002, T1546",
"title": "Suspicious Write Registry Key ScreenSaver"
},
"ru": {
"description": "Suspicious_Write_Registry_Key_ScreenSaver\nСредняя критичность; Высокая точность; Техники MITRE: T1546.002, T1546",
"title": "Suspicious Write Registry Key ScreenSaver"
}
}
},
"fields": {
"category.generic": {
"en": {
"description": "category generic",
"title": "category.generic"
},
"ru": {
"description": "category generic",
"title": "category.generic"
}
},
"category.high": {
"en": {
"description": "category high",
"title": "category.high"
},
"ru": {
"description": "category high",
"title": "category.high"
}
},
"correlation_name": {
"en": {
"description": "correlation name",
"title": "correlation_name"
},
"ru": {
"description": "correlation name",
"title": "correlation_name"
}
},
"numfield1": {
"en": {
"description": "numfield1",
"title": "numfield1"
},
"ru": {
"description": "numfield1",
"title": "numfield1"
}
},
"object.fullpath": {
"en": {
"description": "object fullpath",
"title": "object.fullpath"
},
"ru": {
"description": "object fullpath",
"title": "object.fullpath"
}
},
"object.name": {
"en": {
"description": "object name",
"title": "object.name"
},
"ru": {
"description": "object name",
"title": "object.name"
}
},
"object.new_value": {
"en": {
"description": "object new value",
"title": "object.new_value"
},
"ru": {
"description": "object new value",
"title": "object.new_value"
}
},
"object.path": {
"en": {
"description": "object path",
"title": "object.path"
},
"ru": {
"description": "object path",
"title": "object.path"
}
},
"object.process.cmdline": {
"en": {
"description": "object process cmdline",
"title": "object.process.cmdline"
},
"ru": {
"description": "object process cmdline",
"title": "object.process.cmdline"
}
},
"object.process.fullpath": {
"en": {
"description": "object process fullpath",
"title": "object.process.fullpath"
},
"ru": {
"description": "object process fullpath",
"title": "object.process.fullpath"
}
},
"object.process.guid": {
"en": {
"description": "object process guid",
"title": "object.process.guid"
},
"ru": {
"description": "object process guid",
"title": "object.process.guid"
}
},
"object.process.id": {
"en": {
"description": "object process id",
"title": "object.process.id"
},
"ru": {
"description": "object process id",
"title": "object.process.id"
}
},
"object.process.name": {
"en": {
"description": "object process name",
"title": "object.process.name"
},
"ru": {
"description": "object process name",
"title": "object.process.name"
}
},
"object.process.parent.fullpath": {
"en": {
"description": "object process parent fullpath",
"title": "object.process.parent.fullpath"
},
"ru": {
"description": "object process parent fullpath",
"title": "object.process.parent.fullpath"
}
},
"object.process.parent.id": {
"en": {
"description": "object process parent id",
"title": "object.process.parent.id"
},
"ru": {
"description": "object process parent id",
"title": "object.process.parent.id"
}
},
"object.process.parent.name": {
"en": {
"description": "object process parent name",
"title": "object.process.parent.name"
},
"ru": {
"description": "object process parent name",
"title": "object.process.parent.name"
}
},
"object.process.path": {
"en": {
"description": "object process path",
"title": "object.process.path"
},
"ru": {
"description": "object process path",
"title": "object.process.path"
}
},
"object.property": {
"en": {
"description": "object property",
"title": "object.property"
},
"ru": {
"description": "object property",
"title": "object.property"
}
},
"object.type": {
"en": {
"description": "object type",
"title": "object.type"
},
"ru": {
"description": "object type",
"title": "object.type"
}
},
"object.value": {
"en": {
"description": "object value",
"title": "object.value"
},
"ru": {
"description": "object value",
"title": "object.value"
}
},
"reason": {
"en": {
"description": "reason",
"title": "reason"
},
"ru": {
"description": "reason",
"title": "reason"
}
},
"subject.process.cmdline": {
"en": {
"description": "subject process cmdline",
"title": "subject.process.cmdline"
},
"ru": {
"description": "subject process cmdline",
"title": "subject.process.cmdline"
}
},
"subject.process.fullpath": {
"en": {
"description": "subject process fullpath",
"title": "subject.process.fullpath"
},
"ru": {
"description": "subject process fullpath",
"title": "subject.process.fullpath"
}
},
"subject.process.guid": {
"en": {
"description": "subject process guid",
"title": "subject.process.guid"
},
"ru": {
"description": "subject process guid",
"title": "subject.process.guid"
}
},
"subject.process.id": {
"en": {
"description": "subject process id",
"title": "subject.process.id"
},
"ru": {
"description": "subject process id",
"title": "subject.process.id"
}
},
"subject.process.name": {
"en": {
"description": "subject process name",
"title": "subject.process.name"
},
"ru": {
"description": "subject process name",
"title": "subject.process.name"
}
},
"subject.process.path": {
"en": {
"description": "subject process path",
"title": "subject.process.path"
},
"ru": {
"description": "subject process path",
"title": "subject.process.path"
}
}
},
"module": {
"en": {
"description": "Performs normalization, aggregation, and correlation of a stream of raw events from sources. When malicious or suspicious activities are detected, it registers information security events (correlation events)",
"title": "Correlator (Windows)"
},
"ru": {
"description": "Выполняет нормализацию, агрегацию и корреляцию потока необработанных событий от источников. При обнаружении вредоносных или подозрительных действий регистрирует события ИБ (корреляционные события)",
"title": "Коррелятор (Windows)"
}
},
"secure_config": {},
"tags": {
"detector": {
"en": {
"description": "Analyzes collected events, detects suspicious and malicious activity on the end device, and registers information security events",
"title": "detector"
},
"ru": {
"description": "Анализиpирует собранные события, обнаруживают подозрительную и вредоносную активность на конечном устройстве — и регистрируют события ИБ",
"title": "detector"
}
},
"responder": {
"en": {
"description": "Stops suspicious and malicious activity on the end device by performing actions in accordance with the configuration of detection modules",
"title": "responder"
},
"ru": {
"description": "Пресекает подозрительную и вредоносную активность на конечном устройстве, выполняя действия в соответствии с конфигурацией модулей обнаружения",
"title": "responder"
}
}
}
}
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,10 @@
[
{
"module_name": "sysmon",
"type": "to_receive_data"
},
{
"module_name": "wineventlog",
"type": "to_receive_data"
}
]
+1
View File
@@ -0,0 +1 @@
{}
+28
View File
@@ -0,0 +1,28 @@
__api.add_cbs({
-- data = function(src, data)
-- file = function(src, path, name)
-- text = function(src, text, name)
-- msg = function(src, msg, mtype)
-- action = function(src, data, name)
control = function(cmtype, data)
__log.debugf("receive control msg '%s' with payload: %s", cmtype, data)
-- cmtype: "quit"
-- cmtype: "agent_connected"
-- cmtype: "agent_disconnected"
-- cmtype: "update_config"
return true
end,
})
__log.infof("module '%s' was started", __config.ctx.name)
__api.await(-1)
__log.infof("module '%s' was stopped", __config.ctx.name)
return 'success'
+15
View File
@@ -0,0 +1,15 @@
<template>
<div>
</div>
</template>
<script>
const name = "empty";
module.exports = {
name,
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
data: () => ({
})
};
</script>
+4
View File
@@ -0,0 +1,4 @@
{
"debug_engines": ["false"],
"debug_correlator": ["false"]
}
Binary file not shown.
@@ -0,0 +1,190 @@
require("yaci")
require("strict")
require("engines.base_engine")
require("engines.corr_engine")
local json = require("cjson.safe")
CActsEngine = newclass("CActsEngine", CBaseEngine)
--[[
cfg top keys:
* config - module arguments (hard limits)
]]
function CActsEngine:init(cfg)
__log.debug("init CActsEngine object")
assert(type(cfg) == "table", "configuration object has invalid type")
cfg.engine = "acts_engine"
self.super:init(cfg)
self.correlator = CCorrEngine(
function(event)
self:push_result(event)
end
)
if not self.correlator.valid then
__log.info("try to restore correlator instance")
self.correlator = CCorrEngine(
function(event)
self:push_result(event)
end,
true
)
end
assert(self.correlator.valid == true, "failed to initilize correlator")
self.proc_id_fields = {
"object.process.id",
"object.process.parent.id",
"subject.process.id",
"subject.process.parent.id",
}
-- initialization of object after base class constructing
self:update_config_cb()
end
-- in: nil
-- out: nil
function CActsEngine:free()
__log.debug("finalize CActsEngine object")
-- here will be triggered after closing vxproto object (destructor of the state)
end
-- in: nil
-- out: number
-- amount of milliseconds timeout to wait next call of the timer_cb
function CActsEngine:timer_cb()
-- __log.debug("timer_cb CActsEngine")
local acts_engine = CActsEngine:cast(self)
acts_engine.correlator:pullEvents()
__metric.add_int_gauge_counter("corr_agent_mem_usage", collectgarbage("count")*1024)
return 500
end
-- in: nil
-- out: nil
function CActsEngine:quit_cb()
__log.debug("quit_cb CActsEngine")
-- here will be triggered before closing vxproto object and destroying the state
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CActsEngine:agent_connected_cb(dst)
__log.debugf("agent_connected_cb CActsEngine with token '%s'", dst)
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CActsEngine:agent_disconnected_cb(dst)
__log.debugf("agent_disconnected_cb CActsEngine with token '%s'", dst)
end
-- in: nil
-- out: nil
function CActsEngine:update_config_cb()
__log.debug("update_config_cb CActsEngine")
-- actual current configuration contains into next fields
-- self.config.actions
-- self.config.events
-- self.config.module
end
-- in: string, string
-- source token (string) of sender module side
-- data payload (string) as a custom string serialized struct object (json)
-- out: boolean
-- result of data processing from business logic
function CActsEngine:recv_data_cb(src, data)
__log.debugf("perform custom logic for data with payload len %d from '%s'", #data, src)
local acts_engine = CActsEngine:cast(self)
local odata, err = json.decode(data)
if not odata then
__log.errorf("failed to parse events packet: %s", err)
return true
end
if acts_engine.correlator then
__metric.add_int_counter("corr_agent_events_recv_count", #odata)
__metric.add_int_counter("corr_agent_events_recv_size", #data)
for _,v in ipairs(odata) do
v.body = json.encode(v.body)
while acts_engine.correlator:sendEvent(json.encode(v)) == false do
__api.await(50)
end
end
else
__metric.add_int_counter("corr_agent_events_drop", #odata)
end
return true
end
-- in: string, string, string
-- source token (string) of sender module side
-- file path (string) on local FS where received file was stored
-- file name (string) is a original file name which was set on sender side
-- out: boolean
-- result of file processing from business logic
function CActsEngine:recv_file_cb(src, path, name)
__log.debugf("perform custom logic for file with path '%s' and name '%s' from '%s'", path, name, src)
return true
end
-- in: string, string, table
-- source token (string) of sender module side
-- action name (string) to execute it into the acts_engine
-- action data (table) as a arguments to execute action via acts_engine
-- e.x. {"data": {"key": "val"}, "actions": ["mod1.act1"]}
-- out: boolean
-- result of action processing from business logic
function CActsEngine:recv_action_cb(src, data, name)
__log.debugf("perform custom logic for action '%s' from '%s'", name, src)
local acts_engine = CActsEngine:cast(self)
if name == "some_action" then
return acts_engine:dummy(data.data["arg"])
end
return false
end
-- in: table
-- out: nil
function CActsEngine:push_result(event)
local oevent = json.decode(event)
if type(oevent) ~= "table" then
__log.errorf("failed to parse event from correlator: %s", tostring(event))
return
end
local event_name = oevent["_rule"]
local result = oevent
if event_name == nil or event_name == "" then return end
local config_events = self.config["events"] or {events={}}
local config_event = config_events[event_name] or {fields={}}
local config_fields = self.config["fields"] or {properties={}}
local _fields = config_event["fields"] or {}
local defaults = {string = "", number = 0, integer = 0, object = {}, array = {}, boolean = false, null = nil}
for _, v in ipairs(self.proc_id_fields) do
result[v] = tonumber(result[v])
end
for _, v in ipairs(_fields) do
result[v] = result[v] or defaults[(config_fields.properties[v] or {}).type or "null"]
end
__log.debugf("perform logic to push result: '%s'", json.encode(result))
self:push_event(event_name,result)
end
@@ -0,0 +1,336 @@
require("yaci")
require("strict")
require("engine")
local glue = require("glue")
local crc32 = require("crc32")
local cjson = require("cjson.safe")
math.randomseed(crc32(tostring({})))
CBaseEngine = newclass("CBaseEngine")
--[[
cfg top keys:
* config - module arguments (hard limits)
]]
function CBaseEngine:init(cfg)
__log.debug("init CBaseEngine object")
assert(type(cfg) == "table", "configuration object has invalid type")
self.config = glue.merge(self.config or {}, cfg.config or {})
self.config.actions = cjson.decode(__config.get_current_action_config())
self.config.events = cjson.decode(__config.get_current_event_config())
self.config.module = cjson.decode(__config.get_current_config())
self.config.fields = cjson.decode(__config.get_fields_schema())
self.mod_name = __config.ctx.name
self.is_debug = __args["debug_engines"][1] == "true"
self.prefix_db = __gid .. "."
self.server_token = ""
self.action_engine = CActionEngine(
{},
__args["debug_correlator"][1] == "true"
)
self.event_engine = CEventEngine(
__config.get_fields_schema(),
__config.get_current_event_config(),
__config.get_module_info(),
self.prefix_db,
__args["debug_correlator"][1] == "true"
)
end
-- in: nil
-- out: nil
function CBaseEngine:free()
__log.debug("finalize CBaseEngine object")
if self.event_engine ~= nil then
self.event_engine:free()
self.event_engine = nil
end
if self.action_engine ~= nil then
self.action_engine:free()
self.action_engine = nil
end
collectgarbage("collect")
end
-- in: nil
-- out: nil
function CBaseEngine:run()
__log.debug("run CBaseEngine started")
while not __api.is_close() do
local timeout = self:timer_cb()
assert(type(timeout) == "number", "await timeout has invalid type")
__api.await(timeout)
end
__log.debug("run CBaseEngine stopped")
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CBaseEngine:agent_connected(dst)
__log.debugf("agent_connected CBaseEngine with token '%s'", dst)
self:agent_connected_cb(dst)
end
-- in: string
-- destination token (string) of server module side
-- out: nil
function CBaseEngine:agent_disconnected(dst)
__log.debugf("agent_disconnected CBaseEngine with token '%s'", dst)
self:agent_disconnected_cb(dst)
end
-- in: nil
-- out: nil
function CBaseEngine:quit()
__log.debug("quit CBaseEngine")
self:quit_cb()
end
-- in: nil
-- out: nil
function CBaseEngine:update_config()
__log.debug("update_config CBaseEngine")
-- renew actions and events config according by the module configuration
self.config.actions = cjson.decode(__config.get_current_action_config())
self.config.events = cjson.decode(__config.get_current_event_config())
self.config.module = cjson.decode(__config.get_current_config())
self.config.fields = cjson.decode(__config.get_fields_schema())
-- renew current event engine instance
if self.event_engine ~= nil then
self.event_engine:free()
self.event_engine = nil
collectgarbage("collect")
self.event_engine = CEventEngine(
__config.get_fields_schema(),
__config.get_current_event_config(),
__config.get_module_info(),
self.prefix_db,
__args["debug_correlator"][1] == "true"
)
end
-- notify engine about update config from the server
self:update_config_cb()
end
-- in: string, string, string, table
-- out: nil
function CBaseEngine:commit_event(src, event_name, action_name, action_data)
__log.debug("commit_event CBaseEngine")
if self.config.events[event_name] == nil then
__log.errorf("requested event '%s' does not exists in current event config", event_name)
return
end
local is_imc, mod_name, group_id = self:get_sender_info(src)
action_data.data.action = {
["name"] = action_name,
["source"] = {
["is_imc"] = is_imc,
["mod_name"] = mod_name,
["group_id"] = group_id,
},
}
self:push_event(event_name, action_data.data, action_data.actions)
end
-- in: string, string, table
-- out: nil
function CBaseEngine:commit_success(src, action_name, action_data)
__log.debug("commit_success CBaseEngine")
local event_name = tostring(self.mod_name) .. "_action_exec_success"
action_data.data.result = true
action_data.data.reason = "action_exec_success"
self:commit_event(src, event_name, action_name, action_data)
-- case to notify other side about action execution result
if type(action_data.retaddr) == "string" and action_data.retaddr ~= "" then
local data = cjson.encode(glue.merge({status = "success"}, action_data))
__api.send_data_to(src, data)
end
end
-- in: string, string, table
-- out: nil
function CBaseEngine:commit_failed(src, action_name, action_data)
__log.debug("commit_failed CBaseEngine")
local event_name = tostring(self.mod_name) .. "_action_exec_failed"
action_data.data.result = false
action_data.data.reason = "action_exec_failed"
self:commit_event(src, event_name, action_name, action_data)
-- case to notify other side about action execution result
if type(action_data.retaddr) == "string" and action_data.retaddr ~= "" then
local data = cjson.encode(glue.merge({status = "error"}, action_data))
__api.send_data_to(src, data)
end
end
-- in: string
-- source token (string) of sender module side
-- out: boolean, string, string
-- is it inter modules communication packet (boolean)
-- module name (string) which was a sender the packet
-- group id (string) which contained the sender module
function CBaseEngine:get_sender_info(src)
if __imc.is_exist(src) then
local mod_name, group_id = __imc.get_info(src)
__log.debugf("received internal from module '%s' and group '%s'", mod_name, group_id)
return true, mod_name, group_id
end
__log.debugf("message received from the server")
return false, self.mod_name, __gid
end
-- in: nil
-- out: string
-- destination token (string) it'll be empty if agent disconnected
function CBaseEngine:get_server_token()
local tablelength = function(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
if tablelength(__agents.get_by_dst(self.server_token)) == 0 then
self.server_token = ""
else
return self.server_token
end
for client_id, client_info in pairs(__agents.dump()) do
if tostring(client_info.Type) == "VXAgent" then
self.server_token = tostring(client_id)
return self.server_token
end
end
return ""
end
-- in: string, table, table or nil
-- event name (string) to execute it into event engine
-- event data (table) to store key-value struct into the event
-- previous actions array (table or nil) to avoid loop actions execution
-- out: boolean
-- result of event processing received from event engine (true if event exists)
function CBaseEngine:push_event(name, data, actions)
assert(type(name) == "string", "input event name type is invalid")
assert(type(data) == "table", "input event data type is invalid")
assert(not actions or type(actions) == "table", "input event data type is invalid")
assert(self.event_engine ~= nil, "event engine is not initialized")
assert(self.action_engine ~= nil, "action engine is not initialized")
__log.debugf("try push event '%s' with data json: %s", name, cjson.encode(data))
if self.config.events[name] == nil then
__log.errorf("requested event '%s' does not exists in current event config", name)
return false
end
-- build event info structure
local info = {
["name"] = name,
["data"] = data,
["actions"] = actions or {},
}
local event_result, action_list = self.event_engine:push_event(info)
__log.debugf("result of pushing event '%s' is %s", name, event_result)
-- check result return variable as marker is there need to execute actions
if event_result then
__log.debugf("try to exec event '%s' actions list %s", name, cjson.encode(action_list))
for action_id, action_result in ipairs(self.action_engine:exec(__aid, action_list)) do
__log.debugf("result of executing action '%s' is %s", action_id, action_result)
end
end
return event_result
end
-- in: string, string
-- source token (string) of sender module side
-- data payload (string) as a custom string serialized struct object (json)
-- out: boolean
-- result of data processing received from acts_engine
function CBaseEngine:recv_data(src, data)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(data) == "string", "input action data type is invalid")
__log.debugf("try process data with payload len %d from '%s'", #data, src)
return self:recv_data_cb(src, data)
end
-- in: string, string, string
-- source token (string) of sender module side
-- file path (string) on local FS where received file was stored
-- file name (string) is a original file name which was set on sender side
-- out: boolean
-- result of file processing received from acts_engine
function CBaseEngine:recv_file(src, path, name)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(path) == "string", "input file path type is invalid")
assert(type(name) == "string", "input file name type is invalid")
__log.debugf("try process file with path '%s' and name '%s' from '%s'", path, name, src)
return self:recv_file_cb(src, path, name)
end
-- in: string, string, string
-- source token (string) of sender module side
-- action data (string) json string as a arguments to execute action via acts_engine
-- action name (string) to execute it into the acts_engine
-- out: boolean
-- result of action processing received from acts_engine
function CBaseEngine:recv_action(src, data, name)
assert(type(src) == "string", "sender module source token type is invalid")
assert(type(data) == "string", "input action data type is invalid")
assert(type(name) == "string", "input action name type is invalid")
__log.debugf("try exec action '%s' with data json '%s' from '%s'", name, data, src)
if self.config.actions[name] == nil then
__log.errorf("requested action '%s' does not exists in current action config", name)
return false
end
-- normalize action data payload
local action_name, action_data = name, cjson.decode(data)
action_data.data = action_data.data or {}
action_data.actions = action_data.actions or {}
-- add the action name to executed actions list to avoid infinity recursive calls
local action_full_name = tostring(self.mod_name) .. "." .. action_name
if glue.indexof(action_full_name, action_data.actions) == nil then
table.insert(action_data.actions, action_full_name)
end
local action_result = self:recv_action_cb(src, action_data, action_name)
if action_result then
self:commit_success(src, action_name, action_data)
else
self:commit_failed(src, action_name, action_data)
end
return action_result
end
-- virtual methods
CBaseEngine:virtual("timer_cb")
CBaseEngine:virtual("quit_cb")
CBaseEngine:virtual("agent_connected_cb")
CBaseEngine:virtual("agent_disconnected_cb")
CBaseEngine:virtual("update_config_cb")
CBaseEngine:virtual("recv_data_cb")
CBaseEngine:virtual("recv_file_cb")
CBaseEngine:virtual("recv_action_cb")
@@ -0,0 +1,266 @@
require("module")
local ffi = require("ffi")
local lfs = require("lfs")
local md5 = require("md5")
local zip = require("minizip")
local glue = require("glue")
local json = require("cjson.safe")
local luapath = require("path")
local sprofile = [[
{
"wrapper": {
"timeout_thread":5000,
"steps":["normalizer", "correlator"],
"messages_limit":100
},
"modules": {
"normalizer": {
"filename":"normalizer-module",
"formats": {
"input":"JSON",
"output":"OBJECT"
},
"graph_filename":"formulas_graph.json",
"timeout_pull":500,
"timeout_thread":10,
"keepalive_timeout":1000,
"transfer_count":100,
"messages_limit":500,
"failure_alert":false,
"workers": {
"count":1,
"timeout":5
}
},
"correlator": {
"filename":"correlator-module",
"formats": {
"input":"OBJECT",
"output":"JSON"
},
"graph_filename":"rules_graph.json",
"enricher_graph_filename":"enrules_graph.json",
"timeout_thread":20,
"timeout_pull":500,
"keepalive_timeout":1000,
"messages_limit":1000,
"failure_transfer":false,
"workers": {
"count":1
},
"cache": {
"update_period":30,
"messages_limit":5000,
"soft_ttl":1800,
"hard_ttl":7200
},
"database_extensions": {
"fpta": {
"enabled":false,
"path":"fpta_db.db"
},
"enricher": {
"enabled":false,
"path":"fpta_db.db"
}
}
}
}
}
]]
CCorrEngine = newclass("CCorrEngine")
function CCorrEngine:free()
if self and self.valid == true then
self.mdl:unregister()
self.mdl = nil
self.statistics = nil
self.callbacks = nil
self.valid = nil
end
end
--init correlator [receiveEvents - callback result correlations, restore - restore database]
function CCorrEngine:init(receiveEvents, restore)
local tmpdir_data = luapath.combine(__tmpdir, "data")
zip.unzip(luapath.combine(tmpdir_data, "graphs.zip"), "-d", tmpdir_data)
self.callbacks = {
receive = function(type, data, size)
if type == 1 and receiveEvents then
receiveEvents(ffi.string(data,size))
elseif type == 2 then
self.statistics = json.decode(ffi.string(data,size))
elseif type == 3 then
__log.errorf("caught error from corr lib: '%s'", ffi.string(data,size))
end
return size
end
}
self.statistics = {}
self.valid = false
local jprofile = json.decode(sprofile)
local _ext = ""
if ffi.os == "Linux" then
_ext = ".so"
elseif ffi.os == "Windows" then
_ext = ".dll"
end
for key, val in pairs(jprofile["modules"]) do
jprofile["modules"][key]["filename"] = luapath.combine(__tmpdir, val["filename"] .. _ext)
jprofile["modules"][key]["graph_filename"] = luapath.combine(tmpdir_data, val["graph_filename"])
if val["enricher_graph_filename"] then
jprofile["modules"][key]["enricher_graph_filename"] = luapath.combine(tmpdir_data, val["enricher_graph_filename"])
end
end
local current_dir = luapath.normalize(lfs.currentdir())
local global_dir = luapath.combine(current_dir, "_global")
local global_dir_correlator = luapath.combine(global_dir, "correlator")
for key, val in pairs(jprofile["modules"]["correlator"]["database_extensions"]) do
local origfile = luapath.combine(tmpdir_data, val["path"] .. ".default")
local orighash = self.get_file_hash_md5(origfile)
local filename = luapath.combine(global_dir_correlator, orighash .. "_" .. key .. "_" .. val["path"])
if lfs.attributes(filename, "size") == nil then
restore = true
break
end
end
if restore == true then
__log.infof("try to restore global database folder '%s'", global_dir_correlator)
if lfs.attributes(global_dir_correlator, "modification") then
__log.infof("clear global database folder '%s'", global_dir_correlator)
for file in lfs.dir(global_dir_correlator) do
if file ~= "." and file ~= ".." then
__log.infof("remove file '%s'", file)
os.remove(luapath.combine(global_dir_correlator, file))
end
end
end
lfs.mkdir(global_dir)
lfs.mkdir(global_dir_correlator)
end
for key, val in pairs(jprofile["modules"]["correlator"]["database_extensions"]) do
local filename = val["path"]
local origfile = luapath.combine(tmpdir_data, filename .. ".default")
local orighash = self.get_file_hash_md5(origfile)
local localpath = luapath.combine(global_dir_correlator, orighash .. "_" .. key .. "_" .. filename)
self.copyFile(origfile, localpath)
if lfs.attributes(localpath, "size") then
jprofile["modules"]["correlator"]["database_extensions"][key]["enabled"] = true
jprofile["modules"]["correlator"]["database_extensions"][key]["path"] = localpath
__log.infof("enable '%s' database extensions with path '%s'", key, localpath)
end
end
self.mdl = CModule(luapath.combine(__tmpdir, "CorrelationInterface" .. _ext))
__log.debugf("self.mdl=%s module_dir=%s/CorrelationInterface", tostring(self.mdl), __tmpdir)
if self.mdl:register(json.encode(jprofile), self.callbacks) == true then
self.mdl:start()
self.valid = true
else
self:free()
end
end
function CCorrEngine.get_file_hash_md5(filepath)
local md5_digest = md5.digest()
local file = io.open(filepath, "rb")
if not file then
return ""
end
local read_num, content = 1024 * 1024 -- 1 MB as a chunk to read file
while true do
content = file:read(read_num)
if content == nil then break end
md5_digest(content)
end
file:close()
return glue.tohex(md5_digest())
end
function CCorrEngine.copyFile(src, dst, force)
local f, err = io.open(src, 'rb')
if not f then return nil, err end
local t, ok
if not force then
t = io.open(dst, 'rb')
if t then
f:close()
t:close()
return nil, "file alredy exists"
end
end
t, err = io.open(dst, 'w+b')
if not t then
f:close()
return nil, err
end
local CHUNK_SIZE = 4096
while true do
local chunk = f:read(CHUNK_SIZE)
if not chunk then break end
ok, err = t:write(chunk)
if not ok then
t:close()
f:close()
return nil, err or "can not write"
end
end
t:close()
f:close()
collectgarbage("collect")
return true
end
function CCorrEngine:copyDir(dir_from, dir_to, force)
for file in lfs.dir(dir_from) do
if file ~= "." and file ~= ".." then
local f = dir_from .. '/' .. file
local attr = lfs.attributes(f)
if attr.mode == "directory" then
self:copyDir(f, dir_to, force)
end
self.copyFile(f, luapath.combine(dir_to, file), force)
end
end
end
function CCorrEngine:isValid()
return self.valid ~= nil and self.valid
end
function CCorrEngine:updateStats()
if self:isValid() == false then return end
self.mdl:send(2, "") --get statistics
self.mdl:send(4, "") --pull events
end
function CCorrEngine:pullEvents()
if self:isValid() == false then return end
self.mdl:send(4, "") --pull events
end
function CCorrEngine:sendEvent(data)
if self:isValid() == false then return false end
if self.mdl:send(1, data) ~= #data then -- if push event failed
self:pullEvents()
return false
end
return true
end
+86
View File
@@ -0,0 +1,86 @@
require("engines.acts_engine")
-- base config to actions engine
local cfg = {
config = {}
}
-- actions engine initialize
local acts_engine = CActsEngine(cfg)
-- set default timeout to wait exit on blocking of recv_* functions
__api.set_recv_timeout(5000) -- 5s
__api.add_cbs({
data = function(src, data)
__log.debugf("receive data from '%s' with data", src)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
return acts_engine:recv_data(src, data)
end,
file = function(src, path, name)
__log.infof("receive file from '%s' with name '%s' path '%s'", src, name, path)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
return acts_engine:recv_file(src, path, name)
end,
-- text = function(src, text, name)
-- msg = function(src, msg, mtype)
action = function(src, data, name)
__log.infof("receive action '%s' from '%s' with data %s", name, src, data)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
local action_result = acts_engine:recv_action(src, data, name)
__log.infof("requested action '%s' was executed: %s", name, action_result)
return action_result
end,
control = function(cmtype, data)
__log.debugf("receive control msg '%s' with data %s", cmtype, data)
assert(acts_engine ~= nil, "actions engine instance is not initialized")
if cmtype == "quit" then
acts_engine:quit()
end
if cmtype == "agent_connected" then
acts_engine:agent_connected(data)
end
if cmtype == "agent_disconnected" then
acts_engine:agent_disconnected(data)
end
if cmtype == "update_config" then
acts_engine:update_config()
end
return true
end,
})
__log.infof("module '%s' was started", __config.ctx.name)
acts_engine:run()
__log.infof("module '%s' was stopped", __config.ctx.name)
-- explicit destroy engine
__log.info("before destroy correlator phase")
if acts_engine.correlator ~= nil then
acts_engine.correlator:free()
acts_engine.correlator = nil
end
collectgarbage("collect")
__log.info("after destroy correlator phase")
if acts_engine.event_engine ~= nil then
acts_engine.event_engine:free()
acts_engine.event_engine = nil
end
if acts_engine.action_engine ~= nil then
acts_engine.action_engine:free()
acts_engine.action_engine = nil
end
acts_engine = nil
collectgarbage("collect")
return "success"
+171
View File
@@ -0,0 +1,171 @@
require("yaci")
require("strict")
local ffi = require("ffi")
local lfs = require("lfs")
ffi.cdef [[
typedef long (*Module__transport_data_Ptr)(void *transport,
int type, void *data, long size);
typedef struct _api_module_transport {
Module__transport_data_Ptr to_module;
void *module_ptr;
Module__transport_data_Ptr to_client;
void *client_ptr;
} api_module_transport;
typedef bool (*Module__Init_Ptr)(api_module_transport *transport, const void *profile,
size_t profileSize);
typedef void (*Module__Void_Ptr)(api_module_transport *transport);
typedef struct _api_module_interface {
Module__Init_Ptr init;
Module__Void_Ptr start;
Module__Void_Ptr stop;
Module__Void_Ptr pause;
Module__Void_Ptr resume;
} api_module_interface;
typedef api_module_interface *(*Module_Create_Ptr)(api_module_transport *transport,
int argc, const char **argv);
typedef void(*Module_Destroy_Ptr)(api_module_transport *transport);
typedef int(*Module_Version_Ptr)();
api_module_interface* module_create(api_module_transport *transport, int argc, const char **argv);
void module_destroy(api_module_transport *transport);
int module_version();
]]
CModule = newclass("CModule")
function CModule:init(moduleName)
-- dependencies loading for linux agent because there is use custom folder for libs
if ffi.os == "Linux" then
self.deps = {}
local ld_lib_dir = __tmpdir .. "/lib"
for file in lfs.dir(ld_lib_dir) do
if file ~= "." and file ~= ".." then
table.insert(self.deps, ffi.load(ld_lib_dir .. "/" .. file))
end
end
end
self.wrap_load(function()
self.module = ffi.load(moduleName)
end)
self.api = {
create = self.module.module_create,
destroy = self.module.module_destroy,
version = nil,--self.module.Module__Version,
is_inited = false
}
self.transport = ffi.new("api_module_transport[1]", {})
end
function CModule:free()
__log.info("call CModule:free")
self:unregister()
end
function CModule:unregister()
__log.info("call CModule:unregister")
if self.module_i then
self.module_i.stop(self.transport)
self.api.destroy(self.transport)
__log.info("destroy successful")
end
if self.functions then
self.functions["receive"] = nil
end
self.functions = nil
self.transport = nil
if self.api then
self.api.create = nil
self.api.destroy = nil
self.api.version = nil
self.api.is_inited = nil
end
self.api = nil
self.module_i = nil
self.module = nil
self.profile = nil
collectgarbage("collect")
self.deps = nil
collectgarbage("collect")
end
function CModule:register(profile, callbacks)
__log.info("call CModule:register")
assert(type(profile) == "string", "module profile is invalid")
assert(type(callbacks) == "table", "callbacks is invalid")
if self.module == nil then
return false, "module not loaded"
end
self.functions = {}
self.functions["receive"] = function(transport, type, data, size)
if callbacks and transport == self.transport and callbacks["receive"] then
return callbacks["receive"](type, data, size)
end
return -1
end
self.transport[0].to_client = ffi.cast("Module__transport_data_Ptr", self.functions["receive"])
self.module_i = self.api.create(self.transport, 0, nil)
self.profile = ffi.new("const char[?]", #profile + 1, profile)
self.wrap_load(function()
self.api.is_inited = self.module_i.init(self.transport, self.profile, #profile)
end)
return self.api.is_inited, ""
end
function CModule:start()
__log.info("call CModule:start")
if self.api.is_inited == false then
return
end
self.module_i.start(self.transport)
end
function CModule:send(type,data)
if self.transport[0].to_module == nil then
return
end
local _data
if #data ~= 0 then
_data = ffi.cast("void*", data)
end
return self.transport[0].to_module(self.transport, type, _data, #data)
end
if ffi.os == "Linux" then
function CModule.wrap_load(callback)
callback()
end
end
if ffi.os == "Windows" then
function CModule.wrap_load(callback)
local lk32 = require("waffi.windows.kernel32")
local ctmpdir = ffi.new("char[?]", 256)
lk32.GetDllDirectoryA(256, ctmpdir)
lk32.SetDllDirectoryA(__tmpdir)
callback()
lk32.SetDllDirectoryA(ctmpdir)
end
end
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
@@ -0,0 +1,14 @@
{
"1.0.0": {
"en": {
"date": "06-19-2022",
"title": "Base functionality",
"description": "Implemented normalization, aggregation, and correlation of raw events from sources."
},
"ru": {
"date": "19.06.2022",
"title": "Базовая функциональность",
"description": "Реализована нормализация, агрегация и корреляция потока необработанных событий от источников."
}
}
}
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,240 @@
{
"Malware_Exploit_Elf_CVE_2021_4034_a": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Boot_Modification": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Boot_RCScripts": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Scheduler_Cron": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Ssh_AuthorizedKeys": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_Process_Iptables_ModifyFirewall": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.id",
"object.process.path"
],
"type": "atomic"
},
"Suspicious_Read_File_Passwd_CredentialsEnumeration": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Read_File_Shadow_CredentialsDumping": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_File_PAM_Persistence": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_Ptrace": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.id",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
}
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,240 @@
{
"Malware_Exploit_Elf_CVE_2021_4034_a": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Boot_Modification": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Boot_RCScripts": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Scheduler_Cron": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_File_Ssh_AuthorizedKeys": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Create_Process_Iptables_ModifyFirewall": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.id",
"object.process.path"
],
"type": "atomic"
},
"Suspicious_Read_File_Passwd_CredentialsEnumeration": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Read_File_Shadow_CredentialsDumping": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_File_PAM_Persistence": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
},
"Suspicious_Write_Process_Inject_Ptrace": {
"actions": [
{
"fields": [],
"module_name": "this",
"name": "log_to_db",
"priority": 10
}
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.id",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "atomic"
}
}
@@ -0,0 +1 @@
[]
@@ -0,0 +1,504 @@
{
"additionalProperties": false,
"properties": {
"Malware_Exploit_Elf_CVE_2021_4034_a": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "string"
},
"maxItems": 8,
"minItems": 8,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_File_Boot_Modification": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_File_Boot_RCScripts": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_File_Scheduler_Cron": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_File_Ssh_AuthorizedKeys": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Create_Process_Iptables_ModifyFirewall": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.id",
"object.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.id",
"object.process.path"
],
"type": "string"
},
"maxItems": 10,
"minItems": 10,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Read_File_Passwd_CredentialsEnumeration": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "string"
},
"maxItems": 12,
"minItems": 12,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Read_File_Shadow_CredentialsDumping": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.state",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "string"
},
"maxItems": 12,
"minItems": 12,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_File_PAM_Persistence": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
},
"Suspicious_Write_Process_Inject_Ptrace": {
"allOf": [
{
"$ref": "#/definitions/events.atomic"
},
{
"properties": {
"fields": {
"default": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.id",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"items": {
"enum": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.process.id",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"type": "string"
},
"maxItems": 11,
"minItems": 11,
"type": "array"
}
},
"required": [
"fields"
],
"type": "object"
}
]
}
},
"required": [
"Malware_Exploit_Elf_CVE_2021_4034_a",
"Suspicious_Create_File_Boot_Modification",
"Suspicious_Create_File_Boot_RCScripts",
"Suspicious_Create_File_Scheduler_Cron",
"Suspicious_Create_File_Ssh_AuthorizedKeys",
"Suspicious_Create_Process_Iptables_ModifyFirewall",
"Suspicious_Read_File_Passwd_CredentialsEnumeration",
"Suspicious_Read_File_Shadow_CredentialsDumping",
"Suspicious_Write_File_PAM_Persistence",
"Suspicious_Write_Process_Inject_Ptrace"
],
"type": "object"
}
@@ -0,0 +1,154 @@
{
"additionalProperties": true,
"properties": {
"category.generic": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"category.high": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"correlation_name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"numfield1": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.cmdline": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.process.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.process.parent.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"object.process.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.state": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"object.value": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.fullpath": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"subject.process.meta": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.name": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
},
"subject.process.parent.id": {
"rules": {},
"type": "number",
"ui": {
"widgetConfig": {}
}
},
"subject.process.path": {
"rules": {},
"type": "string",
"ui": {
"widgetConfig": {}
}
}
},
"required": [],
"type": "object"
}
+55
View File
@@ -0,0 +1,55 @@
{
"actions": [],
"events": [
"Malware_Exploit_Elf_CVE_2021_4034_a",
"Suspicious_Create_File_Boot_Modification",
"Suspicious_Create_File_Boot_RCScripts",
"Suspicious_Create_File_Scheduler_Cron",
"Suspicious_Create_File_Ssh_AuthorizedKeys",
"Suspicious_Create_Process_Iptables_ModifyFirewall",
"Suspicious_Read_File_Passwd_CredentialsEnumeration",
"Suspicious_Read_File_Shadow_CredentialsDumping",
"Suspicious_Write_File_PAM_Persistence",
"Suspicious_Write_Process_Inject_Ptrace"
],
"fields": [
"category.generic",
"category.high",
"correlation_name",
"numfield1",
"object.fullpath",
"object.name",
"object.path",
"object.process.cmdline",
"object.process.fullpath",
"object.process.id",
"object.process.name",
"object.process.parent.id",
"object.process.path",
"object.state",
"object.value",
"subject.process.fullpath",
"subject.process.id",
"subject.process.meta",
"subject.process.name",
"subject.process.parent.id",
"subject.process.path"
],
"name": "correlator_linux",
"os": {
"linux": [
"amd64"
]
},
"system": false,
"tags": [
"detector",
"responder"
],
"template": "responder",
"version": {
"major": 1,
"minor": 0,
"patch": 0
}
}
+364
View File
@@ -0,0 +1,364 @@
{
"action_config": {},
"actions": {},
"config": {},
"event_config": {
"Malware_Exploit_Elf_CVE_2021_4034_a": {},
"Suspicious_Create_File_Boot_Modification": {},
"Suspicious_Create_File_Boot_RCScripts": {},
"Suspicious_Create_File_Scheduler_Cron": {},
"Suspicious_Create_File_Ssh_AuthorizedKeys": {},
"Suspicious_Create_Process_Iptables_ModifyFirewall": {},
"Suspicious_Read_File_Passwd_CredentialsEnumeration": {},
"Suspicious_Read_File_Shadow_CredentialsDumping": {},
"Suspicious_Write_File_PAM_Persistence": {},
"Suspicious_Write_Process_Inject_Ptrace": {}
},
"events": {
"Malware_Exploit_Elf_CVE_2021_4034_a": {
"en": {
"description": "Malware_Exploit_Elf_CVE_2021_4034_a",
"title": "Malware Exploit Elf CVE 2021 4034 a"
},
"ru": {
"description": "Malware_Exploit_Elf_CVE_2021_4034_a",
"title": "Malware Exploit Elf CVE 2021 4034 a"
}
},
"Suspicious_Create_File_Boot_Modification": {
"en": {
"description": "Detect /boot/ modification; \nSeverity medium; Precision high",
"title": "Suspicious Create File Boot Modification"
},
"ru": {
"description": "Detect /boot/ modification; \nСредняя критичность; Высокая точность",
"title": "Suspicious Create File Boot Modification"
}
},
"Suspicious_Create_File_Boot_RCScripts": {
"en": {
"description": "Detect creation of Boot or Logon initialization scripts; \nSeverity medium; Precision high; MITRE techniques: T1037",
"title": "Suspicious Create File Boot RCScripts"
},
"ru": {
"description": "Detect creation of Boot or Logon initialization scripts; \nСредняя критичность; Высокая точность; Техники MITRE: T1037",
"title": "Suspicious Create File Boot RCScripts"
}
},
"Suspicious_Create_File_Scheduler_Cron": {
"en": {
"description": "Persistence via cron jobs; \nSeverity medium; Precision high; MITRE techniques: T1053",
"title": "Suspicious Create File Scheduler Cron"
},
"ru": {
"description": "Persistence via cron jobs; \nСредняя критичность; Высокая точность; Техники MITRE: T1053",
"title": "Suspicious Create File Scheduler Cron"
}
},
"Suspicious_Create_File_Ssh_AuthorizedKeys": {
"en": {
"description": "Persistence via SSH keys; \nSeverity high; Precision high; MITRE techniques: T1098",
"title": "Suspicious Create File Ssh AuthorizedKeys"
},
"ru": {
"description": "Persistence via SSH keys; \nВысокая критичность; Высокая точность; Техники MITRE: T1098",
"title": "Suspicious Create File Ssh AuthorizedKeys"
}
},
"Suspicious_Create_Process_Iptables_ModifyFirewall": {
"en": {
"description": "Disable or modify system firewalls in order to bypass controls limiting network usage; \nSeverity high; Precision high; MITRE techniques: T1562",
"title": "Suspicious Create Process Iptables ModifyFirewall"
},
"ru": {
"description": "Disable or modify system firewalls in order to bypass controls limiting network usage; \nВысокая критичность; Высокая точность; Техники MITRE: T1562",
"title": "Suspicious Create Process Iptables ModifyFirewall"
}
},
"Suspicious_Read_File_Passwd_CredentialsEnumeration": {
"en": {
"description": "Read file /etc/passwd with users login information; \nSeverity medium; Precision high; MITRE techniques: T1003",
"title": "Suspicious Read File Passwd CredentialsEnumeration"
},
"ru": {
"description": "Read file /etc/passwd with users login information; \nСредняя критичность; Высокая точность; Техники MITRE: T1003",
"title": "Suspicious Read File Passwd CredentialsEnumeration"
}
},
"Suspicious_Read_File_Shadow_CredentialsDumping": {
"en": {
"description": "Dump the contents of /etc/shadow; \nSeverity high; Precision high; MITRE techniques: T1003",
"title": "Suspicious Read File Shadow CredentialsDumping"
},
"ru": {
"description": "Dump the contents of /etc/shadow; \nВысокая критичность; Высокая точность; Техники MITRE: T1003",
"title": "Suspicious Read File Shadow CredentialsDumping"
}
},
"Suspicious_Write_File_PAM_Persistence": {
"en": {
"description": "Adversaries may modify pluggable authentication modules (PAM) to access user credentials; \nSeverity high; Precision high; MITRE techniques: T1556",
"title": "Suspicious Write File PAM Persistence"
},
"ru": {
"description": "Adversaries may modify pluggable authentication modules (PAM) to access user credentials; \nВысокая критичность; Высокая точность; Техники MITRE: T1556",
"title": "Suspicious Write File PAM Persistence"
}
},
"Suspicious_Write_Process_Inject_Ptrace": {
"en": {
"description": "Detect injection in process via ptrace syscall; \nSeverity high; Precision high; MITRE techniques: T1055",
"title": "Suspicious Write Process Inject Ptrace"
},
"ru": {
"description": "Detect injection in process via ptrace syscall; \nВысокая критичность; Высокая точность; Техники MITRE: T1055",
"title": "Suspicious Write Process Inject Ptrace"
}
}
},
"fields": {
"category.generic": {
"en": {
"description": "category generic",
"title": "category.generic"
},
"ru": {
"description": "category generic",
"title": "category.generic"
}
},
"category.high": {
"en": {
"description": "category high",
"title": "category.high"
},
"ru": {
"description": "category high",
"title": "category.high"
}
},
"correlation_name": {
"en": {
"description": "correlation name",
"title": "correlation_name"
},
"ru": {
"description": "correlation name",
"title": "correlation_name"
}
},
"numfield1": {
"en": {
"description": "numfield1",
"title": "numfield1"
},
"ru": {
"description": "numfield1",
"title": "numfield1"
}
},
"object.fullpath": {
"en": {
"description": "object fullpath",
"title": "object.fullpath"
},
"ru": {
"description": "object fullpath",
"title": "object.fullpath"
}
},
"object.name": {
"en": {
"description": "object name",
"title": "object.name"
},
"ru": {
"description": "object name",
"title": "object.name"
}
},
"object.path": {
"en": {
"description": "object path",
"title": "object.path"
},
"ru": {
"description": "object path",
"title": "object.path"
}
},
"object.process.cmdline": {
"en": {
"description": "object process cmdline",
"title": "object.process.cmdline"
},
"ru": {
"description": "object process cmdline",
"title": "object.process.cmdline"
}
},
"object.process.fullpath": {
"en": {
"description": "object process fullpath",
"title": "object.process.fullpath"
},
"ru": {
"description": "object process fullpath",
"title": "object.process.fullpath"
}
},
"object.process.id": {
"en": {
"description": "object process id",
"title": "object.process.id"
},
"ru": {
"description": "object process id",
"title": "object.process.id"
}
},
"object.process.name": {
"en": {
"description": "object process name",
"title": "object.process.name"
},
"ru": {
"description": "object process name",
"title": "object.process.name"
}
},
"object.process.parent.id": {
"en": {
"description": "object process parent id",
"title": "object.process.parent.id"
},
"ru": {
"description": "object process parent id",
"title": "object.process.parent.id"
}
},
"object.process.path": {
"en": {
"description": "object process path",
"title": "object.process.path"
},
"ru": {
"description": "object process path",
"title": "object.process.path"
}
},
"object.state": {
"en": {
"description": "object state",
"title": "object.state"
},
"ru": {
"description": "object state",
"title": "object.state"
}
},
"object.value": {
"en": {
"description": "object value",
"title": "object.value"
},
"ru": {
"description": "object value",
"title": "object.value"
}
},
"subject.process.fullpath": {
"en": {
"description": "subject process fullpath",
"title": "subject.process.fullpath"
},
"ru": {
"description": "subject process fullpath",
"title": "subject.process.fullpath"
}
},
"subject.process.id": {
"en": {
"description": "subject process id",
"title": "subject.process.id"
},
"ru": {
"description": "subject process id",
"title": "subject.process.id"
}
},
"subject.process.meta": {
"en": {
"description": "subject process meta",
"title": "subject.process.meta"
},
"ru": {
"description": "subject process meta",
"title": "subject.process.meta"
}
},
"subject.process.name": {
"en": {
"description": "subject process name",
"title": "subject.process.name"
},
"ru": {
"description": "subject process name",
"title": "subject.process.name"
}
},
"subject.process.parent.id": {
"en": {
"description": "subject process parent id",
"title": "subject.process.parent.id"
},
"ru": {
"description": "subject process parent id",
"title": "subject.process.parent.id"
}
},
"subject.process.path": {
"en": {
"description": "subject process path",
"title": "subject.process.path"
},
"ru": {
"description": "subject process path",
"title": "subject.process.path"
}
}
},
"module": {
"en": {
"description": "Performs normalization, aggregation, and correlation of a stream of raw events from sources. When malicious or suspicious activities are detected, it registers information security events (correlation events)",
"title": "Correlator (Linux)"
},
"ru": {
"description": "Выполняет нормализацию, агрегацию и корреляцию потока необработанных событий от источников. При обнаружении вредоносных или подозрительных действий регистрирует события ИБ (корреляционные события)",
"title": "Коррелятор (Linux)"
}
},
"secure_config": {},
"tags": {
"detector": {
"en": {
"description": "Analyzes collected events, detects suspicious and malicious activity on the end device, and registers information security events",
"title": "detector"
},
"ru": {
"description": "Анализиpирует собранные события, обнаруживают подозрительную и вредоносную активность на конечном устройстве — и регистрируют события ИБ",
"title": "detector"
}
},
"responder": {
"en": {
"description": "Stops suspicious and malicious activity on the end device by performing actions in accordance with the configuration of detection modules",
"title": "responder"
},
"ru": {
"description": "Пресекает подозрительную и вредоносную активность на конечном устройстве, выполняя действия в соответствии с конфигурацией модулей обнаружения",
"title": "responder"
}
}
}
}
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
[]
+1
View File
@@ -0,0 +1 @@
{}
+28
View File
@@ -0,0 +1,28 @@
__api.add_cbs({
-- data = function(src, data)
-- file = function(src, path, name)
-- text = function(src, text, name)
-- msg = function(src, msg, mtype)
-- action = function(src, data, name)
control = function(cmtype, data)
__log.debugf("receive control msg '%s' with payload: %s", cmtype, data)
-- cmtype: "quit"
-- cmtype: "agent_connected"
-- cmtype: "agent_disconnected"
-- cmtype: "update_config"
return true
end,
})
__log.infof("module '%s' was started", __config.ctx.name)
__api.await(-1)
__log.infof("module '%s' was stopped", __config.ctx.name)
return 'success'
+15
View File
@@ -0,0 +1,15 @@
<template>
<div>
</div>
</template>
<script>
const name = "empty";
module.exports = {
name,
props: ["protoAPI", "hash", "module", "eventsAPI", "modulesAPI", "components", "viewMode"],
data: () => ({
})
};
</script>
+6
View File
@@ -0,0 +1,6 @@
{
"debug_engine": ["false"],
"debug_correlator": ["false"],
"queue_size": ["1000"],
"receivers": []
}
+124
View File
@@ -0,0 +1,124 @@
require("yaci")
local thread = require("thread")
local luapath = require("path")
CFileReader = newclass("CFileReader")
local worker_safe = function(ctx, q_in, q_out, e_stop, e_quit)
local pp = require("pp")
local glue = require("glue")
local lpath = require("path")
local socket = require("socket")
-- custom module loader to take module from __files valiable per module
local function load(modulename)
local errmsg = ""
local modulepath = string.gsub(modulename, "%.", "/")
local filenames = {modulepath .. "/init.lua", modulepath .. ".lua"}
for _, filename in ipairs(filenames) do
local filedata = ctx.__files[filename]
if filedata then
return assert(loadstring(filedata, filename), "can't load " .. tostring(modulename))
end
errmsg = errmsg .. "\n\tno file '" .. filename .. "' (checked with custom loader)"
end
return errmsg
end
table.insert(package.loaders, 2, load)
local print = function(...)
if ctx.__debug then
local t = glue.pack(...)
for i, v in ipairs(t) do
t[i] = pp.format(v)
end
q_out:push({
type = "debug",
data = t,
})
end
end
local function worker()
require("strict")
require("module")
-- INIT --
local is_close = false
local mdl = CModule(lpath.combine(ctx.tmpdir, "SysLog"), lpath.combine(ctx.tmpdir, "lib"), print)
local callbacks = {
result = function(data)
if not data then return end
while q_out:length() == q_out:maxlength() do e_stop:wait(os.time() + 0.1) end
q_out:push({
type = "result",
data = data,
})
end,
keep_alive = function()
local status, msg
if e_stop:isset() then
print("want to stop file reader library")
if not is_close then
mdl:stop()
is_close = true
return
end
end
repeat
status, msg = q_in:shift(os.time())
if status and type(msg) == "table" then
print("new incoming message to worker", msg.type)
end
until not status
end
}
mdl:register(ctx.profile, callbacks, ctx.svp_filename)
-- RUN --
local res = mdl:run()
print("run is unlocked: ", res.FinishCode, res.RestartMePlease)
mdl:unregister()
collectgarbage("collect")
print("quit from worker")
end
local status, err
repeat
status, err = glue.pcall(worker)
if not status then
print("failed to execute file reader worker: ", err)
q_out:push({
type = "error",
data = "unexpected exit from worker",
err = err,
})
socket.sleep(5)
end
print("quit from worker loop", status, err, e_stop:isset())
collectgarbage("collect")
until status or not e_stop:isset()
-- notify main lua state about library was exited
e_quit:set()
end
function CFileReader:init(q_in, q_out, e_stop, e_quit, profile, store_dir)
self.wrth = thread.new(worker_safe, {
tmpdir = __tmpdir,
profile = profile,
svp_filename = luapath.combine(store_dir, "frd_sp"),
__files = __files,
__debug = __args["debug_engine"][1] == "true",
__module_id = tostring(__config.ctx.name)
}, q_in, q_out, e_stop, e_quit)
end
function CFileReader:wait()
if self.wrth ~= nil then
self.wrth:join()
self.wrth = nil
end
end
+395
View File
@@ -0,0 +1,395 @@
require("engine")
require("file_reader")
local lfs = require("lfs")
local glue = require("glue")
local cjson = require("cjson.safe")
local thread = require("thread")
local luapath = require("path")
-- variables to initialize event and action engines
local prefix_db = __gid .. "."
local fields_schema = __config.get_fields_schema()
local current_event_config = __config.get_current_event_config()
local module_info = __config.get_module_info()
local module_config = cjson.decode(__config.get_current_config())
-- event and action engines initialization
local action_engine = CActionEngine(
{},
__args["debug_correlator"][1] == "true"
)
local event_engine = CEventEngine(
fields_schema,
current_event_config,
module_info,
prefix_db,
__args["debug_correlator"][1] == "true"
)
-- creating module store folder
local store_dir = luapath.combine(lfs.currentdir(), "store")
lfs.mkdir(store_dir)
-- Module mutable global variables
local receivers = {}
local messages_queue = {}
local server_token = ""
local queue_size = tonumber(__args["queue_size"][1])
local is_send_messages = module_config.target_path ~= ""
-- return number
local function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
-- events executor by event name and data
local function push_event(event_name, event_data)
assert(type(event_name) == "string", "event_name must be a string")
assert(type(event_data) == "table", "event_data must be a table")
__log.debugf("push event to correlator: '%s'", event_name)
-- push the event to the engine
local info = {
["name"] = event_name,
["data"] = event_data,
["actions"] = {},
}
local result, list = event_engine:push_event(info)
-- check result return variable as marker is there need to execute actions
if result then
for action_id, action_result in ipairs(action_engine:exec(__aid, list)) do
__log.debugf("action '%s' was requested: '%s'", action_id, action_result)
end
end
end
-- return nil
local function update_receivers()
receivers = {}
local args_receivers = type(__args["receivers"]) == "table" and __args["receivers"] or {}
local mlist = glue.extend({}, module_config.receivers or {}, args_receivers)
for irx, module_name in ipairs(mlist) do
local minfo = " | group_id: " .. __gid .. " | module: " .. module_name
local token = __imc.make_token(module_name, __gid)
__log.debugf("receiver[%s] | token: '%s' %s", irx, token, minfo)
receivers[module_name] = token
end
end
-- return boolean
local function send(message)
if tablelength(__agents.get_by_dst(server_token)) == 0 then
local agents = __agents.dump()
for _, data in pairs(agents) do
server_token = data.Dst
if server_token ~= "" then
break
end
end
end
if server_token == "" then
return false
end
if __api.send_data_to(server_token, message.data) then
__metric.add_int_counter("frd_agent_events_send_count", message.count)
__metric.add_int_counter("frd_agent_events_send_size", message.size)
return true
end
server_token = ""
return false
end
-- return boolean
local function send_to_receivers(events)
local msg = cjson.encode(events)
if msg == nil then
__log.errorf("failed to serialize events message: %s", tostring(events))
return
end
for _, imc_token in pairs(receivers) do
__api.send_data_to(imc_token, msg)
end
end
-- return nil
local function resend()
for _=1,#messages_queue do
if send(messages_queue[1]) then
table.remove(messages_queue, 1)
else
return
end
end
end
-- return nil
local function send_log(msgs)
if not is_send_messages then
return
end
local msg_data = {
["type"] = "log",
["message"] = msgs,
["data"] = {},
}
local data = cjson.encode(msg_data)
local message = {data = data, count = #msgs, size = #data}
if not send(message) then
if #messages_queue >= queue_size + 100 then
__log.error("drop message from queue because size limit exceeded")
local cnt = 0
for _=1,100 do
cnt = cnt + messages_queue[1].count
table.remove(messages_queue, 1)
end
__metric.add_int_counter("frd_agent_events_drop", cnt)
collectgarbage("collect")
__metric.add_int_gauge_counter("frd_agent_mem_usage", collectgarbage("count")*1024)
end
table.insert(messages_queue, message)
end
end
-- return string
local function get_profile()
local params = {
scope_id = "00000000-0000-0000-0000-000000000005",
tenant_id = "00000000-0000-0000-0000-000000000000",
}
local config_json = string.format([[{
"servers": {
"tcp_and_udp": {
"tcp": {
"binding": {
"FQDN": "0.0.0.0"
},
"port": 0,
"message_size_max": 1048576
},
"udp": {
"binding": {
"IP4": "0.0.0.0"
},
"port": 0,
"read_buffer_size": 65536
}
}
},
"event_buffer_size": 512,
"output_format": "JSON",
"special_events_assembly_settings": {
"assembly_interval": 1,
"event_record_groups": {
"auditd": {
"key_includes_src_ip": false,
"key_fields_from_records": [
"timestamp",
"eventid"
],
"filter_regexps": [
".*type=(?P<type>\\S+)\\s.*audit.*\\((?P<timestamp>[0-9]*[.,]?[0-9]+):(?P<eventid>[0-9]+)\\):\\s*(?P<value>.*)"
],
"group_by_field_settings": {
"regex_group_for_field_name": "type",
"regex_group_for_value": "value"
}
}
}
},
"inputs": {
"00000000-0000-0000-0000-000000000000": {
"description": {
"expected_datetime_formats": [
"DATETIME_ISO8601",
"DATETIME_YYYYMMDD_HHMMSS"
]
}
}
},
"result_package": {
"package_quantity": 100,
"send_interval": 500
},
"module_settings": {
"keepalive_interval": 500,
"metric": false,
"scope_id": "%s",
"tenant_id": "%s",
"logging": "<?xml version='1.0' encoding='utf-8'?><config><root><Logger level='ERROR'/><Metric level='ERROR'/><SysLog level='ERROR'/><ModuleRunner level='ERROR'/><ModuleHost level='ERROR'/></root></config>",
"agent_id": "",
"task_id": "",
"historical": false
},
"memory_settings": {
"chunk_size": 1024,
"pre_allocated_memory": 3,
"max_allowed_memory": 64
}
}]], tostring(params.scope_id), tostring(params.tenant_id))
local config = cjson.decode(config_json)
local log_files = {}
for _, fl in ipairs(module_config.log_files or {}) do
log_files[fl["filepath"]] = {
["select"] = fl["select"] or "*",
["suppress"] = fl["suppress"] or "",
}
end
config["log_channels"] = log_files
return cjson.encode(config)
end
local want_to_quit = false
local q_in = thread.queue(100)
local q_out = thread.queue(100)
local q_e_stop = thread.event()
local q_e_quit = thread.event()
local wm_e = CFileReader(q_in, q_out, q_e_stop, q_e_quit, get_profile(), store_dir)
-- return nil
local function handler()
local cnt = 0
local status, msg
repeat
status, msg = q_out:shift(os.time() + 0.05)
if status and type(msg) == "table" then
if msg.type == "result" and type(msg.data) == "string" then
local events = cjson.decode(msg.data) or {}
local messages = {}
for _, event in ipairs(events) do
if type(event) == "table" then
local jbody = cjson.decode(event.body)
if jbody and type(jbody) == "table" then
if (jbody.node == nil) then jbody.node = "127.0.0.1" end
event.body = cjson.encode(jbody) or ""
table.insert(messages, cjson.encode(event) or "")
event.body = jbody
elseif type(event.body) == "string" and string.find(event.body, "node=") == nil then
event.body = event.body .. " node=127.0.0.1"
table.insert(messages, cjson.encode(event) or "")
end
end
end
if not want_to_quit and not __api.is_close() then
send_to_receivers(events)
end
send_log(messages)
elseif msg.type == "debug" and type(msg.data) == "table" then
__log.info(glue.unpack(msg.data))
elseif msg.type == "error" and type(msg.data) == "string" then
__log.errorf("catch error from file reader log collector: '%s': '%s'", msg.data, msg.err)
push_event("frd_module_internal_error", {reason = msg.data})
end
end
cnt = cnt + 1
__api.await(10)
until not status or cnt >= 20
if q_e_quit:isset() and want_to_quit then
__log.info("condition to quit worker is set")
end
resend()
return q_e_quit:isset() and want_to_quit
end
__api.add_cbs({
-- data = function(src, data)
-- file = function(src, path, name)
-- text = function(src, text, name)
-- msg = function(src, msg, mtype)
-- action = function(src, data, name)
control = function(cmtype, data)
__log.debugf("receive control msg '%s' with payload: %s", cmtype, data)
-- cmtype: "agent_connected"
-- cmtype: "agent_disconnected"
if cmtype == "quit" then
-- notify library to quit
q_e_stop:set()
want_to_quit = true
__log.info("send message to the library to stop")
end
if cmtype == "update_config" then
-- update current action and event list from new config
current_event_config = __config.get_current_event_config()
module_info = __config.get_module_info()
-- renew current event engine instance
if event_engine ~= nil then
event_engine:free()
event_engine = nil
collectgarbage("collect")
event_engine = CEventEngine(
fields_schema,
current_event_config,
module_info,
prefix_db,
__args["debug_correlator"][1] == "true"
)
end
-- renew receivers list from new current config
module_config = cjson.decode(__config.get_current_config())
update_receivers()
is_send_messages = module_config.target_path ~= ""
-- reload configuration for file reader library
q_e_stop:set()
wm_e:wait()
q_e_stop:clear()
q_e_quit:clear()
wm_e = CFileReader(q_in, q_out, q_e_stop, q_e_quit, get_profile(), store_dir)
end
return true
end,
})
__log.infof("module '%s' was started", __config.ctx.name)
push_event("frd_module_started", {reason = "regular start"})
update_receivers()
while not handler() do
__metric.add_int_gauge_counter("frd_agent_mem_usage", collectgarbage("count")*1024)
__api.await(300)
end
-- wait file reader library instance
__log.info("wait to stop the library")
wm_e:wait()
q_e_stop:clear()
q_e_quit:clear()
-- free posix obects
q_in:free()
q_out:free()
-- all events mark as drop
do
local cnt = 0
for i=1,#messages_queue do
cnt = cnt + messages_queue[i].count
end
if cnt ~= 0 then
__metric.add_int_counter("frd_agent_events_drop", cnt)
end
end
push_event("frd_module_stopped", {reason = "regular stop"})
action_engine = nil
event_engine = nil
collectgarbage("collect")
__log.infof("module '%s' was stopped", __config.ctx.name)
return "success"
+449
View File
@@ -0,0 +1,449 @@
require("yaci")
require("strict")
local ffi = require("ffi")
ffi.cdef [[
// Сигнатура колбэка для возврата ошибок
typedef void(*Module__Error_Ptr)(const char* descr, void* userData);
// Структура для возврата ошибок
typedef struct _Module__ErrorHandler
{
Module__Error_Ptr OnError; // колбэк
void* UserData; // произвольные данные, юзер может их использовать для проброса в колбэк доп. инфы
} Module__ErrorHandler;
// Результат модуля
typedef struct _Module__ResultInfo
{
int Type; // тип результата
int Format; // формат результата
int Encoding; // кодировка
} Module__ResultInfo;
// Результат завершения модуля
typedef struct _Module__FinishResult
{
int FinishCode; // код завершения
bool RestartMePlease; // сообщить агенту, что модуль надо рестартануть
} Module__FinishResult;
typedef struct Module_I Module_I;
typedef void(*Module__Init_Ptr)(Module_I* module, const void* profile, size_t profileSize, const void* savepoint, size_t savepointSize, const Module__ErrorHandler* eh);
typedef Module__FinishResult(*Module__Run_Ptr)(Module_I* module, const Module__ErrorHandler* eh);
typedef void(*Module__Stop_Ptr)(Module_I* module, const Module__ErrorHandler* eh);
typedef void(*Module__Pause_Ptr)(Module_I* module, const Module__ErrorHandler* eh);
typedef void(*Module__Resume_Ptr)(Module_I* module, const Module__ErrorHandler* eh);
]]
if ffi.arch == 'x86' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры раскладывается на стек по элементно
typedef bool(*Module__OnResult_Ptr)(Module_I* module, const char* jobId, int type, int format, int encoding, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
if ffi.arch == 'x64' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры передаётся через указатель, чтобы не кастовать каждый элемент в отдельности, заранее определяем его как указатель на int
typedef bool(*Module__OnResult_Ptr)(Module_I* module, const char* jobId, int info, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
ffi.cdef [[
typedef const char*(*Module__GetName_Ptr)(Module_I* module, const Module__ErrorHandler* eh);
// Интерфейс модуля
struct Module_I
{
// Указатель на функцию, которая вызывается при получении пакета "Старт" от агента
Module__Init_Ptr Init;
/** Указатель на функцию, реализующую логику модуля.
Вызов этой функции происходит в отдельном потоке после вызова функции "Init"
*/
Module__Run_Ptr Run;
// Указатель на функцию, реализающую остановку модуля
Module__Stop_Ptr Stop;
// Указатель на функцию, реализающую паузу модуля
Module__Pause_Ptr Pause;
// Указатель на функцию, реализающую возобновление работы модуля
Module__Resume_Ptr Resume;
// Указатель на функцию, которая будет вызвана для результатов, пришедших от других модулей
Module__OnResult_Ptr OnResult;
// Указатель на функцию, возвращающую уникальный идентификатор модуля
Module__GetName_Ptr GetName;
};
typedef struct ModuleTransport_I ModuleTransport_I;
typedef void(*ModuleTransport__SendKeepAlive_Ptr)(ModuleTransport_I* transport, const Module__ErrorHandler* eh);
typedef void(*ModuleTransport__SendProgress_Ptr)(ModuleTransport_I* transport, uint32_t progress, const Module__ErrorHandler* eh);
]]
if ffi.os == "Windows" then
if ffi.arch == 'x86' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры раскладывается на стек по элементно
typedef void(*ModuleTransport__SendResult_Ptr)(ModuleTransport_I* transport, int type, int format, int encoding, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
if ffi.arch == 'x64' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры передаётся через указатель, чтобы не кастовать каждый элемент в отдельности, заранее определяем его как указатель на int
typedef void(*ModuleTransport__SendResult_Ptr)(ModuleTransport_I* transport, int *info, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
end
if ffi.os == "Linux" then
if ffi.arch == 'x86' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры раскладывается на стек по элементно
typedef void(*ModuleTransport__SendResult_Ptr)(ModuleTransport_I* transport, int type, int format, int encoding, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
if ffi.arch == 'x64' then
ffi.cdef [[
// Параметр info оригинальной сигнатуры передаётся через указатель, чтобы не кастовать каждый элемент в отдельности, заранее определяем его как указатель на int
typedef void(*ModuleTransport__SendResult_Ptr)(ModuleTransport_I* transport, int *info, int i, const void* data, size_t size, const Module__ErrorHandler* eh);
]]
end
end
ffi.cdef [[
typedef void(*ModuleTransport__SendSavePoint_Ptr)(ModuleTransport_I* transport, const void* data, size_t size, const Module__ErrorHandler* eh);
typedef void(*ModuleTransport__SendState_Ptr)(ModuleTransport_I* transport, int state, const Module__ErrorHandler* eh);
typedef void(*ModuleTransport__SendError_Ptr)(ModuleTransport_I* transport, const void* data, size_t size, const Module__ErrorHandler* eh);
// Интерфейс транспорта модуля
struct ModuleTransport_I
{
ModuleTransport__SendKeepAlive_Ptr SendKeepAlive;
ModuleTransport__SendProgress_Ptr SendProgress;
ModuleTransport__SendResult_Ptr SendResult;
ModuleTransport__SendSavePoint_Ptr SendSavePoint;
ModuleTransport__SendState_Ptr SendState;
ModuleTransport__SendError_Ptr SendError;
};
// Экспортируемые функции из dll-ки модуля
/** Создать модуль.
** @param transport
** Указатель на транспорт, который модуль должен использовать для отправки сообщений.
** Модуль не должен удалять этот указатель!
** @param argc, argv
** Аргументы, с которыми был запущен агентом модуль.
** @param eh
** Структура для возврата ошибок.
*/
Module_I* Module__Create(ModuleTransport_I* transport, int argc, const char** argv, const Module__ErrorHandler* eh);
// Удалить ранее созданный модуль
void Module__Destroy(Module_I* module);
// Вернуть версию модуля
int Module__Version();
// Вернуть версию API, которую реализует модуль
int Module__API_Version();
]]
CModule = newclass("CModule")
function CModule:init(moduleName, libdir, fprint)
assert(type(moduleName) == "string", "module name is invalid")
assert(type(libdir) == "string", "library directory path is invalid")
self.print = type(print) == "function" and fprint or print
self:unregister()
self.libdir = libdir
if ffi.os == "Linux" then self:load_depends() end
self:wrap_load(function()
if ffi.os == "Linux" then
self.module = ffi.load(moduleName .. ".so")
else
self.module = ffi.load(moduleName .. ".dll")
end
end)
self.api = {
create = self.module.Module__Create,
destroy = self.module.Module__Destroy,
version = self.module.Module__Version,
api_version = self.module.Module__API_Version,
}
self.sd = ""
end
function CModule:free()
self.print("call CModule:free")
self.deps = nil
self:unregister()
end
function CModule:unregister()
self.print("call CModule:unregister")
if self.module_i then
self:destroy()
self.print("destroy successful")
end
if self.functions then
self.functions["SendKeepalive"] = nil
self.functions["SendProgress"] = nil
self.functions["SendResult"] = nil
self.functions["SendSavepoint"] = nil
self.functions["SendState"] = nil
self.functions["SendError"] = nil
self.functions["HandleError"] = nil
end
self.functions = nil
self.error = nil
if self.transport then
self.transport.SendKeepAlive = nil
self.transport.SendProgress = nil
self.transport.SendResult = nil
self.transport.SendSavePoint = nil
self.transport.SendState = nil
self.transport.SendError = nil
end
self.transport = nil
if self.api then
self.api.create = nil
self.api.destroy = nil
self.api.version = nil
self.api.api_version = nil
end
self.api = nil
self.module_i = nil
self.module = nil
self.profile = nil
self.argv_type = nil
self.argc = nil
self.argv = nil
self.sp_filename = nil
self.sd = nil
collectgarbage("collect")
end
function CModule:register(profile, callbacks, sp_filename)
self.print("call CModule:register")
assert(type(profile) == "string", "module profile is invalid")
assert(type(callbacks) == "table", "callbacks is invalid")
assert(type(sp_filename) == "string", "savepoint file path is invalid")
if self.module == nil then
return false, "module not loaded"
end
local function get_argv(...)
local nargs = select("#", ...)
local argv = {...}
for i = 1, nargs do
local v = tostring(argv[i])
argv[i] = v
end
return nargs, self.argv_type(nargs, argv)
end
self.functions = {}
self.functions["SendKeepalive"] = function(transport, _)
if callbacks and transport == self.transport and callbacks["keep_alive"] then
callbacks["keep_alive"]()
end
end
self.functions["SendProgress"] = function(transport, progress, _)
if callbacks and transport == self.transport and callbacks["progress"] then
callbacks["progress"](progress)
end
end
if ffi.os == "Windows" then
if ffi.arch == 'x86' then
self.functions["SendResult"] = function(transport, _, _, _, data, size, _)
if callbacks and transport == self.transport and callbacks["result"] and data then
callbacks["result"](ffi.string(data, size))
end
end
end
if ffi.arch == 'x64' then
self.functions["SendResult"] = function(transport, _, data, size, _)
if callbacks and transport == self.transport and callbacks["result"] and data then
callbacks["result"](ffi.string(data, size))
end
end
end
end
if ffi.os == "Linux" then
if ffi.arch == 'x86' then
self.functions["SendResult"] = function(transport, _, _, _, data, size, _)
if callbacks and transport == self.transport and callbacks["result"] and data then
callbacks["result"](ffi.string(data, size))
end
end
end
if ffi.arch == 'x64' then
self.functions["SendResult"] = function(transport, _, _, data, size, _)
if callbacks and transport == self.transport and callbacks["result"] and size and data then
callbacks["result"](ffi.string(data, size))
end
end
end
end
self.functions["SendSavepoint"] = function(transport, data, size, _)
if data and size ~= 0 then
local sd = ffi.string(data, size)
if callbacks and transport == self.transport and callbacks["save_point"] and size and data then
callbacks["save_point"](sd)
end
if self.sp_filename and sd and (#self.sd == 0 or self.sd ~= sd) then
self.sd = sd
local file = io.open(self.sp_filename, "wb+")
if file then
file:write(sd)
file:flush()
file:close()
end
return
end
end
end
self.functions["SendState"] = function(transport, state, _)
if callbacks and transport == self.transport and callbacks["state"] then
callbacks["state"](state)
end
end
self.functions["SendError"] = function(transport, data, size, _)
if callbacks and transport == self.transport and callbacks["error"] then
callbacks["error"](ffi.string(data, size))
end
end
self.functions["HandleError"] = function(descr, _)
self.print("file reader library handled error: ", ffi.string(descr))
end
self.error = ffi.new("Module__ErrorHandler", {ffi.cast("Module__Error_Ptr", self.functions["HandleError"]), nil})
self.transport = ffi.new("ModuleTransport_I", {
ffi.cast("ModuleTransport__SendKeepAlive_Ptr", self.functions["SendKeepalive"]),
ffi.cast("ModuleTransport__SendProgress_Ptr", self.functions["SendProgress"]),
ffi.cast("ModuleTransport__SendResult_Ptr", self.functions["SendResult"]),
ffi.cast("ModuleTransport__SendSavePoint_Ptr", self.functions["SendSavepoint"]),
ffi.cast("ModuleTransport__SendState_Ptr", self.functions["SendState"]),
ffi.cast("ModuleTransport__SendError_Ptr", self.functions["SendError"])
})
self.argv_type = ffi.typeof("const char* [?]")
self.argc, self.argv = get_argv("--id", "692db8c2-9d54-11eb-a8b3-0242ac130003")
self.module_i = self.api.create(self.transport, self.argc, self.argv, self.error)
self.sp_filename = sp_filename
-- SAVEPOINT--
local svp = ""
if sp_filename then
local file = io.open(self.sp_filename, "rb")
if file then
svp = file:read("*a")
file:close()
end
end
self.module_i.Init(self.module_i,
ffi.cast("const void*", profile),
#profile, svp, #svp, self.error)
return true, ""
end
function CModule:destroy()
self.print("call CModule:destroy")
assert(self.module, "module library is not exist")
assert(self.module_i, "instance module is not exist")
self.api.destroy(self.module_i)
end
function CModule:registered()
self.print("call CModule:registered")
return self.transport ~= nil
end
function CModule:run()
self.print("call CModule:run")
assert(self.module_i, "instance module is not exist")
return self.module_i.Run(self.module_i, self.error)
end
function CModule:stop()
self.print("call CModule:stop")
assert(self.module_i, "instance module is not exist")
return self.module_i.Stop(self.module_i, self.error)
end
function CModule:pause()
self.print("call CModule:pause")
assert(self.module_i, "instance module is not exist")
return self.module_i.Pause(self.module_i, self.error)
end
function CModule:resume()
self.print("call CModule:resume")
assert(self.module_i, "instance module is not exist")
return self.module_i.Resume(self.module_i, self.error)
end
function CModule:version()
self.print("call CModule:version")
assert(self.module_i, "instance module is not exist")
return self.module_i.Module__Version()
end
function CModule:version_api()
self.print("call CModule:version_api")
assert(self.module_i, "instance module is not exist")
return self.module_i.Module__API_Version()
end
if ffi.os == "Linux" then
function CModule:load_depends()
local lfs = require("lfs")
local lpath = require("path")
self.deps = {}
for file in lfs.dir(self.libdir) do
if file ~= "." and file ~= ".." then
table.insert(self.deps, ffi.load(lpath.combine(self.libdir, file)))
end
end
end
function CModule:wrap_load(callback)
local _ = self
callback()
end
end
if ffi.os == "Windows" then
function CModule:wrap_load(callback)
local lk32 = require("waffi.windows.kernel32")
local ctmpdir = ffi.new("char[?]", 256)
local stmpdir = ffi.new("char[?]", #self.libdir + 1)
ffi.copy(stmpdir, self.libdir)
lk32.GetDllDirectoryA(256, ctmpdir)
lk32.SetDllDirectoryA(stmpdir)
callback()
lk32.SetDllDirectoryA(ctmpdir)
end
end
@@ -0,0 +1,6 @@
{
"additionalProperties": false,
"properties": {},
"required": [],
"type": "object"
}

Some files were not shown because too many files have changed in this diff Show More