source: repository/lib/Metabrik/Forensic/Volatility.pm

Last change on this file was 992:6bd6acfc81d5, checked in by GomoR <gomor@…>, 2 weeks ago
  • update: copyright notice
  • new: support for Kali Linux operating system
  • remove: api::onyphe is no more included, it use handled in its own repository
File size: 10.9 KB
Line 
1#
2# $Id$
3#
4# forensic::Volatility Brik
5#
6package Metabrik::Forensic::Volatility;
7use strict;
8use warnings;
9
10use base qw(Metabrik::Shell::Command Metabrik::System::Package);
11
12# Default attribute values put here will BE inherited by subclasses
13sub brik_properties {
14   return {
15      revision => '$Revision$',
16      tags => [ qw(unstable carving carve file filecarve filecarving) ],
17      author => 'GomoR <GomoR[at]metabrik.org>',
18      license => 'http://opensource.org/licenses/BSD-3-Clause',
19      attributes => {
20         datadir => [ qw(datadir) ],
21         profile => [ qw(profile) ],
22         input => [ qw(file) ],
23         capture_mode => [ qw(0|1) ],
24      },
25      attributes_default => {
26         profile => 'Win7SP1x64',
27         capture_mode => 1,
28      },
29      commands => {
30         install => [ ], # Inherited
31         imageinfo => [ qw(file|OPTIONAL) ],
32         command => [ qw(command file|OPTIONAL profile|OPTIONAL) ],
33         envars => [ qw(file|OPTIONAL profile|OPTIONAL) ],
34         pstree => [ qw(file|OPTIONAL profile|OPTIONAL) ],
35         pslist => [ qw(file|OPTIONAL profile|OPTIONAL) ],
36         netscan => [ qw(file|OPTIONAL profile|OPTIONAL) ],
37         hashdump => [ qw(file|OPTIONAL profile|OPTIONAL) ],
38         psxview => [ qw(file|OPTIONAL profile|OPTIONAL) ],
39         hivelist => [ qw(file|OPTIONAL profile|OPTIONAL) ],
40         hivedump => [ qw(offset file|OPTIONAL profile|OPTIONAL) ],
41         filescan => [ qw(file|OPTIONAL profile|OPTIONAL) ],
42         consoles => [ qw(file|OPTIONAL profile|OPTIONAL) ],
43         memdump => [ qw(pid file|OPTIONAL profile|OPTIONAL) ],
44      },
45      require_modules => {
46         'Metabrik::System::File' => [ ],
47      },
48      require_binaries => {
49         'volatility' => [ ],
50      },
51      need_packages => {
52         ubuntu => [ qw(volatility) ],
53         debian => [ qw(volatility) ],
54         kali => [ qw(volatility) ],
55      },
56   };
57}
58
59sub imageinfo {
60   my $self = shift;
61   my ($file) = @_;
62
63   $file ||= $self->input;
64   my $datadir = $self->datadir;
65   $self->brik_help_run_undef_arg('imageinfo', $file) or return;
66   $self->brik_help_run_file_not_found('imageinfo', $file) or return;
67
68   my $cmd = "volatility imageinfo -f \"$file\"";
69
70   $self->log->info("imageinfo: running...");
71   my $data = $self->capture($cmd);
72   $self->log->info("imageinfo: running...done");
73
74   my @profiles = ();
75   for my $line (@$data) {
76      if ($line =~ m{suggested profile}i) {
77         my @toks = split(/\s+/, $line);
78         @profiles = @toks[4..$#toks];
79         for (@profiles) {
80            s/,$//g;
81         }
82      }
83   }
84
85   return \@profiles;
86}
87
88sub command {
89   my $self = shift;
90   my ($command, $file, $profile) = @_;
91
92   $file ||= $self->input;
93   $profile ||= $self->profile;
94   $self->brik_help_run_undef_arg('command', $command) or return;
95   $self->brik_help_run_undef_arg('command', $file) or return;
96   $self->brik_help_run_undef_arg('command', $profile) or return;
97
98   my $cmd = "volatility --profile $profile $command -f \"$file\"";
99
100   return $self->execute($cmd);
101}
102
103sub envars {
104   my $self = shift;
105   my ($file, $profile) = @_;
106
107   $file ||= $self->input;
108   $profile ||= $self->profile;
109   $self->brik_help_run_undef_arg('envars', $file) or return;
110   $self->brik_help_run_undef_arg('envars', $profile) or return;
111
112   my $cmd = "volatility --profile $profile envars -f $file";
113
114   return $self->execute($cmd);
115}
116
117sub pstree {
118   my $self = shift;
119   my ($file, $profile) = @_;
120
121   $file ||= $self->input;
122   $profile ||= $self->profile;
123   $self->brik_help_run_undef_arg('pstree', $file) or return;
124   $self->brik_help_run_undef_arg('pstree', $profile) or return;
125
126   my $cmd = "volatility --profile $profile pstree -v -f $file";
127
128   return $self->execute($cmd);
129}
130
131sub pslist {
132   my $self = shift;
133   my ($file, $profile) = @_;
134
135   $file ||= $self->input;
136   $profile ||= $self->profile;
137   $self->brik_help_run_undef_arg('pslist', $file) or return;
138   $self->brik_help_run_undef_arg('pslist', $profile) or return;
139
140   my $cmd = "volatility --profile $profile pslist -v -f $file";
141
142   $self->capture_stderr(0);
143   my $lines = $self->execute($cmd) or return;
144   $self->capture_stderr(1);
145
146   # Offset(V)|Name|PID|PPID|Thds|Hnds|Sess|Wow64|Start                          Exit
147   my $skip = 3;
148   my @info = ();
149   for my $line (@$lines) {
150      if ($skip != 0) {
151         $skip--;
152         next;
153      }
154      my @t = split(/\s+/, $line, 9);
155      my $offset = $t[0];
156      my $name = $t[1];
157      my $pid = $t[2];
158      my $ppid = $t[3];
159      my $thds = $t[4];
160      my $hhds = $t[5];
161      my $sess = $t[6];
162      my $wow64 = $t[7];
163      my $start_exit = $t[8];
164
165      # "2016-06-04 16:23:13 UTC+0000"
166      # "2016-06-04 16:26:04 UTC+0000   2016-06-04 16:26:06 UTC+0000"
167      $start_exit =~ s{\s*$}{};
168      my ($start, $exit) = $start_exit =~ m{^(\S+ \S+ \S+)(?:\s+(\S+ \S+ \S+))?$};
169
170      push @info, {
171         offset => $offset,
172         name => $name,
173         pid => $pid,
174         ppid => $ppid,
175         thds => $thds,
176         hhds => $hhds,
177         sess => $sess,
178         wow64 => $wow64,
179         start => $start,
180         exit => $exit,
181         #start_exit => $start_exit,
182      };
183   }
184
185   return \@info;
186}
187
188sub netscan {
189   my $self = shift;
190   my ($file, $profile) = @_;
191
192   $file ||= $self->input;
193   $profile ||= $self->profile;
194   $self->brik_help_run_undef_arg('netscan', $file) or return;
195   $self->brik_help_run_undef_arg('netscan', $profile) or return;
196
197   my $cmd = "volatility --profile $profile netscan -v -f $file";
198
199   $self->capture_stderr(0);
200   my $lines = $self->execute($cmd) or return;
201   $self->capture_stderr(1);
202
203   # "Offset(P)   Proto   Local Address   Foreign Address    State     Pid   Owner     Created",
204   my $skip = 1;
205   my @info = ();
206   my @raw = ();
207   for my $line (@$lines) {
208      if ($skip != 0) {
209         $skip--;
210         next;
211      }
212
213# "0x41b9520  TCPv6  -:0   7808:2401:80fa:ffff:7808:2401:80fa:ffff:0 CLOSED 1820  avgmfapx.exe"
214      if ($line =~ m{\s+TCPv(4|6)\s+}) {
215         my @t = split(/\s+/, $line, 7);
216         my $offset = $t[0];
217         my $proto = $t[1];
218         my $local_address = $t[2];
219         my $foreign_address = $t[3];
220         my $state = $t[4];
221         my $pid = $t[5];
222         my $owner = $t[6];
223
224         push @info, {
225            offset => $offset,
226            proto => $proto,
227            local_address => $local_address,
228            foreign_address => $foreign_address,
229            state => $state,
230            pid => $pid,
231            owner => $owner,
232            created => 'undef',
233         };
234      }
235# "0x171e1360 UDPv4  10.0.3.15:138  *:*    4  System  2016-10-15 14:58:46 UTC+0000",
236      elsif ($line =~ m{\s+UDPv(4|6)\s+}) {
237         my @t = split(/\s+/, $line, 7);
238         my $offset = $t[0];
239         my $proto = $t[1];
240         my $local_address = $t[2];
241         my $foreign_address = $t[3];
242         my $pid = $t[4];
243         my $owner = $t[5];
244         my $created = $t[6];
245
246         push @info, {
247            offset => $offset,
248            proto => $proto,
249            local_address => $local_address,
250            foreign_address => $foreign_address,
251            state => 'undef',
252            pid => $pid,
253            owner => $owner,
254            created => $created,
255         };
256      }
257      else {
258         $self->log->warning("netscan: don't know what to do with line [$line]");
259      }
260   }
261
262   return \@info;
263}
264
265sub memdump {
266   my $self = shift;
267   my ($pid, $file, $profile) = @_;
268
269   $file ||= $self->input;
270   $profile ||= $self->profile;
271   $self->brik_help_run_undef_arg('memdump', $pid) or return;
272   $self->brik_help_run_undef_arg('memdump', $file) or return;
273   $self->brik_help_run_undef_arg('memdump', $profile) or return;
274
275   my $sf = Metabrik::System::File->new_from_brik_init($self) or return;
276   $sf->mkdir($pid) or return;
277
278   my $cmd = "volatility --profile $profile memdump -p $pid --dump-dir $pid/ -f $file";
279   $self->execute($cmd) or return;
280
281   return "$pid/$pid.dmp";
282}
283
284sub hashdump {
285   my $self = shift;
286   my ($file, $profile) = @_;
287
288   $file ||= $self->input;
289   $profile ||= $self->profile;
290   $self->brik_help_run_undef_arg('hashdump', $file) or return;
291   $self->brik_help_run_undef_arg('hashdump', $profile) or return;
292
293   my $cmd = "volatility --profile $profile hashdump -f $file";
294
295   return $self->execute($cmd);
296}
297
298sub psxview {
299   my $self = shift;
300   my ($file, $profile) = @_;
301
302   $file ||= $self->input;
303   $profile ||= $self->profile;
304   $self->brik_help_run_undef_arg('psxview', $file) or return;
305   $self->brik_help_run_undef_arg('psxview', $profile) or return;
306
307   my $cmd = "volatility --profile $profile psxview -f $file";
308
309   return $self->execute($cmd);
310}
311
312sub hivelist {
313   my $self = shift;
314   my ($file, $profile) = @_;
315
316   $file ||= $self->input;
317   $profile ||= $self->profile;
318   $self->brik_help_run_undef_arg('hivelist', $file) or return;
319   $self->brik_help_run_undef_arg('hivelist', $profile) or return;
320
321   my $cmd = "volatility --profile $profile hivelist -f $file";
322
323   $self->capture_stderr(0);
324   my $lines = $self->execute($cmd) or return;
325   $self->capture_stderr(1);
326
327   # "Virtual            Physical           Name"
328   my $skip = 2;
329   my @info = ();
330   for my $line (@$lines) {
331      if ($skip != 0) {
332         $skip--;
333         next;
334      }
335      my @t = split(/\s+/, $line, 3);
336      my $virtual = $t[0];
337      my $physical = $t[1];
338      my $name = $t[2];
339
340      push @info, {
341         virtual => $virtual,
342         physical => $physical,
343         name => $name,
344      };
345   }
346
347   return \@info;
348}
349
350sub hivedump {
351   my $self = shift;
352   my ($offset, $file, $profile) = @_;
353
354   $file ||= $self->input;
355   $profile ||= $self->profile;
356   $self->brik_help_run_undef_arg('hivedump', $offset) or return;
357   $self->brik_help_run_undef_arg('hivedump', $file) or return;
358   $self->brik_help_run_undef_arg('hivedump', $profile) or return;
359
360   my $cmd = "volatility --profile $profile hivedump --hive-offset $offset -f $file";
361
362   return $self->execute($cmd);
363}
364
365sub filescan {
366   my $self = shift;
367   my ($offset, $file, $profile) = @_;
368
369   $file ||= $self->input;
370   $profile ||= $self->profile;
371   $self->brik_help_run_undef_arg('filescan', $offset) or return;
372   $self->brik_help_run_undef_arg('filescan', $file) or return;
373   $self->brik_help_run_undef_arg('filescan', $profile) or return;
374
375   my $cmd = "volatility --profile $profile filescan -f $file";
376
377   return $self->execute($cmd);
378}
379
380sub consoles {
381   my $self = shift;
382   my ($file, $profile) = @_;
383
384   $file ||= $self->input;
385   $profile ||= $self->profile;
386   $self->brik_help_run_undef_arg('consoles', $file) or return;
387   $self->brik_help_run_undef_arg('consoles', $profile) or return;
388
389   my $cmd = "volatility --profile $profile consoles -f $file";
390
391   return $self->execute($cmd);
392}
393
3941;
395
396__END__
397
398=head1 NAME
399
400Metabrik::Forensic::Volatility - forensic::volatility Brik
401
402=head1 COPYRIGHT AND LICENSE
403
404Copyright (c) 2014-2019, Patrice E<lt>GomoRE<gt> Auffret
405
406You may distribute this module under the terms of The BSD 3-Clause License.
407See LICENSE file in the source distribution archive.
408
409=head1 AUTHOR
410
411Patrice E<lt>GomoRE<gt> Auffret
412
413=cut
Note: See TracBrowser for help on using the repository browser.