Skip to main content

Hey all,



I'm researching this, but in the interest of not reinventing the wheel, I thought I'd ask the nation...



The Xprotect Status extension attribute posted here returns the following on 10.11.3:



The domain/default pair of (/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta, LastModification) does not exist


I've looked through the file referenced and there's no instance of a date or the words "modified," "modification," change," or "update" in the XML. Does anyone know where to look for the last Xprotect update?

Hmm. That's a good question and I think the LastModification line has not shown up in that plist for a while now. Its not in my 10.10.5 Mac's plist anyway.



I seem to recall seeing somewhere that XProtect files moved around to different places, but I can't recall now where to find the modification date.



Just in case no-one shows up with a proper explanation, however unlikely that is here, here's a method using stat -s and converting the raw mtime format into a Casper friendly format:



date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +"%Y-%m-%d %T"


As an aside, here's a nice way of getting a full list of the applied XProtect malware blocks. I have not confirmed if the list this pulls is accurate or not. It may or may not be.



xmllint --format /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist | awk -F'>|<' '/Description/{getline; print $3}' | sed '/^$/d'

True. There is no LastModification key in that plist. I use 'Version' myself.


For 10.6.x - 10.8.x, you should still be able to pull the LastModification value from the plist. For 10.9.x and later, I'd go by the installer package receipt, as XProtect updates now come down from the Apple software update feed:



https://derflounder.wordpress.com/2014/12/27/managing-automatic-installation-of-configdata-and-security-software-updates-on-yosemite/



To poll for the last modified date, I've written the following extension attribute:



#!/bin/bash

osvers_major=$(sw_vers -productVersion | awk -F. '{print $1}')
osvers_minor=$(sw_vers -productVersion | awk -F. '{print $2}')


if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -lt 9 ]]; then
last_xprotect_update_human_readable_time=`/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta LastModification`

echo "<result>$last_xprotect_update_human_readable_time</result>"

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 9 ]]; then

last_xprotect_update_install=`pkgutil --pkgs=".*XProtect.*" | tail -1`
last_xprotect_update_epoch_time=`pkgutil --pkg-info "$last_xprotect_update_install" | awk '/install-time/ {print $2}'`
last_xprotect_update_human_readable_time=`date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`

echo "<result>$last_xprotect_update_human_readable_time</result>"

fi

Now that I've seen @mm2270's method, I like his better for pulling the information from the 10.6 - 10.8 XProtect.meta.plist file. Updated EA below:



#!/bin/bash

osvers_major=$(sw_vers -productVersion | awk -F. '{print $1}')
osvers_minor=$(sw_vers -productVersion | awk -F. '{print $2}')

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -lt 6 ]]; then

result="XProtect not available for `sw_vers -productVersion`"

echo "<result>$result</result>"

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 6 ]] && [[ ${osvers_minor} -lt 9 ]]; then

last_xprotect_update_epoch_time=`date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +%s`
last_xprotect_update_human_readable_time=`date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
result="$last_xprotect_update_human_readable_time"

echo "<result>$result</result>"

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 9 ]]; then

last_xprotect_update_epoch_time=$(printf "%s
" `for i in $(pkgutil --pkgs=".*XProtect.*"); do pkgutil --pkg-info $i | awk '/install-time/ {print $2}'; done` | sort -n | tail -1)
last_xprotect_update_human_readable_time=`/bin/date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
result="$last_xprotect_update_human_readable_time"

echo "<result>$result</result>"

fi


That should give consistent human-readable output for 10.6.x and higher, as well as handling 10.5.8 and earlier by indicating that XProtect is not available for those versions of Mac OS X.



EDIT: After more testing, I realized that Apple changed how it named XProtect receipts sometime between 2014 and 2015. That meant that tailing the list may give an inaccurate result.



I've updated the EA so that it's checking when the individual XProtect installer packages were actually installed, as that will give a more accurate reading of the last time XProtect was updated.


Good stuff, thanks!


Cool, thanks for this!



I'm trying to create a Smart Group of machines that haven't received it - but not sure what an "acceptable" timeframe is. Does anybody know the frequency in which Apple pushes these - is it a regular interval at all?



Any suggestions on how best to do that?



Thanks,
mbezzo


@mbezzo Use a Configuration Profile to automate...

ConfigDataInstall is the key that needs to be set to true.



As far as I know, these updates are issued as needed to respond to exploits. I'm planning to ask my Apple rep in later this week if they're able to share a feed of the latest update either by date or version.



