— —– .-. … . .- .-. -.-. …. .. …- .

So, say you stumble across a zip file. You decompress this file, and find a small image file (named pwd.png), and another password protected zip file.

Given the name of the image, pwd.png, I think it’s safe to assume that what ever this image is, it contains the password for the zip file, so let’s figure that out. We see the following …

zoom in in you have to …

The contrast of the colors against each other kind of sucks, but there is obviously something there… Dashes (-), a dot (.), this looks to me to be Morse Code! Let’s feed this into CyberChef, which has a morse function built in, and see what comes back.

So —-. translates to the character “9”, which after attempting to unzip the zipfile using “9” as a password, we successfully unzip our compressed file, Unfortunately though, we find yet another password protected zip file along with another pwd.png file.

Alright, lets do this again… Open up the pwd.png file, get the morse code inside. There is an extra character this time… Feed it into CyberChef. Plug the password into the zip file while unzipping, and ….

Damn. Well, this is going to take some automation….

We notice once again that the password increases by one char. I think it is safe to assume that pattern continues on with possibly no end in length (until proven otherwise). Another thing we can observe about the password’s we’ve found so far, is that they are all numbers. We can attempt to brute force these passwords one after one, but with the length of the password growing by one or maybe even more each time (we don’t know), this becomes a exponentially longer and harder process each time that crack a zip file, making this process not impossible, but you might as well go watch some paint dry. One last thing we must also consider and might as well build into the code in case it does happen is what if numbers aren’t the only part of our charset? We are dealing with Morse code, which has translations to A-Z, 0-9, and some symbols too.

Google around and we can actually find a prebuilt python function to decode Morse to ASCII chars. It’ll save some time in the coding process, and I won’t be covering it here.

So we are going to write a python script that is going to do the following:

  • Analyze the pwd.png file using PIL
  • Translate the Morse code to ASCII
  • Extract data from the zip file with the decoded password
  • Repeat

Let’s start with the function to pull the Morse code from the pwd.png file. If we look at the file, we can see that it is at the pixel level.

A dot (.) is 1 pixel wide, a dash (-) is 3 pixels wide. The lines are also separated by a one pixel space. Using the Python Imaging Library (PIL), we can dump our pixels into an array of data and analyze the color of each pixel. We will keep a count, and be sure to analyze the pixel ahead of the one we are on to see if the dot or dash has ended. After the line is analyzed, we will have a string of dots and dashes that translates to a character, and after the entire image is analyzed, we will have the Morse code for entire password to our zip file.

try:
    import Image
except ImportError:
    from PIL import Image

count = 0
morse = ""
img = Image.open("pwd.png")
pixels = img.load()
width, height = img.size
basecolor = pixels[0,0]
morse_list = []

for y in range(height):
    morse_list.append(morse)
    morse = ""
    for x in range(width):
        if pixels[x,y] != basecolor:
            count+=1
            if count == 1 and pixels[x+1,y] == basecolor:
                morse += "."
                count = 0

            elif count == 3 and pixels[x+1,y] == basecolor:
                morse += "-"
                count = 0

In the code above, we make sure to set the base color of the image as the first pixel in the image. Any other color pixel will essentially be a part of or a whole Morse character (in the case of . being 1 pixel wide). We also use the base color to determine where the character ends with the x+1 in [x+1,y] referring to the next pixel in the row. The count for the character detection also gets reset after the end of char is found, as to reset for the next character.

We send morse_list (stripped of it’s leading white space) to our Morse decoder function, and in return it gives us our password in ASCII…

morse = " ".join(morse_list)
morse = morse.lstrip()
print(morse)
password = morse_decode(morse)

And just like that, we have made our own mini-sized Morse-to-ASCII OCR function! Cool!

Now all we have to do is write a function to unzip our zip files one by one, using the Morse OCR function we built to retrieve the password, and plug it into the unzipping process. We also concatenate the filename being run through the unzipper, and then decrease the count to count down as the filename gets “smaller”.

import zipfile

filenum = 998
header = "foo/foo_"
footer = ".zip"
filename = header + str(filenum) + footer
pwd = "foo/pwd.png"

while filenum >= 0:
    try:
        password = morse_ocr(pwd).encode()
        zip = zipfile.ZipFile(filename)
        zip.setpassword(password)
        zip.extractall()
        zip.close()
        filenum -= 1
        filename =  header + str(filenum) + footer

After this is completed, we can put everything put everything together, sit back, and wait …

-lunchb0x