Datto devices are becoming a popular backup solution for small to medium sized businesses. They are easy to use and well equipped out of the box. We recently found ourselves in an engagement where one of these devices was accessible via the LAN. Gaining access to backups is a bit of a goldmine during an assessment; unrestricted access to file shares, configuration information, extracting hashes from the NTDS.dit file, and a multitude of other things. Anyone familiar enough with Datto devices knows you have a few useful restore options like mounting backups over open SMB shares or even starting your own VM . Let’s review what we found.

Initial Access

These Datto devices have quite a few attack surfaces out of the box, a web control panel for management, SSH is configured, and VNC is enabled by default. The authentication password for VNC, “Northern”, is well documented by Datto, so that didn’t take long to find. This allowed us to connect to the device remotely and luckily, the user was already logged in! However, VNC access isn’t very stealthy, and we wanted SSH access to the device instead.

Via VNC access we noticed the “root” user is managed by Datto. By looking through logs, it appears these accounts have their passwords changed frequently (once/day), so they aren’t prime targets for attacks directly. However, they do appear to get used so Datto must be tracking these changes somewhere. Hmmm…

Moving on, “backup-admin” is an account created for the client use. The password to this account can be viewed in the partner portal (https://auth.dattobackup.com/simplesaml), where clients can also view device status, backup progress, and initiate a remote web connection to the device. This might be an interesting attack vector as well, but we’ll focus on more local attacks.

Another account, “aurorauser” looks interesting and potentially promising. This account is an unprivileged user account, used for automatic login on boot…providing the easy VNC access. Unfortunately, the SSH password didn’t match the VNC password for this user. However, with a bit of research the default password to the account was found, “NorthernLight$”. Throw it into SSH and we’re in!

Pulling out the root

The Datto device is really just an Ubuntu Linux install with LAMP and bash scripts providing a web console and dashboard intelligence. SSH tunnels and rsync are used to connect back to Datto for off-site duplication. Running ‘uname -ar’ shows the OS is Ubuntu 10.04, released February, 2012 with an EOL May, 2013 for desktops and April, 2015 for servers. Privilege escalation was trivial thanks to a CVE-2012-0056. The exploit used was Mempodipper, courtesy of Jason Donenfeld (https://blog.zx2c4.com/749). Thankfully, Datto was kind enough to provide GCC, so simply pop open vim on the box, throw in the source, compile, and we’re root!

Building a backdoor

Where can we go from here? Our first goal to access the backup data was to obtain access to the web console. Poking through some files revealed “/datto/config/local/webaccess”, which is a text file containing MD5 hashes in a “user:hash:” format. Easy enough…just add our username and MD5 password to the file and we’re in! It’s also worth noting that while the newly added user credentials worked, the username did not appear in the list of users within the web console management interface.

With our purpose being to restore data from a backup (SAM file, sensitive files, etc.), we hopped into the “Restore” page in the web console, selected the DC, chose the backup date, and hit the mount button. Uh oh! Datto devices offer backup encryption for agents added to the device. While not enabled by default, in this case the customer enabled it manually requiring a decryption password prior to mounting or accessing any backup data.

Finding the keys

Let’s dig a little deeper into how this encryption system works. Dan Fuhry, an engineer from Datto has provided a nice little “Datto vs. NSA” paper here, which provides some insight. Here is the relevant section:

“My design for Datto’s encryption system provides unique encryption keys per agent, so there is no single key that can decrypt every dataset we have. The key used to encrypt your actual data is the master key, and that master key is only ever stored in an encrypted fashion. It’s completely random – not derived from a passphrase – and no human ever sees it. When you enter your passphrase, your Datto device does some number crunching on that passphrase and some additional data to get a user key. That user key is used to decrypt an encrypted copy of the master key. This gives you the ability to change your passphrase without having to re-encrypt the entire dataset, and have multiple valid passwords per agent.

The important thing to realize here is how vital your passphrase is to decrypting your data. Without it, the number crunching required to find your data is impossibly immense, even for the NSA. Datto doesn’t keep your passphrase anywhere. Therefore, no court can compel us to hand over your unencrypted data, because we don’t have it and can’t get it.”

This all sounds very promising. To summarize, you need to access the decrypted user key (requires passphrase), to then decrypt the master key, to then decrypt the backup data.

But wait, let’s think about this. If the Datto is backing up agents continuously, and you don’t have to type in your passphrase every time, the Datto must be storing this master key somewhere. This is where “sealing” comes in (Datto’s term). Essentially, when you first reboot a Datto, you need to login to the web console and “un-seal” your agents. This means typing in your passphrase so that the Datto can begin encrypting the backups its taking.

Your first thought might be to just dump the live memory from the device. The master key must be in there somewhere! Let’s first learn a little more about what this “un-sealing” process. As mentioned earlier, pretty much all of the functions on the Datto are controlled through either PHP scripts, or bash scripts. The PHP scripts are obfuscated using ion-cube, so we can’t just throw them into a text-editor. Luckily for us, a neat little decoder tool exists (https://phpdecode.blogspot.com/) that will decode the files to a more readable format. It’s not perfect, but it works great for our purposes. Digging through the source, you’ll notice a function  named “stashAgentKey()” in the encryptionFunctions.php file.

This snippet tells us that Datto is utilizing Linux shared memory at /dev/shm/ to store the master keys while the agent is unsealed. <3 u Datto. Here is an example dump of that file:


Ahh, that’s much better. EditNow that we have the master keys for the agents, we should be able to decrypt the backups! However, that sounds like quite a bit of work. Based on Datto’s response, we learned we obtained the encrypted master key, not the actual master key. Here’s more detail taken from their response to this blog post.

“On a technical point, I will note that what your post concludes is a master key is in fact not, it’s an encrypted master key. At device boot we generate a completely random key and salt, that is then used to encrypt the master key while in memory. Granted, the boot key is in memory as well as the salt and encrypted master key. But now an adversary must know all three. It’s not insurmountable if you’re already in the device shell as root, but it is another hurdle.”

If you haven’t read their response, it’s definitely worth while to look it over. It’s not every day that an organization is proactive and receptive to potential security vulnerabilities regarding their product.

While perusing the source, another potentially interesting rabbit hole…or, “rat” hole was found.

Did someone say RAT?

All of the Datto functions are available through a command line application called “snapctl”. Here are the documented arguments:

add                     [hostname]                              -Registers a new agent' . '
removeAgent             [hostname]                              -DESTROYS ALL DATA AND LOG FOR AN AGENT! DANGER!
restartAgent            [hostname]                              -Restarts the replay agent (Wait 30 seconds for agent to restart)
renameAgent             [old-hostname]  [new-hostname]          -Rename an agent, it's ZFS shares, and it's offsite shares
makeStorage             [hostname]                              -creates zpool for agent
command                 [hostname]      [command] [args] [dir]  -Runs a physical command on the host system
updateAgent             [hostname]                              -Updates the SnapToVM agent to latest version
setCompatibility        [hostname]      [on]                    -Set compatibility mode (1 = on 0 = off)
setWriteCaching         [hostname]      [on]                    -Set write caching enabled/disabled (1 = on 0 = off)
clearAllCompatibility                                           -Disables share compatibility for all agents.
list                                                            -Lists all agents protected by this core
dirtyUpgrade            [hostname]                              -This function updates the version of ShadowSnap regardless of previous version
cleanupAppassure        [hostname]                              -This function will clean up any left over Snap2VM files left in the agent directory
restartSystem           [hostname]                              -Reboots the system the agent is running on
setEngine               [hostname]      [engine]                -Allows you to set the backup engine

start                   [hostname]                              -Starts a backup for hostname
foregroundStart         [hostname]                              -Starts a backup on the command line for hostname
stop                    [hostname]                              -Stops the backup for hostname
forceFull               [hostname]                              -Forces the next backup to be full
forceDiffMerge          [hostname]                              -Forces the next backup to be diffmerge
setInterval             [hostname]      [interval]              -Sets the backup interval in minutes
getInterval             [hostname]                              -Prints the backup interval
status                  [hostname]                              -Prints the status of the hostnames backup
excludeVol              [hostname]      [mount]                 -Excludes a mountpoint from backup. Mountpoint must be a volume
includeVol              [hostname]      [mount]                 -Includes a mountpoint from backup. Mountpoint must be a volume
forceRemoveVol          [hostname]      [mount]                 -Removes an excluded mountpoint from the live dataset. Mountpoint must be a volume
checkVol                [hostname]      [mount]                 -Prints the Exclude status for volume
retention               [hostname]                              -Runs ZFS retention operations
dryRunRetention         [hostname]                              -Runs a dry run of ZFS retention operations, which will return the points that will be removed
offsiteRetention        [hostname]                              -Runs ZFS retention operations on offsite servers
setShareAccess          [hostname]      [username]              -Sets all future shares for this hostname to be password protected with access for specified user. A blank user value will disable.

createVM                [hostname]      (snap)       (suffix)   -Clones a snapshot of a host using an optional suffix. Defaults to the most recent snapshot and a suffix of -active.
startVM                 [hostname]                              -Starts a virtual machine for specified host
stopVM                  [hostname]                              -Stops a virtual machine for specified host
destroyVM               [hostname]      (keepClone)  (suffix)   -Destroys virtual machine and optionally keeps clone

setController           [hostname]      [controller]            -Sets the VBox Controller type (IDE or SCSI)
getController           [hostname]                              -Prints the controller type
updateVBox                                                      -Updates VirtualBox to the latest version
mountPoint              [hostname]      (snap)       (suffix)   -Mounts a cloned snapshot's volumes for file restore. Optional snapshot defaults to the most recent. Optional suffix defaults to "[SNAPSHOT#]-file"
unmountPoint            [hostname]      (suffix)                -Unmounts a cloned snapshot's volumes after file restore. Optional suffix defaults to "[SNAPSHOT#]-file"

shareVMDK               [hostname]      [snap]                  -Share RAW vmdk file
unshareVMDK             [hostname]      [snap]                  -Unmounts and de-share raw VMDK
shareVHD                [hostname]      [snap]                  -Share RAW vhd file
unshareVHD              [hostname]      [snap]                  -Unmounts and de-share raw VHD
convertVHD              [path]                                  -Converts a specified image or images in the specified directory to vhd
hostOverride            [hostname]      [newHostname]           -Overrides the hostname given to the agent for the path to the Samba share. Set blank value to disable.
agentSetConfig          [hostname]      [key]        [value]    -Sets an agent configuration variable given the correct key and a valid value. Host must be running.
agentGetConfig          [hostname]                              -Returns the current agent configuration for a given host. Host must be running.
screenshotOverride      [hostname]      [cpus]       [ram]      -Sets the resources to be used for the screenshot VM for this host. (RAM specified in MB)
hir                     [hostname]      [path]       (cowMerge) -Performs HIR on a target location using the hostname as a source of agent information. Optionally will merge the HIR with the images.
clearShares             [hostname]                              -Removes all mapped network drives that point to the datto from the agent machine
attachDMCrypt           [path]                                  -Attach an encrypted image to dm-crypt
detachDMCrypt           [path]                                  -Detach a dm-crypt device
decryptAgentKey         [hostname]                              -Enter a passphrase to unlock an agent's images
sealAgent               [hostname]                              -Discard an agent's master key from memory
addAgentPassphrase      [hostname]                              -Add an additional passphrase that can decrypt an agent
removeAgentPassphrase   [hostname]                              -Remove an existing passphrase from an agent
encryptAgent            [hostname]                              -Set an agent up for encryption. Any existing snapshots/live dataset will be destroyed.
uploadEncryption                                                -Force manual upload of encryption salt/mkey information
downloadEncryption                                              -Fetch encryption salt/mkey information and merge with local stash

screenshot              [hostname]      [delay]      (snap)     -screenshots the agent after delay in seconds using snap (optional)
addScreenshot           [hostname]      [snap]                  -adds snap to the screenshot queue
screenshotAll           [hostname]                              -Screenshot all hostnames on this machine that have not had a screenshot in the last 24 hours
killScreenshot          [hostname]                              -kills the screenshot operation
cleanupScreenshots      (hostname)                              -Cleans up screenshot remnants. Optionally, specify an agent whose screenshot remnants you want cleaned up.
debugScreenshot                                                 -Run the whole screenshot process in the foreground
testFilesystems         [hostname]      (path)                  -Test all backed up filesystems for an agent to verify that they can be mounted. Optionally, specify a path containing a clone of that hostname.

bmrInstall                                                      -Installs the latest network BMR environment.
kzfs                                                            -Upgrade the device to use kernel based zfs
r8169upgrade                                                    -Upgrades the realtek network drivers to version 6.015.00
largeFiles              [directory]     [minSize]               -Show all files in the target directory that are larger than minSize kilobytes
timestamp               [timestamp]                             -Convert a linux timestamp to human readable date
health                  (verbose)                               -Print a device health summary
device-key              show|hide                               -Show or hide the Encryption options section on the Admin page
runTask                                                         -Run a task from the Admin page

checkHost               [hostname]                              -Prints connectivity information about host
update                  [hostname]                              -Updates the agent info about the host
info                    [hostname]                              -Prints info about the host
viewLog                 [hostname]      [lines]                 -Prints lines number of lines from the end of the log file
printErrors             [hostname]                              -Echos the replay log (Should be used with TAIL)
getVMX                  [hostname]                              -Print the VMX Array data stored about the host
getWriters              [hostname]                              -Returns a list of installed VSS Writers
clearError              [hostname]                              -Clears last reported error from the system
truncateLogs            [hostname]                              -forces a truncate of the exchange and SQL logs
setTruncate             [hostname]      [time]                  -Sets the log truncate time out in minutes

updateOffSite                                                   -Updates which points are stored off-site
sendWeekly                                                      -Send the weekly backup digest
updateVols                                                      -Transfer sync/volume information offsite
syncNetworkConfig                                               -Updates /etc/network/interfaces with current state of physical interfaces
totalFreeRam                                                    -Gets the true total free memory available. Includes ZFS cache.
updateHardwareProfile                                           -Update the model of this device after a field upgrade.
updateVbox                                                      -Update VirtualBox to the latest supported version.
suppressUpdateNotification [hostname]   [hours]                 -Suppresses ShadowSnap update notification for given number of hours
agentUpdateStatus          [hostname]                           -Gets current agent update info as JSON data';

That’s a lot of functionality, and immediately you’ll notice some glaring issues. First off, the “command” option sends and executes an arbitrary command to any agent added to the Datto.

command                 [hostname]      [command] [args] [dir]  -Runs a physical command on the host system

Wow, remote command execution built into a backup device. It really is fully featured! Let’s run a quick test to try it out:

Perfect! We’re SYSTEM! Presumably this comes from the ShadowSnap agent that Datto requires you to install on agents backing up to the device. Based on the source code, the command doesn’t appear to be used that much. Moving past command execution, this utility has some other useful features. For one, the “screenshot” ability could be very useful for snooping.

screenshot              [hostname]      [delay]      (snap)     -screenshots the agent after delay in seconds using snap (optional)

Or how about restartSystem?

restartSystem           [hostname]                              -Reboots the system the agent is running on

Or possibly removeAgent if you are feeling dangerous?

removeAgent             [hostname]                              -DESTROYS ALL DATA AND LOG FOR AN AGENT! DANGER!

However, none of these are quite as interesting as two of the encryption commands.

addAgentPassphrase      [hostname]                              -Add an additional passphrase that can decrypt an agent
removeAgentPassphrase   [hostname]                              -Remove an existing passphrase from an agent

So let’s wrap this up. Datto states the because a master key is separate from the user key, that you can have multiple passphrases per agent. The web console doesn’t let you configure this. It requires you to enter the current passphrase in order to change it. But we know that the Datto device already has access to the decrypted master key while an agent is unsealed. So theoretically…

Perfect! We were able to add a temporary passphrase to an existing un-sealed agent, mount a backup with it, demount, and remove the temporary passphrase all without knowing or disturbing the current passphrase.

Now of course this is only scratching the surface of these devices. Here are a few other things we didn’t have time to fully explore:

  • Datto downloads scripts over HTTP periodically and executes them blindly, some DNS modifications  or MiTM could make this very dangerous.
  • Datto’s SSH syncing to the cloud might be vulnerable to different attacks including device traversal.
  • How do user passwords get changed remotely?
  • Can raw backup Datto be decrypted with the master keys obtained?
  • How does Datto open remote HTTP tunnels from the partner site to enable remote login?

Hopefully this this post will be useful to anyone currently using or considering a Datto device.

Update: Datto wrote a great response to the findings reviewed above. They even straighten out some of our erroneous conclusions regarding identifying the encrypted master key (as opposed to the actual master key). The fixes are shown above. Their response can be found here.