找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2888

积分

1

好友

403

主题
发表于 11 小时前 | 查看: 0| 回复: 0

最近在复盘 SQL注入 相关的技术,看到一个利用文件EXIF信息进行注入的技巧非常有意思。这个攻击的核心在于,后端程序可能会将检测到的文件EXIF信息直接拼接到SQL语句中,从而导致注入漏洞。

本文将从一个实际的CTF题目出发,解析攻击原理,并深入到PHP底层源码,通过调试来验证整个利用链。

什么是EXIF?

在深入探讨这个技巧之前,我们先简单了解一下什么是EXIF。

EXIF是可交换图像文件格式的缩写,它是为数码相机照片专门设定的,能够记录照片的属性信息和拍摄时的数据。例如,当你用手机或相机拍照时,EXIF会记录下光圈大小、焦距、拍摄时间、设备型号等一系列属性。

从一道CTF题目说起

这里我们以一道模拟的CTF题目为例。题目环境是一个简单的文件上传后台。

打开上传页面,是一个非常基础的文件上传表单。

文件上传界面

经过测试发现,上传的任何文件都不会被过滤,且每次上传的文件名都不同。这通常意味着后端使用了随机数生成MD5值作为新文件名。查看文件列表时,我们能看到每个文件对应的“filetype”。

文件列表与类型信息

观察filetype字段,其内容格式非常眼熟,类似于Linux系统中 file 命令的输出结果。查询 PHP 手册可以发现,finfo 对象及其 finfo_file() 函数正是用来获取此类文件类型信息的。

PHP finfo_file函数文档

因此,可以合理猜测,filetype 字段的数据来源于 finfo_file() 函数的返回结果,并且该结果被直接拼接到了 数据库 的INSERT语句中,从而构成了SQL注入点。

那么问题来了:如何控制 finfo_file() 函数的返回结果呢?

利用EXIF信息构造注入

在Linux中,file 命令可以查看文件信息,如下图所示,其输出与题目中的 filetype 字段高度相似。

file命令查看文件信息

我们可以使用 exiftool 工具来修改图片的EXIF信息(如Comment评论字段),从而“污染” file 命令的输出。

假设后端SQL语句大致如下(实战中需要不断测试和猜测):

insert into columns('字段1','字段2','字段3') value('值1','值2','值3')

那么我们可以构造注入Payload为:

123\"');select if(1,sleep(5),sleep(5));--+

使用 exiftool 执行以下命令,将Payload写入图片的Comment字段:

exiftool -overwrite_original -comment="123\"');select if(1,sleep(5),sleep(5));--+" avatar.jpg

再次使用 file 命令查看图片,可以看到我们的注入语句已经成功嵌入到了文件信息中。

使用exiftool修改图片Comment并验证

此时上传这张图片,如果页面响应出现明显延迟,就证明时间盲注成功。后续利用 into outfile 写入Webshell等操作就属于常规操作,此处不再赘述。

那么,究竟是哪个函数如此“诚实”地将EXIF信息返回,并导致了注入呢?让我们深入题目源码一探究竟。

源码分析:漏洞根源

我们直接查看核心的上传处理代码。为了突出重点,以下仅展示关键部分:

$filename = md5(md5(rand(1,10000))).".zip";
$filetype = (new finfo)->file($_FILES['file']['tmp_name']);
$filepath = "upload/".$filename;
$sql = "INSERT INTO file(filename,filepath,filetype) VALUES ('".$filename."','".$filepath."','".$filetype."');";
  • 第一行:使用双重MD5哈希的随机数作为新文件名,验证了我们之前的猜测。
  • 第二行:漏洞核心。使用 finfo::file() 方法获取上传临时文件的类型信息。
  • 第四行:存在SQL注入的SQL语句,$filetype 被未经任何过滤直接拼接。

列文件列表的代码逻辑很简单,就是从数据库读取并展示,不再详述。

所以,整个注入链的罪魁祸首就是这一行:

$filetype = (new finfo)->file($_FILES['file']['tmp_name']);

finfo::file() 方法在PHP手册中的描述相对简单。为了彻底理解其行为,我们需要深入PHP底层进行跟踪和调试。

深入底层:跟踪 finfo::file

finfo::file 方法在PHP源码的 ext/fileinfo/fileinfo.c 中定义。finfo 类主要包含以下几个方法:

class finfo
{
    /** @alias finfo_open */
    public function __construct(int $flags = FILEINFO_NONE, ?string $magic_database = null) {}

    /**
     * @param resource|null $context
     * @return string|false
     * @alias finfo_file
     */
    public function file(string $filename, int $flags = FILEINFO_NONE, $context = null) {}

    /** @alias finfo_buffer */
    public function buffer(string $string, int $flags = FILEINFO_NONE, $context = null) {}

    /** @alias finfo_set_flags */
    public function set_flags(int $flags) {}
}

我们跟进 finfo::file 的实际实现 finfo_file 函数。通过调试,可以定位到关键的执行流程。

首先,在 ext/fileinfo/fileinfo.c 中,函数会调用 php_stream_open_wrapper_ex 打开文件流。
php_stream_open_wrapper_ex 调用处

随后,进入 magic_stream 函数,并进一步调用 file_or_stream 函数进行处理。
magic_stream 函数内部

file_or_stream 函数的最后,其返回值由 file_getbuffer 函数决定。
file_or_stream 函数返回

跟踪进入 file_getbuffer 函数,此时观察数据结构,可以清晰看到 ms->o.buf 中已经包含了从图片文件中读取到的EXIF信息,其中就有我们植入的恶意注释内容。
file_getbuffer 函数内部

至此,整个流程就非常清晰了:finfo::file() 方法会调用底层的libmagic库对文件进行检测,该库会读取包括EXIF注释在内的各种文件元数据,并将其作为文件类型描述信息的一部分返回。当后端开发者未经处理直接将此信息拼接进SQL语句时,便导致了注入漏洞。

总结与思考

这个利用图片EXIF信息进行SQL注入的技巧,虽然看似冷门,却揭示了安全攻防中一个重要的原则:任何来自用户可控输入的数据,在进入关键逻辑(如数据库查询)前都必须进行严格的校验和过滤,无论这个数据是来自表单、URL还是看似“无害”的文件元数据。

对于开发者而言,防范此类漏洞的关键在于:

  1. finfo_file() 等函数返回的内容进行过滤或转义。
  2. 使用参数化查询(预编译语句)来执行数据库操作,从根本上杜绝SQL拼接。

对于安全研究者来说,每深入理解一个攻击技巧,就意味着对系统脆弱点的认知又拓宽了一分。在云栈社区,我们鼓励这种深度探究的精神,因为只有透彻理解攻击,才能构建更有效的防御。




上一篇:CPU缓存与访存时间一致性问题解析
下一篇:SQL避坑指南:详解NULL、索引失效、JOIN过滤等5个易错点
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-25 20:31 , Processed in 0.295944 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表