tftp
macOS ships with both a TFTP client (/usr/bin/tftp) and server daemon (/usr/libexec/tftpd). TFTP is a lightweight, unauthenticated file transfer protocol that operates over UDP. The server is inactive by default but can be activated through launchd using the system-provided plist. In a lateral movement context, an attacker with root access can activate the built-in TFTP server to receive file transfers. Without root, tftpd can be started on a non-standard port using a user-created launchd plist, removing the root requirement entirely.
Paths
/usr/bin/tftp/usr/libexec/tftpd Example Use Cases
Activate the built-in TFTP server via launchctl
macOS ships with a launchd plist for tftpd at /System/Library/LaunchDaemons/tftp.plist. Loading it with launchctl starts the TFTP server on UDP port 69, serving /private/tftpboot. Requires root. A placeholder file must be created for each file to be transferred, as the default configuration does not allow tftpd to create new files.
sudo launchctl load -w /System/Library/LaunchDaemons/tftp.plist
# Create placeholder for each file to be received
sudo touch /private/tftpboot/payload.sh && sudo chmod 666 /private/tftpboot/payload.sh Transfer a file to a target using the tftp client
The built-in tftp client can push files to a remote TFTP server. The binary mode flag ensures files are not corrupted during transfer.
tftp <TARGET_IP> << EOF
binary
put /tmp/payload.sh payload.sh
quit
EOF Run unprivileged TFTP server on a non-standard port
Without root access, tftpd can be loaded from a user-created launchd plist stored anywhere on disk (e.g., /tmp). Passing the -w flag allows tftpd to create new files on write, removing the placeholder requirement. The server can be bound to any unprivileged port.
mkdir -p /tmp/tftp_server && chmod 777 /tmp/tftp_server
tee /tmp/com.user.tftp.plist > /dev/null << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.tftp</string>
<key>WorkingDirectory</key>
<string>/tmp/tftp_server</string>
<key>ProgramArguments</key>
<array>
<string>/usr/libexec/tftpd</string>
<string>-w</string>
<string>-l</string>
<string>-u</string>
<string>$(whoami)</string>
</array>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<true/>
</dict>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>6969</string>
<key>SockType</key>
<string>dgram</string>
<key>SockFamily</key>
<string>IPv4</string>
</dict>
</dict>
</dict>
</plist>
EOF
launchctl load -w /tmp/com.user.tftp.plist Detections
- No detections at time of publishing