So I had a bunch of machines with a standard naming convention that I needed to scan for the Shellshock bug. Since I just needed to run a command on each one and check the output, and I had SSH access, it seemed easy enough to put together a quick script to manage the process.
Here’s a skeleton of that script, with the details on what machines I was logging into elided. This does a pretty reasonable job, checking 300 machines in about a minute. You need to have a more recent copy of Parallel::ForkManager, as versions prior to 1.0 don’t have the ability to return a data structure from the child.
$|++; use strict; use warnings; use Parallel::ForkManager 1.07; my $MAX_PROCESSES = 25; my $pm = Parallel::ForkManager->new($MAX_PROCESSES); my @servers = @SERVER_NAMES; my %statuses; my @diagnostics; $pm-> run_on_finish ( sub { my($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_; if (defined($data_structure_reference)) { my ($host_id, $status, $results) = @{$data_structure_reference}; if ($status eq 'Unknown') { push @diagnostics, $host_id, $results; } else { push @{ $statuses{$status} }, $host_id; } } else { warn qq|No message received from child process $pid!\n|; } } ); print "Testing servers: "; for my $host_id (@servers) { my $pid = $pm->start and next; my $result = << `EOF`; ssh -o StrictHostKeyChecking=no $host_id <<'ENDSSH' 2>&1 env x='() { :;}; echo vulnerable' bash -c "echo this is a test" ENDSSH EOF my $status; if ($result =~ /Permission denied/is) { $status = q{Inacessible}; } elsif ($result =~ /key verification failed/s) { $status = q{Key changed}; } elsif ($result =~ /timed out/is) { $status = q{Timed out}; } elsif ($result =~ /vulnerable/s) { $status = q{Vulnerable}; } elsif ($result =~ /ignoring function definition attempt/s) { $status = q{Patched}; } elsif ($result =~ /Name or service not known/s) { $status = q{Nonexistent}; } else { $status = q{Unknown} } print "$host_id, "; $pm->finish(0, [$host_id, $status, $result]); } $pm->wait_all_children; print "done!\n"; for my $status (keys %statuses) { print "$status: ",join(',', @{$statuses{$status}}), "\n"; } print "The following hosts returned an undiagnosed status:", join("\n", @diagnostics), "\n";
Note that this doesn’t test the most recent version (#3) of the bug; I have modified it slightly to test for that, but that’s a reasonable exercise for the reader.
Leave a Reply
You must be logged in to post a comment.