15

I am trying to overcome a CTF steganography challenge. I tried different methods to unhide the hidden data in the file without luck. I used JPEGsnoop on the image and I got this output:

*** Decoding SCAN Data ***
  OFFSET: 0x0000026F
  Scan Decode Mode: Full IDCT (AC + DC)
  Scan Data encountered marker   0xFFD9 @ 0x0001DF10.0
*** NOTE: YCC Clipped. MCU=(  15,  10) YCC=(  256,  132,  130) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  15,  10) YCC=(  256,  123,  121) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  256,  131,  126) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  258,  127,  127) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  256,  126,  126) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  256,  129,  122) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  258,  129,  124) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  16,  10) YCC=(  258,  126,  129) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  17,  10) YCC=(  256,  120,  137) Y Overflow @ Offset 0x0001DF0F.3
*** NOTE: YCC Clipped. MCU=(  17,  10) YCC=(  258,  124,  126) Y Overflow @ Offset 0x0001DF0F.3
    Only reported first 10 instances of this message...
  Compression stats:
    Compression Ratio: 31.12:1
    Bits per pixel:     0.77:1

Can these notes indicate on a hidden data segment?

Update

The image is well formed. There are no double FFD9. the file ends with FFD9 without gap between the end of data and the FFD9. I tried to find the "overshooting" luma (Y) values using python:

#!/usr/bin/python

from PIL import Image


def main():
    im = Image.open("l0v3m3.jpg")
    im = im.convert("YCbCr")
    y, cb, cr = im.split()
    seq = y.getdata()
    for x in seq:
        if x > 255:
            print x


if __name__ == '__main__':
    main()

But, as it seems, the Y values are clipped. If someone knows a way to get the Y value without clipping I would be very thankful. btw: here is the file

Uriel Frankel
  • 251
  • 2
  • 6
  • by the way, some JPEG encoders actually use overshooting intentionally for quality reasons when encoding black and white inputs, at least mozjpeg does this. so it's possible to encounter overshooting in "regular" jpeg files as well. – Display Name Jul 01 '17 at 18:26

1 Answers1

21

I don't think you're looking at a hidden data segment. The FFD9 is an EOI marker and data following it should be ignored, so I wouldn't expect JPEGSnoop to try to actually decode it. The fact that it does seems to indicate the error isn't related to the EOI.

An illegal YCC value could indicate that an out-of-range value is actually used to code information. Several possible schemes are possible. For example you might be looking at a double-bit scheme in which violation either do not occur, or occur in singlets or in pairs:

OK OK    = it was not possible to code a bit in this pixel
FAIL OK  = this pixel codes a zero (or a one)
FAIL FAIL= this pixel codes a one (or a zero)

Since most JPEG decoders silently clip values out of range, this kind of encoding is not immediately visible, and does not greatly impact on image size (i.e., there is no high frequency noise superimposed on the image).

Another scheme possible with JPEG specifically is to abuse ITU-R BT.601 encoding, which has legal YCC values between 16 and 235 (but in a byte you can store values 0-255). Whenever you find a pixel that is very black (16) or very white (235), that is suitable for embedding four extra bits in its least significant nibble. Output 12 instead of 16, and ITU decoders will translate it as "black", while your steganography decoder will read "1100b".

Also, when YCC is denormal, the values for the Cb and Cr components should be insignificant (I think). Black color has no hue, so whatever hue you specify will always decode to black. This means that you can use these values to store additional information.

On the other hand, everything above might be wrong and those data might actually be after the End-Of-Image marker. What it is, I couldn't say; you can try and view it through a hex editor and see whether it makes sense. It could be, say, an ASCII sequence, and the reason it throws YCC clipping error is because "SQUEAMISH OSSIFRAGE" is not actually a valid DCT decomposition after all, so it vanishes to zero (or to 1), and once converted to YCC it naturally falls outside the range.

Update

Okay, the file ends with FFD9 (EOI), so provided it hasn't got two EOIs:

 ....legitimate image.... FFD9 EXTRA DATA ...FFD9

then the YCC "errors" reported by JPEGSnoop must refer to the "legitimate image" data.

These bytes are correctly DCT decoded, but they decode to a triplet (Y, Cb, Cr) where the Y value is out of range, and is therefore clipped. You see in the JPEGsnoop debug that you have values of 256 and 258, which are (obviously) not 8 bit.

This can be used to carry information by mapping denormal YCbCr values to single bits:

         JPEG    Stego
255 ...  white   00
256 ...  white   01
257 ...  white   10
258 ...  white   11

This way, every pixel with full luma might encode two bits of hidden information (or you might encode only 0 as 256 and 1 as 258, if by some chance the integer algorithm never outputs 257).

To decode it, you need to recover all those samples (you need some JPEG decoder that does not clip values), and dump out the "extra" bits. Then figure out what those bits mean.

LSerni
  • 22,521
  • 4
  • 51
  • 60
  • 23
    Answers like this is why i love this site. Someone asks about a JPEG error in the context of security and you give him an analysis of the stated behavior, references for the internal workings that are relevant to his goal, possible encoding schemes and methods to verify and build upon your ideas. I'd literally trust an interested SE crowd to save my life over someone getting paid to do it. – J.A.K. Feb 13 '17 at 12:53
  • The above file ends with FFD9. What I understand from your answer that this might be stegangraphy, but you can tell for sure. Is that correct? – Uriel Frankel Feb 13 '17 at 13:41
  • 1
    It **could** of course be a very buggy JPEG encoder, but... in a context of steganography, it is likely to be an intentionally poor stego scheme (there are more clever schemes that don't give themselves away by outputting illegal values. Of course, for educational purposes, you *want* the scheme to be somewhat visible, and this seems to be what happened here). – LSerni Feb 13 '17 at 15:29
  • It does not have 2 EOI's. I can send you the file. BTW the link - JPEG decoder that does not clip values - is wrong (i think) – Uriel Frankel Feb 13 '17 at 15:37