Posted on 08-05-2015 03:17 PM
Posted on 08-05-2015 04:08 PM
http://www.getmacapps.com/
Posted on 08-05-2015 05:54 PM
There was another thread opened on this today as well.
https://jamfnation.jamfsoftware.com/discussion.html?id=15382
It all looks interesting but it looks super risky.
Posted on 08-05-2015 07:22 PM
Sure, let's use installers from untrusted sources. What could possibly go wrong?
Posted on 08-06-2015 02:23 AM
I used to find Google Pack pretty useful.
Posted on 08-06-2015 10:09 AM
Ugh, I don't know who would choose to save a little time by introducing risk this way. Nobody here, I hope. :-)
Posted on 08-06-2015 11:17 AM
Hi Everyone,
I just wanted to chime and state the obvious here. Pipping a curl or wget command into a shell can be very dangerous. Even though you may not be running the command as root or with sudo privileges there have been exploits out there like root pipe that can escalate themselves to root. This is a pretty good way to get your Mac rooted, maybe a Trojan Horse installed, etc.
I actually looked at this yesterday. I used curl
to download the Chrome installer script in memory on my VM and looked at it, here it is (I had tossed it in paste bin):
#/bin/bash
clear && rm -rf ~/macapps && mkdir ~/macapps > /dev/null && cd ~/macapps
###############################
# Print script header #
###############################
echo $"
███╗ ███╗ █████╗ ██████╗ █████╗ ██████╗ ██████╗ ███████╗
████╗ ████║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝
██╔████╔██║███████║██║ ███████║██████╔╝██████╔╝███████╗
██║╚██╔╝██║██╔══██║██║ ██╔══██║██╔═══╝ ██╔═══╝ ╚════██║
██║ ╚═╝ ██║██║ ██║╚██████╗██║ ██║██║ ██║ ███████║╔═════════╗
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═ .link ═╝
"
###############################
# Define worker functions #
###############################
versionChecker() {
local v1=$1; local v2=$2;
while [ `echo $v1 | egrep -c [^0123456789.]` -gt 0 ]; do
char=`echo $v1 | sed 's/.*([^0123456789.]).*/1/'`; char_dec=`echo -n "$char" | od -b | head -1 | awk {'print $2'}`; v1=`echo $v1 | sed "s/$char/.$char_dec/g"`; done
while [ `echo $v2 | egrep -c [^0123456789.]` -gt 0 ]; do
char=`echo $v2 | sed 's/.*([^0123456789.]).*/1/'`; char_dec=`echo -n "$char" | od -b | head -1 | awk {'print $2'}`; v2=`echo $v2 | sed "s/$char/.$char_dec/g"`; done
v1=`echo $v1 | sed 's/../.0/g'`; v2=`echo $v2 | sed 's/../.0/g'`;
checkVersion "$v1" "$v2"
}
checkVersion() {
[ "$1" == "$2" ] && return 1
v1f=`echo $1 | cut -d "." -f -1`;v1b=`echo $1 | cut -d "." -f 2-`;v2f=`echo $2 | cut -d "." -f -1`;v2b=`echo $2 | cut -d "." -f 2-`;
if [[ "$v1f" != "$1" ]] || [[ "$v2f" != "$2" ]]; then [[ "$v1f" -gt "$v2f" ]] && return 1; [[ "$v1f" -lt "$v2f" ]] && return 0;
[[ "$v1f" == "$1" ]] || [[ -z "$v1b" ]] && v1b=0; [[ "$v2f" == "$2" ]] || [[ -z "$v2b" ]] && v2b=0; checkVersion "$v1b" "$v2b"; return $?
else [ "$1" -gt "$2" ] && return 1 || return 0; fi
}
appStatus() {
if [ ! -d "/Applications/$1" ]; then echo "uninstalled"; else
if [[ $5 == "build" ]]; then BUNDLE="CFBundleVersion"; else BUNDLE="CFBundleShortVersionString"; fi
INSTALLED=`/usr/libexec/plistbuddy -c Print:$BUNDLE: "/Applications/$1/Contents/Info.plist"`
if [ $4 == "dmg" ]; then COMPARETO=`/usr/libexec/plistbuddy -c Print:$BUNDLE: "/Volumes/$2/$1/Contents/Info.plist"`;
elif [[ $4 == "zip" || $4 == "tar" ]]; then COMPARETO=`/usr/libexec/plistbuddy -c Print:$BUNDLE: "$3$1/Contents/Info.plist"`; fi
checkVersion "$INSTALLED" "$COMPARETO"; UPDATED=$?;
if [[ $UPDATED == 1 ]]; then echo "updated"; else echo "outdated"; fi; fi
}
installApp() {
echo $'360237214200 - ['$2'] Downloading app...'
if [ $1 == "dmg" ]; then curl -s -L -o "$2.dmg" $4; yes | hdiutil mount -nobrowse "$2.dmg" -mountpoint "/Volumes/$2" > /dev/null;
if [[ $(appStatus "$3" "$2" "" "dmg" "$7") == "updated" ]]; then echo $'342235214 - ['$2'] Skipped because it was already up to date!
';
elif [[ $(appStatus "$3" "$2" "" "dmg" "$7") == "outdated" && $6 != "noupdate" ]]; then ditto "/Volumes/$2/$3" "/Applications/$3"; echo $'360237214216 - ['$2'] Successfully updated!
'
elif [[ $(appStatus "$3" "$2" "" "dmg" "$7") == "outdated" && $6 == "noupdate" ]]; then echo $'342235214 - ['$2'] This app cant be updated!
'
elif [[ $(appStatus "$3" "$2" "" "dmg" "$7") == "uninstalled" ]]; then cp -R "/Volumes/$2/$3" /Applications; echo $'360237221215 - ['$2'] Succesfully installed!
'; fi
hdiutil unmount "/Volumes/$2" > /dev/null && rm "$2.dmg"
elif [ $1 == "zip" ]; then curl -s -L -o "$2.zip" $4; unzip -qq "$2.zip";
if [[ $(appStatus "$3" "" "$5" "zip" "$7") == "updated" ]]; then echo $'342235214 - ['$2'] Skipped because it was already up to date!
';
elif [[ $(appStatus "$3" "" "$5" "zip" "$7") == "outdated" && $6 != "noupdate" ]]; then ditto "$5$3" "/Applications/$3"; echo $'360237214216 - ['$2'] Successfully updated!
'
elif [[ $(appStatus "$3" "" "$5" "zip" "$7") == "outdated" && $6 == "noupdate" ]]; then echo $'342235214 - ['$2'] This app cant be updated!
'
elif [[ $(appStatus "$3" "" "$5" "zip" "$7") == "uninstalled" ]]; then mv "$5$3" /Applications; echo $'360237221215 - ['$2'] Succesfully installed!
'; fi;
rm -rf "$2.zip" && rm -rf "$5" && rm -rf "$3"
elif [ $1 == "tar" ]; then curl -s -L -o "$2.tar.bz2" $4; tar -zxf "$2.tar.bz2" > /dev/null;
if [[ $(appStatus "$3" "" "$5" "tar" "$7") == "updated" ]]; then echo $'342235214 - ['$2'] Skipped because it was already up to date!
';
elif [[ $(appStatus "$3" "" "$5" "tar" "$7") == "outdated" && $6 != "noupdate" ]]; then ditto "$3" "/Applications/$3"; echo $'360237214216 - ['$2'] Successfully updated!
';
elif [[ $(appStatus "$3" "" "$5" "tar" "$7") == "outdated" && $6 == "noupdate" ]]; then echo $'342235214 - ['$2'] This app cant be updated!
'
elif [[ $(appStatus "$3" "" "$5" "tar" "$7") == "uninstalled" ]]; then mv "$5$3" /Applications; echo $'360237221215 - ['$2'] Succesfully installed!
'; fi
rm -rf "$2.tar.bz2" && rm -rf "$3"; fi
}
###############################
# Install selected apps #
###############################
installApp "dmg" "Chrome" "Google Chrome.app" "https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg" "" "" ""
###############################
# Print script footer #
###############################
echo $'------------------------------------------------------------------------------'
echo $'360237222254 - Thank you for using macapps.link! Liked it? Recommend us to your friends!'
echo $'------------------------------------------------------------------------------
'
So the author of the script is basically passing 7 arguments to a function called installApp(). As far as I can tell it is nothing out of the ordinary and the script is literally just using curl
to download the Chrome DMG, mount it, and file copy it over to the /Applications
folder.
I strongly suggest that if you want to use a method like this you vet and parse the scripts that this site relies on, and you read all the code. Then simply use it to write your own methods. There looks to be a bunch of logic in that function to look for tar.gz files, PKG installers, or DMG disk images, and I am willing to take a guess that the author reuses that same function in all the scripts but just changes the arguments passed to them and the URL of where to download the App from.
There are other methods to automate package updates like AutoPKG which is not the same exact workflow as just pipping script into the shell you download from the Internet, but the community at least vets all the AutoPKG recipes.
So bottom line is, be extremely careful with things like this, and if you want to go this route I suggest writing your own code that you know is not malicious.
Cheers
Tom
Posted on 08-06-2015 12:01 PM
So bottom line is, be extremely careful with things like this, and if you want to go this route I suggest writing your own code that you know is not malicious.
Yes, this is more or less what I have done with one of my scripts. Although the code above from this tool looks very different from mine, the general idea is similar in practice. At least since I wrote it, I know whats in it and what its doing.
Also, all those relative home paths (~) in the script aren't going to work too well if you put this script into a Casper Suite policy.
In the end, better to use Autopkg/Autopkgr, or roll your own solution if that's more your style.
Posted on 08-06-2015 12:17 PM
Yes, this is more or less what I have done with one of my scripts. Although the code above from this tool looks very different from mine, the general idea is similar in practice. At least since I wrote it, I know whats in it and what its doing. Also, all those relative home paths (~) in the script aren't going to work too well if you put this script into a Casper Suite policy. In the end, better to use Autopkg/Autopkgr, or roll your own solution if that's more your style.
That is a problem I find common with bash. Everyone has their own writing style and there are lots of things you can do with bash. The author of this script wrote what looks to me, as a reusable function to pass arguments to, so they can recycle code to download and install Apps. I definitely would not have written it that way either because my coding style/preference is different.
There is also no redundancy in any of those scripts, if something fails it doesn't retry, or even verify that the download completed and installed. At least with a AutoPKG workflow you have a tangible package that you can test and verify and you know it will work. Plus if it fails for whatever reason you can just have it reinstall the PKG pretty easily with Casper or Self Service. With this workflow I feel that a number of failure points are introduced and they will be impossible to track or easily remedy if say curl fails, or the DMG fails to mount, or the end user lets their device go to sleep or shuts the lid on their laptop, etc.