Files, directories, and devices that are writable by any user (“world-writable”) on a multi-user system can be dangerous locally exploitable security holes. There are very few legitimate reasons for having world-writable files and directories on a system.
Many UNIX and Linux systems actually have cron jobs that check for world-writable files. On Apple’s OS X there is no such safeguard and many vendors do not seem to care about file permissions much at all. Several well-known applications are either installed with world-writable files or create them when used:
World-writable files in system directories
The following applications install world-writable files in shared directories (/Applications
, /Library
, …):
- Adobe CS 4, CS 5: Some uninstallers + several files and directories in /Library/Application Support + various stuff in other locations
-
Adobe Media Player: directory + some files in
Contents/Resources
-
Adobe Flash Player: directories (including
AddIns
undAddIns/airappinstaller
) - Amazon MP3 Downloader: some directories
- EPSON (Scan, TWAIN data source, Easy Photo Print, …): pretty much everything, including executables
- Eye-One Match 3: complete app, including executable
- eMusic Download Manager: complete app, including executable and JavaScript (the application is based on Mozilla)
- Telltale games: complete apps including executable and libraries
- Apple OS X: some plist and cache files, including at least one LaunchDaemon plist file
- Google+Growl Utility (not a Google product): whole app including executable
- HP Scan Pro (plus supporting files): everything including executables
- DivX Converter: resource files
- Apple Remote Desktop: some plist files
- Apple GarageBand: several plist and data files
- Apple ColorSync: some profiles
- Microsoft Office 2011: directory in /Library Application Support
- Elgato EyeTV: several plist files
- ABBYY FineReader Sprint 8.0: several data files
- ArcSoft (Connect Suite, MediaImpression 2): all files, including executables
- Extensis Suitcase Fusion 2: all files, including executables
World-writable files in user directories
The following applications install world-writable files in user directories (/Users/$USER
):
- GoogleGrowl.plugin: whole plugin including executable
- 3rd-party extensions for Apple Safari: some extensions (e.g. AdBlock) install world-writable files
- Apple iPhoto: the whole library seems to be world-writable
- Adium add-ons: several add-ons install world-writable files
- eMusic Download Manager:some preferences files are world-writable
- Adobe (CS 4, CS5, Flash, …): several preferences files
- Apple MobileDevice: crash logs are world-writable
The lists have been compiled by inspecting my own systems and those of several friends by running
sudo sh -c \ "find / -xdev -perm +o=w ! \( -type d -perm +o=t \) ! -type l -print0 | \ xargs -0 ls -dl 2>&1 | \ tee world-writable-files.txt"
and analyzing the output.
Note that running Disk Utility‘s “Repair Disk Permissions” does not have any influence on the issues described here.
Most OS X installations are probably single-user systems in reality but the situation is still somewhat ugly.
It’s very disgusting, indeed. I wonder what happens with applications installed via Appstore. The way you show it, if you grant remote access to a guest account, they (or some malicious script running on their machines) could replace your applications with infected executables. May be a chmod -R could help?
Besides dangerous file and directory permissions I am also concerned with ownerships: everything in /System, /Library and /Applications should be owned by system uids and not by real human users as the security implications are quite similar. Unfortunately, the OSX-typical practice of users installing apps by moving them into /Applications will create just this scenario, and also apps which do come with installers will often have their items installed using undesirable user and group ownerships (even non-existing users and groups which probably slipped through from the development or build systems).
This problem has bothered me enough to come up with below script to check and fix the /Applications and /Library directory trees. (I leave /System, /usr, /bin etc. alone since I found no problems here on my machines, but the script will still display a short report about “noteworthy stuff” in these directories, too.)
Enjoy!
Arndt
#!/bin/bash -e
# vi: set ts=4 sw=4 ai:
# normalize file ownerhip and permissions for /Applications and /Library
# version: 1.0 2013-08-03 for Mac OS X 10.8.4
DOIT=-1 # default: ask for confirmation before making any changes
AREA=ALO # default: do /Applications, /Library and other checks
while (($# > 0))
do
case “$1” in
-y|–yes) DOIT=1;; # don’t ask, just do it
-n|–no) DOIT=0;; # don’t ask, don’t do it
-A) OAPP=1;; # select /Applications
-L) OLIB=1;; # select /Library
-O) OOTH=1;; # select other checks
*) echo >&2 “${0##*/}: bad args”; exit 2;;
esac
shift
done
[[ -z “$OAPP$OLIB$OOTH” ]] || AREA=”${OAPP:+A}${OLIB:+L}${OOTH:+O}”
if [[ $(id -u) != 0 ]]
then
echo “${0##*/}: please run this script as root”
exit 2
fi
M() { (IFS=” “; printf “\n### %s\n\n” “$*”) }
A()
{
if ((${#ITEMS[*]} == 0))
then
echo “(nothing to do)”
return 0
fi
# list all offending files and dirs
printf “%s\n” “${ITEMS[@]}” | tr ’12’ ” | xargs -0 ls -leOd
if (($DOIT == 0))
then
return 0
elif (($DOIT < 0))
then
while :
do
(IFS=" "; echo -n "Command for these items: $* — execute (y|n) ? ")
read yn
[[ $yn = n ]] && return 2
[[ $yn = y ]] && break
done
fi
# execute the given command on all offending files and dirs
if [[ $1 != SetOwnerGroup ]]
then
printf "%s\n" "${ITEMS[@]}" | tr '12' '' | xargs -0t "$@"
return $?
else
for i in "${ITEMS[@]}"
do
grp=$(stat -f %Sg "${i%/*}") && [[ $grp = admin ]] || grp=wheel
(set -x; chown -h "root:$grp" "$i")
done
fi
}
# IFS must be set to \n for the ITEMS=($(…)) assignments below
IFS="${IFS#??}"
if [[ $AREA = *A* ]]
then
echo
echo ====== /Applications ======
M remove .DS_Store files except those inside an app and belonging to root
ITEMS=($(
find -s /Applications \
-name .DS_Store "(" ! -user root -or ! -path "*.app/.DS_Store" ! -path "*.app/*/.DS_Store" ")"
))
A rm -f
M make everything below /Applications world readable and executable
ITEMS=($(
find -s /Applications ! -perm -0044 -or -perm +0100 ! -perm -0011
))
A chmod -h go+rX
M revoke write permission for group and other
ITEMS=($(
# valid as of 10.8.4:
# all files and dirs should be ???r-Xr-X, except
# – g=w: /Applications/, /Applications/System Preferences.app//
# – g=w is okay if user=root and group=admin
# A violation of the exception condition (i.e. if o=w) will cause
# the removal of the g=w permission, too.
find -sE /Applications \
! "(" -regex "/Applications/System Preferences.app(/.*)?" -or -user root -group admin ")" -perm +0022 \
-or -perm +0002
))
A chmod -h go-w
M assign all apps, subdirectories and files to user root, group wheel
ITEMS=($(
# 10.8.4: all files and dirs should be root:wheel or root:admin
find -s /Applications ! "(" -user root "(" -group wheel -or -group admin ")" ")"
))
A chown -h root:wheel
fi
if [[ $AREA = *L* ]]
then
echo
echo "====== /Library ======"
M remove all .DS_Store files
ITEMS=($(
find -s /Library -name .DS_Store
))
A rm -f
M ensure universal readability and executability
ITEMS=($(
find -s /Library \
-user root -or -path "/Library/Caches/*" \
-or "(" ! -perm -0044 -or -perm +0100 ! -perm -0011 ")" -print
))
A chmod -h go+rX
M revoke write permission for other
ITEMS=($(
# generally leave files alone which are owned by root, but make sure
# /Library/Application Support// gets fixed
find -sE /Library \
-regex "/Library/Application Support(/.*)?" -perm +0002 -print \
-or -user root -or -path "/Library/Caches/*" -or -path "/Library/Preferences/*" \
-or -perm +0002 -print
))
A chmod -h o-w
M assign stray items of group wheel or admin to user root
ITEMS=($(
find -s /Library \
! -path "/Library/Caches/*" ! -path "/Library/Logs/*" \
! -user root "(" -group wheel -or -group admin ")" |
while read i; do
# filter by uid to ignore items owned by system users
[[ $(stat -f %u "$i") -lt 500 && $(stat -f %Su "$i") != "("*")" ]] || echo "$i"
done
))
A chown -h root
# only proceed if above step has been successfully executed
if (($? == 0 && $DOIT != 0))
then
M for stray items of other groups, use the group of the parent dir
ITEMS=($(
find -s /Library \
! -path "/Library/Caches/*" ! -path "/Library/Logs/*" \
"(" ! -user root -or ! -group wheel ! -group admin ")" |
perl -e 'print reverse ‘ |
while read i; do
# filter by uid to ignore items owned by system users
[[ $(stat -f %u “$i”) -lt 500 && $(stat -f %Su “$i”) != “(“*”)” ]] || echo “$i”
done
))
A SetOwnerGroup
fi
fi
if [[ $AREA = *O* ]]
then
echo
echo “====== other checks ======”
M check for unsual permissions and ownerships in /bin, /etc, /sbin, /usr, /System
# ignores softlinks, and items owned by root with group wheel or admin
# which don’t have the setuid, setgid and sticky bit set and which are
# only writable by user; lists everything else
find -s /bin /etc /sbin /usr /System \
-type l -or -user root “(” -group wheel -o -group admin “)” ! -perm +7022 -or -ls
fi
###