Hello! I've made a small puzzle recently that lead to a small train. The puzzle involved image steganography. I'm posting a solution here for people that are interested. ^_^

Solution:

Ok, so Steganography is the practice of concealing a file, message, image, or video within another file, message, image, or video (according to wikipedia). What this particular puzzle was about and what I tried to hint to with "hidden image steganography" is that inside the given image was hidden another image that contained the link to the giveaway train.
How to do this is explained reasonably well here

If that doesn't satisfy you, or you would like to read it from me, you can read my attempt at explaining here:

=========================================== my explanation ===========================================

In order to understand how you could hide an image in another image, you first need to understand how an image is stored inside a computer.

An electronic image is composed of very small squares which have a constant, solid color (called pixels). If you get a lot of those spots of color, you can make yourself an image. A pixel itself has three components: red, green, blue (RGB). Each of these is a number from 0 to 255 which say how much of that color is in the pixel. For instance the pixel (255, 0, 0) is completely red while (255, 255, 255) has the maximum amount of red, green and blue and this yields white. (0, 0, 0) is black.
We now need to move from the decimal number system to the binary number system.

  • In decimal, you have 10 digits (0,1,...,9) and each number is of the type a 10^0 + b 10^1 + c 10^2 + d 10^3 + ...; here a, b, c, d are digits from 0 to 9.
  • In binary, you have 2 digits (0,1) and each number is of the type a 2^0 + b 2^1 + c 2^2 + d 2^3 + ...; here, a, b, c, d are either 0 or 1.
    Uncoincidentally, the red, green and blue components range from 0 to 255 because these are the values that you can get if you make a number of at most 8 binary digits:
    1 2^0 + 1 2^1 + 1 2^2 + 1 2^3 + 1 2^4 + 1 2^5 + 1 2^6 + 1 2^7 = 1 + 2 + 4 + 8 + ... 128 = 255.
    So
    0 <= a 2^0 + b 2^1 + c 2^2 + d 2^3 + e 2^4 + f 2^5 + g 2^6 + h 2^7 <= 255.

Now, just like you represent a number in decimal by placing together digits, you do the same in binary, except you use just 0 and 1. This gives you numbers that look like 1101, which is 1 2^3 + 1 2^2 + 0 2^1 + 1 2^0.

Each color component of a pixel is represented by an 8-bit number, like 10001010. If you change the last bit the number changes by adding/substracting 1, if you do the same with the second-last bit, the number can change by 2, the next bit changes it by 4 and so on. With this, you can see the the further to the left you go, the more impact changing a bit has to the overall number value. This is why the leftmost bit is called the most significant bit and the rightmost bit is called the least significant bit.

Let's say we have two images of the same dimensions, one which will be the host and one that will be hidden inside it. To hide an image in the other, what you do is that you take each corresponding pixels of the two, and for each color component you make a new number that has some number of significant bits from the host image in the left side and some number of significant bits from the hidden image in the right side. For instance, if you have 1111 1111 in the host image pixel and 0110 0101 in the hidden image pixel and you go half-half with what bits you use for each image, you would get 1111 0110. By doing this for all pixels and all color components, you can create a new image. Since you kept significant bits from the host image, the new color numbers are usually not far off the original numbers, so the new composite image looks a lot like the original image. It's not the same, but it can be difficult for the human eye to notice.

To get back the hidden image, you just go through the pixels of the composite image again and make a new pixel by taking the rightmost bits that you used when making it and placing them on the left with zeroes at the end. For instance, if you take the 1111 0110 number that we got earlier, you would now have 0110 0000. As you might have noticed, this is different from the 0110 0101 that we had originally in the hidden image, but those last 4 bits don't make that much of a difference. The decoded image looks slightly different, sure, but you would still probably get the same idea from it.

=========================================== my explanation ===========================================

In this particular puzzle, the hidden image just has black text on a white background. The black text contained something like /xxxxx/ which represent the giveaway link. Since I just had only full black and full white pixels, I could use 7 leftmost bits from the host image and just 1 rightmost bit from the hidden image to make the new image. The resulting image looks almost identical to the original image and you can still quite clearly understand what the hidden image was when you extract it again.

I've personally done the work for this using some python code and the PILLOW library for working with images. I've posted the commented code on pastebin. You can find the code for extracting here. If you are interested in how I've added the photos, you can see here.

Also, some people have used online solvers like these ones:
https://incoherency.co.uk/image-steganography/
https://osric.com/chris/steganography/decode.html

Oh, right. There you go

4 years ago

Comment has been collapsed.

Oh, I bookmarked that puzzle for later and forgot about it :|

4 years ago
Permalink

Comment has been collapsed.

Thanks for the source code solution :)

4 years ago
Permalink

Comment has been collapsed.

Of course. It was a programming puzzle after all :D

4 years ago
Permalink

Comment has been collapsed.

It was a good puzzle. Thanks for the solution

4 years ago
Permalink

Comment has been collapsed.

I'm glad you found it useful ^_^

4 years ago
Permalink

Comment has been collapsed.

Wow I need to come back to that and read it when I'm home. I suck at these and I love learning new things.
Thanks for the puzzle and the detailed explanation!

4 years ago
Permalink

Comment has been collapsed.

I'm glad you found it useful ^_^

4 years ago
Permalink

Comment has been collapsed.

This is a great explanation, thank you!

4 years ago
Permalink

Comment has been collapsed.

I'm glad you found it useful ^_^

4 years ago
Permalink

Comment has been collapsed.

Sign in through Steam to add a comment.