1package Nmap::Scanner::Backend::XML; 2 3use strict; 4 5use vars qw(@ISA); 6@ISA = qw(Nmap::Scanner::Backend::Processor); 7 8use XML::SAX::ParserFactory; 9 10use Nmap::Scanner; 11use Nmap::Scanner::Backend::Results; 12use Nmap::Scanner::Backend::Processor; 13 14sub new { 15 my $class = shift; 16 my $you = $class->SUPER::new(); 17 return bless $you, $class; 18} 19 20# Process results from "-oX -" 21 22sub process { 23 24 my $self = shift; 25 my $pid = shift; 26 my $read = shift; 27 my $cmdline = shift; 28 my $error = shift; 29 30 # Suppress warnings about reading unopened handle 31 $^W = 0; 32 my $err = join('', (<$error>)); 33 $^W = 1; 34 35 if ($err ne '') { 36 37 close($read); 38 close($error); 39 40 warn <<EOF; 41<nmap-error> 42 <pid="$pid"/> 43 <cmdline="$cmdline"/> 44 <nmap-err>$err</nmap-msg> 45</nmap-error> 46EOF 47 exit 1; 48 } 49 50 my $handler = NmapHandler->new($self); 51 my $parser = XML::SAX::ParserFactory->parser(Handler => $handler); 52 53 eval { $parser->parse_file($read) }; 54 55 56 if (defined($@) && ($@ ne '')) { 57 58 my $msg = join('', <$read>); 59 60 Nmap::Scanner::debug("bytes in input stream: " . tell($read)); 61 Nmap::Scanner::debug("bytes in error stream: " . tell($error)); 62 63 warn <<EOF; 64<nmap-error> 65 <pid="$pid"/> 66 <cmdline="$cmdline"/> 67 <perl-msg>$@</perl-msg> 68 <nmap-msg>$msg</nmap-msg> 69 <nmap-err>$err</nmap-msg> 70</nmap-error> 71EOF 72 close($read); 73 exit 1; 74 75 } 76 77 close($read); 78 79 return $handler->results(); 80 81} 82 831; 84 85# 86# SAX listener to process XML output from nmap. 87# 88 89package NmapHandler; 90 91 use strict; 92 use base qw(XML::SAX::Base); 93 94 use XML::SAX::Base; 95 96 use Nmap::Scanner::Host; 97 use Nmap::Scanner::Hostname; 98 use Nmap::Scanner::Port; 99 use Nmap::Scanner::Service; 100 use Nmap::Scanner::Address; 101 use Nmap::Scanner::Hosts; 102 use Nmap::Scanner::ExtraPorts; 103 use Nmap::Scanner::RunStats; 104 use Nmap::Scanner::RunStats::Finished; 105 use Nmap::Scanner::NmapRun; 106 use Nmap::Scanner::ScanInfo; 107 use Nmap::Scanner::Task; 108 use Nmap::Scanner::TaskProgress; 109 use Nmap::Scanner::Distance; 110 use Nmap::Scanner::Backend::Results; 111 112 use Nmap::Scanner::OS; 113 use Nmap::Scanner::OS::PortUsed; 114 use Nmap::Scanner::OS::Uptime; 115 use Nmap::Scanner::OS::Class; 116 use Nmap::Scanner::OS::Match; 117 use Nmap::Scanner::OS::TCPSequence; 118 use Nmap::Scanner::OS::TCPTSSequence; 119 use Nmap::Scanner::OS::IPIdSequence; 120 use Nmap::Scanner::OS::Fingerprint; 121 122 # One function per element .. fun! ;) 123 124 my %HANDLERS = ( 125 host => \&host, 126 hosts => \&hosts, 127 status => \&hoststatus, 128 hostname => \&hostname, 129 smurf => \&smurf, 130 address => \&hostaddress, 131 hostnames => \&hostnames, 132 port => \&port, 133 ports => \&ports, 134 state => \&state, 135 service => \&service, 136 owner => \&owner, 137 addport => \&addport, 138 extraports => \&extraports, 139 os => \&os, 140 portused => \&portused, 141 osclass => \&osclass, 142 osfingerprint => \&osfingerprint, 143 osmatch => \&osmatch, 144 uptime => \&uptime, 145 tcpsequence => \&tcpsequence, 146 tcptssequence => \&tcptssequence, 147 ipidsequence => \&ipidsequence, 148 nmaprun => \&nmaprun, 149 scaninfo => \&scaninfo, 150 taskbegin => \&taskbegin, 151 taskend => \&taskend, 152 taskprogress => \&taskprogress, 153 verbose => \&verbose, 154 debugging => \&debugging, 155 runstats => \&runstats, 156 finished => \&finished, 157 distance => \&distance, 158 ); 159 160 sub new { 161 my $class = shift; 162 my $backend = shift; 163 my $self = $class->SUPER::new(); 164 $self->{NMAP_BACKEND} = $backend; 165 $self->{NMAP_PORT} = undef; 166 $self->{NMAP_HOST} = undef; 167 $self->{NMAP_RUNSTATS} = undef; 168 $self->{NMAP_NMAPRUN} = undef; 169 $self->{PORT_COUNT} = 0; 170 $self->{NMAP_OSGUESS} = undef; 171 $self->{NMAP_RESULTS} = Nmap::Scanner::Backend::Results->new(); 172 $self->{NMAP_TASK} = undef; 173 $self->{NMAP_TASK_PROGRESS} = undef; 174 return bless $self, $class; 175 } 176 177 # Controller for start element handlers 178 179 sub start_element { 180 my ($self, $el) = @_; 181 my $name = $el->{Name}; 182 183 if (exists $HANDLERS{$name}) { 184 Nmap::Scanner::debug("About to handle $name"); 185 &{$HANDLERS{$name}}($self, $el->{Attributes}); 186 Nmap::Scanner::debug("Handled $name"); 187 } else { 188 189 my %attrs = %{$el->{Attributes}}; 190 191 return unless Nmap::Scanner::debug("Received unhandled XML: $name"); 192 193 for my $key (keys %attrs) { 194 Nmap::Scanner::debug("Unhandled[$name]: $key = $attrs{$key}"); 195 } 196 } 197 } 198 199 # Controller for end element handlers 200 201 sub end_element { 202 203 my ($self, $el) = @_; 204 205 if ($el->{Name} eq 'host') { 206 my $host = $self->{NMAP_HOST}; 207 $self->{NMAP_HOST}->os($self->{NMAP_OSGUESS}) 208 if $self->{NMAP_OSGUESS}; 209 $self->{NMAP_RESULTS}->add_host($host); 210 $self->{NMAP_BACKEND}->notify_scan_complete($self->{NMAP_HOST}); 211 undef $self->{NMAP_OSGUESS}; 212 } elsif ($el->{Name} eq 'hosts') { 213 $self->{NMAP_NMAPRUN}->run_stats($self->{NMAP_RUNSTATS}); 214 } elsif ($el->{Name} eq 'port') { 215 my $port = $self->{NMAP_PORT}; 216 Nmap::Scanner::debug("Adding port: " . $port->portid()); 217 $self->{NMAP_HOST}->add_port($port); 218 $self->{PORT_COUNT}++; 219 $self->{NMAP_BACKEND}->notify_port_found( 220 $self->{NMAP_HOST}, $self->{NMAP_PORT} 221 ); 222 undef $self->{NMAP_PORT}; 223 } elsif ($el->{Name} eq 'ports') { 224 unless ($self->{PORT_COUNT} > 0) { 225 $self->{NMAP_BACKEND}->notify_no_ports_open( 226 $self->{NMAP_HOST}, $self->{NMAP_HOST}->extra_ports() 227 ); 228 } 229 $self->{PORT_COUNT} = 0; 230 } elsif ($el->{Name} eq 'hostnames') { 231 $self->{NMAP_BACKEND}->notify_scan_started($self->{NMAP_HOST}); 232 } elsif ($el->{Name} eq 'taskbegin') { 233 $self->{NMAP_BACKEND}->notify_task_started($self->{NMAP_TASK}); 234 } elsif ($el->{Name} eq 'taskend') { 235 $self->{NMAP_BACKEND}->notify_task_ended($self->{NMAP_TASK}); 236 } elsif ($el->{Name} eq 'taskprogress') { 237 $self->{NMAP_BACKEND}->notify_task_progress( 238 $self->{NMAP_TASK_PROGRESS}); 239 } elsif ($el->{Name} eq 'nmaprun') { 240 $self->{NMAP_RESULTS}->nmap_run($self->{NMAP_NMAPRUN}); 241 } 242 } 243 244 sub host { 245 my ($self, $ref) = @_; 246 $self->{NMAP_HOST} = Nmap::Scanner::Host->new(); 247 } 248 249 sub hoststatus { 250 my ($self, $ref) = @_; 251 my $state = $ref->{'{}state'}->{Value}; 252 $self->{NMAP_HOST}->status($state); 253 } 254 255 sub hostname { 256 my ($self, $ref) = @_; 257 my $host = $self->{NMAP_HOST}; 258 my $hostname = Nmap::Scanner::Hostname->new(); 259 $hostname->name($ref->{'{}name'}->{Value}); 260 $hostname->type($ref->{'{}type'}->{Value}); 261 $host->add_hostname($hostname); 262 } 263 264 sub hostnames { 265 my $self = shift; 266 # Do nothing, as this is just an array of hostnames, held in Host object. 267 } 268 269 sub ports { 270 my $self = shift; 271 # Do nothing, as this is just an array of ports, held in Host object. 272 } 273 274 sub smurf { 275 my ($self, $ref) = @_; 276 my $smurf = $ref->{'{}responses'}->{Value}; 277 $self->{NMAP_HOST}->smurf($smurf); 278 } 279 280 sub hostaddress { 281 my ($self, $ref) = @_; 282 my $addr = Nmap::Scanner::Address->new(); 283 $addr->addr($ref->{'{}addr'}->{Value}); 284 $addr->addrtype($ref->{'{}addrtype'}->{Value}); 285 $addr->vendor($ref->{'{}vendor'}->{Value}) 286 if $ref->{'{}vendor'}->{Value}; 287 $self->{NMAP_HOST}->add_address($addr); 288 } 289 290 sub port { 291 my ($self, $ref) = @_; 292 my $port = Nmap::Scanner::Port->new(); 293 $port->protocol($ref->{'{}protocol'}->{Value}); 294 $port->portid($ref->{'{}portid'}->{Value}); 295 $self->{NMAP_PORT} = $port; 296 } 297 298 sub state { 299 my ($self, $ref) = @_; 300 $self->{NMAP_PORT}->state($ref->{'{}state'}->{Value}); 301 } 302 303 sub owner { 304 my ($self, $ref) = @_; 305 my $owner = $ref->{'{}name'}->{Value}; 306 $self->{NMAP_PORT}->owner($owner); 307 } 308 309 sub service { 310 311 my ($self, $ref) = @_; 312 my $port = $self->{NMAP_PORT}; 313 my $svc = Nmap::Scanner::Service->new(); 314 $svc->name($ref->{'{}name'}->{Value}); 315 $svc->proto($ref->{'{}proto'}->{Value}); 316 $svc->rpcnum($ref->{'{}rpcnum'}->{Value}); 317 $svc->lowver($ref->{'{}lowver'}->{Value}); 318 $svc->highver($ref->{'{}highver'}->{Value}); 319 $svc->method($ref->{'{}method'}->{Value}); 320 $svc->conf($ref->{'{}conf'}->{Value}); 321 $svc->tunnel($ref->{'{}tunnel'}->{Value}); 322 $svc->product($ref->{'{}product'}->{Value}); 323 $svc->version($ref->{'{}version'}->{Value}); 324 $svc->extrainfo($ref->{'{}extrainfo'}->{Value}); 325 $port->service($svc); 326 } 327 328 sub addport { 329 my ($self, $ref) = @_; 330 331 my $port = Nmap::Scanner::Port->new(); 332 $port->state($ref->{'{}state'}->{Value}); 333 $port->protocol($ref->{'{}protocol'}->{Value}); 334 $port->portid($ref->{'{}portid'}->{Value}); 335 $port->owner($ref->{'{}owner'}->{Value}) 336 if $ref->{'{}owner'}; 337 $self->{NMAP_BACKEND}->notify_port_found( 338 $self->{NMAP_HOST}, $port 339 ); 340 } 341 342 sub extraports { 343 my ($self, $ref) = @_; 344 my $extras = Nmap::Scanner::ExtraPorts->new(); 345 $extras->state($ref->{'{}state'}->{Value}); 346 $extras->count($ref->{'{}count'}->{Value}); 347 $self->{NMAP_HOST}->extra_ports($extras); 348 } 349 350 sub os { 351 my ($self, $ref) = @_; 352 $self->{NMAP_OSGUESS} = Nmap::Scanner::OS->new(); 353 } 354 355 sub osclass { 356 my ($self, $ref) = @_; 357 my $os = $self->{NMAP_OSGUESS}; 358 my $class = Nmap::Scanner::OS::Class->new(); 359 $class->type($ref->{'{}type'}->{Value}); 360 $class->vendor($ref->{'{}vendor'}->{Value}); 361 $class->osfamily($ref->{'{}osfamily'}->{Value}); 362 $class->osgen($ref->{'{}osgen'}->{Value}); 363 $class->accuracy($ref->{'{}accuracy'}->{Value}); 364 $os->add_os_class($class); 365 } 366 367 sub osfingerprint { 368 my ($self, $ref) = @_; 369 my $os = $self->{NMAP_OSGUESS}; 370 my $fingerprint = Nmap::Scanner::OS::Fingerprint->new(); 371 $fingerprint->fingerprint($ref->{'{}fingerprint'}->{Value}); 372 $os->osfingerprint($fingerprint); 373 } 374 375 sub osmatch { 376 my ($self, $ref) = @_; 377 my $os = $self->{NMAP_OSGUESS}; 378 my $match = Nmap::Scanner::OS::Match->new(); 379 $match->name($ref->{'{}name'}->{Value}); 380 $match->accuracy($ref->{'{}accuracy'}->{Value}); 381 $os->add_os_match($match); 382 } 383 384 sub portused { 385 my ($self, $ref) = @_; 386 my $os = $self->{NMAP_OSGUESS}; 387 my $port = Nmap::Scanner::OS::PortUsed->new(); 388 $port->state($ref->{'{}state'}->{Value}); 389 $port->proto($ref->{'{}proto'}->{Value}); 390 $port->portid($ref->{'{}portid'}->{Value}); 391 $os->add_port_used($port); 392 } 393 394 sub uptime { 395 my ($self, $ref) = @_; 396 my $os = $self->{NMAP_OSGUESS}; 397 my $u = Nmap::Scanner::OS::Uptime->new(); 398 $u->seconds($ref->{'{}seconds'}->{Value}); 399 $u->lastboot($ref->{'{}lastboot'}->{Value}); 400 $os->uptime($u); 401 } 402 403 sub tcpsequence { 404 my ($self, $ref) = @_; 405 my $os = $self->{NMAP_OSGUESS}; 406 my $t = Nmap::Scanner::OS::TCPSequence->new(); 407 $t->index($ref->{'{}index'}->{Value}); 408 $t->class($ref->{'{}class'}->{Value}); 409 $t->difficulty($ref->{'{}difficulty'}->{Value}); 410 $t->values($ref->{'{}values'}->{Value}); 411 $os->tcpsequence($t); 412 } 413 414 sub tcptssequence { 415 my ($self, $ref) = @_; 416 my $os = $self->{NMAP_OSGUESS}; 417 my $t = Nmap::Scanner::OS::TCPTSSequence->new(); 418 $t->class($ref->{'{}class'}->{Value}); 419 $t->values($ref->{'{}values'}->{Value}); 420 $os->tcptssequence($t); 421 } 422 423 sub ipidsequence { 424 my ($self, $ref) = @_; 425 my $os = $self->{NMAP_OSGUESS}; 426 my $t = Nmap::Scanner::OS::IPIdSequence->new(); 427 $t->class($ref->{'{}class'}->{Value}); 428 $t->values($ref->{'{}values'}->{Value}); 429 $os->ipidsequence($t); 430 } 431 432 sub nmaprun { 433 my ($self, $ref) = @_; 434 my $run = Nmap::Scanner::NmapRun->new(); 435 $run->scanner($ref->{'{}scanner'}->{Value}); 436 $run->args($ref->{'{}args'}->{Value}); 437 $run->start($ref->{'{}start'}->{Value}); 438 $run->startstr($ref->{'{}startstr'}->{Value}); 439 $run->version($ref->{'{}version'}->{Value}); 440 $run->xmloutputversion($ref->{'{}xmloutputversion'}->{Value}); 441 $self->{NMAP_NMAPRUN} = $run; 442 } 443 444 sub scaninfo { 445 my ($self, $ref) = @_; 446 my $info = Nmap::Scanner::ScanInfo->new(); 447 $info->type($ref->{'{}type'}->{Value}); 448 $info->protocol($ref->{'{}protocol'}->{Value}); 449 $info->numservices($ref->{'{}numservices'}->{Value}); 450 $info->services($ref->{'{}services'}->{Value}); 451 $self->{NMAP_NMAPRUN}->add_scan_info($info); 452 } 453 454 sub taskbegin { 455 my ($self, $ref) = @_; 456 my $name = $ref->{'{}task'}->{'Value'}; 457 my $time = $ref->{'{}time'}->{'Value'}; 458 my $task = Nmap::Scanner::Task->new(); 459 $task->name($name); 460 $task->begin_time($time); 461 $self->{NMAP_TASK} = $task; 462 } 463 464 sub taskprogress { 465 466 my ($self, $ref) = @_; 467 468 my $time = $ref->{'{}time'}->{'Value'}; 469 my $percent = $ref->{'{}percent'}->{'Value'}; 470 my $remaining = $ref->{'{}remaining'}->{'Value'}; 471 my $etc = $ref->{'{}etc'}->{'Value'}; 472 my $tp = Nmap::Scanner::TaskProgress->new(); 473 474 $tp->task($self->{NMAP_TASK}); 475 $tp->time($time); 476 $tp->percent($percent); 477 $tp->remaining($remaining); 478 $tp->etc($etc); 479 480 $self->{NMAP_TASK_PROGRESS} = $tp; 481 482 } 483 484 sub taskend { 485 486 my ($self, $ref) = @_; 487 my $name = $ref->{'{}task'}->{'Value'}; 488 my $time = $ref->{'{}time'}->{'Value'}; 489 my $task = $self->{NMAP_TASK}; 490 491 $task->end_time($time); 492 493 $self->{NMAP_NMAPRUN}->add_task($task); 494 495 } 496 497 sub distance { 498 my ($self, $ref) = @_; 499 my $distance = Nmap::Scanner::Distance->new(); 500 my $value = $ref->{'{}value'}->{Value}; 501 $distance->value($value); 502 $self->{NMAP_HOST}->distance($distance); 503 } 504 505 sub verbose { 506 my ($self, $ref) = @_; 507 $self->{NMAP_NMAPRUN}->verbose($ref->{'{}level'}->{Value}); 508 } 509 510 sub debugging { 511 my ($self, $ref) = @_; 512 $self->{NMAP_NMAPRUN}->debugging($ref->{'{}level'}->{Value}); 513 } 514 515 sub runstats { 516 my ($self, $ref) = @_; 517 my $stats = Nmap::Scanner::RunStats->new(); 518 $self->{NMAP_RUNSTATS} = $stats; 519 } 520 521 sub hosts { 522 my ($self, $ref) = @_; 523 my $hosts = Nmap::Scanner::Hosts->new(); 524 $hosts->up($ref->{'{}up'}->{Value}); 525 $hosts->down($ref->{'{}down'}->{Value}); 526 $hosts->total($ref->{'{}total'}->{Value}); 527 $self->{NMAP_RUNSTATS}->hosts($hosts); 528 } 529 530 sub finished { 531 my ($self, $ref) = @_; 532 my $f = Nmap::Scanner::RunStats::Finished->new(); 533 $f->time($ref->{'{}time'}->{Value}); 534 $f->timestr($ref->{'{}timestr'}->{Value}); 535 $self->{NMAP_RUNSTATS}->finished($f); 536 } 537 538 sub results { 539 my $self = shift; 540 return $self->{NMAP_RESULTS}; 541 } 542 5431; 544 545