From 1d923041e0df860384c1f3d398c2171eb36bb2ea Mon Sep 17 00:00:00 2001 From: csavelief Date: Wed, 21 Aug 2024 12:32:44 +0200 Subject: [PATCH] [REF. #62] Fill table ynhOsqueryRules with actual rules and display them on the UI side. --- app/Http/Controllers/HomeController.php | 8 + database/seeds/DatabaseSeeder.php | 369 ++++++++++++++++++ .../views/home/cards/_osquery_rules.blade.php | 55 +++ resources/views/home/index.blade.php | 11 + 4 files changed, 443 insertions(+) create mode 100644 resources/views/home/cards/_osquery_rules.blade.php diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 5cd21c0..687d465 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -6,6 +6,7 @@ use App\Models\YnhNginxLogs; use App\Models\YnhOrder; use App\Models\YnhOsquery; +use App\Models\YnhOsqueryRule; use App\Models\YnhServer; use App\Models\YnhSshTraces; use App\User; @@ -60,6 +61,12 @@ public function index(Request $request) ]; } + $security_rules = collect(); + + if ($tab === 'security_rules') { + $security_rules = YnhOsqueryRule::get(); + } + $interdependencies = collect(); if ($tab === 'interdependencies') { @@ -138,6 +145,7 @@ public function index(Request $request) 'memory_usage', 'disk_usage', 'security_events', + 'security_rules', 'interdependencies', 'traces', 'pendingActions', diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 0d5d9a2..08d8bd8 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -24,6 +24,7 @@ public function run() $this->setupProductCategories(); $this->setupProductProperties(); $this->setupProducts(); + $this->setupOsqueryRules(); } private function setupTenants(): void @@ -247,4 +248,372 @@ private function setupProducts(): void $product->taxons()->syncWithoutDetaching($taxon); } } + + private function setupOsqueryRules(): void + { + $rules = $this->palantirOsqueryRulesForLinux()['schedule']; + foreach ($rules as $name => $rule) { + $fields = []; + if (isset($rule['description'])) { + $fields['description'] = $rule['description']; + } + if (isset($rule['query'])) { + $fields['query'] = $rule['query']; + } + if (isset($rule['interval'])) { + $fields['interval'] = $rule['interval']; + } + if (isset($rule['removed'])) { + $fields['removed'] = $rule['removed']; + } + if (isset($rule['snapshot'])) { + $fields['snapshot'] = $rule['snapshot']; + } + if (isset($rule['platform'])) { + $fields['platform'] = $rule['platform']; + } + \App\Models\YnhOsqueryRule::updateOrCreate(['name' => $name], $fields); + } + $rules = $this->customRules(); + foreach ($rules as $rule) { + $fields = []; + if (isset($rule['description'])) { + $fields['description'] = $rule['description']; + } + if (isset($rule['query'])) { + $fields['query'] = $rule['query']; + } + if (isset($rule['interval'])) { + $fields['interval'] = $rule['interval']; + } + if (isset($rule['removed'])) { + $fields['removed'] = $rule['removed']; + } + if (isset($rule['snapshot'])) { + $fields['snapshot'] = $rule['snapshot']; + } + if (isset($rule['platform'])) { + $fields['platform'] = $rule['platform']; + } + \App\Models\YnhOsqueryRule::updateOrCreate(['name' => $rule['name']], $fields); + } + } + + private function customRules(): array + { + return [[ + 'name' => "packages_available_snapshot", + 'query' => "SELECT name, version, source FROM deb_packages;", + 'description' => "Display all installed DEB packages", + 'interval' => 86400, + 'snapshot' => true, + ], [ + 'name' => "memory_available_snapshot", + 'query' => "SELECT printf('%.2f',((memory_total - memory_available) * 1.0)/1073741824) AS used_space_gb, printf('%.2f',(1.0 * memory_available / 1073741824)) AS space_left_gb, printf('%.2f',(1.0 * memory_total / 1073741824)) AS total_space_gb, printf('%.2f',(((memory_total - memory_available) * 1.0)/1073741824)/(1.0 * memory_total / 1073741824)) * 100 AS '%_used', printf('%.2f',(1.0 * memory_available / 1073741824)/(1.0 * memory_total / 1073741824)) * 100 AS '%_available' FROM memory_info;", + 'description' => "Track memory usage.", + 'interval' => 300, + 'snapshot' => true, + ], [ + 'name' => "disk_available_snapshot", + 'query' => "SELECT printf('%.2f',((blocks - blocks_available * 1.0) * blocks_size)/1073741824) AS used_space_gb, printf('%.2f',(1.0 * blocks_available * blocks_size / 1073741824)) AS space_left_gb, printf('%.2f',(1.0 * blocks * blocks_size / 1073741824)) AS total_space_gb, printf('%.2f',(((blocks - blocks_available * 1.0) * blocks_size)/1073741824)/(1.0 * blocks * blocks_size / 1073741824)) * 100 AS '%_used', printf('%.2f',(1.0 * blocks_available * blocks_size / 1073741824)/(1.0 * blocks * blocks_size / 1073741824)) * 100 AS '%_available' FROM mounts WHERE path = '/';", + 'description' => "Track disk usage.", + 'interval' => 300, + 'snapshot' => true, + ]]; + } + + private function palantirOsqueryRulesForLinux(): array + { + // See https://github.com/palantir/osquery-configuration/blob/master/Classic/Servers/Linux/osquery.conf for details + $rules = <<< EOF +{ + "options": { + "logger_snapshot_event_type": "true", + "schedule_splay_percent": 10 + }, + "platform": "linux", + "schedule": { + "process_events": { + "query": "SELECT auid, cmdline, ctime, cwd, egid, euid, gid, parent, path, pid, time, uid FROM process_events WHERE path NOT IN ('/bin/sed', '/usr/bin/tr', '/bin/gawk', '/bin/date', '/bin/mktemp', '/usr/bin/dirname', '/usr/bin/head', '/usr/bin/jq', '/bin/cut', '/bin/uname', '/bin/basename') and cmdline NOT LIKE '%_key%' AND cmdline NOT LIKE '%secret%';", + "interval": 10, + "description": "Process events collected from the audit framework" + }, + "socket_events": { + "query": "SELECT action, auid, family, local_address, local_port, path, pid, remote_address, remote_port, success, time FROM socket_events WHERE success=1 AND path NOT IN ('/usr/bin/hostname') AND remote_address NOT IN ('127.0.0.1', '169.254.169.254', '', '0000:0000:0000:0000:0000:0000:0000:0001', '::1', '0000:0000:0000:0000:0000:ffff:7f00:0001', 'unknown', '0.0.0.0', '0000:0000:0000:0000:0000:0000:0000:0000');", + "interval": 10, + "description": "Socket events collected from the audit framework" + }, + "file_events": { + "query": "SELECT * FROM file_events;", + "interval": 10, + "description": "File events collected from file integrity monitoring", + "removed": false + }, + "apt_sources": { + "query": "SELECT * FROM apt_sources;", + "interval": 86400, + "description": "Display apt package manager sources.", + "snapshot": true, + "platform": "ubuntu" + }, + "authorized_keys": { + "query": "SELECT * FROM users CROSS JOIN authorized_keys USING (uid);", + "interval": 86400, + "description": "A line-delimited authorized_keys table." + }, + "behavioral_reverse_shell": { + "query": "SELECT DISTINCT(processes.pid), processes.parent, processes.name, processes.path, processes.cmdline, processes.cwd, processes.root, processes.uid, processes.gid, processes.start_time, process_open_sockets.remote_address, process_open_sockets.remote_port, (SELECT cmdline FROM processes AS parent_cmdline WHERE pid=processes.parent) AS parent_cmdline FROM processes JOIN process_open_sockets USING (pid) LEFT OUTER JOIN process_open_files ON processes.pid = process_open_files.pid WHERE (name='sh' OR name='bash') AND remote_address NOT IN ('0.0.0.0', '::', '') AND remote_address NOT LIKE '10.%' AND remote_address NOT LIKE '192.168.%';", + "interval": 600, + "description": "Find shell processes that have open sockets" + }, + "cpu_time": { + "query": "SELECT * FROM cpu_time;", + "interval": 3600, + "description": "Displays information from /proc/stat file about the time the CPU cores spent in different parts of the system" + }, + "crontab": { + "query": "SELECT * FROM crontab;", + "interval": 3600, + "description": "Retrieves all the jobs scheduled in crontab in the target system." + }, + "crontab_snapshot": { + "query": "SELECT * FROM crontab;", + "interval": 86400, + "description": "Retrieves all the jobs scheduled in crontab in the target system.", + "snapshot": true + }, + "deb_packages": { + "query": "SELECT * FROM deb_packages;", + "interval": 86400, + "description": "Display all installed DEB packages", + "snapshot": true, + "platform": "ubuntu" + }, + "dns_resolvers": { + "query": "SELECT * FROM dns_resolvers;", + "interval": 3600, + "description": "DNS resolvers used by the host" + }, + "ec2_instance_metadata": { + "query": "SELECT * FROM ec2_instance_metadata;", + "interval": 3600, + "description": "Retrieve the EC2 metadata for this endpoint" + }, + "ec2_instance_metadata_snapshot": { + "query": "SELECT * FROM ec2_instance_metadata;", + "interval": 86400, + "description": "Snapshot query to retrieve the EC2 metadata for this endpoint", + "snapshot": true + }, + "ec2_instance_tags": { + "query": "SELECT * FROM ec2_instance_tags;", + "interval": 3600, + "description": "Retrieve the EC2 tags for this endpoint" + }, + "ec2_instance_tags_snapshot": { + "query": "SELECT * FROM ec2_instance_tags;", + "interval": 86400, + "description": "Snapshot query to retrieve the EC2 tags for this instance", + "snapshot": true + }, + "etc_hosts": { + "query": "SELECT * FROM etc_hosts;", + "interval": 3600, + "description": "Retrieves all the entries in the target system /etc/hosts file." + }, + "etc_hosts_snapshot": { + "query": "SELECT * FROM etc_hosts;", + "interval": 86400, + "description": "Retrieves all the entries in the target system /etc/hosts file.", + "snapshot": true + }, + "hardware_events": { + "query": "SELECT * FROM hardware_events;", + "description": "Track hardware events.", + "interval": 10, + "removed": false + }, + "iptables": { + "query": "SELECT * FROM iptables;", + "interval": 86400, + "platform": "linux", + "description": "Retrieves the current filters and chains per filter in the target system." + }, + "kernel_info": { + "query": "SELECT * FROM kernel_info;", + "interval": 86400, + "description": "Retrieves information from the current kernel in the target system.", + "snapshot": true + }, + "kernel_integrity": { + "query": "SELECT * FROM kernel_integrity;", + "interval": 86400, + "description": "Various Linux kernel integrity checked attributes." + }, + "kernel_modules": { + "query": "SELECT * FROM kernel_modules;", + "interval": 3600, + "description": "Linux kernel modules both loaded and within the load search path." + }, + "kernel_modules_snapshot": { + "query": "SELECT * FROM kernel_modules;", + "interval": 86400, + "description": "Linux kernel modules both loaded and within the load search path.", + "snapshot": true + }, + "last": { + "query": "SELECT * FROM last;", + "interval": 3600, + "description": "Retrieves the list of the latest logins with PID, username and timestamp." + }, + "ld_preload": { + "query": "SELECT process_envs.pid, process_envs.key, process_envs.value, processes.name, processes.path, processes.cmdline, processes.cwd FROM process_envs join processes USING (pid) WHERE key = 'LD_PRELOAD';", + "interval": 60, + "description": "Any processes that run with an LD_PRELOAD environment variable", + "snapshot": true + }, + "ld_so_preload_exists": { + "query": "SELECT * FROM file WHERE path='/etc/ld.so.preload' AND path!='';", + "interval": 3600, + "description": "Generates an event if ld.so.preload is present - used by rootkits such as Jynx", + "snapshot": true + }, + "listening_ports": { + "query": "SELECT pid, port, processes.path, cmdline, cwd FROM listening_ports JOIN processes USING (pid) WHERE port!=0;", + "interval": 86400, + "description": "Gather information about processes that are listening on a socket.", + "snapshot": true + }, + "memory_info": { + "query": "SELECT * FROM memory_info;", + "interval": 3600, + "description": "Information about memory usage on the system" + }, + "mounts": { + "query": "SELECT device, device_alias, path, type, blocks_size, flags FROM mounts;", + "interval": 86400, + "description": "Retrieves the current list of mounted drives in the target system." + }, + "network_interfaces_snapshot": { + "query": "SELECT a.interface, a.address, d.mac FROM interface_addresses a JOIN interface_details d USING (interface);", + "interval": 600, + "description": "Record the network interfaces and their associated IP and MAC addresses", + "snapshot": true + }, + "os_version": { + "query": "SELECT * FROM os_version;", + "interval": 86400, + "description": "Retrieves information from the Operating System where osquery is currently running.", + "snapshot": true + }, + "osquery_info": { + "query": "SELECT * FROM osquery_info;", + "interval": 86400, + "description": "Information about the running osquery configuration", + "snapshot": true + }, + "processes_snapshot": { + "query": "select name, path, cmdline, cwd, on_disk from processes;", + "interval": 86400, + "description": "A snapshot of all processes running on the host. Useful for outlier analysis.", + "snapshot": true + }, + "rpm_packages": { + "query": "SELECT name, version, release, arch FROM rpm_packages;", + "interval": 86400, + "description": "Display all installed RPM packages", + "snapshot": true, + "platform": "centos" + }, + "runtime_perf": { + "query": "SELECT ov.version AS os_version, ov.platform AS os_platform, ov.codename AS os_codename, i.*, p.resident_size, p.user_time, p.system_time, time.minutes AS counter, db.db_size_mb AS database_size from osquery_info i, os_version ov, processes p, time, (SELECT (SUM(size) / 1024) / 1024.0 AS db_size_mb FROM (SELECT value FROM osquery_flags WHERE name = 'database_path' LIMIT 1) flags, file WHERE path LIKE flags.value || '%%' AND type = 'regular') db WHERE p.pid = i.pid;", + "interval": 1800, + "description": "Records system/user time, db size, and many other system metrics" + }, + "shell_history": { + "query": "SELECT * FROM users CROSS JOIN shell_history USING (uid);", + "interval": 3600, + "description": "Record shell history for all users on system (instead of just root)" + }, + "suid_bin": { + "query": "SELECT * FROM suid_bin;", + "interval": 86400, + "description": "Display any SUID binaries that are owned by root" + }, + "system_info": { + "query": "SELECT * FROM system_info;", + "interval": 86400, + "description": "Information about the system hardware and name", + "snapshot": true + }, + "usb_devices": { + "query": "SELECT * FROM usb_devices;", + "interval": 120, + "description": "Retrieves the current list of USB devices in the target system." + }, + "user_ssh_keys": { + "query": "SELECT * FROM users CROSS JOIN user_ssh_keys USING (uid);", + "interval": 86400, + "description": "Returns the private keys in the users ~/.ssh directory and whether or not they are encrypted" + }, + "users": { + "query": "SELECT * FROM users;", + "interval": 86400, + "description": "Local system users." + }, + "users_snapshot": { + "query": "SELECT * FROM users;", + "interval": 86400, + "description": "Local system users.", + "snapshot": true + }, + "yum_sources": { + "query": "SELECT name, baseurl, enabled, gpgcheck FROM yum_sources;", + "interval": 86400, + "description": "Display yum package manager sources", + "snapshot": true, + "platform": "centos" + } + }, + "file_paths": { + "configuration": [ + "/etc/passwd", + "/etc/shadow", + "/etc/ld.so.preload", + "/etc/ld.so.conf", + "/etc/ld.so.conf.d/%%", + "/etc/pam.d/%%", + "/etc/resolv.conf", + "/etc/rc%/%%", + "/etc/my.cnf", + "/etc/modules", + "/etc/hosts", + "/etc/hostname", + "/etc/fstab", + "/etc/crontab", + "/etc/cron%/%%", + "/etc/init/%%", + "/etc/rsyslog.conf" + ], + "binaries": [ + "/usr/bin/%%", + "/usr/sbin/%%", + "/bin/%%", + "/sbin/%%", + "/usr/local/bin/%%", + "/usr/local/sbin/%%" + ] + }, + "events": { + "disable_subscribers": [ + "user_events" + ] + }, + "packs": { + "ossec-rootkit": "/etc/osquery/packs/ossec-rootkit.conf" + } +} +EOF; + return json_decode($rules, true); + } } diff --git a/resources/views/home/cards/_osquery_rules.blade.php b/resources/views/home/cards/_osquery_rules.blade.php new file mode 100644 index 0000000..4b34129 --- /dev/null +++ b/resources/views/home/cards/_osquery_rules.blade.php @@ -0,0 +1,55 @@ +
+ @if($rules->isEmpty()) +
+
+
+ None. +
+
+
+ @else +
+ + + + + + + + + + + + @foreach($rules->sortBy('name', SORT_NATURAL|SORT_FLAG_CASE) as $rule) + + + + + + + + @endforeach + +
+  {{ __('Name') }} + {{ __('Interval (in seconds)') }}{{ __('Platform') }}{{ __('Snapshot') }}{{ __('Removed') }}
+ + {{ $rule->name }} + +
+ {{ $rule->description }} +
+
+ {{ $rule->interval }} + + + {{ $rule->platform->value }} + + + {{ $rule->snapshot ? 'YES' : 'NO' }} + + {{ $rule->removed ? 'YES' : 'NO' }} +
+
+ @endif +
\ No newline at end of file diff --git a/resources/views/home/index.blade.php b/resources/views/home/index.blade.php index ef546f1..052b84b 100644 --- a/resources/views/home/index.blade.php +++ b/resources/views/home/index.blade.php @@ -20,6 +20,8 @@ {{ __('Resources Usage') }} @elseif($tab === 'security') {{ __('Security') }} + @elseif($tab === 'security_rules') + {{ __('Security Rules') }} @elseif($tab === 'orders') {{ __('Orders') }} @elseif($tab === 'users') @@ -109,6 +111,12 @@ @endif + @if(Auth::user()->canListOrders())