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. Get the files from the challenge page on CyLab Security Academy (formerly play.picoctf.org).
Install Wireshark to inspect and export objects from the capture.
sudo apt install wiresharkSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Export HTTP objects from the capture
ObservationThe capture mixes TLS-encrypted traffic with plain HTTP. Export the HTTP objects first, since those transfers are readable immediately and may well carry something suspicious.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 Allbashls -lh duck.png evil_duck.pngbashfile duck.png evil_duck.pngWhat didn't work first
Tried: Running steghide extract -sf evil_duck.png to find the hidden data
steghide uses its own passphrase-protected format, modifying DCT coefficients in JPEG or manipulating a palette, and reports that it could not extract anything, because this PNG uses Invoke-PSImage's 4-bit pixel encoding instead. No passphrase guess helps. Read the 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 one bit per channel. Invoke-PSImage writes into the low four bits, so zsteg returns garbled output or nothing. Target bits 0 through 3 of the blue and green channels directly 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
steghideandzstegfind 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.
Step 2Identify the steganography scheme: Invoke-PSImage
Observationevil_duck.png is more than twice the size of duck.png at identical dimensions and visibly lower quality, and the capture's browsing history includes PowerShell and GitHub. That points at a PowerShell pixel steganography tool such as Invoke-PSImage.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.
Step 3Decode evil_duck.png and run the extracted script
ObservationInvoke-PSImage packs exactly one payload byte per pixel, into bits 0 through 3 of the blue and green channels. A Python PIL loop reconstructs those nibbles and recovers the hidden PowerShell script, which 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):pythonpython3 -c "pythonfrom PIL import Imagebashim = Image.open('evil_duck.png')bashw, h = im.sizebashout = []bashfor x in range(h):bashfor y in range(w):bashr, g, b = im.getpixel((y, x))bashout.append(chr(((b & 15) << 4) | (g & 15)))pythonprint(''.join(out))" > extracted.ps1bashbash# Then run the extracted PowerShell (Windows / pwsh):bashpwsh extracted.ps1bashcat flag.txtExpected output
picoCTF{n1c3_job_f1nd1ng_th3_s3cr3t_in_the_im@g3}The extracted script XORs
$string1against$string2byte-by-byte and writes the binary result toflag.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 with no payload in it, so reading its pixel LSBs gives random-looking garbage rather than a PowerShell script. The target is evil_duck.png, the file whose unexpectedly large size marked it as suspicious.
Tried: Trying to extract the flag by XORing the strings manually in CyberChef before running the pixel decoder
The two XOR strings live inside the PowerShell script hidden in evil_duck.png; they are not available separately. Finish the pixel extraction, read both values out of the recovered script, and only then can CyberChef's XOR do anything.
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.