[CryptoChallenge] Basic Stego - Making Of (Spoiler warning)

steganography
crackme

(pico) #1

As requested here is the program used to produce the image for the Basic Stego challenge we published yesterday.

If you are still trying to solve it, you may want to wait to read this.

The image was generated with a very simple C program using libgd. `libgd’ (http://libgd.github.io/) is a classical library to produce images. The name stands for _GIF Draw. It was (I think still is) very popular to generate images on websites and, despite of its name, it supports many different images formats nowadays.

The Encoding

To easily understand the code, I will just explain how the message has been encoded into the image. As you probably already know the message was stored in the blue component of the image. The blue component was chose as this is the light wave length the eye is less sensitive to. Green is the colour with the light wave length firing the highest excitation in the cell in the back of our retina. That’s one of the reason the old monochrome displays used green phosphor. The image looked brighter with less energy :stuck_out_tongue:

Anyway, the program, just stores an ASCII string in this component. ASCII text is actually 7 bits long, so the program keeps the higher bit to do not fully destroy the blue component. For the selected image, with a lot of black, it does not really make a difference, but this is something you may consider when writing your own encoders.

Then, instead of stopping once the original message has been stored in the image, the rest of the image is filled with random data, just to make the whole image look a bit more uniform and making a bit more difficult to figure out where the hidden message is actually stored.

Finally, note that you have to use an image format that supports lossless compression or no compression at all. GIF, PNG, BMP should be fine, but JPEG will destroy your encoding… it can be tweaked but in general it will just destroy your data. We have to do encode the information in a different way in that case.

The code

The code is not very optimal, but, as you had already checked it works :slight_smile:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gd.h>

char *s = "0x00sec.org is an awesome community!\n"
  "Open the image with GIMP and separate the channels in layers (Colors > Components > Decompose)\n"
  "Then remove the green and red layers and export the file as .pgm... Choose RAW encoding\n"
  "Then you can just cat the pgm file to see this message\n"
  "\0";

int 
main(int argc, char *argv[])
{
  FILE *f;
  gdImagePtr  image;                                   
  int         i, l, x, y, w, h;
  int         rgb, color, r, g, b, c;

  if (argc != 2)
    {
      fprintf (stderr, "usage:%s input_image.png\n", argv[0]);
      exit (1);
    }
  f = fopen (argv[1], "rb");

  image = gdImageCreateFromPng (f);
  w = image->sx;
  h = image->sy;
  fprintf (stderr, "Image size: %dx%d\n", image->sx, image->sy);
  fclose (f);

  i = 0;
  l = strlen (s) + 1;
  for (y = 0; y < h; y++)
    {
      for (x = 0; x < w; x++)
	{
	  if (i >= l)
	    c = rand () % 127;
	  else
	    c = s[i];

	  /* Get pixel value */
	  rgb = gdImageGetPixel (image, x, y);
	  
	  r = (gdImageRed(image, rgb));
	  g = (gdImageGreen(image, rgb));
	  b = (gdImageBlue(image, rgb) & 0x80) + c;
	  
	  color = gdTrueColor (r, g, b);
	  gdImageSetPixel (image, x, y, color);
	  i++;
	}
    }

  gdImagePng (image, stdout);
  return 0;
}

Well, there is not much to say about the program. Just loads the image and then, for each pixel, either adds the ASCII value of the message into the lower bits of the blue component or it adds some random value.

To compile the code just link the library. Remember to install the dev package for libgd in your system.

gcc -o stego_enc stego_enc.c -lgd

Supossing you have named stego_enc.c to your source code file

Why it can be decoded without a program?

This is just by chance. What happen is that the whole message fits into an image area that is black. That means that the eighth bit of each blue component is just 0 and then the blue component is effectively containing the ASCII value of the message. Try to use a image with something different to black in the first image row and you will get some strange results… OK supposing some pixels has a blue component higher than 127.

The PGM format mentioned in the hints is a raw grey scale format. When saving the blue component in this format, the values of the text are actually popping up from the file when you just cat it.

Actually this can be done in just one command, if you have the tool pngtopnm installed.

pngtopnm c.png | head -10

However, I though that using GIMP to manually go through the process was more didactic.

It is very easy to modify this program to produce stego messages without artifacts as strong as the ones in the “Basic Stego CryptoChallenger”.


[CryptoChallenge] Basic Stego 2 - Solution
[CryptoChallenge] Basic Stego
(oaktree) #2

Why do you use & here?


(pico) #3

@oaktree to mask the lower 7 bits where the message character goes (each character is 7bits). If you just add, the blue component can overflow (go over 255). As the value cannot be clamped (otherwise you cannot recover the stored character) it will have a very noticeable impact on the image (a original high value will become a low value after the overflow).

For illustration purposes:


#4

Reminds me of when I used to hide a cipher in a picture, and see if anyone ever thought of checking out the picture up close! Good job! Yet again you amaze me with these absolutely great posts!


(system) #5

This topic was automatically closed after 30 days. New replies are no longer allowed.