From bc359d69ce7a698be288f6b538bf9eb17f63e9e5 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Feb 2023 10:40:58 -0500 Subject: [PATCH 1/4] Linux events: decrease CPU usage of elevated children & execdir --- .../unexpected-execdir-events-linux.sql | 170 +++++++++--------- ...xpected-elevated-children-events_linux.sql | 45 +++-- 2 files changed, 113 insertions(+), 102 deletions(-) diff --git a/detection/execution/unexpected-execdir-events-linux.sql b/detection/execution/unexpected-execdir-events-linux.sql index d21fea3..e2c6c0c 100644 --- a/detection/execution/unexpected-execdir-events-linux.sql +++ b/detection/execution/unexpected-execdir-events-linux.sql @@ -6,90 +6,92 @@ -- false positives: -- * programs running in alternative namespaces (Docker) -- --- interval: 300 +-- interval: 600 -- platform: linux -- tags: process events -SELECT - pe.pid, - pe.path, - REGEX_MATCH (pe.path, '(.*)/', 1) AS dirname, - pe.mode, - pe.cwd, - pe.euid, - pe.parent, - pp.path AS parent_path, - pp.name AS parent_name, - pp.cmdline AS parent_cmd, - pp.euid AS parent_euid, - phash.sha256 AS parent_sha256, - hash.sha256 AS sha256 -FROM - process_events pe - LEFT JOIN processes p ON pe.pid = pe.pid - LEFT JOIN processes pp ON pe.parent = p.pid - LEFT JOIN hash ON pe.path = hash.path - LEFT JOIN hash phash ON pp.path = hash.path -WHERE - pe.time > (strftime('%s', 'now') -300) - AND dirname NOT LIKE '/home/%' - AND dirname NOT LIKE '/nix/store/%/bin' - AND dirname NOT LIKE '/nix/store/%/lib/%' - AND dirname NOT LIKE '/nix/store/%/libexec' - AND dirname NOT LIKE '/nix/store/%/libexec/%' - AND dirname NOT LIKE '/nix/store/%/share/%' - AND dirname NOT LIKE '/opt/%' - AND dirname NOT LIKE '/tmp/go-build%' - AND dirname NOT LIKE '/snap/%' - AND dirname NOT LIKE '/usr/libexec/%' - AND dirname NOT LIKE '/usr/local/%/bin/%' - AND dirname NOT LIKE '/usr/local/%bin' - AND dirname NOT LIKE '/usr/local/%libexec' - and dirname NOT LIKE '/usr/local/Cellar/%' - AND dirname NOT LIKE '/usr/lib/%' - AND dirname NOT LIKE '%/.terraform/providers/%' - AND dirname NOT LIKE '/usr/lib64/%' - AND dirname NOT LIKE '/tmp/%/bin' - AND dirname NOT LIKE '/usr/local/go/pkg/tool/%' - AND dirname NOT IN ( - '/', - '/app', - '/bin', - '/ko-app', - '/sbin', - '/usr/bin', - '/usr/lib', - '/usr/lib64/firefox', - '/usr/lib/bluetooth', - '/usr/lib/cups/notifier', - '/usr/lib/evolution-data-server', - '/usr/libexec', - '/usr/libexec/ApplicationFirewall', - '/usr/libexec/rosetta', - '/usr/lib/firefox', - '/usr/lib/fwupd', - '/usr/lib/ibus', - '/usr/lib/libreoffice/program', - '/usr/lib/polkit-1', - '/usr/lib/slack', - '/usr/lib/snapd', - '/usr/lib/systemd', - '/usr/lib/telepathy', - '/usr/lib/udisks2', - '/usr/lib/xorg', - '/usr/sbin', - '/usr/share/code', - '/usr/share/teams', - '/usr/share/teams/resources/app.asar.unpacked/node_modules/slimcore/bin' +SELECT -- Child + pe.path AS p0_path, + REGEX_MATCH (pe.path, '.*/(.*)', 1) AS p0_name, + TRIM(pe.cmdline) AS p0_cmd, + pe.cwd AS p0_cwd, + pe.pid AS p0_pid, + p.cgroup_path AS p0_cgroup, + -- Parent + pe.parent AS p1_pid, + p1.cgroup_path AS p1_cgroup, + TRIM(COALESCE(p1.cmdline, pe1.cmdline)) AS p1_cmd, + COALESCE(p1.path, pe1.path) AS p1_path, + COALESCE(p1.euid, pe1.euid) AS p1_euid, + COALESCE(p_hash1.sha256, pe_hash1.sha256) AS p1_hash, + REGEX_MATCH (COALESCE(p1.path, pe1.path), '.*/(.*)', 1) AS p1_name, + -- Grandparent + COALESCE(p1.parent, pe1.parent) AS p2_pid, + COALESCE(p1_p2.cgroup_path, pe1_p2.cgroup_path) AS p2_cgroup, + TRIM( + COALESCE(p1_p2.cmdline, pe1_p2.cmdline, pe1_pe2.cmdline) + ) AS p2_cmd, + COALESCE(p1_p2.path, pe1_p2.path, pe1_pe2.path) AS p2_path, + COALESCE( + p1_p2_hash.path, + pe1_p2_hash.path, + pe1_pe2_hash.path + ) AS p2_hash, + REGEX_MATCH ( + COALESCE(p1_p2.path, pe1_p2.path, pe1_pe2.path), + '.*/(.*)', + 1 + ) AS p2_name +FROM process_events pe + LEFT JOIN processes p ON pe.pid = pe.pid -- Parents (via two paths) + LEFT JOIN processes p1 ON pe.parent = p1.pid + LEFT JOIN hash p_hash1 ON p1.path = p_hash1.path + LEFT JOIN process_events pe1 ON pe.parent = pe1.pid + AND pe1.cmdline != '' + LEFT JOIN hash pe_hash1 ON pe1.path = pe_hash1.path -- Grandparents (via 3 paths) + LEFT JOIN processes p1_p2 ON p1.parent = p1_p2.pid -- Current grandparent via parent processes + LEFT JOIN processes pe1_p2 ON pe1.parent = pe1_p2.pid -- Current grandparent via parent events + LEFT JOIN process_events pe1_pe2 ON pe1.parent = pe1_p2.pid + AND pe1_pe2.cmdline != '' -- Past grandparent via parent events + LEFT JOIN hash p1_p2_hash ON p1_p2.path = p1_p2_hash.path + LEFT JOIN hash pe1_p2_hash ON pe1_p2.path = pe1_p2_hash.path + LEFT JOIN hash pe1_pe2_hash ON pe1_pe2.path = pe1_pe2_hash.path +WHERE pe.pid IN ( + SELECT pid + FROM process_events + WHERE time > (strftime('%s', 'now') -600) + AND syscall = "execve" + AND path NOT LIKE '/home/%' + AND path NOT LIKE '/nix/%' + AND path NOT LIKE '/opt/%' + AND path NOT LIKE '/usr/local/%' + AND path NOT LIKE '/snap/%' + AND path NOT LIKE '%/.terraform/providers/%' + AND path NOT LIKE '/tmp/%/bin' + AND path NOT LIKE '/tmp/go-build%' + AND REGEX_MATCH (path, '(.*)/', 1) NOT IN ( + '/', + '/app', + '/bin', + '/ko-app', + '/sbin', + '/usr/bin', + '/usr/sbin', + '/usr/share/code', + '/usr/share/teams', + '/usr/lib/NetworkManager', + '/usr/lib/firefox', + '/usr/lib64/firefox', + '/usr/libexec', + '/usr/bin', + '/usr/sbin', + '/usr/share/teams/resources/app.asar.unpacked/node_modules/slimcore/bin' + ) + GROUP BY pid ) - AND NOT pe.path IN ('/usr/lib32/ld-linux.so.2') - AND NOT ( - dirname = '' - AND p.name LIKE 'runc%' - ) - AND NOT ( - dirname = '' - AND parent_name IN ('dockerd') - ) - AND NOT (pe.euid = 65532) -GROUP BY - pe.pid + AND pe.time > (strftime('%s', 'now') -600) + AND pe.syscall = "execve" + AND p.cgroup_path NOT LIKE '/system.slice/docker-%' + AND p.cgroup_path NOT LIKE '/user.slice/user-1000.slice/user@1000.service/user.slice/nerdctl-%' + AND p1.cgroup_path NOT LIKE '/system.slice/docker-%' + AND p1.cgroup_path NOT LIKE '/user.slice/user-1000.slice/user@1000.service/user.slice/nerdctl-%' +GROUP BY pe.pid \ No newline at end of file diff --git a/detection/privesc/unexpected-elevated-children-events_linux.sql b/detection/privesc/unexpected-elevated-children-events_linux.sql index 22dacf8..be78259 100644 --- a/detection/privesc/unexpected-elevated-children-events_linux.sql +++ b/detection/privesc/unexpected-elevated-children-events_linux.sql @@ -1,5 +1,6 @@ -- Find processes that run with a lower effective UID than their parent (event-based) -- +-- -- references: -- * https://attack.mitre.org/techniques/T1548/001/ (Setuid and Setgid) -- * https://cybersecurity.att.com/blogs/labs-research/shikitega-new-stealthy-malware-targeting-linux @@ -9,9 +10,8 @@ -- -- tags: events process escalation -- platform: linux --- interval: 300 -SELECT - file.mode AS p0_binary_mode, +-- interval: 600 +SELECT file.mode AS p0_binary_mode, pe.cmdline_size AS p0_cmd_size, -- Child pe.path AS p0_path, @@ -45,17 +45,14 @@ SELECT '.*/(.*)', 1 ) AS p2_name -FROM - process_events pe +FROM process_events pe LEFT JOIN file ON pe.path = file.path - LEFT JOIN processes p ON pe.pid = pe.pid - -- Parents (via two paths) + LEFT JOIN processes p ON pe.pid = pe.pid -- Parents (via two paths) LEFT JOIN processes p1 ON pe.parent = p1.pid LEFT JOIN hash p_hash1 ON p1.path = p_hash1.path LEFT JOIN process_events pe1 ON pe.parent = pe1.pid AND pe1.cmdline != '' - LEFT JOIN hash pe_hash1 ON pe1.path = pe_hash1.path - -- Grandparents (via 3 paths) + LEFT JOIN hash pe_hash1 ON pe1.path = pe_hash1.path -- Grandparents (via 3 paths) LEFT JOIN processes p1_p2 ON p1.parent = p1_p2.pid -- Current grandparent via parent processes LEFT JOIN processes pe1_p2 ON pe1.parent = pe1_p2.pid -- Current grandparent via parent events LEFT JOIN process_events pe1_pe2 ON pe1.parent = pe1_p2.pid @@ -63,11 +60,26 @@ FROM LEFT JOIN hash p1_p2_hash ON p1_p2.path = p1_p2_hash.path LEFT JOIN hash pe1_p2_hash ON pe1_p2.path = pe1_p2_hash.path LEFT JOIN hash pe1_pe2_hash ON pe1_pe2.path = pe1_pe2_hash.path -WHERE - pe.time > (strftime('%s', 'now') -300) - AND pe.euid < p1_euid +WHERE pe.pid IN ( + SELECT pid + FROM process_events + WHERE time > (strftime('%s', 'now') -600) + AND syscall = "execve" + AND euid < 500 + AND ( + uid = 0 + OR euid < uid + ) + ) + AND pe.time > (strftime('%s', 'now') -600) + AND pe.syscall = "execve" + AND pe.euid < 500 + AND ( + pe.euid < pe.uid + OR pe.euid < p1_euid + OR pe.euid < pe1.euid + ) AND pe.path NOT IN ( - '/', '/bin/ps', '/usr/bin/doas', '/usr/bin/fusermount', @@ -96,11 +108,6 @@ WHERE '/usr/lib/systemd/systemd --user', '/bin/sh -c /usr/bin/pkexec /usr/share/apport/apport-gtk' ) - -- used by kind - AND NOT ( - pe.path = '/usr/bin/bash' - AND pe.cmdline = '/bin/bash /usr/local/bin/mount-product-files' - ) AND NOT ( p0_name = 'polkit-agent-helper-1' AND p1_path = '/usr/bin/gnome-shell' @@ -114,3 +121,5 @@ WHERE AND p1_path = '/usr/bin/update-notifier' ) AND NOT p.cgroup_path LIKE '/system.slice/docker-%' + AND NOT p1.cgroup_path LIKE '/system.slice/docker-%' +GROUP BY pe.pid \ No newline at end of file From 00398d447b90476f61fc373270adcf6107cc8db5 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Feb 2023 10:41:28 -0500 Subject: [PATCH 2/4] Look for setuid binaries in /usr/libexec too --- detection/execution/unexpected-setuid-binaries.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/detection/execution/unexpected-setuid-binaries.sql b/detection/execution/unexpected-setuid-binaries.sql index 5a36dae..41e75ac 100644 --- a/detection/execution/unexpected-setuid-binaries.sql +++ b/detection/execution/unexpected-setuid-binaries.sql @@ -40,6 +40,7 @@ FROM '/etc', '/tmp', '/var/lib', + '/usr/libexec', '/usr/bin', '/usr/lib', '/usr/lib64', From 3d13d4995aa1f1b80cadce54286b29411379443f Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Feb 2023 10:41:42 -0500 Subject: [PATCH 3/4] hidden system paths: include inode --- detection/evasion/unexpected-hidden-system-paths.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/detection/evasion/unexpected-hidden-system-paths.sql b/detection/evasion/unexpected-hidden-system-paths.sql index b45c4ae..53c9356 100644 --- a/detection/evasion/unexpected-hidden-system-paths.sql +++ b/detection/evasion/unexpected-hidden-system-paths.sql @@ -10,6 +10,7 @@ -- tags: persistent filesystem state SELECT file.path, + file.inode, file.directory, uid, gid, From a655122eec130d1cc44846ed68ed1df40395ea25 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 17 Feb 2023 10:47:49 -0500 Subject: [PATCH 4/4] name path mismatch: only whitelist shells with same cmdlines --- detection/evasion/name_path_mismatch.sql | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/detection/evasion/name_path_mismatch.sql b/detection/evasion/name_path_mismatch.sql index 10a48a5..3228337 100644 --- a/detection/evasion/name_path_mismatch.sql +++ b/detection/evasion/name_path_mismatch.sql @@ -51,13 +51,17 @@ FROM WHERE short_filename != short_name AND NOT p0_cmd LIKE '/nix/store/%/bin/bash%' -- Serial masqueraders - AND NOT short_filename IN ( - 'bash', - 'ruby', - 'python', - 'python3', - 'perl', - 'node' + AND NOT ( + short_filename IN ( + 'bash', + 'ruby', + 'python', + 'python3', + 'perl', + 'node' + ) + -- ddexec + AND LENGTH(p0.cmdline) > 2 ) AND exception_key NOT IN ( 'name=apt,file=dash,0',