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