From 85fdfaaa627e3b2f1c10abf2d115bc921d390b1c Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Fri, 18 Nov 2022 09:32:00 -0500 Subject: [PATCH] empty-environ: only check root pids to reduce false-positives --- detection/evasion/empty_environ_linux.sql | 67 ------------------- .../evasion/empty_root_environ_linux.sql | 52 ++++++++++++++ ...macos.sql => empty_root_environ_macos.sql} | 31 ++------- 3 files changed, 59 insertions(+), 91 deletions(-) delete mode 100644 detection/evasion/empty_environ_linux.sql create mode 100644 detection/evasion/empty_root_environ_linux.sql rename detection/evasion/{empty_environ_macos.sql => empty_root_environ_macos.sql} (62%) diff --git a/detection/evasion/empty_environ_linux.sql b/detection/evasion/empty_environ_linux.sql deleted file mode 100644 index 0777d36..0000000 --- a/detection/evasion/empty_environ_linux.sql +++ /dev/null @@ -1,67 +0,0 @@ --- Find programs which have cleared their environment --- --- references: --- * https://www.sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/ --- --- tags: persistent state daemon process --- platform: linux --- interval: 600 -SELECT - COUNT(key) AS count, - p.pid, - p.path, - p.name, - p.on_disk, - hash.sha256, - p.parent, - p.cmdline, - pp.name AS parent_name, - pp.cmdline AS parent_cmd -- Processes is 20X faster to scan than process_envs -FROM - processes p - LEFT JOIN hash ON p.path = hash.path - LEFT JOIN process_envs pe ON p.pid = pe.pid - LEFT JOIN processes pp ON p.parent = pp.pid -WHERE -- This time should match the interval - p.start_time > (strftime('%s', 'now') - 605) -- Filter out transient processes that may not have an envs entry by the time we poll for it - AND p.start_time < (strftime('%s', 'now') - 5) -- This pattern is common with kthreadd processes - AND p.parent NOT IN (0, 2) - AND NOT p.path IS NULL - AND p.name NOT IN ( - 'gpg-agent', - 'bwrap', - 'spotify', - 'chrome', - 'jcef_helper', - 'slack', - 'gnome-boxes-sea', - 'gnome-contacts-', - 'gnome-clocks', - 'systemd-userwor', - 'nginx', - 'gnome-terminal-', - 'sshd', - 'zoom.real', - 'teams', - 'zoom', - 'zypak-sandbox' - ) - AND p.path NOT IN ( - '/usr/bin/gpg-agent', - '/usr/bin/bwrap', - '/usr/lib/slack/slack', - '/usr/sbin/nginx', - '/usr/libexec/gnome-terminal-server', - '/usr/lib/systemd/systemd-userdbd', - '/opt/google/chrome/chrome', - '/opt/spotify/spotify' - ) - AND NOT pp.name IN ('yum', 'chrome', 'zoom.real', 'ZoomLauncher') - AND NOT pp.cmdline LIKE 'bwrap %' - AND NOT p.cmdline LIKE '%--type=zygote%' - AND NOT p.cmdline LIKE '%--disable-seccomp-filter-sandbox%' - AND NOT p.cmdline LIKE '%--enable-crashpad%' -GROUP BY - p.pid -HAVING - count == 0; diff --git a/detection/evasion/empty_root_environ_linux.sql b/detection/evasion/empty_root_environ_linux.sql new file mode 100644 index 0000000..6938e92 --- /dev/null +++ b/detection/evasion/empty_root_environ_linux.sql @@ -0,0 +1,52 @@ +-- Find programs which spawn root children without propagating environment variables +-- +-- references: +-- * https://www.sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/ +-- +-- tags: persistent state daemon process +-- interval: 600 +-- platform: linux +SELECT + COUNT(key) AS count, + p.pid, + p.path, + p.name, + p.on_disk, + p.cgroup_path, + hash.sha256, + p.parent, + p.cmdline, + pp.name AS parent_name, + pp.cmdline AS parent_cmd + -- Processes is 20X faster to scan than process_envs +FROM + processes p + LEFT JOIN hash ON p.path = hash.path + LEFT JOIN process_envs pe ON p.pid = pe.pid + LEFT JOIN processes pp ON p.parent = pp.pid +WHERE + p.euid = 0 + -- This time should match the interval + AND p.start_time > (strftime('%s', 'now') - 601) -- Filter out transient processes that may not have an envs entry by the time we poll for it + AND p.start_time < (strftime('%s', 'now') - 1) + AND p.parent NOT IN (0, 2) + AND NOT p.path IS NULL + AND p.name NOT IN ( + 'gpg-agent', + 'dhcpcd', + 'bwrap', + 'systemd-userwor', + 'systemd-userdbd', + 'nginx', + 'cupsd', + 'sshd', + 'zypak-sandbox' + ) + AND NOT pp.cmdline LIKE 'bwrap %' + AND NOT p.cmdline LIKE '%--type=zygote%' + AND NOT p.cmdline LIKE '%--disable-seccomp-filter-sandbox%' + AND NOT p.cgroup_path LIKE '/system.slice/docker-%' +GROUP BY + p.pid +HAVING + count == 0; diff --git a/detection/evasion/empty_environ_macos.sql b/detection/evasion/empty_root_environ_macos.sql similarity index 62% rename from detection/evasion/empty_environ_macos.sql rename to detection/evasion/empty_root_environ_macos.sql index c2853e3..80be8a4 100644 --- a/detection/evasion/empty_environ_macos.sql +++ b/detection/evasion/empty_root_environ_macos.sql @@ -1,4 +1,4 @@ --- Find programs which have cleared their environment +-- Find programs which spawn root children without propagating environment variables -- -- references: -- * https://www.sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/ @@ -28,16 +28,18 @@ SELECT signature.identifier, ',', signature.authority - ) AS exception_key -- Processes is 20X faster to scan than process_envs + ) AS exception_key FROM processes p LEFT JOIN process_envs pe ON p.pid = pe.pid LEFT JOIN processes pp ON p.parent = pp.pid LEFT JOIN hash ON p.path = hash.path LEFT JOIN signature ON p.path = signature.path -WHERE -- This time should match the interval - p.start_time > (strftime('%s', 'now') - 605) -- Filter out transient processes that may not have an envs entry by the time we poll for it - AND p.start_time < (strftime('%s', 'now') - 5) +WHERE + p.euid = 0 AND + -- This time should match the interval + p.start_time > (strftime('%s', 'now') - 601) -- Filter out transient processes that may not have an envs entry by the time we poll for it + AND p.start_time < (strftime('%s', 'now') - 1) AND p.path NOT LIKE '/System/Library/%' AND signature.authority NOT IN ( 'Software Signing', @@ -59,25 +61,6 @@ WHERE -- This time should match the interval 'Developer ID Application: Parallels International GmbH (4C6364ACXT)', 'Developer ID Application: Yubico Limited (LQA3CS5MM7)' ) - AND NOT exception_key IN ( - '500,CraftWidgetExtension,com.lukilabs.lukiapp.CraftWidget,Apple Mac OS Application Signing', - '500,gsleep,sleep,', - '500,ssh,,', - '500,gopls,a.out,', - '500,esbuild,a.out,', - '500,ssh-sk-helper,,', - '500,Obsidian Helper (Renderer),md.obsidian.helper.Renderer,Developer ID Application: Dynalist Inc. (6JSW4SJWN9)', - '500,Pages,com.apple.iWork.Pages,Apple Mac OS Application Signing', - '500,SafariLaunchAgent,SafariLaunchAgent-55554944882a849c6a6839b4b0e7c551bbc81898,Software Signing', - '500,TwitterNotificationServiceExtension,maccatalyst.com.atebits.Tweetie2.NotificationServiceExtension,Apple Mac OS Application Signing' - ) -- Electron apps - AND NOT ( - p.path LIKE '/Applications/%Helper%' - AND ( - exception_key LIKE '500,%Helper%,Renderer,Developer ID Application: % (%)' - OR exception_key LIKE '500,%Helper%,helper,Developer ID Application: % (%)' - ) - ) AND NOT p.path LIKE '/opt/homebrew/Cellar/%' GROUP BY p.pid