CrowdStrike / psfalcon

PowerShell for CrowdStrike's OAuth2 APIs
The Unlicense
369 stars 70 forks source link

[ BUG ] `Uninstall-FalconSensor` issues against Linux boxes #435

Open evoliptic opened 1 week ago

evoliptic commented 1 week ago

Tests executed against a Debian 12.8 with a 7.18.17129.0 version Falcon sensor. Latest psfalcon version with issue #426 fixed.

Running the Uninstall-FalconSensor yields the following error:

/bin/bash: -c: line 2: conditional binary operator expected

More, modifying the _uninstallsensor.sh so that running the Uninstall-FalconSensor command yields to the correct command being called (here apt-get purge) like this:

echo "Started removal of the Falcon sensor"
eval "sudo apt-get purge falcon-sensor -y &" &>/dev/null

Now leads to this command killing /opt/CrowdStrike/falcond binary, thus killing the apt-get purge command itself as it is a child of said binary (as demonstrated by the following invocation, with another modified script):

root         277  0.0  0.0   2712   136 ?        Ss   08:00   0:00 /opt/CrowdStrike/falcond
root         279  1.9  4.1 1416260 82868 ?       Sl   08:00   0:24  \_ falcon-sensor-bpf
root        2295  0.0  0.1   3924  3036 ?        S    08:21   0:00      \_ /bin/bash -c #!/bin/bash # SYNOPSIS #    Run a bash script with specified command line and timeout # DESCRIPTION #   CrowdStrike Real Time Response command # PARAMETER WD #    Current working directory # PARAMETER Param1 #    Script body - Required # PARAMETER Param2 #    Command line sent to script # PARAMETER Param3 #    Local path - path to local file to be used as script body # PARAMETER Param4 #    Timeout in seconds # NOTES #    File Name  : runscript.sh #    Contact    : support@crowdstrike.com #    Copyright  : CrowdStrike 2020 # LINK #    https://www.crowdstrike.com/  set -euo pipefail shopt -s extglob  command=runscript  function die {     echo "$command: $1" >&2     exit 1 }  function err_handler() {     # Rewrite the error message to remove the internal command prefix     echo "$command:${1#*cat:}" >&2 } trap 'err_handler "$script"' ERR  script= if [ "$#" -ge 1 ]; then     script="$1"     shift fi  script_args= if [ "$#" -ge 1 ]; then     script_args="$1"     shift fi  # following Windows behavior where HostPath clobbers Raw if [ "$#" -ge 1 ]; then     if [ -n "$1" ]; then         script="$(/bin/cat "$1" 2>&1)"     fi     shift fi  timeout=60 if [ "$#" -ge 1 ]; then     if [ -n "$1" ]; then         timeout="$1"     fi     shift fi  if [ -z "$script" ]; then     die "Either -Raw or -HostPath must be specified" fi  if [[ "$timeout" =~ .*[^0-9].* ]] || [ "$timeout" -eq 0 ]; then     die "Timeout must be a positive integer" fi  eval set -- "$script_args" /bin/bash -c "$script" /bin/bash "$@" & pid=$!  function get_time() {     sed -n '1s/\([0-9]\+\)\.\([0-9][0-9]\).*/\1\2/p' /proc/uptime }  start_time=$(get_time) last_print_time=$start_time wait_interval=0.1 print_interval=5 resolution=100 while kill -0 $pid 2> /dev/null ; do     current_time=$(get_time)     if ((current_time - start_time >= timeout*resolution)); then         kill -9 $pid >/dev/null 2>&1         echo "$command: Timed out waiting for script to exit" >&2         kill -9 -$$ >/dev/null 2>&1     fi     if ((current_time - last_print_time >= print_interval*resolution)); then         printf %b '\xe2\x80\x8b' # hex for unicode '\u200b' for backward compatibility         last_print_time=$current_time     fi     /bin/sleep $wait_interval done  /bin/bash #!/bin/bash. echo "Started removal of the Falcon sensor" . /bin/ps -auxf > /tmp/output4 . /bin/apt-get purge falcon-sensor -y -f  3600
root        2296  0.0  0.1   3924  2976 ?        S    08:21   0:00          \_ /bin/bash -c #!/bin/bash. echo "Started removal of the Falcon sensor" > /tmp/output3 . /bin/ps -auxf > /tmp/output4 . /bin/apt-get purge falcon-sensor -y -f /bin/bash
root        2300  0.0  0.2   9444  4944 ?        R    08:21   0:00          |   \_ /bin/ps -auxf
root        2301  0.0  0.0   2484   880 ?        S    08:21   0:00          \_ /bin/sleep 0.1

In the end, the apt-get is not fully executed, resulting in a Falcon Sensor in a deactivated state but not uninstalled:

$ sudo systemctl status falcon-sensor.service 

falcon-sensor.service - CrowdStrike Falcon Sensor
     Loaded: loaded (/lib/systemd/system/falcon-sensor.service; enabled; preset: enabled)
     Active: inactive (dead) since Fri 2024-11-15 09:37:33 CST; 12min ago
   Duration: 2min 51.577s
    Process: 4485 ExecStartPre=/opt/CrowdStrike/falconctl -g --cid (code=exited, status=0/SUCCESS)
    Process: 4486 ExecStart=/opt/CrowdStrike/falcond (code=exited, status=0/SUCCESS)
   Main PID: 4487 (code=exited, status=0/SUCCESS)
        CPU: 9.159s

XXXXXXXXXXX  vbox-debian sudo[4571]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
XXXXXXXXXXX  systemd[1]: Stopping falcon-sensor.service - CrowdStrike Falcon Sensor...
XXXXXXXXXXX  falcond[4487]: forwarding signal 15 Terminated to falcon-sensor[4488]
XXXXXXXXXXX  falcond[4487]: sending SIGCONT to falcon-sensor[4488]
XXXXXXXXXXX  sudo[4571]: pam_unix(sudo:session): session closed for user root
XXXXXXXXXXX  falcon-sensor-bpf[4488]: CrowdStrike(4): calling SSL_shutdown
XXXXXXXXXXX  falcon-sensor-bpf[4488]: CrowdStrike(4): SSLSocket Disconnected from Cloud.
XXXXXXXXXXX  systemd[1]: falcon-sensor.service: Deactivated successfully.
XXXXXXXXXXX  systemd[1]: Stopped falcon-sensor.service - CrowdStrike Falcon Sensor.
XXXXXXXXXXX systemd[1]: falcon-sensor.service: Consumed 9.159s CPU time.

Typically, here is the output of the apt-get purge command when executed through the Uninstall-FalconSensor command:

Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be REMOVED:
  falcon-sensor*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
1 not fully installed or removed.
After this operation, 82.0 MB disk space will be freed.
(Reading database ... 137137 files and directories currently installed.)
Removing falcon-sensor (7.19.0-17219) ...

While here is the output for the apt-get purge command when fully executed by hand (please note the last three lines):

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be REMOVED:
  falcon-sensor*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
1 not fully installed or removed.
After this operation, 82.0 MB disk space will be freed.
(Reading database ... 137137 files and directories currently installed.)
Removing falcon-sensor (7.19.0-17219) ...
Processing triggers for libc-bin (2.36-9+deb12u9) ...
(Reading database ... 137111 files and directories currently installed.)
Purging configuration files for falcon-sensor (7.19.0-17219) ...

I have to say I tried to change the uninstall-script.sh script to detach the apt-get purge from the falcond parent binary (through setsid and disown, but without any success at the moment). Right now, the only solution I came up with is to use cron instead. Could you please have a look? This would really help our company if this cmdlet would work against Linux hosts. Thanks in advance!

bk-cs commented 2 days ago

I've been experimenting with this and haven't found a solution either. Do you have an example of how you're using cron to do it?