Give a partner file transfer and nothing else

applied · 75 min · Objective 3.2

Task

Replace a plain-FTP partner exchange with SFTP for one named partner account that can upload files and do nothing else: no shell, no tunnels, no view of the rest of the server, and an expiry date. This is least privilege for remote access, applied to the kind of internet-facing file transfer service the lesson says attackers target for mass exploitation.

Steps

  1. Record what is listening now with sudo ss -ltnp. If anything listens on port 21, stop and disable it: plain FTP sends credentials and files in cleartext, and the point of this lab is that it is not needed.
  2. Create the partner account with no usable shell and an expiry date 30 days out, because third-party access is time-limited: sudo useradd -m -s /usr/sbin/nologin partner then sudo chage -E $(date -d '+30 days' +%F) partner.
  3. Build the jail. The chroot directory and every directory above it must be owned by root and writable by nobody else, with one subdirectory the partner may write to: sudo mkdir -p /srv/sftp/partner/upload, sudo chmod 755 /srv/sftp/partner and sudo chown partner:partner /srv/sftp/partner/upload.
  4. Append a block to the END of /etc/ssh/sshd_config that applies to this one account:
Match User partner
    ChrootDirectory /srv/sftp/partner
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PermitTTY no

Check the syntax with sudo sshd -t BEFORE reloading -- reloading a broken file is how you lose the server -- then run sudo systemctl reload ssh (the unit is sshd on some distributions). 5. Give the partner a key: ssh-keygen -t ed25519 -f ~/.ssh/partner_lab -N '', then sudo install -d -m 700 -o partner -g partner /home/partner/.ssh and sudo install -m 600 -o partner -g partner ~/.ssh/partner_lab.pub /home/partner/.ssh/authorized_keys. Authentication happens before the chroot, so the key lives in the real home directory, not inside the jail. 6. Test as the partner: upload a file into upload/ with sftp -i ~/.ssh/partner_lab partner@127.0.0.1; inside the same session try cd /etc, which must fail because the jail has no /etc; and try running a command over ssh, which must not run because the server replaces it with the file transfer subsystem. 7. Write /tmp/partner-access.md: who approved this access, for what job, the expiry date, and the date it will next be reviewed. Remote access without a named owner and an end date is the standing access the lesson warns about.

Verify

printf 'put /etc/hostname upload/hello.txt\n' | sftp -b - -i ~/.ssh/partner_lab partner@127.0.0.1 && sudo ls -l /srv/sftp/partner/upload/hello.txt
printf 'ls /etc\n' | sftp -b - -i ~/.ssh/partner_lab partner@127.0.0.1; echo "escape attempt exit code: $?"
ssh -i ~/.ssh/partner_lab partner@127.0.0.1 whoami < /dev/null | grep -c partner
python3 - <<'PY'
import subprocess
def run(cmd):
    return subprocess.run(cmd, shell=True, capture_output=True, text=True).stdout
cfg = run('sudo sshd -T -C user=partner,host=partner.lab,addr=127.0.0.1').lower().splitlines()
got = dict(l.split(None, 1) for l in cfg if ' ' in l)
want = {'chrootdirectory': '/srv/sftp/partner', 'forcecommand': 'internal-sftp',
        'allowtcpforwarding': 'no', 'permittty': 'no'}
for k, v in want.items():
    print('%-20s %s' % (k, got.get(k)))
    assert got.get(k) == v, k + ' is not ' + v + ' for the partner account'
exp = [l for l in run('sudo chage -l partner').splitlines() if 'Account expires' in l][0]
print(exp.strip())
assert 'never' not in exp.lower(), 'third-party access with no expiry date'
assert not run('ss -ltnH sport = :21').strip(), 'something still listens on port 21'
print('no plain FTP listener')
PY

The upload must succeed and the file must exist under the jail. The escape attempt must exit non-zero, and the grep -c must print 0: the account name never comes back because whoami never ran. The Python block reads the settings the server will actually apply to this one user, so a block that was appended in the wrong place, or overridden by an earlier Match, fails here rather than in front of a partner.

Notes

sshd -T is the evidence an auditor wants: not the file you edited but the effective configuration for that account. The expiry date is the control that gets forgotten, because vendor access left in place after the job is how a temporary opening becomes a permanent one. A managed file transfer platform adds the logging and automatic deletion of collected files that this lab leaves to you.

This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.