304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

Image Steganography – Ship and Ship2 (MicroCTF 2017)

This week I’d like to share some basic image steganography techniques that I used during the Amazon MicroCTF 2017.

Ship 1

The first challenge that I faced was simple, but one common to CTFs.

First, I opened the image and took a look at it.

Image Steganography - Ship

Seeing nothing of interest in the particular image, I checked it for strings. While this is not always fruitful, it is always worth checking for coverage’s sake.

root@kali:~# strings ship.png | grep CTF

Next, I opened up stegsolve.jar. This is a handy tool written by Cronos that simplifies a number of common image analysis techniques.

Looking through the various layers, I found my flag in the Red, Blue, and Green plane 0!

Image Steganography - Flag 1

The reason that the flag showed up here is that it was hidden in the LSB of the original image.

Ship 2

The next challenge was very like the first, albeit a bit harder.

First, I opened up the picture, and it looked similar to the first.

Image Steganography - Ship 2

Next, I ran strings again, but it still wasn’t fruitful.

root@kali:~# strings ship2.png | grep CTF

Once I got back to the Red/Blue/Green plane 0, I found the next step of my challenge.

Image Steganography - Flag 2

After searching the internet and various character maps for some time, I discovered that each of these symbols belongs to the dingbats font.

Unfortunately, I was unable to turn this string into the final flag in time, keeping me outside of the top 10.

Talking to the organizers, the final flag is in the format of “CTF{xxxxxxxx}”.

I attempted to use the following script to brute force a shift from the digits I found.

import string

theChars = ['92', '70', '67', '73', '9B', '98',
            '88', '88', '99', '85', '8c', '84', '91', '9d']

charInts = []

for c in theChars:
    x = int(c, 16)

# 157 is largest

for count in range(-98, 157):
    newString = []
    for x in charInts:
        x -= count
    modified = ''.join(chr(x) for x in newString)
    if all(c in string.printable for c in modified):
        print "PRINTABLE @ " + str(count) + " = " + str(modified)

Unfortunately, none of the outputted strings matched the proper format.

PRINTABLE @ 31 = sQHT|yiizfmer~
PRINTABLE @ 32 = rPGS{xhhyeldq}
PRINTABLE @ 33 = qOFRzwggxdkcp|
PRINTABLE @ 34 = pNEQyvffwcjbo{
PRINTABLE @ 35 = oMDPxueevbianz
PRINTABLE @ 36 = nLCOwtdduah`my
PRINTABLE @ 37 = mKBNvscct`g_lx
PRINTABLE @ 38 = lJAMurbbs_f^kw
PRINTABLE @ 39 = kI@Ltqaar^e]jv
PRINTABLE @ 40 = jH?Ksp``q]d\iu
PRINTABLE @ 41 = iG>Jro__p\c[ht
PRINTABLE @ 42 = hF=Iqn^^o[bZgs
PRINTABLE @ 51 = _=4@heUUfRYQ^j
PRINTABLE @ 52 = ^<3?gdTTeQXP]i
PRINTABLE @ 53 = ];2>fcSSdPWO\h
PRINTABLE @ 54 = \:1=ebRRcOVN[g
PRINTABLE @ 55 = [90KW

Resources and References – CTF Resources guide on steganography, including text or images hidden in images. – The Caesum image steganography guide, including the link to stegtool.jar. – Hexcellents tools and tips for a few possible image steganography challenges.

Image Steganography – Conclusion

While I am far from an image steganography expert, hopefully you learned a few new tools or techniques from this post.

If you have any idea what I’m missing for ship2, then please let me know.

I may have another write-up or two coming from the MicroCTF, so stay tuned!

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.