Very very very Hidden picoCTF 2021 Solution

Published: April 2, 2026

Description

Find the hidden flag. A packet capture file is provided containing network traffic - dig through it to uncover something suspicious.

Download try_me.pcap.

Install Wireshark to inspect and export objects from the capture.

bash
sudo apt install wireshark

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Export HTTP objects from the capture
    Observation
    I noticed that the PCAP contains a mix of TLS-encrypted and plain HTTP traffic, which suggested exporting HTTP objects as the first step since cleartext transfers would be immediately readable and might contain suspicious files.
    Open try_me.pcap in Wireshark. Most traffic is TLS-encrypted, but five plain HTTP transfers are visible. Use File > Export Objects > HTTP and click Save All. Among the exports you will find duck.png and evil_duck.png. Both images share the same pixel dimensions, yet evil_duck.png is more than twice the file size of duck.png despite appearing lower quality - a clear sign that extra data is packed inside it.
    bash
    # In Wireshark: File -> Export Objects -> HTTP -> Save All
    bash
    ls -lh duck.png evil_duck.png
    bash
    file duck.png evil_duck.png
    What didn't work first

    Tried: Running steghide extract -sf evil_duck.png to find the hidden data

    steghide uses its own passphrase-protected embedding format (DCT coefficient modification in JPEG or palette manipulation) and will report 'steghide: could not extract any data with that passphrase' because evil_duck.png uses Invoke-PSImage's LSB-4 pixel encoding, not steghide's scheme. No passphrase guess will succeed; the correct approach reads raw pixel values with PIL.

    Tried: Running zsteg evil_duck.png to detect the hidden payload automatically

    zsteg scans common LSB bit-planes but defaults to checking 1 bit per channel. Invoke-PSImage writes into the low 4 bits (not just 1 bit), so zsteg either produces garbled output or no hits at all. The correct approach targets exactly bits 0-3 of the blue and green channels rather than relying on a generic scanner.

    Learn more

    Why evil_duck.png is suspicious. When two images are the same dimensions but one is dramatically larger, the extra bytes are almost always hidden payload rather than image data. Standard tools like steghide and zsteg find nothing here because the data is not hidden with those schemes.

    The HTTP traffic also reveals a tell: Wireshark's Server Name column shows the user browsed GitHub, Microsoft documentation, and powershell.org before the image downloads. That browsing trail is a hint that PowerShell steganography is involved.

  2. Step 2
    Identify the steganography scheme: Invoke-PSImage
    Observation
    I noticed that evil_duck.png was more than twice the file size of duck.png despite identical dimensions and lower apparent quality, and the PCAP's browsing history included PowerShell and GitHub visits, which suggested a PowerShell-based pixel steganography tool like Invoke-PSImage was responsible.
    Searching for 'powershell steganography' surfaces the peewpw/Invoke-PSImage GitHub repository. This tool hides a PowerShell script inside a PNG file by writing the payload into the least significant 4 bits of the blue and green channel of each pixel. The image looks nearly normal to the eye, but every pixel carries 1 byte of hidden script data, which explains why evil_duck.png is so much larger than a clean image of the same dimensions.
    Learn more

    How LSB-4 pixel encoding works. Each pixel stores 1 byte of payload across two channels: the low 4 bits of blue hold the upper nibble, and the low 4 bits of green hold the lower nibble. Reconstructing the byte:

    r, g, b = pixel
    byte = ((b & 0x0F) << 4) | (g & 0x0F)

    Walking every pixel in order yields a complete PowerShell script embedded invisibly inside the image.

  3. Step 3
    Decode evil_duck.png and run the extracted script
    Observation
    I noticed that Invoke-PSImage encodes exactly one payload byte per pixel using bits 0-3 of the blue and green channels, which suggested writing a Python PIL loop to reconstruct those nibbles and recover the hidden PowerShell script that XORs two strings to produce the flag.
    Use the PCsXcetra/Decode_PS_Stego tool (PowershellStegoDecode.exe on Windows) to extract the hidden PowerShell from evil_duck.png. Alternatively, the Python snippet below decodes it manually. The extracted script XORs two hardcoded strings together and writes the result to flag.txt. Running that script produces the flag.
    bash
    # Python manual decode (Linux-friendly):
    python
    python3 -c "
    python
    from PIL import Image
    bash
    im = Image.open('evil_duck.png')
    bash
    w, h = im.size
    bash
    out = []
    bash
    for x in range(h):
    bash
        for y in range(w):
    bash
            r, g, b = im.getpixel((y, x))
    bash
            out.append(chr(((b & 15) << 4) | (g & 15)))
    python
    print(''.join(out))" > extracted.ps1
    bash
    bash
    # Then run the extracted PowerShell (Windows / pwsh):
    bash
    pwsh extracted.ps1
    bash
    cat flag.txt

    Expected output

    picoCTF{n1c3_job_f1nd1ng_th3_s3cr3t_in_the_im@g3}

    The extracted script XORs $string1 against $string2 byte-by-byte and writes the binary result to flag.txt. You can also paste the two strings into CyberChef's XOR operation to decode without PowerShell.

    What didn't work first

    Tried: Running the Python pixel extraction on duck.png instead of evil_duck.png

    duck.png is the clean original image with no hidden payload; reading its pixel LSBs produces random-looking garbage characters rather than a recognizable PowerShell script. The correct target is evil_duck.png, which is the file identified as suspicious by its unexpectedly large file size compared to duck.png.

    Tried: Trying to extract the flag by XORing the strings manually in CyberChef before running the pixel decoder

    The two XOR strings ($string1 and $string2) are embedded inside the PowerShell script that is hidden in evil_duck.png, not available as standalone data. You must first complete the pixel extraction step to obtain extracted.ps1 and read the two string values from it before CyberChef XOR can be applied.

    Learn more

    The embedded PowerShell payload (for reference).

    $out = "flag.txt"
    $enc = [system.Text.Encoding]::UTF8
    $string1 = "HEYWherE(IS_tNE)50uP?^DId_YOu(\]E@t*mY_3RD()B2g3l?"
    $string2 = "8,:8+14>Fx0l+$*KjVD>[o*.;+1|*[n&2G^201l&,Mv+_'T_B"
    $data1 = $enc.GetBytes($string1)
    $bytes = $enc.GetBytes($string2)
    for($i=0; $i -lt $bytes.count ; $i++) {
        $bytes[$i] = $bytes[$i] -bxor $data1[$i]
    }
    [System.IO.File]::WriteAllBytes("$out", $bytes)

    XOR-ing those two strings byte-by-byte produces the ASCII bytes of the flag. The XOR key and ciphertext are baked into the image - no external password or key file is needed.

Interactive tools
  • StegallDrop any file and Stegall runs every applicable steg technique in parallel: LSB sweeps, bit planes, spectrograms, polyglot carving, metadata, whitespace decode, and a 6-layer base/ROT/XOR/zlib cascade. Recursively unpacks results and surfaces flag matches.
  • 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{n1c3_job_f1nd1ng_th3_s3cr3t_in_the_im@g3}

The flag is recovered by exporting HTTP objects from the PCAP, then decoding evil_duck.png with the Invoke-PSImage reversal tool (or a Python pixel-reader) to extract a PowerShell XOR script that writes flag.txt.

Key takeaway

Steganography can encode arbitrary payloads inside image files by exploiting the low-significance bits of pixel color channels, which contribute almost nothing to visual appearance. This challenge stacks two techniques: pixel-level LSB encoding hides a script inside a PNG, and that script uses XOR to obscure the final payload. Network captures preserve the full transfer context, and browsing artifacts in the same PCAP (like visits to a stego tool repository) often point directly to the decoding method before any image analysis is needed.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for Forensics

What to try next