Challenge Writeup: Squirrel


This little bugger caused me no end of grief the last two days.

It’s part of a ctf challenge. The text of the challenge reads as below.

a picture tells a story. search for more details. download

The download link is a zipped file containing the squirrel image above. Once unzipped, I checked the file out.

[bash 5.1.16] $ file squirrel.jpg
squirrel.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 180x180, segment length 16

Looks normal. Running strings produces a ton of output; I find it’s easier to start with longer bits and you don’t even need strings if you have grep.

[bash 5.1.16] $ grep -aEo '[[:graph:]]{15,}' squirrel.jpg

That mediafire link looks interesting. It gives you, which is an encrypted zip file. No clue about the password, so I needed to crack it. I started by trying fcrackzip (because it was in the Arch Linux repositories), but… it didn’t work with the rockyou wordlist. Even running it with just a simple password input throws tons of errors.

[bash 5.1.16] $ fcrackzip -v -u -D -p /usr/share/wordlists/seclists/Passwords/Leaked-Databases/rockyou.txt
*** buffer overflow detected ***: terminated
Aborted (core dumped)

[bash 5.1.16] $ fcrackzip -uvp squirrel
found file 'evil/EVIL', (size cp/uc 415382/422982, flags 9, chk 982f)
sh: -c: line 1: unexpected EOF while looking for matching `"'
sh: -c: line 2: syntax error: unexpected end of file
sh: -c: line 1: unexpected EOF while looking for matching `"'
sh: -c: line 2: syntax error: unexpected end of file

Next try: zip2john. I originally skipped over this option because I couldn’t find it to install on Arch, but eventually I realized that’s because it’s part of john, which is on Arch.

[bash 5.1.16] $ zip2john > iamnotreal.john
ver 2.0 efh 5455 efh 7875 PKZIP Encr: 2b chk, TS_chk, cmplen=415382, decmplen=422982, crc=B9A27A8

[bash 5.1.16] $ john iamnotreal.john --wordlist=/usr/share/wordlists/seclists/Passwords/Leaked-Databases/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
squirrel07       (
1g 0:00:00:00 DONE (2022-02-10 09:22) 2.325g/s 2971Kp/s 2971Kc/s 2971KC/s swell!..slavemaster69
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Using the cracked password (squirrel07), unzips to a folder called evil with one file in it, called EVIL. Scary! What’s scarier is the evil/EVIL file doesn’t match a known filetype.

[bash 5.1.16] $ unzip
[] evil/EVIL password:
  inflating: evil/EVIL

[bash 5.1.16] $ file evil/EVIL
evil/EVIL: data

greping for strings in evil/EVIL yielded another mediafire link, but it led to a missing file. The contest organizers confirmed this was by design.

I tried a few file carvers: binwalk, foremost, and scalpel. They all gave basically the same few results: two copies of a smaller (lower resolution) version of the original squirrel picture. Out of curiosity, I ran the carver on the original squirrel.jpg. Same result: two copies of the smaller version.

[bash 5.1.16] $ md5sum evilEVIL_output/jpg/* squirreljpg_output/jpg/*
489243ba7f9ba7998e4a777253ecde35  evilEVIL_output/jpg/00000002.jpg
489243ba7f9ba7998e4a777253ecde35  evilEVIL_output/jpg/00000015.jpg
489243ba7f9ba7998e4a777253ecde35  squirreljpg_output/jpg/00000002.jpg
489243ba7f9ba7998e4a777253ecde35  squirreljpg_output/jpg/00000016.jpg

So, it looks like our EVIL might be a squirrel JPEG. Attempting to open it in any number of image viewers failed, so I needed to look closely at the format. I compared the first few bytes against squirrel.jpg.

[bash 5.1.16] $ xxd squirrel.jpg | head -n1
00000000: ffd8 ffe0 0010 4a46 4946 0001 0101 00b4  ......JFIF......

[bash 5.1.16] $ xxd evil/EVIL | head -n1
00000000: a119 74bc 0010 4a46 4946 0001 0101 0048  ..t...JFIF.....H

This seemed to confirm my suspicions: it looks like a JPEG, but is missing the file signature (in the first four bytes). At this point things went off the rails and I got stuck. The right way to do this would be to open evil/EVIL in a hex editor, change the first four bytes, and save the file. But no, I try it in Vim, with xxd. I open it using the binary switch (vim -b evil/EVIL), run it through xxd (:%!xxd), and get a nice hex representation. I change the first four bytes from a119 74bc to ffd8 ffe0, then use xxd to go back to binary (:%!xxd -r). Hooray, right? I try to open the file again in an image viewer and I get Error interpreting JPEG image file (Invalid JPEG file structure: two SOI markers). So I try a lot of other things: removing the first bit of the file (up to the next SOI marker ffd8 ffe0), which gets me “Error interpreting JPEG image file (Bogus DHT index 4)”, looking more closely at the found strings, OSINT on the broken mediafire link, wasting hours and hours….

Eventually I asked, and the contest organizer confirmed that fixing the first four bytes should have resulted in a valid JPEG. What had I done wrong? I piped the original evil/EVIL and my “fixed” version each to xxd and then ran diff on the output, expecting to see that they only differed in the first four bytes. WRONG! Somehow my attempt to change only the first four bytes resulted in a radically different file. PEBKAC, surely, so I tried it again, and again… and confirmed that whatever I was doing in Vim was not working. I tried walking through the binary -> xxd -> binary steps in Vim, without changing anything: the file still changed.

[bash 5.1.16] $ md5sum EVIL.fix evil/EVIL
8902c2752e0a8e4a21eef405d4841c52  EVIL.fix
5cd6869c76d3ae42eb1a2b5cf27c299e  evil/EVIL

Based on a StackOverflow post, I think it has to do with file encodings, or something. I tried everything I could think of to make Vim treat the file correctly, and time ran out on the contest. Finally, I decided to try dd. And it worked.

sh 5.1.16] $ echo -ne \\xff\\xd8\\xff\\xe0 | dd conv=notrunc bs=4 count=1 of=EVIL.jpg
1+0 records in
1+0 records out
4 bytes copied, 7.6742e-05 s, 52.1 kB/s

The file (the picture below) opened just fine, and the flag was had… too late. I have Bless and hexcurse installed now (makes a nice symmetry of names); I’ll use one of those next time.


[bash 5.1.16] $ echo MZWGCZ33IV3DC3C7KM4XK2LSOIZWY6T5 | base32 -d

Then I saw Braden Best’s comment on the StackOverflow answer:

The only thing that works is :r !xxd file (or $ xxd file | vim -) to read, and :w !xxd -r > file to write, but this is not ideal.

Braden Best, Apr 1 2018 at 19:46

I tried it. It worked. I am very upset.