App-zipdetails
view release on metacpan or search on metacpan
bin/zipdetails view on Meta::CPAN
# Slip Vulnerability with use of ".." in a relative path
# https://security.snyk.io/research/zip-slip-vulnerability
return ["Use of '..' in filename is a Zip Slip Vulnerability",
"See https://security.snyk.io/research/zip-slip-vulnerability" ]
if $filename =~ m#^\.\./# || $filename =~ m#/\.\./# || $filename =~ m#/\.\.# ;
# Cannot have "." or ".." as the full filename
return "Use of current-directory filename '.' may not unzip correctly"
if $filename eq '.' ;
return "Use of parent-directory filename '..' may not unzip correctly"
if $filename eq '..' ;
# Portability (mostly with Windows)
{
# see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
state $badDosFilename = join '|', map { quotemeta }
qw(CON PRN AUX NUL
COM1 COM2 COM3 COM4 COM5 COM6 COM7 COM8 COM9
LPT1 LPT2 LPT3 LPT4 LPT5 LPT6 LPT7 LPT8 LPT9
) ;
# if $filename contains any invalid codepoints, we will get a warning like this
#
# Operation "pattern match (m//)" returns its argument for non-Unicode code point
#
# so silence it for now.
no warnings;
return "Portability Issue: '$1' is a reserved Windows device name"
if $filename =~ /^($badDosFilename)$/io ;
# Can't have the device name with an extension either
return "Portability Issue: '$1' is a reserved Windows device name"
if $filename =~ /^($badDosFilename)\./io ;
}
state $illegal_windows_chars = join '|', map { quotemeta } qw( < > : " | ? * );
return "Portability Issue: Windows filename cannot contain '$1'"
if $filename =~ /($illegal_windows_chars)/o ;
return "Portability Issue: Null character '\\x00' is not allowed in a Windows or Linux filename"
if $filename =~ /\x00/ ;
return sprintf "Portability Issue: Control character '\\x%02X' is not allowed in a Windows filename", ord($1)
if $filename =~ /([\x00-\x1F])/ ;
return undef;
}
sub getOutputFilename
{
my $raw_filename = shift;
my $LanguageEncodingFlag = shift;
my $message = shift // "Filename";
my $filename ;
my $decoded_filename;
if ($raw_filename eq '')
{
if ($message eq 'Filename')
{
warning $FH->tell() ,
"Filename ''",
"Zero Length Filename" ;
}
return '', '', 0;
}
elsif ($opt_Redact)
{
return redactFilename($raw_filename), '', 0 ;
}
else
{
$decoded_filename = TextEncoding::decode($raw_filename, $message, $LanguageEncodingFlag) ;
$filename = TextEncoding::encode($decoded_filename, $message, $LanguageEncodingFlag) ;
}
return $filename, $decoded_filename, $filename ne $raw_filename ;
}
sub outputFilename
{
my $raw_filename = shift;
my $LanguageEncodingFlag = shift;
my $message = shift // "Filename";
my ($filename, $decoded_filename, $modified) = getOutputFilename($raw_filename, $LanguageEncodingFlag);
out $raw_filename, $message, "'". $filename . "'";
if (! $opt_Redact && TextEncoding::debugEncoding())
{
# use Devel::Peek;
# print "READ " ; Dump($raw_filename);
# print "INTERNAL " ; Dump($decoded_filename);
# print "OUTPUT " ; Dump($filename);
debug $FH->tell() - length($raw_filename),
"$message Encoding Change"
if $modified ;
# use Unicode::Normalize;
# my $NormalizedForm ;
# if (defined $decoded_filename)
# {
# $NormalizedForm .= Unicode::Normalize::checkNFD $decoded_filename ? 'NFD ' : '';
# $NormalizedForm .= Unicode::Normalize::checkNFC $decoded_filename ? 'NFC ' : '';
# $NormalizedForm .= Unicode::Normalize::checkNFKD $decoded_filename ? 'NFKD ' : '';
# $NormalizedForm .= Unicode::Normalize::checkNFKC $decoded_filename ? 'NFKC ' : '';
# $NormalizedForm .= Unicode::Normalize::checkFCD $decoded_filename ? 'FCD ' : '';
# $NormalizedForm .= Unicode::Normalize::checkFCC $decoded_filename ? 'FCC ' : '';
# }
debug $FH->tell() - length($raw_filename),
"Encoding Debug for $message",
"Octets Read from File [$raw_filename][" . length($raw_filename). "] [" . charDump2($raw_filename) . "]",
"Via Unicode Codepoints [$decoded_filename][" . length($decoded_filename) . "] [" . charDump($decoded_filename) . "]",
# "Unicode Normalization $NormalizedForm",
"Octets Written [$filename][" . length($filename). "] [" . charDump2($filename) . "]";
}
if ($message eq 'Filename' && $opt_want_warning_messages)
{
# Check for bad, unsafe & not portable filenames
my $v = validateFilename($decoded_filename);
if ($v)
{
my @v = ref $v eq 'ARRAY'
? @$v
: $v;
warning $FH->tell() - length($raw_filename),
"Filename '$filename'",
@v
}
}
return $filename;
}
sub CentralHeader
{
my $signature = shift ;
my $data = shift ;
my $startRecordOffset = shift ;
my $cdEntryOffset = $FH->tell() - 4 ;
++ $CentralHeaderCount;
print "\n";
out $data, "CENTRAL HEADER #$CentralHeaderCount", Value_V($signature);
my $buffer;
need 42, Signatures::name($signature);
out_C "Created Zip Spec", \&decodeZipVer;
my $made_by = out_C "Created OS", \&decodeOS;
my $extractVer = out_C "Extract Zip Spec", \&decodeZipVer;
out_C "Extract OS", \&decodeOS;
my ($bgp, $gpFlag) = read_v();
my ($bcm, $compressedMethod) = read_v();
my $cdEntry = CentralDirectoryEntry->new($cdEntryOffset);
out $bgp, "General Purpose Flag", Value_v($gpFlag) ;
GeneralPurposeBits($compressedMethod, $gpFlag);
my $LanguageEncodingFlag = $gpFlag & ZIP_GP_FLAG_LANGUAGE_ENCODING ;
$cdEntry->languageEncodingFlag($LanguageEncodingFlag) ;
out $bcm, "Compression Method", compressionMethod($compressedMethod) ;
info $FH->tell() - 2, "Unknown 'Compression Method' ID " . decimalHex0x($compressedMethod, 2)
if ! defined $ZIP_CompressionMethods{$compressedMethod} ;
my $lastMod = out_V "Modification Time", sub { LastModTime($_[0]) };
my $crc = out_V "CRC";
my $compressedSize = out_V "Compressed Size";
my $std_compressedSize = $compressedSize;
my $uncompressedSize = out_V "Uncompressed Size";
my $std_uncompressedSize = $uncompressedSize;
my $filenameLength = out_v "Filename Length";
if ($filenameLength == 0)
bin/zipdetails view on Meta::CPAN
}
1;
__END__
=head1 NAME
zipdetails - display the internal structure of zip files
=head1 SYNOPSIS
zipdetails [options] zipfile.zip
=head1 DESCRIPTION
This program creates a detailed report on the internal structure of zip
files. For each item of metadata within a zip file the program will output
=over 5
=item the offset into the zip file where the item is located.
=item a textual representation for the item.
=item an optional hex dump of the item.
=back
The program assumes a prior understanding of the internal structure of Zip
files. You should have a copy of the zip file definition,
L<APPNOTE.TXT|https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT>,
at hand to help understand the output from this program.
=head2 Default Behaviour
By default the program expects to be given a well-formed zip file. It will
navigate the zip file by first parsing the zip C<Central Directory> at the end
of the file. If the C<Central Directory> is found, it will then walk
sequentially through the zip records starting at the beginning of the file.
See L<Advanced Analysis> for other processing options.
If the program finds any structural or portability issues with the zip file
it will print a message at the point it finds the issue and/or in a summary
at the end of the output report. Whilst the set of issues that can be
detected it exhaustive, don't assume that this program can find I<all> the
possible issues in a zip file - there are likely edge conditions that need
to be addressed.
If you have suggestions for use-cases where this could be enhanced please
consider creating an enhancement request (see L<"SUPPORT">).
=head3 Date & Time fields
Date/time fields found in zip files are displayed in local time. Use the
C<--utc> option to display these fields in Coordinated Universal Time (UTC).
=head3 Filenames & Comments
Filenames and comments are decoded/encoded using the default system
encoding of the host running C<zipdetails>. When the system encoding cannot
be determined C<cp437> will be used.
The exceptions are
=over 5
=item *
when the C<Language Encoding Flag> is set in the zip file, the
filename/comment fields are assumed to be encoded in UTF-8.
=item *
the definition for the metadata field implies UTF-8 charset encoding
=back
See L<"Filename Encoding Issues"> and L<Filename & Comment Encoding
Options> for ways to control the encoding of filename/comment fields.
=head2 OPTIONS
=head3 General Options
=over 5
=item C<-h>, C<--help>
Display help
=item C<--redact>
Obscure filenames and payload data in the output. Handy for the use case
where the zip files contains sensitive data that cannot be shared.
=item C<--scan>
Pessimistically scan the zip file looking for possible zip records. Can be
error-prone. For very large zip files this option is slow. Consider using
the C<--walk> option first. See L<"Advanced Analysis Options">
=item C<--utc>
By default, date/time fields are displayed in local time. Use this option to
display them in in Coordinated Universal Time (UTC).
=item C<-v>
Enable Verbose mode. See L<"Verbose Output">.
=item C<--version>
Display version number of the program and exit.
=item C<--walk>
Optimistically walk the zip file looking for possible zip records.
See L<"Advanced Analysis Options">
( run in 3.935 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )