#!/bin/bash # # Run through a series of tests to try out the various capability # manipulations posible through exec. # # [Run this as root in a root-enabled process tree.] try_capsh () { echo "TEST: ./capsh $*" ./capsh "$@" if [ $? -ne 0 ]; then echo FAILED return 1 else echo PASSED return 0 fi } fail_capsh () { echo -n "EXPECT FAILURE: " try_capsh "$@" if [ $? -eq 1 ]; then echo "[WHICH MEANS A PASS!]" return 0 else echo "Undesired result - aborting" echo "PROBLEM TEST: $*" exit 1 fi } pass_capsh () { echo -n "EXPECT SUCCESS: " try_capsh "$@" if [ $? -eq 0 ]; then return 0 else echo "Undesired result - aborting" echo "PROBLEM TEST: $*" exit 1 fi } pass_capsh --print # Make a local non-setuid-0 version of capsh and call it privileged cp ./capsh ./privileged && chmod -s ./privileged if [ $? -ne 0 ]; then echo "Failed to copy capsh for capability manipulation" exit 1 fi # Give it the forced capability it could need ./setcap all=ep ./privileged if [ $? -ne 0 ]; then echo "Failed to set all capabilities on file" exit 1 fi ./setcap cap_setuid,cap_setgid=ep ./privileged if [ $? -ne 0 ]; then echo "Failed to set limited capabilities on privileged file" exit 1 fi # Explore keep_caps support pass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print rm -f tcapsh cp capsh tcapsh chown root.root tcapsh chmod u+s tcapsh ls -l tcapsh # leverage keep caps maintain capabilities accross a change of uid # from setuid root to capable luser (as per wireshark/dumpcap 0.99.7) pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=500 --caps=\"cap_net_raw,cap_net_admin=pie\" --print" # This fails, on 2.6.24, but shouldn't pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=500 --forkfor=10 --caps= --print --killit=9 --print" # only continue with these if --secbits is supported ./capsh --secbits=0x2f > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "unable to test securebits manipulation - assume not supported (PASS)" rm -f tcapsh rm -f privileged exit 0 fi # nobody's uid. Static compilation of the capsh binary can disable pwd # info discovery. nouid=$(/usr/bin/id nobody -u) pass_capsh --secbits=42 --print fail_capsh --secbits=32 --keep=1 --keep=0 --print pass_capsh --secbits=10 --keep=0 --keep=1 --print fail_capsh --secbits=47 -- -c "./tcapsh --uid=$nouid" rm -f tcapsh # Suppress uid=0 privilege fail_capsh --secbits=47 --print -- -c "./capsh --uid=$nouid" # suppress uid=0 privilege and test this privileged pass_capsh --secbits=0x2f --print -- -c "./privileged --uid=$nouid" # observe that the bounding set can be used to suppress this forced capability fail_capsh --drop=cap_setuid --secbits=0x2f --print -- -c "./privileged --uid=$nouid" # change the way the capability is obtained (make it inheritable) ./setcap cap_setuid,cap_setgid=ei ./privileged # Note, the bounding set (edited with --drop) only limits p # capabilities, not i's. pass_capsh --secbits=47 --inh=cap_setuid,cap_setgid --drop=cap_setuid \ --uid=500 --print -- -c "./privileged --uid=$nouid" rm -f ./privileged # test that we do not support capabilities on setuid shell-scripts cat > hack.sh <<EOF #!/bin/bash /usr/bin/id mypid=\$\$ caps=\$(./getpcaps \$mypid 2>&1 | /usr/bin/cut -d: -f2) if [ "\$caps" != " =" ]; then echo "Shell script got [\$caps] - you should upgrade your kernel" exit 1 else ls -l \$0 echo "Good, no capabilities [\$caps] for this setuid-0 shell script" fi exit 0 EOF chmod +xs hack.sh ./capsh --uid=500 --inh=none --print -- ./hack.sh status=$? rm -f ./hack.sh if [ $status -ne 0 ]; then echo "shell scripts can have capabilities (bug)" exit 1 fi # Max lockdown pass_capsh --keep=1 --uid=$nouid --caps=cap_setpcap=ep \ --drop=all --secbits=0x2f --caps= --print # Verify we can chroot pass_capsh --chroot=$(/bin/pwd) pass_capsh --chroot=$(/bin/pwd) == fail_capsh --chroot=$(/bin/pwd) -- -c "echo oops"