File Coverage

blib/lib/Net/SinFP3/Output/AddSignature.pm
Criterion Covered Total %
statement 57 230 24.7
branch 0 38 0.0
condition 0 6 0.0
subroutine 19 45 42.2
pod n/a
total 76 319 23.8


line stmt bran cond sub pod time code
1             #
2             # $Id: AddSignature.pm 22 2015-01-04 16:42:47Z gomor $
3             #
4             package Net::SinFP3::Output::AddSignature;
5 1     1   614 use strict;
  1         2  
  1         36  
6 1     1   4 use warnings;
  1         47  
  1         38  
7              
8 1     1   5 use base qw(Net::SinFP3::Output);
  1         1  
  1         350  
9             our @AS = qw(
10             trusted
11             );
12             __PACKAGE__->cgBuildIndices;
13             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
14              
15 1     1   682 use Data::Dumper;
  1         6777  
  1         154  
16              
17 1     1   8 use Net::SinFP3::Ext::DBI::Signature;
  1         2  
  1         15  
18 1     1   39 use Net::SinFP3::Ext::DBI::IpVersion;
  1         2  
  1         11  
19 1     1   36 use Net::SinFP3::Ext::DBI::SystemClass;
  1         2  
  1         10  
20 1     1   33 use Net::SinFP3::Ext::DBI::Vendor;
  1         3  
  1         9  
21 1     1   32 use Net::SinFP3::Ext::DBI::Os;
  1         3  
  1         7  
22 1     1   33 use Net::SinFP3::Ext::DBI::OsVersion;
  1         1  
  1         10  
23 1     1   43 use Net::SinFP3::Ext::DBI::OsVersionFamily;
  1         2  
  1         8  
24 1     1   34 use Net::SinFP3::Ext::DBI::OsVersionChildren;
  1         4  
  1         8  
25 1     1   35 use Net::SinFP3::Ext::DBI::PatternBinary;
  1         2  
  1         9  
26 1     1   29 use Net::SinFP3::Ext::DBI::PatternTcpFlags;
  1         2  
  1         6  
27 1     1   19 use Net::SinFP3::Ext::DBI::PatternTcpWindow;
  1         4  
  1         6  
28 1     1   21 use Net::SinFP3::Ext::DBI::PatternTcpOptions;
  1         1  
  1         6  
29 1     1   17 use Net::SinFP3::Ext::DBI::PatternTcpMss;
  1         1  
  1         6  
30 1     1   15 use Net::SinFP3::Ext::DBI::PatternTcpWScale;
  1         1  
  1         9  
31 1     1   17 use Net::SinFP3::Ext::DBI::PatternTcpOLength;
  1         2  
  1         5  