Failing that, you could set up a Mac or OS X VM with known-good automatic updates enabled. Then use it and the JSS API to update your smart group whenever the version/date changes.


Anyone have a one liner similar to @mm2270 's XProtect malware blocks list that will output the pluglin and extension blacklists in the format of <bundleIdentifier><space><minimumPluginBundleVersion>?



I want Extension Attributes that InfoSec teams can reference to verify remediation.



I'll give it a whirl when I get home unless anyone else gets it before then.


Hey @milesleacy, something like this is close I think:



/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist PlugInBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;N;s/
/ /'


On my 10.10.5 Mac this outputs:



com.apple.java.JavaAppletPlugin 14.8.0
com.apple.java.JavaPlugin2_NPAPI 14.8.0
com.macromedia.Flash Player ESR.plugin 18.0.0.324
com.macromedia.Flash Player.plugin 20.0.0.267
com.microsoft.SilverlightPlugin 5.1.41212.0
com.oracle.java.JavaAppletPlugin 1.8.51.16


The only issue is that there is a key above the 'PlugInBlacklist' dict that has the following, which won't show up in the results:



<key>JavaWebComponentVersionMinimum</key>
<string>1.6.0_45-b06-451</string>


I believe that's a very old Java version for 10.6 and earlier, back when Apple maintained it, not Oracle. (Actually this looks like Oracle Java now that I'm looking closer at it, so it may just be a simple minimum version string for that, just as it implies) I'm not sure how relevant it is to get that in the results since I don't think that line has changed now in years. For some reason, Apple keeps it outside of the PlugInBlacklist section.



EDIT: Actually I just realized you also wanted the ExtensionBlacklist, not just the Plugin one. Hmm. Not sure if its possible to have a one liner, but you could combine two or three commands to pull it all together I think.
Or, I'd probably maintain two separate EAs. One for the Plugins and one for Safari Extensions.
Here's one for pulling the Safari Extension Blacklist.



/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist ExtensionBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;/Developer Identifier/d'


And the output:



com.searchnt.safari
com.spigot.safari.searchme
com.spigot.safari.ebayshopassist
com.smokycap.safari
com.searchconnect.safariext
com.codec.extension
com.zako.chatzum
com.adobe.flash
com.optimalcycling.safari.popupblocker
com.genieo.safari
com.app65867
com.defaultsearch.safariext
com.jbsearch.safariext
com.mtsearch.safariext
com.rohit.MacMInSale
com.tabgreg.safariext
com.gold.safari
com.eliaho.safari
com.nariabox.safari
com.diigo.safari.awesomeScreenshot
com.portsayd.safari

Thanks @mm2270! That's exactly what I was looking for. I owe you a beer next time you're in the Bay Area.


Thanks to @rtrouton as well.



The second script you posted is great for environments where running an old OS X version is acceptable.


FWIW, you can force this stuff to update using:



sudo softwareupdate --background-critical

@thoule I used "Version" as you suggested and my EA works now by pulling the version and I get "2076" as the output for the EA on my test device. Where do you cross reference or look up to actually see what the latest version is? Does Apple post it somewhere? All of my Google searches have tuned up empty.


There are a number of items that fall within Apple's newer security updates scheme. Here is a screenshot of the little AppleScript app we use that shows the items and the dates, etc.
I won't post up the code as it's a rudimentary AS that was written by someone else and it got a lot of grief from guys that know how to write code properly. It does the job nicely, and we can see when the Macs are getting behind on things or not.




@scottb Nice lil trick there. I am by know means a coder, would love a look at the code if you don't mind off this thread somehow? Having those stats would be extremely helpful!


@scottb Never be afraid of rough code. It's how we all learn. I'd love to see what's behind that screenshot!


@scottb



Me too : ) I know that I can use your exact AS in my environment. And I don't care what it looks like : ) it will get the job done and allow me move on to the next thing I have to fix/improve : )



C


+1 to the above comments. I'm interested to see how its pulling the above info. I took a quick look yesterday, and I can see where its getting the XProtect version, as already mentioned on this thread, but I'm not sure where its getting the other data from. Would love to see it.


OK, I'll post it. Again - I did NOT write this. I didn't even know it was "crap" until I put it on Slack one day and got endless ribbing over it. I'm just learning the basics now and was only trying to be helpful. So, again, with apologies towards those who know WTH they are doing with code, here it is. Hope you find it useful.
This one if for 10.11.x. I think I also have one setup for the older OS X's. I'll locate that and post later.



