0x00 前言
PHP里头比较常见的Web图像处理库有GD和ImageMagick
GD里头比较常用的有imagecopyresized和imagecopyresampled 怎么调戏这两个函数的变换已经有很多文章和代码了,比如Github gist
今天简单看看ImageMagick里头有没有什么可以保留数据的方法
0x01 开始
我们的Imagemagick版本
stonemoe@desktop ~/Desktop> magick --version
Version: ImageMagick 7.0.10-6 Q16 x86_64 2020-04-07 https://imagemagick.org
Copyright: © 1999-2020 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(4.5)
Delegates (built-in): bzlib cairo fontconfig freetype heic jbig jng jp2 jpeg lcms lqr ltdl lzma openexr pangocairo png raqm raw rsvg tiff webp wmf x xml zlib
随便找张图片看看都有哪些属性
stonemoe@desktop ~/Desktop> magick identify -verbose payload.jpg
Image: payload.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 139x97+0+0
Units: Undefined
Colorspace: sRGB
Type: TrueColor
Base type: Undefined
Endianess: Undefined
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Channel statistics:
Pixels: 13483
Red:
min: 0 (0)
max: 255 (1)
mean: 93.4788 (0.366584)
standard deviation: 69.5047 (0.272567)
kurtosis: -0.519383
skewness: 1.02065
entropy: 0.839877
Green:
min: 0 (0)
max: 255 (1)
mean: 110.394 (0.43292)
standard deviation: 41.334 (0.162094)
kurtosis: 2.00187
skewness: 1.46048
entropy: 0.816047
Blue:
min: 0 (0)
max: 244 (0.956863)
mean: 118.63 (0.465215)
standard deviation: 75.5964 (0.296456)
kurtosis: -1.50408
skewness: -0.589183
entropy: 0.805144
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 107.501 (0.421573)
standard deviation: 62.145 (0.243706)
kurtosis: -1.06579
skewness: 0.236057
entropy: 0.820356
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 139x97+0+0
Dispose: Undefined
Iterations: 0
Compression: JPEG
Quality: 72
Orientation: Undefined
Convex hull: 0,0 138,0 138,95 136,96 0,96 0,0
Minimum bounding box: 138,0 138,96 0,96 -5.8783e-15,0
Properties:
date:create: 2020-04-17T19:39:25+00:00
date:modify: 2020-04-17T19:39:17+00:00
jpeg:colorspace: 2
jpeg:sampling-factor: 1x1,1x1,1x1
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 13248
minimum-bounding-box:height: 138
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 96
signature: d40b11152ffe08839367333e59c2e375970adb7e05457af8022092ac1147bc21
Artifacts:
verbose: true
Tainted: False
Filesize: 4311B
Number pixels: 13483
Pixels per second: 18.1345MP
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 7.0.10-6 Q16 x86_64 2020-04-07 https://imagemagick.org
0x02 jpeg comment
首先看看jpeg comment如何,我们使用exiv2写一下
stonemoe@desktop ~/Desktop> exiv2 -c im_so_happy modify payload.jpg
stonemoe@desktop ~/Desktop> magick identify -verbose payload.jpg
...省略...(只贴Properties部分,下同)
Properties:
comment: im_so_happy
date:create: 2020-04-17T19:47:54+00:00
date:modify: 2020-04-17T19:47:54+00:00
jpeg:colorspace: 2
jpeg:sampling-factor: 1x1,1x1,1x1
...省略...
可以看到在Properies下出现了comment属性
然后再使用imagemagick resize和thumbnail处理一下图片
stonemoe@desktop ~/Desktop> convert -size 110x110 payload.jpg payload_resize.png
stonemoe@desktop ~/Desktop> convert -thumbnail 110x110 payload.jpg payload_thumb.png
看看resize的结果
stonemoe@desktop ~/Desktop> magick identify -verbose payload_resize.png
...省略...
Properties:
comment: im_so_happy
date:create: 2020-04-17T19:50:02+00:00
date:modify: 2020-04-17T19:50:02+00:00
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 13248
minimum-bounding-box:height: 138
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 96
png:bKGD: chunk was found (see Background color, above)
png:cHRM: chunk was found (see Chromaticity, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 8
png:IHDR.bit_depth: 8
png:IHDR.color-type-orig: 2
png:IHDR.color_type: 2 (Truecolor)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 139, 97
png:sRGB: intent=0 (Perceptual Intent)
png:text: 3 tEXt/zTXt/iTXt chunks were found
signature: d40b11152ffe08839367333e59c2e375970adb7e05457af8022092ac1147bc21
...省略...
然后看看thumbnail的结果
stonemoe@desktop ~/Desktop> magick identify -verbose payload_thumb.png
...省略...
Properties:
date:create: 2020-04-17T19:51:41+00:00
date:modify: 2020-04-17T19:51:41+00:00
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 8284
minimum-bounding-box:height: 109
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 76
png:bKGD: chunk was found (see Background color, above)
png:cHRM: chunk was found (see Chromaticity, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 8
png:IHDR.bit_depth: 8
png:IHDR.color-type-orig: 6
png:IHDR.color_type: 6 (RGBA)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 110, 77
png:sRGB: intent=0 (Perceptual Intent)
png:text: 10 tEXt/zTXt/iTXt chunks were found
png:tIME: 2020-04-17T19:51:41Z
signature: 0649a56200e5c9888c93a78b9b2951b3d1f64db16e824fa90fc865bd9a83450d
software: https://imagemagick.org
Thumb::Document::Pages: 1
Thumb::Image::Height: 97
Thumb::Image::Width: 139
Thumb::Mimetype: image/jpeg
Thumb::MTime: 1587152874
Thumb::Size: 4327B
Thumb::URI: file://payload.jpg
...省略...
可以看到resize保留了comment,而thumbnail把comment去掉了
0x03 EXIF
再看 EXIF,EXIF的定义很多,可以参考Exiv2 Exif Tags Reference
我们先选取部分String类型的数据添加一下
exiv2 -M "add Exif.GPSInfo.GPSMeasureMode fuzz" modify payload.jpg
exiv2 -M "add Exif.GPSInfo.GPSStatus fuzz" modify payload.jpg
exiv2 -M "add Exif.GPSInfo.GPSStatus fuzz" modify payload.jpg
exiv2 -M "add Exif.GPSInfo.GPSSatellites fuzz" modify payload.jpg
exiv2 -M "add Exif.GPSInfo.GPSLongitudeRef fuzz" modify payload.jpg
exiv2 -M "add Exif.GPSInfo.GPSLatitudeRef fuzz" modify payload.jpg
exiv2 -M "add Exif.Iop.RelatedImageFileFormat fuzz" modify payload.jpg
exiv2 -M "add Exif.Iop.InteroperabilityIndex fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.LensSerialNumber fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.LensSerialNumber fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.LensModel fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.LensMake fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.BodySerialNumber fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.CameraOwnerName fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.ImageUniqueID fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.RelatedSoundFile fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.SubSecTimeDigitized fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.SubSecTimeOriginal fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.SubSecTime fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.DateTimeDigitized fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.DateTimeOriginal fuzz" modify payload.jpg
exiv2 -M "add Exif.Photo.SpectralSensitivity fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.CameraLabel fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ReelName fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.PreviewDateTime fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.CameraSerialNumber fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.UniqueCameraModel fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ImageHistory fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.SecurityClassification fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.DateTimeOriginal fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.SpectralSensitivity fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.Copyright fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ImageID fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.TargetPrinter fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.InkNames fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.HostComputer fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.Artist fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.DateTime fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.Software fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.Model fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.Make fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ProcessingSoftware fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.DocumentName fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ImageDescription fuzz" modify payload.jpg
exiv2 -M "add Exif.Image.ProcessingSoftware fuzz" modify payload.jpg
看看图片现在的状态
Image: payload.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 139x97+0+0
Units: Undefined
Colorspace: sRGB
Type: TrueColor
Base type: Undefined
Endianess: Undefined
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Channel statistics:
Pixels: 13483
Red:
min: 0 (0)
max: 255 (1)
mean: 93.4788 (0.366584)
standard deviation: 69.5047 (0.272567)
kurtosis: -0.519383
skewness: 1.02065
entropy: 0.839877
Green:
min: 0 (0)
max: 255 (1)
mean: 110.394 (0.43292)
standard deviation: 41.334 (0.162094)
kurtosis: 2.00187
skewness: 1.46048
entropy: 0.816047
Blue:
min: 0 (0)
max: 244 (0.956863)
mean: 118.63 (0.465215)
standard deviation: 75.5964 (0.296456)
kurtosis: -1.50408
skewness: -0.589183
entropy: 0.805144
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 107.501 (0.421573)
standard deviation: 62.145 (0.243706)
kurtosis: -1.06579
skewness: 0.236057
entropy: 0.820356
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 139x97+0+0
Dispose: Undefined
Iterations: 0
Compression: JPEG
Quality: 72
Orientation: Undefined
Convex hull: 0,0 138,0 138,95 136,96 0,96 0,0
Minimum bounding box: 138,0 138,96 0,96 -5.8783e-15,0
Profiles:
Profile-exif: 884 bytes
Properties:
comment: im_so_happy
date:create: 2020-04-17T20:04:46+00:00
date:modify: 2020-04-17T20:04:46+00:00
exif:Artist: fuzz
exif:BodySerialNumber: fuzz
exif:CameraOwnerName: fuzz
exif:Copyright: fuzz
exif:DateTime: fuzz
exif:DateTimeDigitized: fuzz
exif:DateTimeOriginal: fuzz
exif:DocumentName: fuzz
exif:ExifOffset: 452
exif:GPSInfo: 764
exif:GPSLatitudeRef: fuzz
exif:GPSLongitudeRef: fuzz
exif:GPSMeasureMode: fuzz
exif:GPSSatellites: fuzz
exif:GPSStatus: fuzz
exif:ImageDescription: fuzz
exif:ImageHistory: fuzz
exif:ImageID: fuzz
exif:ImageUniqueID: fuzz
exif:InkNames: fuzz
exif:InteroperabilityOffset: 722
exif:LensMake: fuzz
exif:LensModel: fuzz
exif:LensSerialNumber: fuzz
exif:Make: fuzz
exif:Model: fuzz
exif:RelatedSoundFile: fuzz
exif:SecurityClassification: fuzz
exif:Software: fuzz
exif:SpectralSensitivity: fuzz
exif:SubSecTime: fuzz
exif:SubSecTimeDigitized: fuzz
exif:SubSecTimeOriginal: fuzz
exif:TargetPrinter: fuzz
exif:thumbnail:InteroperabilityIndex: fuzz
exif:thumbnail:RelatedImageFileFormat: fuzz
jpeg:colorspace: 2
jpeg:sampling-factor: 1x1,1x1,1x1
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 13248
minimum-bounding-box:height: 138
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 96
signature: d40b11152ffe08839367333e59c2e375970adb7e05457af8022092ac1147bc21
unknown: fuzz
Artifacts:
verbose: true
Tainted: False
Filesize: 5215B
Number pixels: 13483
Pixels per second: 26.032MP
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 7.0.10-6 Q16 x86_64 2020-04-07 https://imagemagick.org
这里不知道为啥写了个unknown属性进去,不过无伤大雅
这些内容在文件中数据长这样 这里可以看到数据被写在了文件的头部
再resize和thumbnail一下试试
stonemoe@desktop ~/Desktop> convert -size 110x110 payload.jpg payload_resize.png
stonemoe@desktop ~/Desktop> magick convert -thumbnail 110x110 payload.jpg payload_thumb.png
先看看resize的结果
stonemoe@desktop ~/Desktop> magick identify -verbose payload_resize.png
...省略...
Properties:
comment: im_so_happy
date:create: 2020-04-17T20:13:41+00:00
date:modify: 2020-04-17T20:13:41+00:00
exif:Artist: fuzz
exif:BodySerialNumber: fuzz
exif:CameraOwnerName: fuzz
exif:Copyright: fuzz
exif:DateTime: fuzz
exif:DateTimeDigitized: fuzz
exif:DateTimeOriginal: fuzz
exif:DocumentName: fuzz
exif:ExifOffset: 452
exif:GPSInfo: 764
exif:GPSLatitudeRef: fuzz
exif:GPSLongitudeRef: fuzz
exif:GPSMeasureMode: fuzz
exif:GPSSatellites: fuzz
exif:GPSStatus: fuzz
exif:ImageDescription: fuzz
exif:ImageHistory: fuzz
exif:ImageID: fuzz
exif:ImageUniqueID: fuzz
exif:InkNames: fuzz
exif:InteroperabilityOffset: 722
exif:LensMake: fuzz
exif:LensModel: fuzz
exif:LensSerialNumber: fuzz
exif:Make: fuzz
exif:Model: fuzz
exif:RelatedSoundFile: fuzz
exif:SecurityClassification: fuzz
exif:Software: fuzz
exif:SpectralSensitivity: fuzz
exif:SubSecTime: fuzz
exif:SubSecTimeDigitized: fuzz
exif:SubSecTimeOriginal: fuzz
exif:TargetPrinter: fuzz
exif:thumbnail:InteroperabilityIndex: fuzz
exif:thumbnail:RelatedImageFileFormat: fuzz
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 13248
minimum-bounding-box:height: 138
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 96
png:bKGD: chunk was found (see Background color, above)
png:cHRM: chunk was found (see Chromaticity, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 8
png:IHDR.bit_depth: 8
png:IHDR.color-type-orig: 2
png:IHDR.color_type: 2 (Truecolor)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 139, 97
png:sRGB: intent=0 (Perceptual Intent)
png:text: 40 tEXt/zTXt/iTXt chunks were found
signature: d40b11152ffe08839367333e59c2e375970adb7e05457af8022092ac1147bc21
unknown: fuzz
...省略...
可以看到信息完好无损
并且因为我们resize为png格式,属性相关数据会被移动到文件末尾 相关标准可以参考PNG Chunks Spec以及PNG Options and Extensions
再看看thumnail的结果
...省略...
Properties:
date:create: 2020-04-17T20:13:47+00:00
date:modify: 2020-04-17T20:13:47+00:00
exif:Artist: fuzz
exif:BodySerialNumber: fuzz
exif:CameraOwnerName: fuzz
exif:Copyright: fuzz
exif:DateTime: fuzz
exif:DateTimeDigitized: fuzz
exif:DateTimeOriginal: fuzz
exif:DocumentName: fuzz
exif:ExifOffset: 452
exif:GPSInfo: 764
exif:GPSLatitudeRef: fuzz
exif:GPSLongitudeRef: fuzz
exif:GPSMeasureMode: fuzz
exif:GPSSatellites: fuzz
exif:GPSStatus: fuzz
exif:ImageDescription: fuzz
exif:ImageHistory: fuzz
exif:ImageID: fuzz
exif:ImageUniqueID: fuzz
exif:InkNames: fuzz
exif:InteroperabilityOffset: 722
exif:LensMake: fuzz
exif:LensModel: fuzz
exif:LensSerialNumber: fuzz
exif:Make: fuzz
exif:Model: fuzz
exif:RelatedSoundFile: fuzz
exif:SecurityClassification: fuzz
exif:Software: fuzz
exif:SpectralSensitivity: fuzz
exif:SubSecTime: fuzz
exif:SubSecTimeDigitized: fuzz
exif:SubSecTimeOriginal: fuzz
exif:TargetPrinter: fuzz
exif:thumbnail:InteroperabilityIndex: fuzz
exif:thumbnail:RelatedImageFileFormat: fuzz
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 8284
minimum-bounding-box:height: 109
minimum-bounding-box:unrotate: 0
minimum-bounding-box:width: 76
png:bKGD: chunk was found (see Background color, above)
png:cHRM: chunk was found (see Chromaticity, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 8
png:IHDR.bit_depth: 8
png:IHDR.color-type-orig: 6
png:IHDR.color_type: 6 (RGBA)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 110, 77
png:sRGB: intent=0 (Perceptual Intent)
png:text: 47 tEXt/zTXt/iTXt chunks were found
png:tIME: 2020-04-17T20:13:47Z
signature: 0649a56200e5c9888c93a78b9b2951b3d1f64db16e824fa90fc865bd9a83450d
software: https://imagemagick.org
Thumb::Document::Pages: 1
Thumb::Image::Height: 97
Thumb::Image::Width: 139
Thumb::Mimetype: image/jpeg
Thumb::MTime: 1587153886
Thumb::Size: 5215B
Thumb::URI: file://payload.jpg
unknown: fuzz
...省略...
可以看到jpeg comment没了,但是EXIF还在
看看文件内容长什么样 看起来比resize的结果还少了一部分冗余数据
0x0? 试试效果
写一段人畜无害的php代码进去
stonemoe@desktop ~/Desktop> exiv2 -M "add Exif.Image.Copyright <?php echo \"php_is_happy\"; ?>" modify payload.jpg
stonemoe@desktop ~/Desktop> magick convert -thumbnail 110x110 payload.jpg payload_thumb.png
执行一下
stonemoe@desktop ~/Desktop> mv payload_thumb.png test.php
stonemoe@desktop ~/Desktop> php test.php | xxd | grep -2 php_is
00003bf0: 6572 4e61 6d65 0066 757a 7a31 7bc0 6000 erName.fuzz1{.`.
00003c00: 0000 2c74 4558 7465 7869 663a 436f 7079 ..,tEXtexif:Copy
00003c10: 7269 6768 7400 7068 705f 6973 5f68 6170 right.php_is_hap
00003c20: 7079 f9d4 5fce 0000 0012 7445 5874 6578 py.._.....tEXtex
00003c30: 6966 3a44 6174 6554 696d 6500 6675 7a7a if:DateTime.fuzz
可以看到可以执行