32              
33             # For easier access
34             my $tIpVersion = 'Net::SinFP3::Ext::DBI::IpVersion';
35             my $tPatternBinary = 'Net::SinFP3::Ext::DBI::PatternBinary';
36             my $tPatternTcpFlags = 'Net::SinFP3::Ext::DBI::PatternTcpFlags';
37             my $tPatternTcpWindow = 'Net::SinFP3::Ext::DBI::PatternTcpWindow';
38             my $tPatternTcpOptions = 'Net::SinFP3::Ext::DBI::PatternTcpOptions';
39             my $tPatternTcpMss = 'Net::SinFP3::Ext::DBI::PatternTcpMss';
40             my $tPatternTcpWScale = 'Net::SinFP3::Ext::DBI::PatternTcpWScale';
41             my $tPatternTcpOLength = 'Net::SinFP3::Ext::DBI::PatternTcpOLength';
42             my $tSystemClass = 'Net::SinFP3::Ext::DBI::SystemClass';
43             my $tVendor = 'Net::SinFP3::Ext::DBI::Vendor';
44             my $tOs = 'Net::SinFP3::Ext::DBI::Os';
45             my $tOsVersion = 'Net::SinFP3::Ext::DBI::OsVersion';
46             my $tOsVersionFamily = 'Net::SinFP3::Ext::DBI::OsVersionFamily';
47             my $tOsVersionChildren = 'Net::SinFP3::Ext::DBI::OsVersionChildren';
48              
49             sub new {
50 0     0     my $self = shift->SUPER::new(
51             trusted => 0,
52             @_,
53             );
54              
55 0           return $self;
56             }
57              
58             sub run {
59 0 0   0     my $self = shift->SUPER::run(@_) or return;
60              
61 0           my $global = $self->global;
62 0           my $log = $global->log;
63 0           my @results = $global->result;
64 0           my $db = $global->db;
65              
66 0           my $r = $results[0];
67              
68 0 0         if (ref($r) =~ /^Net::SinFP3::Result::PortError$/) {
69 0           $log->error("We cannot add a signature for a port in error");
70 0           return;
71             }
72              
73 0           my $buf = '';
74 0 0         $buf .= 'P1: '.$r->s1->print."\n" if $r->s1;
75 0 0         $buf .= 'P2: '.$r->s2->print."\n" if $r->s2;
76 0 0         $buf .= 'P3: '.$r->s3->print."\n" if $r->s3;
77              
78 0           $buf .= "[+] Results for target: [".$r->ip."]:".$r->port."\n";
79              
80 0 0         if (ref($r) =~ /^Net::SinFP3::Result::Unknown$/) {
    0          
81 0           $buf .= $r->print;
82             }
83             elsif (ref($r) =~ /^Net::SinFP3::Result::Active$/) {
84 0           for my $r (@results) {
85 0           $buf .= $r->print."\n";
86             }
87             }
88             else {
89 0           $log->error("Don't know what to do with this result object [".
90             ref($r)."]");
91 0           return;
92             }
93              
94 0           my $s2 = $r->s2;
95 0 0 0       if ($s2 && length($s2->O) <= 9) {
96 0           $buf .= '[!] WARNING: not enough TCP options for P2 reply, '.
97             'result may be false'."\n";
98             }
99              
100 0           print $buf."\n";
101              
102             # Disconnect, give access to this process, it is not using
103             # the same Perl interface to SQLite
104 0           $db->post;
105              
106 0           my $dbh = Net::SinFP3::Ext::DBI->connection(
107             "dbi:SQLite:dbname=".$db->file,
108             '',
109             '',
110             { AutoCommit => 0 },
111             );
112              
113 0           my $p1 = $r->s1->print;
114 0           my $p2 = $r->s2->print;
115 0           my $p3 = $r->s3->print;
116            
117 0           my @patternsP1 = (split('\s+', $p1))[0..6];
118 0           my @patternsP2 = (split('\s+', $p2))[0..6];
119 0           my @patternsP3 = (split('\s+', $p3))[0..6];
120            
121             # Get possible option if a match is similar to this new signature
122 0           my %systemClassList = ();
123 0           my %vendorList = ();
124 0           my %osList = ();
125 0           my %osVersionList = ();
126 0           my %osVersionFamilyList = ();
127 0           my $addOsVersionChildren = 0;
128 0           for my $o (@results) {
129 0 0 0       if ($o->matchType eq "S1S2S3" && $o->matchMask eq "BH0FH0WH0OH0MH0SH0LH0") {
130 0           print "[-] A HEURISTIC0 match was found, you may want to add an ".
131             "OsVersionChildren instead.\n";
132 0 0         _addOsVersionChildren($o) && $addOsVersionChildren++;
133             }
134 0           $systemClassList {$o->systemClass}++;
135 0           $vendorList {$o->vendor}++;
136 0           $osList {$o->os}++;
137 0           $osVersionList {$o->osVersion}++;
138 0           $osVersionFamilyList{$o->osVersionFamily}++;
139             }
140             # We only wanted to add osVersionChildren
141 0 0         if ($addOsVersionChildren) {
142 0           return 1;
143             }
144 0           print "[+] POSSIBLE systemClass : [", join(' ', keys %systemClassList), "]\n";
145 0           print "[+] POSSIBLE vendor : [", join(' ', keys %vendorList), "]\n";
146 0           print "[+] POSSIBLE os : [", join(' ', keys %osList), "]\n";
147 0           print "[+] POSSIBLE osVersion : [", join(' ', keys %osVersionList), "]\n";
148 0           print "[+] POSSIBLE osVersionFamily: [", join(' ', keys %osVersionFamilyList), "]\n";
149              
150             # Add new possible patterns
151 0           for my $p (\@patternsP1, \@patternsP2, \@patternsP3) {
152 0           _addNewPatternBinary ({ patternBinaryHeuristic0 => $p->[0] });
153 0           _addNewPatternTcpFlags ({ patternTcpFlagsHeuristic0 => $p->[1] });
154 0           _addNewPatternTcpWindow ({ patternTcpWindowHeuristic0 => $p->[2] });
155 0           _addNewPatternTcpOptions({ patternTcpOptionsHeuristic0 => $p->[3] });
156 0           _addNewPatternTcpMss ({ patternTcpMssHeuristic0 => $p->[4] });
157 0           _addNewPatternTcpWScale ({ patternTcpWScaleHeuristic0 => $p->[5] });
158 0           _addNewPatternTcpOLength({ patternTcpOLengthHeuristic0 => $p->[6] });
159             }
160            
161             # Get input from user
162 0           my $systemClass = _getSystemClass();
163 0           my $vendor = _getVendor();
164 0           my $os = _getOs();
165 0           my $osVersion = _getOsVersion();
166 0           my $osVersionFamily = _getOsVersionFamily();
167            
168             # Add new possible elements
169 0           my $nSystemClass = _addNewElementSystemClass ({ systemClass => $systemClass });
170 0           my $nVendor = _addNewElementVendor ({ vendor => $vendor });
171 0           my $nOs = _addNewElementOs ({ os => $os });
172 0           my $nOsVersion = _addNewElementOsVersion ({ osVersion => $osVersion });
173 0           my $nOsVersionFamily = _addNewElementOsVersionFamily({ osVersionFamily => $osVersionFamily });
174            
175             # Get stored IDs
176 0           my ($idBinaryP1, $idTcpFlagsP1, $idTcpWindowP1, $idTcpOptionsP1,
177             $idTcpMssP1, $idTcpWScaleP1, $idTcpOLengthP1) =
178             _selectPatterns(\@patternsP1);
179 0           my ($idBinaryP2, $idTcpFlagsP2, $idTcpWindowP2, $idTcpOptionsP2,
180             $idTcpMssP2, $idTcpWScaleP2, $idTcpOLengthP2) =
181             _selectPatterns(\@patternsP2);
182 0           my ($idBinaryP3, $idTcpFlagsP3, $idTcpWindowP3, $idTcpOptionsP3,
183             $idTcpMssP3, $idTcpWScaleP3, $idTcpOLengthP3) =
184             _selectPatterns(\@patternsP3);
185 0 0         my @idIpVersion = $tIpVersion->search(
186             ipVersion => $self->global->ipv6 ? 'IPv6' : 'IPv4',
187             );
188 0           my $idIpVersion = $idIpVersion[0]->idIpVersion;
189 0           my $idSystemClass = $nSystemClass->idSystemClass;
190 0           my $idVendor = $nVendor->idVendor;
191 0           my $idOs = $nOs->idOs;
192 0           my $idOsVersion = $nOsVersion->idOsVersion;
193 0           my $idOsVersionFamily = $nOsVersionFamily->idOsVersionFamily;
194            
195             # Add the signature
196 0 0         my $sig = Net::SinFP3::Ext::DBI::Signature->insert({
197             idIpVersion => $idIpVersion,
198             trusted => $self->trusted ? 1 : 0,
199             idSystemClass => $idSystemClass,
200             idVendor => $idVendor,
201             idOs => $idOs,
202             idOsVersion => $idOsVersion,
203             idOsVersionFamily => $idOsVersionFamily,
204             idS1PatternBinary => $idBinaryP1,
205             idS1PatternTcpFlags => $idTcpFlagsP1,
206             idS1PatternTcpWindow => $idTcpWindowP1,
207             idS1PatternTcpOptions => $idTcpOptionsP1,
208             idS1PatternTcpMss => $idTcpMssP1,
209             idS1PatternTcpWScale => $idTcpWScaleP1,
210             idS1PatternTcpOLength => $idTcpOLengthP1,
211             idS2PatternBinary => $idBinaryP2,
212             idS2PatternTcpFlags => $idTcpFlagsP2,
213             idS2PatternTcpWindow => $idTcpWindowP2,
214             idS2PatternTcpOptions => $idTcpOptionsP2,
215             idS2PatternTcpMss => $idTcpMssP2,
216             idS2PatternTcpWScale => $idTcpWScaleP2,
217             idS2PatternTcpOLength => $idTcpOLengthP2,
218             idS3PatternBinary => $idBinaryP3,
219             idS3PatternTcpFlags => $idTcpFlagsP3,
220             idS3PatternTcpWindow => $idTcpWindowP3,
221             idS3PatternTcpOptions => $idTcpOptionsP3,
222             idS3PatternTcpMss => $idTcpMssP3,
223             idS3PatternTcpWScale => $idTcpWScaleP3,
224             idS3PatternTcpOLength => $idTcpOLengthP3,
225             });
226 0           $sig->update;
227 0           $sig->dbi_commit;
228              
229 0           return 1;
230             }
231              
232             sub __getInput {
233 0     0     my ($type) = @_;
234 0           print "Enter $type:\n";
235 0           my $value;
236 0           while (<>) {
237 0           chomp;
238 0           $value .= $_;
239             }
240 0 0         die("No $type entered") unless $value;
241 0           return $value;
242             }
243 0     0     sub _getSystemClass { __getInput('systemClass') }
244 0     0     sub _getVendor { __getInput('vendor') }
245 0     0     sub _getOs { __getInput('os') }
246 0     0     sub _getOsVersion { __getInput('osVersion') }
247 0     0     sub _getOsVersionFamily { __getInput('osVersionFamily') }
248             sub _getOsVersionChildren {
249 0     0     my $list = __getInput('osVersionChildren (comma speparated list)');
250 0           my @osVersionChildrenList = split('\s*,\s*', $list);
251 0           return \@osVersionChildrenList;
252             }
253              
254             sub _selectPatterns {
255 0     0     my ($p) = @_;
256 0           my @idPatternBinary = $tPatternBinary->search (patternBinaryHeuristic0 => $p->[0]);
257 0           my @idPatternTcpFlags = $tPatternTcpFlags->search (patternTcpFlagsHeuristic0 => $p->[1]);
258 0           my @idPatternTcpWindow = $tPatternTcpWindow->search (patternTcpWindowHeuristic0 => $p->[2]);
259 0           my @idPatternTcpOptions = $tPatternTcpOptions->search(patternTcpOptionsHeuristic0 => $p->[3]);
260 0           my @idPatternTcpMss = $tPatternTcpMss->search (patternTcpMssHeuristic0 => $p->[4]);
261 0           my @idPatternTcpWScale = $tPatternTcpWScale->search (patternTcpWScaleHeuristic0 => $p->[5]);
262 0           my @idPatternTcpOLength = $tPatternTcpOLength->search(patternTcpOLengthHeuristic0 => $p->[6]);
263             return (
264 0           $idPatternBinary[0]->idPatternBinary,
265             $idPatternTcpFlags[0]->idPatternTcpFlags,
266             $idPatternTcpWindow[0]->idPatternTcpWindow,
267             $idPatternTcpOptions[0]->idPatternTcpOptions,
268             $idPatternTcpMss[0]->idPatternTcpMss,
269             $idPatternTcpWScale[0]->idPatternTcpWScale,
270             $idPatternTcpOLength[0]->idPatternTcpOLength,
271             );
272             }
273              
274             sub __addNewPattern {
275 0     0     my ($table, $element) = @_;
276 0           my @search = $table->search(%$element);
277 0 0         if (@search < 1) {
278 0           my @values = keys %$element;
279 0           my $key = $values[0]; # We fetch the first and only one key
280 0           my $value = $element->{$key}; # We fetch first key value
281 0           (my $field = $key) =~ s/Heuristic0$//;
282 0           print "[+] New pattern: [$value] for field [$field]\n";
283 0           print "Enter heuristic1 value (enter CTRL+D on a new line when done):\n";
284 0           my $h1;
285 0           while (<>) {
286 0           chomp;
287 0           $h1 .= $_;
288             }
289 0           print "Enter heuristic2 value (enter CTRL+D on a new line when done):\n";
290 0           my $h2;
291 0           while (<>) {
292 0           chomp;
293 0           $h2 .= $_;
294             }
295 0 0         $h1 = $value unless $h1;
296 0 0         $h2 = $value unless $h2;
297 0           return __addNewElement($table, {
298             $field.'Heuristic0' => $value,
299             $field.'Heuristic1' => $h1,
300             $field.'Heuristic2' => $h2,
301             });
302             }
303 0           return $search[0];
304             }
305              
306 0     0     sub _addNewPatternBinary { __addNewPattern($tPatternBinary, @_) }
307 0     0     sub _addNewPatternTcpFlags { __addNewPattern($tPatternTcpFlags, @_) }
308 0     0     sub _addNewPatternTcpWindow { __addNewPattern($tPatternTcpWindow, @_) }
309 0     0     sub _addNewPatternTcpOptions { __addNewPattern($tPatternTcpOptions, @_) }
310 0     0     sub _addNewPatternTcpMss { __addNewPattern($tPatternTcpMss, @_) }
311 0     0     sub _addNewPatternTcpWScale { __addNewPattern($tPatternTcpWScale, @_) }
312 0     0     sub _addNewPatternTcpOLength { __addNewPattern($tPatternTcpOLength, @_) }
313              
314             sub __addNewElement {
315 0     0     my ($table, $element) = @_;
316 0           my @search = $table->search(%$element);
317 0 0         if (@search < 1) {
318 0           my $new = $table->insert($element);
319 0           $new->update;
320 0           print "[+] Added new element: ",Dumper($element),"\n";
321 0           return $new;
322             }
323 0           return $search[0];
324             }
325 0     0     sub _addNewElementSystemClass { __addNewElement($tSystemClass, @_) }
326 0     0     sub _addNewElementVendor { __addNewElement($tVendor, @_) }
327 0     0     sub _addNewElementOs { __addNewElement($tOs, @_) }
328 0     0     sub _addNewElementOsVersion { __addNewElement($tOsVersion, @_) }
329 0     0     sub _addNewElementOsVersionFamily { __addNewElement($tOsVersionFamily, @_) }
330 0     0     sub _addNewElementOsVersionChildren { __addNewElement($tOsVersionChildren, @_) }
331              
332             sub _addOsVersionChildren {
333 0     0     my ($result) = @_;
334              
335 0           my $idSignature = $result->idSignature;
336 0           print "Would you like to add OsVersionChildren for this one? (CTRL+D for not)\n".
337             "=> [", $result->os, " ", $result->osVersion, "]\n";
338 0           my $input = '';
339 0           while (<>) {
340 0           chomp;
341 0           $input .= $_;
342             }
343 0 0         return unless $input;
344              
345 0           my $osVersionChildrenList = _getOsVersionChildren();
346 0           my @idOsVersionList = ();
347 0           for my $o (@$osVersionChildrenList) {
348 0           my $new = _addNewElementOsVersion({ osVersion => $o });
349 0           push @idOsVersionList, $new->idOsVersion;
350             }
351 0           for my $o (@idOsVersionList) {
352 0           _addNewElementOsVersionChildren({
353             idSignature => $idSignature,
354             idOsVersion => $o,
355             });
356             }
357 0           $tOsVersionChildren->dbi_commit;
358              
359 0           return 1;
360             }
361              
362             1;
363              
364             __END__