Skip to content

Instantly share code, notes, and snippets.

@Und3rf10w
Last active January 31, 2018 04:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Und3rf10w/1158987ca570a64b5e5643ac0aef1dd4 to your computer and use it in GitHub Desktop.
Save Und3rf10w/1158987ca570a64b5e5643ac0aef1dd4 to your computer and use it in GitHub Desktop.
Experiment at applying LSB stego to gifs
from PIL import Image
from cStringIO import StringIO
import requests
import imageio
import base64
import re
def GetGifPixel(gif):
frame = Image.open(gif)
nframes = 0
while frame:
print "On frame %d" %(nframes + 1)
pix = frame.load()
print "Upper left pixel for this frame is: %s" % (str(pix[0,0]))
nframes += 1
del pix # yay memory cleanup!
try:
frame.seek(nframes)
except EOFError:
break
return True
def AnalyseGif(gif):
gif = Image.open(gif)
print "Analyzing gif..."
print "Gif contains %d frames" %(gif.n_frames)
print "Gif dimensions: %dx%d" %(gif.size[0], gif.size[1])
print "This gif can store a total of %d bytes" %(gif.n_frames * (gif.size[1]-1))
return True
def GenerateEvilGif(data, gif):
data = base64.urlsafe_b64encode(data)
data_list = [data[i:i+(len(gif[0]) - 1)] for i in range(0, len(data), (len(gif[0])) - 1)]
print "Spliting given data into %d chunks" % (len(data_list))
gif[0][0,0][2] = len(data_list)
for frame in range(1, len(data_list) + 1):
for chunk in data_list:
for index, byte in enumerate(chunk):
gif[frame][index,index][2] = ord(byte)
print "Original data: %s" % (str(data))
# gif right now is a list. Need to convert back to an image
# This is killing the gif
evil_gif_io = StringIO()
with imageio.get_writer(evil_gif_io, mode='I', format="GIF") as writer:
for image in gif:
writer.append_data(image)
return evil_gif_io
def RebuildData(gif):
rebuild_size = gif[0][0,0][2]
rebuild_list = []
for frame in range(1, rebuild_size + 1):
for y in range(0, len(gif[0])):
rebuild_list.append(chr(gif[frame][y,y][2]))
rebuilt_string = ''.join(rebuild_list).strip('\0')
new_data = re.search(r'(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?', ''.join(rebuild_list))
print "Reconstructed data: %s" % (str(new_data.group()))
return base64.urlsafe_b64decode(str(new_data.group()))
# Enoding and sending logic
# ------------
eicar = 'X5O!P%@AP[4\PZX54(P^)7CC)7}'
eicar += '$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'
nyan_cat_link = "http://media3.giphy.com/media/sIIhZliB2McAo/giphy.gif"
nyan_cat_io = StringIO(requests.get(nyan_cat_link).content)
evil_list = imageio.mimread(nyan_cat_io)
evil_gif_io = GenerateEvilGif(eicar, evil_list)
# Now the recontructed gif in 'evil_gif_io' can be uploaded
# Receiving and decoding logic
# ------------
# Let's pretend we transferred that gif somewhere, downloaded it (like how we got the nyan cat gif),
# converted it to an IO (exactly we did above), and saved it in evil_gif_io. We can extract the
# bytes like so:
# This is what it would look like in production, as you would have dowloaded this from the internet in evil_gif_io
# rebuilt_gif_list = imageio.mimread(evil_gif_io)
# Instead, here's a workaround to demonstrate this PoC
rebuilt_gif_list = imageio.mimread(evil_gif_io.getvalue())
RebuildData(rebuilt_gif_list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment