diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..66f1e07 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,12 @@ +version: "3" +services: + tests: + tty: true + entrypoint: + bash -c "cd soldr-modules && ./tests_framework/lua/bin/busted.linux64.cmd tests/." + build: + context: . + dockerfile: tests/Dockerfile + volumes: + - .:/soldr-modules +# command: tail -f /dev/null \ No newline at end of file diff --git a/osquery_linux/1.0.0/bmodule/main.vue b/osquery_linux/1.0.0/bmodule/main.vue new file mode 100644 index 0000000..e4da48a --- /dev/null +++ b/osquery_linux/1.0.0/bmodule/main.vue @@ -0,0 +1,35 @@ + + + diff --git a/osquery_linux/1.0.0/cmodule/args.json b/osquery_linux/1.0.0/cmodule/args.json new file mode 100644 index 0000000..6d99e88 --- /dev/null +++ b/osquery_linux/1.0.0/cmodule/args.json @@ -0,0 +1,3 @@ +{ + "debug": ["true"] +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/cmodule/data/binaries/deb/osquery.deb b/osquery_linux/1.0.0/cmodule/data/binaries/deb/osquery.deb new file mode 100644 index 0000000..ed8aa6c Binary files /dev/null and b/osquery_linux/1.0.0/cmodule/data/binaries/deb/osquery.deb differ diff --git a/osquery_linux/1.0.0/cmodule/data/binaries/rpm/osquery.rpm b/osquery_linux/1.0.0/cmodule/data/binaries/rpm/osquery.rpm new file mode 100644 index 0000000..df7c545 Binary files /dev/null and b/osquery_linux/1.0.0/cmodule/data/binaries/rpm/osquery.rpm differ diff --git a/osquery_linux/1.0.0/cmodule/helpers.lua b/osquery_linux/1.0.0/cmodule/helpers.lua new file mode 100644 index 0000000..01548d1 --- /dev/null +++ b/osquery_linux/1.0.0/cmodule/helpers.lua @@ -0,0 +1,226 @@ +require("system") +require("engine") + +local fs = require("fs") +local cjson = require("cjson.safe") + +-- 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() + +-- event and action engines initialization +local action_engine = CActionEngine( + {}, + __args["debug"][1] == "true" +) + +local event_engine = CEventEngine( + fields_schema, + current_event_config, + module_info, + prefix_db, + __args["debug"][1] == "true" +) + +local function exec_cmd(cmd, raw) + __log.debugf("cmd to exec: %s", tostring(cmd)) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + __log.debugf("cmd output: %s", tostring(s)) + if raw or raw == nil then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end + +local module_config = cjson.decode(__config.get_current_config()) + +local function reread_module_info() + module_config = cjson.decode(__config.get_current_config()) +end + +local function get_opt_cfg__osquery_config() + return module_config["osquery_config"] +end + +local function get_opt_cfg__replace_current_osquery_config() + return module_config["replace_current_osquery_config"] +end + +-- return string with raw content of file (use if agent run with admin permissions) +local function get_file_content(path) + local content = '' + local file = io.open(path, "r") + if file then + content = file:read("*a") + file:close() + end + + return content +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") + + -- 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 + local data = action_engine:exec(__aid, list) + for action_id, action_result in ipairs(data) do + __log.debugf("action '%s' was requested: '%s'", action_id, action_result) + end + end +end + +local function push_event__osquery_already_installed(event_data) + return push_event("osquery_linux_already_installed", event_data) +end + +local function push_event__osquery_already_started(event_data) + return push_event("osquery_linux_already_started", event_data) +end + +local function push_event__osquery_config_updated_error(event_data) + return push_event("osquery_linux_config_updated_error", event_data) +end + +local function push_event__osquery_config_updated_success(event_data) + return push_event("osquery_linux_config_updated_success", event_data) +end + +local function push_event__osquery_installed_error(event_data) + return push_event("osquery_linux_installed_error", event_data) +end + +local function push_event__osquery_installed_success(event_data) + return push_event("osquery_linux_installed_success", event_data) +end + +local function push_event__osquery_started_error(event_data) + return push_event("osquery_linux_started_error", event_data) +end + +local function push_event__osquery_started_success(event_data) + return push_event("osquery_linux_started_success", event_data) +end + +local function push_event__osquery_unexpected_stopped(event_data) + return push_event("osquery_linux_unexpected_stopped", event_data) +end + +local function push_event__osquery_unexpected_uninstalled(event_data) + return push_event("osquery_linux_unexpected_uninstalled", event_data) +end + +local function push_event__osquery_uninstalled_error(event_data) + return push_event("osquery_linux_uninstalled_error", event_data) +end + +local function push_event__osquery_uninstalled_success(event_data) + return push_event("osquery_linux_uninstalled_success", event_data) +end + +-- arguments: +-- * path - path to removed dir +-- return bool +local function is_file_exist(path) + local isfile = fs.is(path, 'file') + + return isfile +end + +-- return true or false +local function create_file(path) + local f, err, errcode = fs.open(path, 'w+') + if not f then + __log.errorf("error creating file (errcode %s) %s: %s", errcode, path, err) + return false + end + f:close() + + return true +end + +-- return 'deb' or 'rpm' or '' +local function detect_package_manager() + local cmd = "which dpkg" + local out = exec_cmd(cmd) + __log.debugf("out of cmd '%s': %s", cmd, out) + + if out ~= "" then + return "deb" + end + + local cmd = "which rpm" + local out = exec_cmd(cmd) + __log.debugf("out of cmd '%s': %s", cmd, out) + + if out ~= "" then + return "rpm" + end + + return "" +end + +local package_manager = detect_package_manager() + +local function data_osquery_pkg_path() + local osquery_pkg_prefix = "osquery." + return tostring(__tmpdir) .. "/data/binaries/" .. package_manager .. '/' .. osquery_pkg_prefix .. package_manager +end + +-- TODO: remake for package manager +local function get_provided_version_osquery() + local cmd = "dpkg -f " .. data_osquery_pkg_path() .. " version" + if package_manager == 'rpm' then + cmd = 'rpm -qip ' .. data_osquery_pkg_path() + end + + local out = exec_cmd(cmd) + __log.debugf("out of cmd '%s': %s", cmd, out) + + local result = out:match("%d+.%d+.%d+") or "" + + if result == "" then __log.warnf("provided version osquery: %s", result) end + + return result +end + +return { + exec_cmd = exec_cmd, + get_opt_cfg__osquery_config = get_opt_cfg__osquery_config, + get_opt_cfg__replace_current_osquery_config = get_opt_cfg__replace_current_osquery_config, + + push_event__osquery_already_installed = push_event__osquery_already_installed, + push_event__osquery_already_started = push_event__osquery_already_started, + push_event__osquery_config_updated_error = push_event__osquery_config_updated_error, + push_event__osquery_config_updated_success = push_event__osquery_config_updated_success, + push_event__osquery_installed_error = push_event__osquery_installed_error, + push_event__osquery_installed_success = push_event__osquery_installed_success, + push_event__osquery_started_error = push_event__osquery_started_error, + push_event__osquery_started_success = push_event__osquery_started_success, + push_event__osquery_unexpected_stopped = push_event__osquery_unexpected_stopped, + push_event__osquery_unexpected_uninstalled = push_event__osquery_unexpected_uninstalled, + push_event__osquery_uninstalled_error = push_event__osquery_uninstalled_error, + push_event__osquery_uninstalled_success = push_event__osquery_uninstalled_success, + + create_file = create_file, + get_file_content = get_file_content, + is_file_exist = is_file_exist, + reread_module_info = reread_module_info, + package_manager = package_manager, + data_osquery_pkg_path = data_osquery_pkg_path, + get_provided_version_osquery = get_provided_version_osquery, +} diff --git a/osquery_linux/1.0.0/cmodule/main.lua b/osquery_linux/1.0.0/cmodule/main.lua new file mode 100644 index 0000000..2ca899b --- /dev/null +++ b/osquery_linux/1.0.0/cmodule/main.lua @@ -0,0 +1,298 @@ +require("engine") +require("system") + +local osquery = require("osquery") +local helpers = require("helpers") + +__log.debugf("path to temp dir '%s'", __tmpdir) + +-- return bool +local function need_to_update_config() + return helpers.get_opt_cfg__replace_current_osquery_config() and + helpers.get_opt_cfg__osquery_config() ~= osquery:get_config() +end + +-- ########## PHASES ########## + +-- return 'install'/'configure'/'controll' +local function preparing_phase() + if not osquery:is_installed() or not osquery:is_version_correct() then return 'install' end + + if osquery:state() ~= "running" and not osquery:start() then + helpers.push_event__osquery_installed_error({ + reason = "osquery is already installed but can not start", + version = osquery:get_version(), + }) + + return "control" + end + + helpers.push_event__osquery_already_installed({ + reason = "service osqueryd has already installed", + version = osquery:get_version(), + }) + + if need_to_update_config() then return 'configure' end + + return "control" +end + +-- installed osquery, check it and push all events +-- return 'configure'/'control' +local function install_phase() + __log.debug("call install_phase") + local success, reason = osquery:install() + + if success then + local state = osquery:state() + if state ~= "running" and not osquery:start() then + __log.info("osquery was not installed") + + helpers.push_event__osquery_installed_error({ + reason = "osquery was installed but can not start", + version = osquery:get_version(), + }) + + return "control" + end + + __log.info("osquery was installed success") + helpers.push_event__osquery_installed_success({ + version = osquery:get_version(), + reason = "", + }) + + if need_to_update_config() then return 'configure' end + + return 'control' + end + + __log.info("osquery was not installed") + helpers.push_event__osquery_installed_error({ + version = helpers.get_provided_version_osquery(), + reason = reason, + }) + + return 'control' +end + +-- update osquery config +-- return 'control' +local function configure_phase() + __log.debug("call configure_phase") + + local replace_current_osquery_config = helpers.get_opt_cfg__replace_current_osquery_config() + + if not replace_current_osquery_config then + __log.debug("skip configure phase, replace_current_osquery_config: %s", replace_current_osquery_config) + return 'control' + end + + local version = osquery:get_version() + local config_path = osquery:get_config_path() + + if config_path == '' then + local err = "failed to update osquery config file, can't find or create config path" + __log.error(err) + helpers.push_event__osquery_config_updated_error({ + reason = err, + version = version, + }) + + return "control" + end + + if not osquery:update_config_file() then + local err = "failed to update config file to module directory" + __log.error(err) + + helpers.push_event__osquery_config_updated_error({ + reason = err, + version = version, + }) + + return "control" + end + + if not osquery:stop() then + local err = "can not restart osquery after update config (can not stop osquery)" + __log.error(err) + + helpers.push_event__osquery_config_updated_error({ + reason = err, + version = version, + }) + + return "control" + end + + if not osquery:start() then + local err = "can not restart osquery after update config (can not start osquery)" + __log.error(err) + + helpers.push_event__osquery_config_updated_error({ + reason = err, + version = version, + }) + + return "control" + end + + __log.info("osquery config updated success") + helpers.push_event__osquery_config_updated_success({ + version = version, + }) + + return "control" +end + +-- return 'install' or nothing +local function control_phase() + local last_state = osquery:state() + local version = helpers.get_provided_version_osquery() + if last_state == "running" then + version = osquery:get_version() + end + + local change_state + + while not __api.is_close() do + local current_state = osquery:state() + if last_state == current_state then goto continue end + + change_state = "from: " .. last_state .. ", to: " .. current_state + + if current_state == "unknown" then + __log.warnf("osquery was unexpected uninstalled (state: %s)", change_state) + + helpers.push_event__osquery_unexpected_uninstalled({ + version = version, + reason = change_state, + }) + + return "install" + end + + if current_state == "stopped" then + __log.warnf("osquery was unexpected stopped (state: %s)", change_state) + + __log.info("osquery is stopped and should be running") + helpers.push_event__osquery_unexpected_stopped({ + reason = change_state, + version = version, + }) + + if not osquery:start() then + local err = "failed to start osquery, change state: " .. change_state + __log.error(err) + + helpers.push_event__osquery_started_error({ + reason = err, + version = version, + }) + + last_state = "stopped" + goto continue + end + + version = osquery:get_version() + __log.infof("osquery %s started success, change state: %s", version, change_state) + + helpers.push_event__osquery_started_success({ + reason = change_state, + version = version, + }) + + last_state = "running" + goto continue + end + + if current_state == "running" then + version = osquery:get_version() + helpers.push_event__osquery_already_started({ + reason = change_state, + version = version, + }) + + last_state = "running" + end + + ::continue:: + __api.await(10000) + end +end + +-- ########## SYSTEM FUNCTIONS AND CALLBACKS ########## + +-- set default timeout to wait exit on blocking of recv_* functions +__api.set_recv_timeout(5000) -- 5s + +__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.infof("receive control msg '%s' with payload: %s", cmtype, data) + + if cmtype == 'update_config' then + helpers.reread_module_info() + configure_phase() + + return true + end + + if cmtype == 'quit' then + if not osquery:is_installed() then + __log.info("quit from module without uninstalation osquery") + return true + end + + local version = osquery:get_version() + local success, reason = osquery:uninstall() + + if success then + __log.info("osquery was uninstalled success") + helpers.push_event__osquery_uninstalled_success({ + version = version, + }) + + return true + end + + __log.errorf("osquery was not uninstalled, reason: %s", reason) + helpers.push_event__osquery_uninstalled_error({ + version = version, + reason = reason, + }) + end + + return true + end, +}) + + +__log.infof("module '%s' was started", __config.ctx.name) + +local next_phase = preparing_phase() + +while next_phase do + __log.debugf("the next phase '%s'", next_phase) + if next_phase == "install" then + next_phase = install_phase() + elseif next_phase == "configure" then + next_phase = configure_phase() + elseif next_phase == "control" then + next_phase = control_phase() + else + __log.errorf("unexpected next handler: %s", next_phase) + break + end +end + +__log.infof("module '%s' was stopped", __config.ctx.name) + +return 'success' diff --git a/osquery_linux/1.0.0/cmodule/osquery.lua b/osquery_linux/1.0.0/cmodule/osquery.lua new file mode 100644 index 0000000..ab8248d --- /dev/null +++ b/osquery_linux/1.0.0/cmodule/osquery.lua @@ -0,0 +1,166 @@ +require("system") +local helpers = require("helpers") + +--local sysinfo = CSystemInfo({}) + +-- Module immutable global variables +local osquery_config_name = "osquery.conf" +local path_to_dumped_config = tostring(__tmpdir) .. "/" .. osquery_config_name + +local Osquery = {} + +-- linux +-- return string with path to config of installed osquery +function Osquery:get_config_path() + local path = '/etc/osquery/osquery.conf' + + if helpers.is_file_exist(path) or helpers.create_file(path) then return path end + + return '' +end + +-- linux +-- return bool +function Osquery:is_installed() + return self:get_version() ~= "" +end + +-- linux +-- return string like '5.5.1' +function Osquery:get_version() + local cmd = "osqueryd --version" + local out = helpers.exec_cmd(cmd) + __log.debugf("out of cmd '%s': %s", cmd, out) + + local result = out:match("%d+.%d+.%d+") or "" + + return result +end + +-- linux +-- return bool +function Osquery:is_version_correct() + local version = self:get_version() + __log.infof("found osquery version '%s'", version) + + return version == helpers.get_provided_version_osquery() +end + +-- linux +-- return string contaned raw config by installed osquery +function Osquery:get_config() + local path = self:get_config_path() + + if path == '' then return '' end + + return helpers.get_file_content(path) +end + +-- linux +-- return boolean +function Osquery:update_config_file() + local config_path = self:get_config_path() + local file = io.open(config_path, "w+") + if not file then + return false + end + + local _ = file:write(helpers.get_opt_cfg__osquery_config()) + file:close() + + return self:get_config() == helpers.get_opt_cfg__osquery_config() +end + +-- linux +-- returns 2 agrs: bool, string (reason) +function Osquery:install() + local cmd = "dpkg -i " .. helpers.data_osquery_pkg_path() + if helpers.package_manager == 'rpm' then + cmd = 'rpm -i ' .. helpers.data_osquery_pkg_path() + end + + local out = helpers.exec_cmd(cmd) or "" + __log.infof("out of cmd '%s': %s", cmd, out) + + local success = self:is_installed() + + local reason = "" + if not success then reason = "osquery can not installed" end + + return success, reason +end + +-- linux +-- remove osquery from machine +-- returns +-- * bool: result of uninstalation +-- * string: reason of failed uninstalation +function Osquery:uninstall() + local cmd = 'systemctl stop osqueryd' + local out = helpers.exec_cmd(cmd) or "" + __log.debugf("out of cmd '%s': %s", cmd, out) + + cmd = 'dpkg --force-all -P osquery' + if helpers.package_manager == 'rpm' then + cmd = 'rpm -e osquery' + end + + out = helpers.exec_cmd(cmd) or "" + __log.debugf("out of cmd '%s': %s", cmd, out) + + os.execute("sleep 2") + if not self:is_installed() then return true, "" end + + local state = self:state() + return false, "error uninstalation osquery, current state: " .. state +end + +-- linux +-- return: string of running, stopped, unknown +function Osquery:state() + if not self:is_installed() then return 'unknown' end + + local cmd = 'systemctl is-active osqueryd' + local out = helpers.exec_cmd(cmd) or '' + __log.debugf("out of cmd '%s': %s", cmd, out) + + if out == "unknown\n" then return "unknown" end + if out == "active\n" then return "running" end + + return "stopped" +end + +-- linux +-- return true/false +function Osquery:start() + local cmd = 'systemctl start osqueryd' + local out = helpers.exec_cmd(cmd) or "" + __log.debugf("out of cmd '%s': %s", cmd, out) + + local state = self:state() + if state == 'running' then return true end + + cmd = 'systemctl enable osqueryd' + out = helpers.exec_cmd(cmd) or "" + __log.debugf("out of cmd '%s': %s", cmd, out) + + state = self:state() + if state == 'running' then return true end + + return false +end + +-- linux +-- return true/false +function Osquery:stop() + local cmd = 'systemctl stop osqueryd' + local out = helpers.exec_cmd(cmd) or "" + __log.debugf("out of cmd '%s': %s", cmd, out) + + local state = self:state() + if state ~= 'stopped' then return false end + + return true +end + +return Osquery diff --git a/osquery_linux/1.0.0/config/action_config_schema.json b/osquery_linux/1.0.0/config/action_config_schema.json new file mode 100644 index 0000000..01d441c --- /dev/null +++ b/osquery_linux/1.0.0/config/action_config_schema.json @@ -0,0 +1,6 @@ +{ + "additionalProperties": false, + "properties": {}, + "required": [], + "type": "object" +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/changelog.json b/osquery_linux/1.0.0/config/changelog.json new file mode 100644 index 0000000..cc73102 --- /dev/null +++ b/osquery_linux/1.0.0/config/changelog.json @@ -0,0 +1,14 @@ +{ + "1.0.0": { + "en": { + "date": "01-09-2023", + "title": "Base functionality", + "description": "Added installation and configure osquery on agent for linux" + }, + "ru": { + "date": "09.01.2023", + "title": "Базовая функциональность", + "description": "Добавлена возможность установки и конфигурирования osquery на агенте для ОС linux" + } + } +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/config_schema.json b/osquery_linux/1.0.0/config/config_schema.json new file mode 100644 index 0000000..ee0ee52 --- /dev/null +++ b/osquery_linux/1.0.0/config/config_schema.json @@ -0,0 +1,31 @@ +{ + "additionalProperties": false, + "properties": { + "osquery_config": { + "rules": {}, + "type": "string", + "ui": { + "widget": "textarea", + "widgetConfig": { + "autoSize": { + "maxRows": 20, + "minRows": 10 + }, + "rows": 10 + } + } + }, + "replace_current_osquery_config": { + "rules": {}, + "type": "boolean", + "ui": { + "widgetConfig": {} + } + } + }, + "required": [ + "osquery_config", + "replace_current_osquery_config" + ], + "type": "object" +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/current_action_config.json b/osquery_linux/1.0.0/config/current_action_config.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/osquery_linux/1.0.0/config/current_action_config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/current_config.json b/osquery_linux/1.0.0/config/current_config.json new file mode 100644 index 0000000..79af50b --- /dev/null +++ b/osquery_linux/1.0.0/config/current_config.json @@ -0,0 +1,4 @@ +{ + "osquery_config": "{\n \"options\": {\n \"logger_plugin\": \"windows_event_log\"\n },\n \"schedule\": {\n \"system_info\": {\n \"query\": \"SELECT hostname, cpu_brand, physical_memory FROM system_info;\",\n \"interval\": 3600\n }\n },\n\n \"decorators\": {\n \"load\": [\n \"SELECT uuid AS host_uuid FROM system_info;\",\n \"SELECT user AS username FROM logged_in_users ORDER BY time DESC LIMIT 1;\"\n ]\n },\n\n // Add default osquery packs or install your own.\n //\n // There are several 'default' packs installed via\n // packages and/or Homebrew.\n //\n // Linux: /opt/osquery/share/osquery/packs\n // OS X: /var/osquery/packs\n // Homebrew: /usr/local/share/osquery/packs\n // make install: {PREFIX}/share/osquery/packs\n //\n \"packs\": {\n // \"osquery-monitoring\": \"/opt/osquery/share/osquery/packs/osquery-monitoring.conf\",\n // \"incident-response\": \"/opt/osquery/share/osquery/packs/incident-response.conf\",\n // \"it-compliance\": \"/opt/osquery/share/osquery/packs/it-compliance.conf\",\n // \"osx-attacks\": \"/var/osquery/packs/osx-attacks.conf\",\n // \"vuln-management\": \"/opt/osquery/share/osquery/packs/vuln-management.conf\",\n // \"hardware-monitoring\": \"/opt/osquery/share/osquery/packs/hardware-monitoring.conf\",\n // \"ossec-rootkit\": \"/opt/osquery/share/osquery/packs/ossec-rootkit.conf\",\n // \"windows-hardening\": \"C:\\\\Program Files\\\\osquery\\\\packs\\\\windows-hardening.conf\",\n // \"windows-attacks\": \"C:\\\\Program Files\\\\osquery\\\\packs\\\\windows-attacks.conf\"\n },\n\n // Provides feature vectors for osquery to leverage in simple statistical \n // analysis of results data. \n //\n // Currently this configuration is only used by Windows in the Powershell\n // Events table, wherein character_frequencies is a list of doubles \n // representing the aggregate occurrence of character values in Powershell \n // Scripts. A default configuration is provided which was adapated from \n // Lee Holmes cobbr project: \n // https://gist.github.com/cobbr/acbe5cc7a186726d4e309070187beee6\n // \n \"feature_vectors\": {\n \"character_frequencies\": [\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.00045, 0.01798,\n 0.0, 0.03111, 0.00063, 0.00027, 0.0, 0.01336, 0.0133,\n 0.00128, 0.0027, 0.00655, 0.01932, 0.01917, 0.00432, 0.0045,\n 0.00316, 0.00245, 0.00133, 0.001029, 0.00114, 0.000869, 0.00067,\n 0.000759, 0.00061, 0.00483, 0.0023, 0.00185, 0.01342, 0.00196,\n 0.00035, 0.00092, 0.027875, 0.007465, 0.016265, 0.013995, 0.0490895,\n 0.00848, 0.00771, 0.00737, 0.025615, 0.001725, 0.002265, 0.017875,\n 0.016005, 0.02533, 0.025295, 0.014375, 0.00109, 0.02732, 0.02658,\n 0.037355, 0.011575, 0.00451, 0.005865, 0.003255, 0.005965, 0.00077,\n 0.00621, 0.00222, 0.0062, 0.0, 0.00538, 0.00122, 0.027875,\n 0.007465, 0.016265, 0.013995, 0.0490895, 0.00848, 0.00771, 0.00737,\n 0.025615, 0.001725, 0.002265, 0.017875, 0.016005, 0.02533, 0.025295,\n 0.014375, 0.00109, 0.02732, 0.02658, 0.037355, 0.011575, 0.00451,\n 0.005865, 0.003255, 0.005965, 0.00077, 0.00771, 0.002379, 0.00766,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0\n ]\n } \n}\n", + "replace_current_osquery_config": true +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/current_event_config.json b/osquery_linux/1.0.0/config/current_event_config.json new file mode 100644 index 0000000..8311b96 --- /dev/null +++ b/osquery_linux/1.0.0/config/current_event_config.json @@ -0,0 +1,179 @@ +{ + "osquery_linux_already_installed": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_already_started": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_config_updated_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_config_updated_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + }, + "osquery_linux_installed_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_installed_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + }, + "osquery_linux_started_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_started_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_unexpected_stopped": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_unexpected_uninstalled": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_uninstalled_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_uninstalled_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + } +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/default_action_config.json b/osquery_linux/1.0.0/config/default_action_config.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/osquery_linux/1.0.0/config/default_action_config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/default_config.json b/osquery_linux/1.0.0/config/default_config.json new file mode 100644 index 0000000..79af50b --- /dev/null +++ b/osquery_linux/1.0.0/config/default_config.json @@ -0,0 +1,4 @@ +{ + "osquery_config": "{\n \"options\": {\n \"logger_plugin\": \"windows_event_log\"\n },\n \"schedule\": {\n \"system_info\": {\n \"query\": \"SELECT hostname, cpu_brand, physical_memory FROM system_info;\",\n \"interval\": 3600\n }\n },\n\n \"decorators\": {\n \"load\": [\n \"SELECT uuid AS host_uuid FROM system_info;\",\n \"SELECT user AS username FROM logged_in_users ORDER BY time DESC LIMIT 1;\"\n ]\n },\n\n // Add default osquery packs or install your own.\n //\n // There are several 'default' packs installed via\n // packages and/or Homebrew.\n //\n // Linux: /opt/osquery/share/osquery/packs\n // OS X: /var/osquery/packs\n // Homebrew: /usr/local/share/osquery/packs\n // make install: {PREFIX}/share/osquery/packs\n //\n \"packs\": {\n // \"osquery-monitoring\": \"/opt/osquery/share/osquery/packs/osquery-monitoring.conf\",\n // \"incident-response\": \"/opt/osquery/share/osquery/packs/incident-response.conf\",\n // \"it-compliance\": \"/opt/osquery/share/osquery/packs/it-compliance.conf\",\n // \"osx-attacks\": \"/var/osquery/packs/osx-attacks.conf\",\n // \"vuln-management\": \"/opt/osquery/share/osquery/packs/vuln-management.conf\",\n // \"hardware-monitoring\": \"/opt/osquery/share/osquery/packs/hardware-monitoring.conf\",\n // \"ossec-rootkit\": \"/opt/osquery/share/osquery/packs/ossec-rootkit.conf\",\n // \"windows-hardening\": \"C:\\\\Program Files\\\\osquery\\\\packs\\\\windows-hardening.conf\",\n // \"windows-attacks\": \"C:\\\\Program Files\\\\osquery\\\\packs\\\\windows-attacks.conf\"\n },\n\n // Provides feature vectors for osquery to leverage in simple statistical \n // analysis of results data. \n //\n // Currently this configuration is only used by Windows in the Powershell\n // Events table, wherein character_frequencies is a list of doubles \n // representing the aggregate occurrence of character values in Powershell \n // Scripts. A default configuration is provided which was adapated from \n // Lee Holmes cobbr project: \n // https://gist.github.com/cobbr/acbe5cc7a186726d4e309070187beee6\n // \n \"feature_vectors\": {\n \"character_frequencies\": [\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.00045, 0.01798,\n 0.0, 0.03111, 0.00063, 0.00027, 0.0, 0.01336, 0.0133,\n 0.00128, 0.0027, 0.00655, 0.01932, 0.01917, 0.00432, 0.0045,\n 0.00316, 0.00245, 0.00133, 0.001029, 0.00114, 0.000869, 0.00067,\n 0.000759, 0.00061, 0.00483, 0.0023, 0.00185, 0.01342, 0.00196,\n 0.00035, 0.00092, 0.027875, 0.007465, 0.016265, 0.013995, 0.0490895,\n 0.00848, 0.00771, 0.00737, 0.025615, 0.001725, 0.002265, 0.017875,\n 0.016005, 0.02533, 0.025295, 0.014375, 0.00109, 0.02732, 0.02658,\n 0.037355, 0.011575, 0.00451, 0.005865, 0.003255, 0.005965, 0.00077,\n 0.00621, 0.00222, 0.0062, 0.0, 0.00538, 0.00122, 0.027875,\n 0.007465, 0.016265, 0.013995, 0.0490895, 0.00848, 0.00771, 0.00737,\n 0.025615, 0.001725, 0.002265, 0.017875, 0.016005, 0.02533, 0.025295,\n 0.014375, 0.00109, 0.02732, 0.02658, 0.037355, 0.011575, 0.00451,\n 0.005865, 0.003255, 0.005965, 0.00077, 0.00771, 0.002379, 0.00766,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,\n 0.0, 0.0, 0.0\n ]\n } \n}\n", + "replace_current_osquery_config": true +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/default_event_config.json b/osquery_linux/1.0.0/config/default_event_config.json new file mode 100644 index 0000000..8311b96 --- /dev/null +++ b/osquery_linux/1.0.0/config/default_event_config.json @@ -0,0 +1,179 @@ +{ + "osquery_linux_already_installed": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_already_started": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_config_updated_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_config_updated_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + }, + "osquery_linux_installed_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_installed_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + }, + "osquery_linux_started_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_started_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_unexpected_stopped": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_unexpected_uninstalled": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_uninstalled_error": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "reason", + "version" + ], + "type": "atomic" + }, + "osquery_linux_uninstalled_success": { + "actions": [ + { + "fields": [], + "module_name": "this", + "name": "log_to_db", + "priority": 10 + } + ], + "fields": [ + "version" + ], + "type": "atomic" + } +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/dynamic_dependencies.json b/osquery_linux/1.0.0/config/dynamic_dependencies.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/osquery_linux/1.0.0/config/dynamic_dependencies.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/event_config_schema.json b/osquery_linux/1.0.0/config/event_config_schema.json new file mode 100644 index 0000000..33fe00b --- /dev/null +++ b/osquery_linux/1.0.0/config/event_config_schema.json @@ -0,0 +1,386 @@ +{ + "additionalProperties": false, + "properties": { + "osquery_linux_already_installed": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_already_started": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_config_updated_error": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_config_updated_success": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "version" + ], + "items": { + "enum": [ + "version" + ], + "type": "string" + }, + "maxItems": 1, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_installed_error": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_installed_success": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "version" + ], + "items": { + "enum": [ + "version" + ], + "type": "string" + }, + "maxItems": 1, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_started_error": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_started_success": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_unexpected_stopped": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_unexpected_uninstalled": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_uninstalled_error": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "reason", + "version" + ], + "items": { + "enum": [ + "reason", + "version" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + }, + "osquery_linux_uninstalled_success": { + "allOf": [ + { + "$ref": "#/definitions/events.atomic" + }, + { + "properties": { + "fields": { + "default": [ + "version" + ], + "items": { + "enum": [ + "version" + ], + "type": "string" + }, + "maxItems": 1, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "fields" + ], + "type": "object" + } + ] + } + }, + "required": [ + "osquery_linux_already_installed", + "osquery_linux_already_started", + "osquery_linux_config_updated_error", + "osquery_linux_config_updated_success", + "osquery_linux_installed_error", + "osquery_linux_installed_success", + "osquery_linux_started_error", + "osquery_linux_started_success", + "osquery_linux_unexpected_stopped", + "osquery_linux_unexpected_uninstalled", + "osquery_linux_uninstalled_error", + "osquery_linux_uninstalled_success" + ], + "type": "object" +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/fields_schema.json b/osquery_linux/1.0.0/config/fields_schema.json new file mode 100644 index 0000000..c4ccae3 --- /dev/null +++ b/osquery_linux/1.0.0/config/fields_schema.json @@ -0,0 +1,23 @@ +{ + "additionalProperties": true, + "properties": { + "reason": { + "rules": {}, + "type": "string", + "ui": { + "widgetConfig": {} + } + }, + "version": { + "rules": {}, + "type": "string", + "ui": { + "widgetConfig": {} + } + } + }, + "required": [ + "version" + ], + "type": "object" +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/info.json b/osquery_linux/1.0.0/config/info.json new file mode 100644 index 0000000..c8235d8 --- /dev/null +++ b/osquery_linux/1.0.0/config/info.json @@ -0,0 +1,38 @@ +{ + "name": "osquery_linux", + "template": "empty", + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "os": { + "linux": [ + "386", + "amd64" + ] + }, + "system": false, + "actions": [], + "events": [ + "osquery_linux_already_installed", + "osquery_linux_already_started", + "osquery_linux_config_updated_error", + "osquery_linux_config_updated_success", + "osquery_linux_installed_error", + "osquery_linux_installed_success", + "osquery_linux_started_error", + "osquery_linux_started_success", + "osquery_linux_unexpected_stopped", + "osquery_linux_unexpected_uninstalled", + "osquery_linux_uninstalled_error", + "osquery_linux_uninstalled_success" + ], + "fields": [ + "reason", + "version" + ], + "tags": [ + "osquery" + ] +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/locale.json b/osquery_linux/1.0.0/config/locale.json new file mode 100644 index 0000000..3f3ff2d --- /dev/null +++ b/osquery_linux/1.0.0/config/locale.json @@ -0,0 +1,206 @@ +{ + "module": { + "en": { + "title": "Osquery installer (linux)", + "description": "The module installed and configured osquery application on linux machines" + }, + "ru": { + "title": "Установщик osquery (linux)", + "description": "Модуль устанавливает и конфигурирует приложение osquery на устройствах linux" + } + }, + "config": { + "osquery_config": { + "en": { + "title": "Osquery config", + "description": "" + }, + "ru": { + "title": "Конфигурация osquery", + "description": "" + } + }, + "replace_current_osquery_config": { + "en": { + "title": "Is need to replace current osquery config?", + "description": "" + }, + "ru": { + "title": "Необходимо заменить текущую конфигурацию osquery?", + "description": "" + } + } + }, + "fields": { + "reason": { + "en": { + "title": "reason", + "description": "reason" + }, + "ru": { + "title": "Причина", + "description": "reason" + } + }, + "version": { + "en": { + "title": "version", + "description": "version" + }, + "ru": { + "title": "Версия", + "description": "версия" + } + } + }, + "actions": {}, + "events": { + "osquery_linux_already_installed": { + "en": { + "title": "The module detected Osquery installed on an agent", + "description": "The module detected Osquery installed in OS:\n{{ reason }}" + }, + "ru": { + "title": "Модуль обнаружил установленный Osquery на агенте", + "description": "Модуль обнаружил установленный Osquery в ОС:\n{{ reason }}" + } + }, + "osquery_linux_already_started": { + "en": { + "title": "The module detected Osquery already running on an agent", + "description": "The module detected Osquery already running in OS:\n{{ reason }}" + }, + "ru": { + "title": "Модуль обнаружил уже запущенный Osquery на агенте", + "description": "Модуль обнаружил уже запущенный Osquery в ОС:\n{{ reason }}" + } + }, + "osquery_linux_config_updated_error": { + "en": { + "title": "The module could not update the Osquery configuration on an agent", + "description": "The module could not update the Osquery configuration {{ version }} on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Модуль не смог обновить конфигурацию Osquery на агенте", + "description": "Модуль не смог обновить конфигурацию Osquery {{ version }}, причина:\n{{ reason }}" + } + }, + "osquery_linux_config_updated_success": { + "en": { + "title": "The module updated the Osquery configuration on an agent", + "description": "The module updated the Osquery configuration '{{ version }}' on an agent" + }, + "ru": { + "title": "Модуль обновил конфигурацию Osquery на агенте", + "description": "Модуль обновил конфигурацию Osquery {{ version }} на агенте" + } + }, + "osquery_linux_installed_error": { + "en": { + "title": "The module could not install the Osquery on an agent", + "description": "The module could not install the Osquery '{{ version }}' on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Модуль не смог установить Osquery на агенте", + "description": "Модуль не смог установить Osquery {{ version }} на агенте, причина:\n{{ reason }}" + } + }, + "osquery_linux_installed_success": { + "en": { + "title": "The module installed Osquery on an agent", + "description": "The module installed Osquery '{{ version }}' on an agent" + }, + "ru": { + "title": "Модуль установил Osquery на агенте", + "description": "Модуль установил Osquery {{ version }} на агенте" + } + }, + "osquery_linux_started_error": { + "en": { + "title": "The module could not start Osquery on an agent", + "description": "The module could not start the Osquery '{{ version }}' on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Модуль не смог запустить Osquery на агенте", + "description": "Модуль не смог запустить Osquery {{ version }} на агенте, причина:\n{{ reason }}" + } + }, + "osquery_linux_started_success": { + "en": { + "title": "The module started Osquery on an agent", + "description": "The module started Osquery '{{ version }}' on an agent" + }, + "ru": { + "title": "Модуль запустил Osquery на агенте", + "description": "Модуль запустил Osquery {{ version }} на агенте" + } + }, + "osquery_linux_unexpected_stopped": { + "en": { + "title": "Osquery was stopped on an agent", + "description": "Osquery '{{ version }}' was stopped on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Osquery был остановлен на агенте", + "description": "Osquery {{ version }} был остановлен на агенте, причина:\n{{ reason }}" + } + }, + "osquery_linux_unexpected_uninstalled": { + "en": { + "title": "Osquery was deleted on an agent", + "description": "Osquery '{{ version }}' was deleted on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Osquery был удален на агенте", + "description": "Osquery {{ version }} был удален на агенте, причина:\n{{ reason }}" + } + }, + "osquery_linux_uninstalled_error": { + "en": { + "title": "The module could not delete Osquery on an agent", + "description": "The module could not delete the Osquery '{{ version }}' on an agent:\n{{ reason }}" + }, + "ru": { + "title": "Модуль не смог удалить Osquery на агенте", + "description": "Модуль не смог удалить Osquery {{ version }} на агенте, причина:\n{{ reason }}" + } + }, + "osquery_linux_uninstalled_success": { + "en": { + "title": "The module deleted Osquery on an agent", + "description": "The module deleted Osquery '{{ version }}' on an agent" + }, + "ru": { + "title": "Модуль удалил Osquery на агенте", + "description": "Модуль удалил Osquery {{ version }} на агенте" + } + } + }, + "action_config": {}, + "event_config": { + "osquery_linux_already_installed": {}, + "osquery_linux_already_started": {}, + "osquery_linux_config_updated_error": {}, + "osquery_linux_config_updated_success": {}, + "osquery_linux_installed_error": {}, + "osquery_linux_installed_success": {}, + "osquery_linux_started_error": {}, + "osquery_linux_started_success": {}, + "osquery_linux_unexpected_stopped": {}, + "osquery_linux_unexpected_uninstalled": {}, + "osquery_linux_uninstalled_error": {}, + "osquery_linux_uninstalled_success": {} + }, + "tags": { + "osquery": { + "en": { + "title": "osquery", + "description": "osquery" + }, + "ru": { + "title": "osquery", + "description": "osquery" + } + } + } +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/config/static_dependencies.json b/osquery_linux/1.0.0/config/static_dependencies.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/osquery_linux/1.0.0/config/static_dependencies.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/osquery_linux/1.0.0/smodule/args.json b/osquery_linux/1.0.0/smodule/args.json new file mode 100644 index 0000000..169ba1f --- /dev/null +++ b/osquery_linux/1.0.0/smodule/args.json @@ -0,0 +1,4 @@ +{ + "debug": ["true"], + "handshake": ["true"] +} \ No newline at end of file diff --git a/osquery_linux/1.0.0/smodule/main.lua b/osquery_linux/1.0.0/smodule/main.lua new file mode 100644 index 0000000..03d7f8d --- /dev/null +++ b/osquery_linux/1.0.0/smodule/main.lua @@ -0,0 +1,161 @@ +require("engine") +local ffi = require'ffi' +local curl = require'libcurl' +local cjson = require "cjson.safe" +local prefix_db = __gid .. "." +local event_data_schema = __config.get_fields_schema() +local current_event_config = __config.get_current_event_config() +local module_info = __config.get_module_info() +local event_engine = CEventEngine(event_data_schema, current_event_config, module_info, prefix_db, true) +local action_engine = CActionEngine({}, true) + +-- for overriding debug argument +local g_print = print +local print = function(...) + if __args["debug"][1] == "true" then + g_print(...); + end +end + +-- for example ganarate test json document by json schema +local function generate_json(schema) + local result = "" + local function wrire(raw) + result = ffi.string(ffi.cast("char*", raw)) + return #result + end + + curl.easy{ + url = 'https://json.vxcontrol.app/api/v1/schema', + post = 1, + httpheader = { + "Content-Type: application/json", + }, + postfields = schema; + writefunction = wrire + } + :perform() + :close() + + return cjson.decode(result) +end + +-- for example push of test events for ones from current config +local function push_events(id) + local event_config = cjson.decode(__config.get_current_event_config()) + for event_name, _ in pairs(event_config or {}) do + local info = { name = event_name, data = generate_json(__config.get_fields_schema()) } + local result, list = event_engine:push_event(info) + if result then + for action_id, action_result in ipairs(action_engine:exec(id, list)) do + print("action " .. tostring(action_id) .. " was executed: ", action_result) + end + end + end +end + +-- for debugging used printing initial agent connected list +local function print_agents() + print("__agents:") + for i, a in pairs(__agents.dump()) do + print("\t", i, type(a)) + print("\t\t", "ID:", a.ID) + print("\t\t", "IP:", a.IP) + print("\t\t", "Src:", a.Src) + print("\t\t", "Dst:", a.Dst) + print("\t\t", "Type:", a.Type) + print("\t\t", "Info:", type(a.Info)) + if a.Info ~= nil then + print("\t\t\t", "Info.Os:", type(a.Info.Os)) + if a.Info.Os ~= nil then + print("\t\t\t\t", "Info.Os.Type:", a.Info.Os.Type) + print("\t\t\t\t", "Info.Os.Name:", a.Info.Os.Name) + print("\t\t\t\t", "Info.Os.Arch:", a.Info.Os.Arch) + end + print("\t\t\t", "Info.User:", type(a.Info.User)) + if a.Info.User ~= nil then + print("\t\t\t\t", "Info.User.Name:", a.Info.User.Name) + print("\t\t\t\t", "Info.User.Group:", a.Info.User.Group) + end + end + print() + end + print() +end + +-- for example getting agent ID by dst token on agent connected event +local function get_agent_id(dst) + for i, a in pairs(__agents.dump()) do + if i == dst then + return a.ID + end + end + return "" +end + +-- set default timeout to wait exit on blocking of recv_* functions +__api.set_recv_timeout(5000) -- 5s + +__api.add_cbs({ + data = function(src, data) + print('receive data: "' .. data .. '" from: ' .. src) + local msg = cjson.decode(data) + if msg['type'] == 'hs_agent' then + local hs_server_msg = cjson.encode({['type'] = 'hs_server', ['data'] = "pong"}) + if __args["handshake"][1] == "true" then + __api.await(100) + print("sent hs server msg to ", src, ": ", __api.send_data_to(src, hs_server_msg)) + end + else + print("receive unknown type message", msg['type']) + end + print() + return true + end, + + file = function(src, path, name) + print('receive file: "' .. path .. '" / "' .. name .. '" from: ' .. src) + return true + end, + + text = function(src, text, name) + print('receive text: "' .. text .. '" / "' .. name .. '" from: ' .. src) + return true + end, + + msg = function(src, msg, mtype) + print('receive msg: "' .. msg .. '" / "' .. tostring(mtype) .. '" from: ' .. src) + return true + end, + + action = function(src, data, name) + print('receive action: "' .. data .. '" / "' .. name .. '" from: ' .. src) + return true + end, + + control = function(cmtype, data) + local src = data + print('receive control msg: "' .. cmtype .. '" from: ' .. src) + print_agents() + if cmtype == "agent_connected" then + print("agent_connected") + push_events(get_agent_id(src)) + end + if cmtype == "agent_disconnected" then + print("agent_disconnected") + end + return true + end, +}) + +g_print("module " .. tostring(__api.get_name()) .. " was started") + +for _, a in pairs(__agents.dump()) do + push_events(a.ID) +end + +__api.await(-1) + +g_print("module " .. tostring(__api.get_name()) .. " was stopped") + +return 'success' diff --git a/tests/Dockerfile b/tests/Dockerfile new file mode 100644 index 0000000..2ef763f --- /dev/null +++ b/tests/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:20.04 + +RUN apt update; apt install -y --no-install-recommends systemctl + +ENV APP_PATH=/soldr-modules \ + LUAPOWER_PLATFORM=linux64 + +ENV LUA_PATH=$APP_PATH/tests_framework/lua/?.lua;$APP_PATH/tests_framework/lua/?/init.lua;$APP_PATH/luapower/?.lua;$APP_PATH/luapower/?/init.lua;$APP_PATH/utils/?.lua;$APP_PATH/utils/?/init.lua \ + LUA_CPATH=$APP_PATH/luapower/bin/$LUAPOWER_PLATFORM/lib?.dylib;$APP_PATH/luapower/bin/$LUAPOWER_PLATFORM/clib/?.so; \ + LUA_BIN=$APP_PATH/luapower/bin/$LUAPOWER_PLATFORM/luajit-bin + +ENTRYPOINT ["/bin/bash"] diff --git a/tests/osquery_linux_client_spec.lua b/tests/osquery_linux_client_spec.lua new file mode 100644 index 0000000..3b4b6c7 --- /dev/null +++ b/tests/osquery_linux_client_spec.lua @@ -0,0 +1,137 @@ +require 'busted.runner'() +local ffi = require('ffi') + +--------------------------------------------------- +-- mock helper functions +--------------------------------------------------- + +local function mock_expect_event(name) + return __mock:expect("event", function(o) + return o.event and o.event.name == name + end) +end + +local function mock_get_event_context(name) + return __mock:pop_from_context("event", function(o) + return o.event and o.event.name == name + end) +end + +--------------------------------------------------- +-- osquery helper functions +--------------------------------------------------- + +local function osquery_uninstall() + print("uninstallation osquery in test") + io.popen('dpkg --force-all -P osquery 2> /dev/null', 'r') +end + +local function osquery_stop() + print("stopping osquery in test") + io.popen('systemctl stop osqueryd', 'r') +end + +describe('osquery_linux agent', function() + setup(function() + _G.__mock = { + vars = {}, + timeout = 60, -- in seconds + cwd = "tmpcwd", + module = "osquery_linux", + version = "1.0.0", + side = "agent", + log_level = os.getenv("LOG_LEVEL") or "info", -- error, warn, info, debug, trace + } + -- load mocked environment + require("mock") + + -- hack, see: https://github.com/vxcontrol/soldr-modules/issues/42 + __mock.module_info.fields = { "reason", "version" } + __mock.module_info.actions = {} + __mock.module_info.events = { + "osquery_linux_already_installed", + "osquery_linux_already_started", + "osquery_linux_config_updated_error", + "osquery_linux_config_updated_success", + "osquery_linux_installed_error", + "osquery_linux_installed_success", + "osquery_linux_started_error", + "osquery_linux_started_success", + "osquery_linux_unexpected_stopped", + "osquery_linux_unexpected_uninstalled", + "osquery_linux_uninstalled_error", + "osquery_linux_uninstalled_success" + } + + osquery_uninstall() + end) + + before_each(function() + __mock:clear_expectations() + end) + + teardown(function() + -- stop module actually wait for module coroutine to finish execution + osquery_uninstall() + __mock:module_stop() + end) + + context('osquery module life circle', function() + if ffi.os ~= 'Linux' then + describe('installing osquery', function() + it('should not install osquery', function() + --__mock:module_start() + + --for i, data in ipairs(__mock.stage.ctx["event"]) do + -- print("i", i) + -- print("data", data) + --end + + assert.equal(table.getn(__mock.stage.ctx["event"]), 1) -- only one event + assert.is_true(mock_expect_event("osquery_linux_installed_error")) + end) + end) + end + + if ffi.os == 'Linux' then + describe('installing osquery', function() + it('should install and configure osquery', function() + -- exec cmd + assert + assert.is_true(mock_expect_event("osquery_linux_installed_success")) + assert.is_true(mock_expect_event("osquery_linux_config_updated_success")) + end) + end) + + describe('when osquery was unexpected stopped', function() + it('should start osquery', function() + assert.is_nil(mock_get_event_context("osquery_linux_unexpected_stopped")) + assert.is_nil(mock_get_event_context("osquery_linux_started_success")) + osquery_stop() + assert.is_true(mock_expect_event("osquery_linux_unexpected_stopped")) + assert.is_true(mock_expect_event("osquery_linux_started_success")) + end) + end) + + describe('when osquery was unexpected removed', function() + it('should reinstall osquery', function() + assert.is_nil(mock_get_event_context("osquery_linux_unexpected_uninstalled")) + assert.is_nil(mock_get_event_context("osquery_linux_installed_success")) + osquery_uninstall() + assert.is_true(mock_expect_event("osquery_linux_unexpected_uninstalled")) + assert.is_true(mock_expect_event("osquery_linux_installed_success")) + end) + end) + + describe('when module get command update_config in callback', function() + it('should start osquery', function() + assert.is_nil(mock_get_event_context("osquery_linux_config_updated_success")) + --assert.is_nil(mock_get_event_context("osquery_linux_installed_success")) + --local src, dst = __mock.mock_token, __mock.module_token + __mock:send_control("update_config") + --mock_command_update_config() + assert.is_true(mock_expect_event("osquery_linux_config_updated_success")) + end) + end) + end + end) +end) diff --git a/utils/mock/core.lua b/utils/mock/core.lua index 77c39a1..f5d4f20 100644 --- a/utils/mock/core.lua +++ b/utils/mock/core.lua @@ -975,4 +975,11 @@ __mock.send_action = function(self, src, dst, data, name) end return false end + +__mock.send_control = function(self, cmtype, data) + if self.module_callbacks.control ~= nil then + return self.module_callbacks.control(cmtype, data) + end + return false +end ---------------------------------------------------