line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# $Id$ |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# forensic::scalpel Brik |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
package Metabrik::Forensic::Scalpel; |
7
|
1
|
|
|
1
|
|
699
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
8
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
5
|
use base qw(Metabrik::Shell::Command Metabrik::System::Package); |
|
1
|
|
|
|
|
23
|
|
|
1
|
|
|
|
|
1683
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Default attribute values put here will BE inherited by subclasses |
13
|
|
|
|
|
|
|
sub brik_properties { |
14
|
|
|
|
|
|
|
return { |
15
|
0
|
|
|
0
|
1
|
|
revision => '$Revision$', |
16
|
|
|
|
|
|
|
tags => [ qw(unstable carving carve file filecarve filecarving) ], |
17
|
|
|
|
|
|
|
author => 'GomoR ', |
18
|
|
|
|
|
|
|
license => 'http://opensource.org/licenses/BSD-3-Clause', |
19
|
|
|
|
|
|
|
attributes => { |
20
|
|
|
|
|
|
|
datadir => [ qw(datadir) ], |
21
|
|
|
|
|
|
|
extensions => [ qw($extensions_list) ], |
22
|
|
|
|
|
|
|
conf => [ qw(file) ], |
23
|
|
|
|
|
|
|
}, |
24
|
|
|
|
|
|
|
attributes_default => { |
25
|
|
|
|
|
|
|
extensions => [ qw(doc pdf jpg png zip odt) ], |
26
|
|
|
|
|
|
|
conf => 'scalpel.conf', |
27
|
|
|
|
|
|
|
}, |
28
|
|
|
|
|
|
|
commands => { |
29
|
|
|
|
|
|
|
install => [ ], # Inherited |
30
|
|
|
|
|
|
|
generate_conf => [ qw($extensions_list|OPTIONAL file|OPTIONAL) ], |
31
|
|
|
|
|
|
|
scan => [ qw(file output|OPTIONAL conf|OPTIONAL) ], |
32
|
|
|
|
|
|
|
}, |
33
|
|
|
|
|
|
|
require_modules => { |
34
|
|
|
|
|
|
|
'Metabrik::File::Find' => [ ], |
35
|
|
|
|
|
|
|
'Metabrik::File::Text' => [ ], |
36
|
|
|
|
|
|
|
'Metabrik::File::Type' => [ ], |
37
|
|
|
|
|
|
|
'Metabrik::System::File' => [ ], |
38
|
|
|
|
|
|
|
}, |
39
|
|
|
|
|
|
|
require_binaries => { |
40
|
|
|
|
|
|
|
'scalpel' => [ ], |
41
|
|
|
|
|
|
|
}, |
42
|
|
|
|
|
|
|
need_packages => { |
43
|
|
|
|
|
|
|
ubuntu => [ qw(scalpel) ], |
44
|
|
|
|
|
|
|
debian => [ qw(scalpel) ], |
45
|
|
|
|
|
|
|
kali => [ qw(scalpel) ], |
46
|
|
|
|
|
|
|
}, |
47
|
|
|
|
|
|
|
}; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub generate_conf { |
51
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
52
|
0
|
|
|
|
|
|
my ($extensions, $file) = @_; |
53
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
my $datadir = $self->datadir; |
55
|
0
|
|
0
|
|
|
|
$extensions ||= $self->extensions; |
56
|
0
|
|
0
|
|
|
|
$file ||= $datadir.'/'.$self->conf; |
57
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('generate_conf', $extensions) or return; |
58
|
0
|
0
|
|
|
|
|
$self->brik_help_run_invalid_arg('generate_conf', $extensions, 'ARRAY') or return; |
59
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg('generate_conf', $file) or return; |
60
|
|
|
|
|
|
|
|
61
|
0
|
0
|
|
|
|
|
my $sf = Metabrik::System::File->new_from_brik_init($self) or return; |
62
|
0
|
0
|
|
|
|
|
$sf->remove($file) or return; |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
my $ext = [ |
65
|
|
|
|
|
|
|
{ case => "y", ext => "art", footer => "\\xcf\\xc7\\xcb", header => "\\x4a\\x47\\x04\\x0e", size => 150000, }, |
66
|
|
|
|
|
|
|
{ case => "y", ext => "art", footer => "\\xd0\\xcb\\x00\\x00", header => "\\x4a\\x47\\x03\\x0e", size => 150000, }, |
67
|
|
|
|
|
|
|
{ case => "y", ext => "gif", footer => "\\x00\\x3b", header => "\\x47\\x49\\x46\\x38\\x37\\x61", size => 5000000, }, |
68
|
|
|
|
|
|
|
{ case => "y", ext => "gif", footer => "\\x00\\x3b", header => "\\x47\\x49\\x46\\x38\\x39\\x61", size => 5000000, }, |
69
|
|
|
|
|
|
|
{ case => "y", ext => "jpg", footer => "\\xff\\xd9", header => "\\xff\\xd8\\xff\\xe0\\x00\\x10", size => 200000000, }, |
70
|
|
|
|
|
|
|
{ case => "y", ext => "png", footer => "\\xff\\xfc\\xfd\\xfe", header => "\\x50\\x4e\\x47?", size => 20000000, }, |
71
|
|
|
|
|
|
|
{ case => "y", ext => "bmp", footer => undef, header => "BM??\\x00\\x00\\x00", size => 100000, }, |
72
|
|
|
|
|
|
|
{ case => "y", ext => "tif", footer => undef, header => "\\x49\\x49\\x2a\\x00", size => 200000000, }, |
73
|
|
|
|
|
|
|
{ case => "y", ext => "tif", footer => undef, header => "\\x4D\\x4D\\x00\\x2A", size => 200000000, }, |
74
|
|
|
|
|
|
|
{ case => "y", ext => "avi", footer => undef, header => "RIFF????AVI", size => 50000000, }, |
75
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????moov", size => 10000000, }, |
76
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????mdat", size => 10000000, }, |
77
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????widev", size => 10000000, }, |
78
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????skip", size => 10000000, }, |
79
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????free", size => 10000000, }, |
80
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????idsc", size => 10000000, }, |
81
|
|
|
|
|
|
|
{ case => "y", ext => "mov", footer => undef, header => "????pckg", size => 10000000, }, |
82
|
|
|
|
|
|
|
{ case => "y", ext => "mpg", footer => "\\x00\\x00\\x01\\xb9", header => "\\x00\\x00\\x01\\xba", size => 50000000, }, |
83
|
|
|
|
|
|
|
{ case => "y", ext => "mpg", footer => "\\x00\\x00\\x01\\xb7", header => "\\x00\\x00\\x01\\xb3", size => 50000000, }, |
84
|
|
|
|
|
|
|
{ case => "y", ext => "fws", footer => undef, header => "FWS", size => 4000000 }, |
85
|
|
|
|
|
|
|
{ case => "y", ext => "doc", footer => "\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1\\x00\\x00", header => "\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1\\x00\\x00", size => 10000000, }, |
86
|
|
|
|
|
|
|
{ case => "y", ext => "doc", footer => undef, header => "\\xd0\\xcf\\x11\\xe0\\xa1\\xb1", size => 10000000, }, |
87
|
|
|
|
|
|
|
{ case => "y", ext => "pst", footer => undef, header => "\\x21\\x42\\x4e\\xa5\\x6f\\xb5\\xa6", size => 500000000, }, |
88
|
|
|
|
|
|
|
{ case => "y", ext => "ost", footer => undef, header => "\\x21\\x42\\x44\\x4e", size => 500000000, }, |
89
|
|
|
|
|
|
|
{ case => "y", ext => "dbx", footer => undef, header => "\\xcf\\xad\\x12\\xfe\\xc5\\xfd\\x74\\x6f", size => 10000000, }, |
90
|
|
|
|
|
|
|
{ case => "y", ext => "idx", footer => undef, header => "\\x4a\\x4d\\x46\\x39", size => 10000000, }, |
91
|
|
|
|
|
|
|
{ case => "y", ext => "mbx", footer => undef, header => "\\x4a\\x4d\\x46\\x36", size => 10000000, }, |
92
|
|
|
|
|
|
|
{ case => "y", ext => "wpc", footer => undef, header => "?WPC", size => 1000000 }, |
93
|
|
|
|
|
|
|
{ case => "n", ext => "htm", footer => "", header => " 50000, }, |
94
|
|
|
|
|
|
|
{ case => "y", ext => "pdf", footer => "%EOF\\x0d", header => "%PDF", size => 5000000, }, |
95
|
|
|
|
|
|
|
{ case => "y", ext => "pdf", footer => "%EOF\\x0a", header => "%PDF", size => 5000000, }, |
96
|
|
|
|
|
|
|
{ case => "y", ext => "mail", footer => undef, header => "\\x41\\x4f\\x4c\\x56\\x4d", size => 500000, }, |
97
|
|
|
|
|
|
|
{ case => "y", ext => "pgd", footer => undef, header => "\\x50\\x47\\x50\\x64\\x4d\\x41\\x49\\x4e\\x60\\x01", size => 500000, }, |
98
|
|
|
|
|
|
|
{ case => "y", ext => "pgp", footer => undef, header => "\\x99\\x00", size => 100000, }, |
99
|
|
|
|
|
|
|
{ case => "y", ext => "pgp", footer => undef, header => "\\x95\\x01", size => 100000, }, |
100
|
|
|
|
|
|
|
{ case => "y", ext => "pgp", footer => undef, header => "\\x95\\x00", size => 100000, }, |
101
|
|
|
|
|
|
|
{ case => "y", ext => "pgp", footer => undef, header => "\\xa6\\x00", size => 100000, }, |
102
|
|
|
|
|
|
|
{ case => "y", ext => "txt", footer => undef, header => "-----BEGIN\\040PGP", size => 100000, }, |
103
|
|
|
|
|
|
|
{ case => "y", ext => "rpm", footer => undef, header => "\\xed\\xab", size => 1000000, }, |
104
|
|
|
|
|
|
|
{ case => "y", ext => "wav", footer => undef, header => "RIFF????WAVE", size => 200000, }, |
105
|
|
|
|
|
|
|
{ case => "y", ext => "ra", footer => undef, header => "\\x2e\\x72\\x61\\xfd", size => 1000000, }, |
106
|
|
|
|
|
|
|
{ case => "y", ext => "ra", footer => undef, header => ".RMF", size => 1000000 }, |
107
|
|
|
|
|
|
|
{ case => "y", ext => "dat", footer => undef, header => "regf", size => 4000000 }, |
108
|
|
|
|
|
|
|
{ case => "y", ext => "dat", footer => undef, header => "CREG", size => 4000000 }, |
109
|
|
|
|
|
|
|
{ case => "y", ext => "zip", footer => "\\x3c\\xac", header => "PK\\x03\\x04", size => 10000000, }, |
110
|
|
|
|
|
|
|
{ case => "y", ext => "java", footer => undef, header => "\\xca\\xfe\\xba\\xbe", size => 1000000, }, |
111
|
|
|
|
|
|
|
{ case => "y", ext => "max", footer => "\\x00\\x00\\x05\\x80\\x00\\x00", header => "\\x56\\x69\\x47\\x46\\x6b\\x1a\\x00\\x00\\x00\\x00", size => 1000000, }, |
112
|
|
|
|
|
|
|
{ case => "y", ext => "pins", footer => undef, header => "\\x50\\x49\\x4e\\x53\\x20\\x34\\x2e\\x32\\x30\\x0d", size => 8000, }, |
113
|
|
|
|
|
|
|
{ ext => "odt", case => "y", size => 20000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.textPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
114
|
|
|
|
|
|
|
{ ext => "ods", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.spreadsheetPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
115
|
|
|
|
|
|
|
{ ext => "odp", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.presentationPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
116
|
|
|
|
|
|
|
{ ext => "odg", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.graphicsPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
117
|
|
|
|
|
|
|
{ ext => "odc", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.chartPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
118
|
|
|
|
|
|
|
{ ext => "odf", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.formulaPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
119
|
|
|
|
|
|
|
{ ext => "odi", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.imagePK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
120
|
|
|
|
|
|
|
{ ext => "odm", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.oasis.opendocument.text-masterPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
121
|
|
|
|
|
|
|
{ ext => "sxw", case => "y", size => 10000000, header => "PK????????????????????????????mimetypeapplication/vnd.sun.xml.writerPK", footer => "META-INF/manifest.xmlPK????????????????????" }, |
122
|
|
|
|
|
|
|
]; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
my @lines = (); |
125
|
0
|
|
|
|
|
|
push @lines, '# To redefine the wildcard character, change the setting below and all'; |
126
|
0
|
|
|
|
|
|
push @lines, '# occurences in the formost.conf file.'; |
127
|
0
|
|
|
|
|
|
push @lines, '#wildcard ?'; |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
my $wanted = { map { $_ => 1 } @$extensions }; |
|
0
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
for my $this (@$ext) { |
131
|
0
|
|
|
|
|
|
my $ext = $this->{ext}; |
132
|
0
|
0
|
|
|
|
|
next unless exists($wanted->{$ext}); |
133
|
0
|
|
|
|
|
|
my $case = $this->{case}; |
134
|
0
|
|
|
|
|
|
my $size = $this->{size}; |
135
|
0
|
|
|
|
|
|
my $header = $this->{header}; |
136
|
0
|
|
0
|
|
|
|
my $footer = $this->{footer} || ''; |
137
|
0
|
|
|
|
|
|
my $line = " $ext $case $size $header $footer"; |
138
|
0
|
|
|
|
|
|
push @lines, $line; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
my $ft = Metabrik::File::Text->new_from_brik_init($self) or return; |
142
|
0
|
0
|
|
|
|
|
$ft->write(\@lines, $file) or return; |
143
|
0
|
|
|
|
|
|
$ft->close; |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
return $file; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub scan { |
149
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
150
|
0
|
|
|
|
|
|
my ($file, $output, $conf) = @_; |
151
|
|
|
|
|
|
|
|
152
|
0
|
0
|
|
|
|
|
$self->brik_help_run_undef_arg("scan", $file) or return; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
my $datadir = $self->datadir; |
155
|
0
|
|
|
|
|
|
my ($base) = $file =~ m{^.*/(.*)$}; |
156
|
0
|
|
0
|
|
|
|
$base ||= $file; |
157
|
0
|
|
0
|
|
|
|
$output ||= $datadir.'/'.$base.'.scalp'; |
158
|
0
|
|
0
|
|
|
|
$conf ||= $datadir.'/'.$self->conf; |
159
|
0
|
0
|
|
|
|
|
$self->brik_help_run_file_not_found('scan', $file) or return; |
160
|
0
|
0
|
|
|
|
|
$self->brik_help_run_file_not_found('scan', $conf) or return; |
161
|
|
|
|
|
|
|
|
162
|
0
|
0
|
|
|
|
|
if (! -d $output) { |
163
|
0
|
|
|
|
|
|
$self->log->info("scan: never launched scalpel on this file, starting..."); |
164
|
0
|
|
|
|
|
|
my $cmd = "scalpel -c $conf -o $output $file"; |
165
|
0
|
0
|
|
|
|
|
$self->system($cmd) or return; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
else { |
168
|
0
|
|
|
|
|
|
$self->log->info("scan: already launched scalpel, skipping new scan"); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
0
|
0
|
|
|
|
|
my $ff = Metabrik::File::Find->new_from_brik_init($self) or return; |
172
|
0
|
0
|
|
|
|
|
my $files = $ff->files($output) or return; |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
my $ext = { |
175
|
|
|
|
|
|
|
'txt' => 'text/plain', |
176
|
|
|
|
|
|
|
'doc' => 'application/msword', |
177
|
|
|
|
|
|
|
'jpg' => 'image/jpeg', |
178
|
|
|
|
|
|
|
'pdf' => 'application/pdf', |
179
|
|
|
|
|
|
|
'png' => 'image/png', |
180
|
|
|
|
|
|
|
'zip' => 'application/zip', |
181
|
|
|
|
|
|
|
'odt' => 'application/vnd.oasis.opendocument.text', |
182
|
|
|
|
|
|
|
}; |
183
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
|
my $ft = Metabrik::File::Type->new_from_brik_init($self) or return; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# If we know the supposed MIME-type of a file, we correlate with it |
187
|
0
|
|
|
|
|
|
my @verified = (); |
188
|
0
|
|
|
|
|
|
my @unverified = (); |
189
|
0
|
|
|
|
|
|
for my $file (@$files) { |
190
|
0
|
|
|
|
|
|
my ($this) = $file =~ m{\.(\w+)$}; |
191
|
0
|
0
|
|
|
|
|
if (exists($ext->{$this})) { |
192
|
0
|
0
|
|
|
|
|
my $check = $ft->get_mime_type($file) or next; |
193
|
0
|
0
|
|
|
|
|
if ($check eq $ext->{$this}) { |
194
|
0
|
|
|
|
|
|
push @verified, $file; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
else { |
197
|
0
|
|
|
|
|
|
push @unverified, $file; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
else { |
201
|
0
|
|
|
|
|
|
push @unverified, $file; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# We remove the audit.txt file which is generated by Scalpel itself |
206
|
0
|
|
|
|
|
|
@verified = grep {!/audit.txt$/} @verified; |
|
0
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
@unverified = grep {!/audit.txt$/} @unverified; |
|
0
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
return { verified => \@verified, unverified => \@unverified }; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
1; |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
__END__ |