├── ea-cs-agentid.sh ├── README.md ├── ea-cs-state.sh ├── ea-cs-lastconnected.sh ├── LICENSE ├── uninstall-csf.sh └── install-csf.sh /ea-cs-agentid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Report the Crowdstrike Agent ID of the client if the Crowdstrike Agent if installed 4 | # Original EA: https://github.com/zoocoup/CrowdstikeEAsforJamfPro/blob/main/CrowdstrikeFalconv6AgentIDEA.sh 5 | 6 | falconctl=$( /usr/bin/find /Applications -iname "falconctl" -type f -maxdepth 4 ) 7 | 8 | if [ "$falconctl" ]; 9 | then 10 | echo "$( "$falconctl" stats agent_info | /usr/bin/awk '/agentID/ {print $2}' | /usr/bin/tr '[:upper:]' '[:lower:]' | /usr/bin/sed 's/\-//g' )" 11 | else 12 | echo "Not Installed" 13 | fi 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crowdstrike-API-Scripts 2 | A collection of handy scripts to run via an MDM for Crowdstrike. 3 | 4 | Relevent blog post(s): 5 | https://richard-purves.com/2022/05/03/downloading-crowdstrike-via-api-for-fun-and-profit/ 6 | 7 | The Extension Attributes (EA) are ready to run directly from Jamf Pro. They're based on the work of https://github.com/zoocoup/CrowdstikeEAsforJamfPro 8 | 9 | The main scripts have placeholder variables for the API credentials. These are not meant to have these values baked in, but instead to utilise some other secure method (e.g. Hashicorp Vault) for secure credential retreival. 10 | -------------------------------------------------------------------------------- /ea-cs-state.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Find any falconctl binary 4 | falconctl=$( /usr/bin/find /Applications/Falcon.app -iname "falconctl" -type f -maxdepth 3 ) 5 | 6 | # If installed 7 | if [ "$falconctl" ]; 8 | then 9 | # Test for status 10 | test=$( "$falconctl" stats CloudInfo | /usr/bin/awk '/Cloud Info | State/ {print $2}' ) 11 | 12 | if [ "$test" = "connected" ]; 13 | then 14 | # Report working 15 | echo "Connected" 16 | else 17 | # We should do something about this 18 | echo "DISCONNECTED" 19 | fi 20 | else 21 | # Not present. Report and exit. 22 | echo "Not Installed" 23 | fi 24 | -------------------------------------------------------------------------------- /ea-cs-lastconnected.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Report the last Crowdstrike connection to the cloud 4 | # Original EA: https://github.com/zoocoup/CrowdstikeEAsforJamfPro/blob/main/CrowdstrikeFalconv6LastEstablishedEA.sh 5 | # With fixes inspired by @sdagley and @rayjd on Mac Admins Slack 6 | 7 | falconctl=$( /usr/bin/find /Applications/Falcon.app -iname "falconctl" -type f -maxdepth 3 ) 8 | 9 | if [ "$falconctl" ]; 10 | then 11 | test=$( "$falconctl" stats Communications | /usr/bin/awk '/Cloud Activity | Established At/ {print $3,$4,$5,$7; exit;}' ); 12 | 13 | [ -z "$test" ] && { test=$( "$falconctl" stats Communications | /usr/bin/awk '/Cloud Activity | Last Established At/ {print $4,$5,$6,$8; exit;}' ) } 14 | 15 | if [ ! -z "$test" ]; 16 | then 17 | echo "$( /bin/date -j -f "%b %d, %Y %H:%M:%S" "$test" "+%Y-%m-%d %H:%M:%S" )" 18 | else 19 | echo "1970-01-01 09:00:00" 20 | fi 21 | else 22 | echo "1970-01-01 09:00:00" 23 | fi 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Richard Purves 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /uninstall-csf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Script to uninstall Crowdstrike 4 | # richard@richard-purves.com - 05/04/2022 5 | 6 | # Is CS installed? Skip if not. 7 | if [ -d "/Applications/Falcon.app" ]; 8 | then 9 | echo "Crowdstrike detected. Starting uninstall." 10 | 11 | # Set up variables here 12 | 13 | # Client ID, Client Secret for the API token. Then make base64 version. 14 | clientid="" 15 | secret="" 16 | b64creds=$( printf "$clientid:$secret" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - ) 17 | 18 | # API Base URL and the various endpoints we need 19 | # Do some autodetection to work out correct URL. Set to default if blank. 20 | baseurl="https://api.crowdstrike.com" 21 | baseurl=$( /usr/bin/curl -s -v -X POST -d "client_id=${clientid}&client_secret=${secret}" "${baseurl}/oauth2/token" 2>&1 | awk '($2 == "Location:") {print $3}' | cut -d/ -f1-3 ) 22 | [ -z "$baseurl" ] && baseurl="https://api.crowdstrike.com" 23 | 24 | oauthtoken="$baseurl/oauth2/token" 25 | oauthrevoke="$baseurl/oauth2/revoke" 26 | maintenancetoken="$baseurl/policy/combined/reveal-uninstall-token/v1" 27 | 28 | # Work out Client ID from current install 29 | # Remove all - characters otherwise CS API shows erroneous results. 30 | csfalconstats=$( /Applications/Falcon.app/Contents/Resources/falconctl stats ) 31 | csfalconid=$( echo $csfalconstats | /usr/bin/grep "agentID:" | /usr/bin/awk '{ print $2 }' | /usr/bin/tr -d "-" ) 32 | 33 | # Request bearer access token using the API 34 | token=$( /usr/bin/curl -s -X POST "$oauthtoken" -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=${clientid}&client_secret=${secret}" ) 35 | 36 | # Extract the bearer token from the json output above 37 | bearer=$( /usr/bin/plutil -extract access_token raw -o - - <<< "$token" ) 38 | 39 | # Retrieve the uninstall token for the current computer 40 | # Generate the json required into a variable, pass to the API and extract the token 41 | data="{ 42 | \"audit_message\": \"Jamf Pro Crowdstrike uninstall script\", 43 | \"device_id\": \"$csfalconid\" 44 | }" 45 | 46 | jsonoutput=$( /usr/bin/curl -s -X POST "$maintenancetoken" -H "accept: application/json" -H "Content-Type: application/json" -H "authorization: Bearer ${bearer}" -d "$data" ) 47 | uninstalltoken=$( /usr/bin/plutil -extract resources.0.uninstall_token raw -o - - <<< "$jsonoutput" ) 48 | 49 | # Invalidate access to the bearer token 50 | /usr/bin/curl -s -X POST "$oauthrevoke" -H "accept: application/json" -H "authorization: Basic ${b64creds}" -H "Content-Type: application/x-www-form-urlencoded" -d "token=${bearer}" 51 | 52 | # Finally action the uninstall using some expect scripting to bypass the interactive part of the token request 53 | /usr/bin/expect <&1 | awk '($2 == "Location:") {print $3}' | cut -d/ -f1-3 ) 26 | [ -z "$baseurl" ] && baseurl="https://api.crowdstrike.com" 27 | 28 | # API Base URL and the various endpoints we need 29 | oauthtoken="$baseurl/oauth2/token" 30 | oauthrevoke="$baseurl/oauth2/revoke" 31 | 32 | # Define which version we want to get. 33 | # 0 means latest. 1 is N-1, 2 is N-2 and so on. 34 | version="1" 35 | 36 | # Now define the API query we need 37 | sensorlist="$baseurl/sensors/combined/installers/v1?sort=version%7Cdesc&offset=${version}&limit=1&filter=platform%3A%22mac%22" 38 | sensordl="$baseurl/sensors/entities/download-installer/v1" 39 | 40 | # Request bearer access token using the API 41 | token=$( /usr/bin/curl -s -X POST "$oauthtoken" -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=${clientid}&client_secret=${secret}" ) 42 | 43 | # Extract the bearer token from the json output above 44 | if [ "$majver" -le 11 ]; 45 | then 46 | bearer=$( /usr/bin/osascript -l 'JavaScript' -e "JSON.parse(\`$token\`).access_token" ) 47 | else 48 | bearer=$( /usr/bin/plutil -extract access_token raw -o - - <<< "$token" ) 49 | fi 50 | 51 | # Work out the CrowdStrike installer, grab the SHA256 hash and use that to download that installer 52 | sensorv=$( /usr/bin/curl -s -X GET "$sensorlist" -H "accept: application/json" -H "authorization: Bearer ${bearer}" ) 53 | if [ "$majver" -le 11 ]; 54 | then 55 | sensorname=$( /usr/bin/osascript -l 'JavaScript' -e "JSON.parse(\`$sensorv\`).resources[0].name" ) 56 | sensorsha=$( /usr/bin/osascript -l 'JavaScript' -e "JSON.parse(\`$sensorv\`).resources[0].sha256" ) 57 | else 58 | sensorname=$( /usr/bin/plutil -extract resources.0.name raw -o - - <<< "$sensorv" ) 59 | sensorsha=$( /usr/bin/plutil -extract resources.0.sha256 raw -o - - <<< "$sensorv" ) 60 | fi 61 | 62 | # Download the client. Retry if required up to 10 times. 63 | for loop in {1..10}; 64 | do 65 | echo "Download attempt: [$loop / 10]" 66 | test=$( /usr/bin/curl -s -o /private/tmp/${sensorname} -H "Authorization: Bearer ${bearer}" -w "%{http_code}" "${sensordl}?id=${sensorsha}" ) 67 | [ "$test" = "200" ] && break 68 | done 69 | 70 | # Invalidate access to the bearer token 71 | /usr/bin/curl -X POST "$oauthrevoke" -H "accept: application/json" -H "authorization: Basic ${b64creds}" -H "Content-Type: application/x-www-form-urlencoded" -d "token=${bearer}" 72 | 73 | # Did the download actually work. Error if not. 74 | [ "$test" != "200" ] && { echo "Download failed. Exiting."; exit 1; } 75 | 76 | # Finally install and clean up 77 | /usr/sbin/installer -target / -pkg /private/tmp/${sensorname} 78 | /bin/rm /private/tmp/${sensorname} 79 | else 80 | echo "Crowdstrike already present." 81 | fi 82 | 83 | # All done! 84 | exit 0 85 | --------------------------------------------------------------------------------