├── 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 |
--------------------------------------------------------------------------------