Open up Script Editor and create a new item. Save as a ".app" and run.



set a to do shell script "defaults read /System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist Version"
tell application "Finder" to set b to get creation date of (POSIX file "/System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist" as alias)
set s to short date string of b
set t to time string of b
set c to do shell script "defaults read /private/var/db/gkopaque.bundle/Contents/version.plist CFBundleShortVersionString"
tell application "Finder" to set d to get creation date of (POSIX file "/private/var/db/gkopaque.bundle/Contents/version.plist" as alias)
set u to short date string of d
set v to time string of d
set e to do shell script "defaults read /System/Library/CoreServices/SystemVersion.plist ProductVersion"
set f to do shell script "defaults read /System/Library/CoreServices/SystemVersion.plist ProductBuildVersion"
set g to do shell script "defaults read /System/Library/Sandbox/Compatibility.bundle/Contents/version.plist CFBundleShortVersionString"
tell application "Finder" to set h to get creation date of (POSIX file "/System/Library/Sandbox/Compatibility.bundle/Contents/version.plist" as alias)
set w to short date string of h
set x to time string of h
set i to do shell script "defaults read /System/Library/CoreServices/MRT.app/Contents/version CFBundleShortVersionString"
tell application "Finder" to set j to get creation date of (POSIX file "/System/Library/CoreServices/MRT.app/Contents/version.plist" as alias)
set y to short date string of j
set z to time string of j
set k to do shell script "defaults read '/System/Library/Intelligent Suggestions/Assets.suggestionsassets/Contents/version.plist' CFBundleShortVersionString"
tell application "Finder" to set l to get creation date of (POSIX file "/System/Library/Intelligent Suggestions/Assets.suggestionsassets/Contents/version.plist" as alias)
set m to short date string of l
set n to time string of l
display dialog "XProtect " & tab & tab & a & tab & tab & s & tab & " " & t & return & "Gatekeeper " & tab & tab & c & tab & tab & tab & u & tab & " " & v & return & "SIP " & tab & tab & tab & tab & g & tab & tab & tab & w & tab & " " & x & return & "MRT " & tab & tab & tab & i & tab & tab & tab & y & tab & " " & z & return & "Core Suggest " & tab & k & tab & tab & tab & m & tab & " " & n & return & return & "OS X " & e & " (" & f & ")" buttons {"Close"} default button 1

Thanks for posting @scottb. Its not crap, but I would say that some of the labels used throughout could be more descriptive. Its a little tough to follow what "h" or "x" means, so if anything I would only change some of the set <label> strings to things that are more descriptive so its easier to understand and troubleshoot. Also, a few items could be shortened, but again, far from crap.


@mm2270 - I was going to try and re-do it and make it a little easier to grasp - just never took the time to do it.
I see what you mean, and honestly, I often grab code here and there and try to understand it and re-form it to my needs. I'll mess around one day to see if I can clean it up while keeping it functional. I already feel subpar when it comes to the guys like you who write the code, so I was a bit thin-skinned over the response to it before, even though it's not my creation.


@scottb Yes, well, its an unfortunate fact of the internet age that snobs of all kinds (code snobs, intellectual snobs, grammar snobs, etc) have found a haven behind their screens and keyboards to make fun of anyone who doesn't know as much as them in their preferred topic. Its a sign of confidence issues in themselves really, and I doubt most of them would say what they say online to someone's face, but.. I digress.



Personally I learned a lot looking at that, because I was honestly not aware of some of those files and plists to check for versions and creation dates, so props to whomever wrote it for knowing what to look for in the first place, even if the code could be a little cleaner.


@scottb



Mike is spot on!!!! : ) Life is way to short for any snobs : ) That said I am an Apple and Casper snob



Thank you very much Scott!!!



C


Excited to get this running but when I create the .app file with TextWrangler and run the file, the .app won't run, throws up an error "You can’t open the application “GetLatestVersionASU” because PowerPC applications are no longer supported.



Researching how to get his done, but if any of the gurus know the answer, I'd greatly appreciate the help!


@TomDay Its an Applescript, so you need to paste it into Script Editor, located in /Applications/Utilities/ and then click the build button in the toolbar. Then save it as an application bundle. See screenshots...



Raw code, click the Build button highlighted



The compiled code. Save from here to an application bundle