| 269 | | use Storable qw(dclone); |
|---|
| | 269 | can_ok('Storable', 'thaw'); |
|---|
| | 270 | use Storable qw(dclone thaw); |
|---|
| | 271 | |
|---|
| | 272 | # Make sure MIME::Base64 loads. |
|---|
| | 273 | BEGIN { use_ok('MIME::Base64', qw(encode_base64 decode_base64)) or diag("Can't load MIME::Base64 package. Check to make sure the package library is correctly listed within the path."); } |
|---|
| | 274 | require_ok('MIME::Base64'); |
|---|
| | 275 | can_ok('MIME::Base64', 'encode_base64'); |
|---|
| | 276 | can_ok('MIME::Base64', 'decode_base64'); |
|---|
| | 277 | use MIME::Base64 qw(encode_base64 decode_base64); |
|---|
| 741 | | # TODO: Comment this. |
|---|
| | 750 | # Helper function designed to "pop" a key off a given hashtable. |
|---|
| | 751 | # When given a hashtable reference, this function will extract a valid key |
|---|
| | 752 | # from the hashtable and delete the (key, value) pair from the |
|---|
| | 753 | # hashtable. The link with the highest score is returned. |
|---|
| | 754 | # |
|---|
| | 755 | # Inputs: hashref |
|---|
| | 756 | # Outputs: valid key, or undef if the hash is empty |
|---|
| | 757 | sub _pop { |
|---|
| | 758 | |
|---|
| | 759 | # Get supplied hash reference. |
|---|
| | 760 | my $hash = shift; |
|---|
| | 761 | |
|---|
| | 762 | # Get the highest score. |
|---|
| | 763 | my @array = sort {$$hash{$b} <=> $$hash{$a}} keys %{$hash}; |
|---|
| | 764 | my $topkey = $array[0]; |
|---|
| | 765 | |
|---|
| | 766 | # Delete the key from the hashtable. |
|---|
| | 767 | if (defined($topkey)) { |
|---|
| | 768 | delete $hash->{$topkey}; |
|---|
| | 769 | } |
|---|
| | 770 | |
|---|
| | 771 | # Return the key found. |
|---|
| | 772 | return $topkey; |
|---|
| | 773 | } |
|---|
| | 774 | |
|---|
| | 775 | # Helper function designed to change the status of a supplied |
|---|
| | 776 | # VM Clone object. |
|---|
| | 777 | # |
|---|
| | 778 | # Output: The updated Clone $object, reflecting the status change |
|---|
| | 779 | # of the clone VM. Will croak if this operation fails. |
|---|
| | 835 | } |
|---|
| | 836 | |
|---|
| | 837 | # XXX: Comment this. |
|---|
| | 838 | sub _dumpFingerprint { |
|---|
| | 839 | |
|---|
| | 840 | # Dump the fingerprint to a file, if needed. |
|---|
| | 841 | my $COMPROMISE_FILE = getVar(name => "fingerprint_dump"); |
|---|
| | 842 | if (length($COMPROMISE_FILE) > 0 && |
|---|
| | 843 | defined($fingerprint)) { |
|---|
| | 844 | $LOG->info("Saving fingerprint to '" . $COMPROMISE_FILE . "'."); |
|---|
| | 845 | my $dump_file = new IO::File($COMPROMISE_FILE, "a"); |
|---|
| | 846 | |
|---|
| | 847 | # XXX: Delete this block, eventually. |
|---|
| | 848 | $Data::Dumper::Terse = 0; |
|---|
| | 849 | $Data::Dumper::Indent = 2; |
|---|
| | 850 | print $dump_file "\$vmName = \"" . $vmName . "\";\n"; |
|---|
| | 851 | print $dump_file Dumper($fingerprint); |
|---|
| | 852 | $dump_file->close(); |
|---|
| | 853 | } |
|---|
| 1186 | | # TODO: Comment this. |
|---|
| 1187 | | sub something { |
|---|
| | 1239 | =pod |
|---|
| | 1240 | |
|---|
| | 1241 | =head2 $object->drive(work => $work) |
|---|
| | 1242 | |
|---|
| | 1243 | =over 4 |
|---|
| | 1244 | |
|---|
| | 1245 | Drives the Agent running inside the Clone VM, based upon |
|---|
| | 1246 | the work supplied. If any portion of the work causes the |
|---|
| | 1247 | VM to become compromised, then the compromised VM will be |
|---|
| | 1248 | suspended, archived, and logged -- while a new clone VM |
|---|
| | 1249 | will be created to continue processing the remaining |
|---|
| | 1250 | work. |
|---|
| | 1251 | |
|---|
| | 1252 | I<Inputs>: |
|---|
| | 1253 | B<$work> is a required argument, referencing a hashtable of |
|---|
| | 1254 | different parameters to pass to the driven application, |
|---|
| | 1255 | which is running on the Agent inside the cloned VM. |
|---|
| | 1256 | |
|---|
| | 1257 | I<Notes>: |
|---|
| | 1258 | Each "key" in the $work hashtable is a parameter; |
|---|
| | 1259 | each "value" in the $work hashtable is an integer, |
|---|
| | 1260 | reflecting the priority assigned to that key. Large values |
|---|
| | 1261 | indicate high priority. |
|---|
| | 1262 | |
|---|
| | 1263 | Here is an example of a possible $work hashtable: |
|---|
| | 1264 | |
|---|
| | 1265 | my $work = { |
|---|
| | 1266 | "http://www.mitre.org/" => 10, # First to process |
|---|
| | 1267 | "http://www.google.com/" => 5, # Second to process |
|---|
| | 1268 | "http://www.cnn.com/" => 1, # Last to process |
|---|
| | 1269 | }; |
|---|
| | 1270 | |
|---|
| | 1271 | =back |
|---|
| | 1272 | |
|---|
| | 1273 | =begin testing |
|---|
| | 1274 | |
|---|
| | 1275 | # Shared test variables. |
|---|
| | 1276 | my ($stub, $som, $URL); |
|---|
| | 1277 | my $testVM = $ENV{PWD} . "/" . getVar(name => "test_vm_config", |
|---|
| | 1278 | namespace => "HoneyClient::Manager::VM::Test"); |
|---|
| | 1279 | |
|---|
| | 1280 | # Catch all errors, in order to make sure child processes are |
|---|
| | 1281 | # properly killed. |
|---|
| | 1282 | eval { |
|---|
| | 1283 | |
|---|
| | 1284 | # Pretend as though no other Clone objects have been created prior |
|---|
| | 1285 | # to this point. |
|---|
| | 1286 | $HoneyClient::Manager::VM::Clone::OBJECT_COUNT = -1; |
|---|
| | 1287 | |
|---|
| | 1288 | my $question; |
|---|
| | 1289 | $question = prompt("#\n" . |
|---|
| | 1290 | "# Note: Testing real drive operations will *ONLY* work\n" . |
|---|
| | 1291 | "# with a fully functional master VM that has the HoneyClient code\n" . |
|---|
| | 1292 | "# loaded upon boot-up.\n" . |
|---|
| | 1293 | "#\n" . |
|---|
| | 1294 | "# Your master VM is: " . getVar(name => "master_vm_config", namespace => "HoneyClient::Manager::VM") . "\n" . |
|---|
| | 1295 | "#\n" . |
|---|
| | 1296 | "# Do you want to test cloning and driving this master VM?", "no"); |
|---|
| | 1297 | if ($question =~ /^y.*/i) { |
|---|
| | 1298 | |
|---|
| | 1299 | # Create a generic empty clone, with test state data. |
|---|
| | 1300 | my $clone = HoneyClient::Manager::VM::Clone->new(); |
|---|
| | 1301 | my $cloneConfig = $clone->{config}; |
|---|
| | 1302 | |
|---|
| | 1303 | # TODO: Fix this. |
|---|
| | 1304 | |
|---|
| | 1305 | # Archive the clone. |
|---|
| | 1306 | #$clone->archive(snapshot_file => $snapshot); |
|---|
| | 1307 | |
|---|
| | 1308 | # Wait for the archive to complete. |
|---|
| | 1309 | #sleep (45); |
|---|
| | 1310 | |
|---|
| | 1311 | # Test if the archive worked. |
|---|
| | 1312 | #is(-f $snapshot, 1, "archive(snapshot_file => '$snapshot')") or diag("The archive() call failed."); |
|---|
| | 1313 | |
|---|
| | 1314 | #unlink $snapshot; |
|---|
| | 1315 | #$clone = undef; |
|---|
| | 1316 | |
|---|
| | 1317 | # Connect to daemon as a client. |
|---|
| | 1318 | $stub = getClientHandle(namespace => "HoneyClient::Manager::VM"); |
|---|
| | 1319 | |
|---|
| | 1320 | # Destroy the clone VM. |
|---|
| | 1321 | $som = $stub->destroyVM(config => $cloneConfig); |
|---|
| | 1322 | } |
|---|
| | 1323 | }; |
|---|
| | 1324 | |
|---|
| | 1325 | # Kill the child daemon, if it still exists. |
|---|
| | 1326 | HoneyClient::Manager::VM->destroy(); |
|---|
| | 1327 | |
|---|
| | 1328 | # Report any failure found. |
|---|
| | 1329 | if ($@) { |
|---|
| | 1330 | fail($@); |
|---|
| | 1331 | } |
|---|
| | 1332 | |
|---|
| | 1333 | =end testing |
|---|
| | 1334 | |
|---|
| | 1335 | =cut |
|---|
| | 1336 | |
|---|
| | 1337 | sub drive { |
|---|
| 1210 | | |
|---|
| | 1360 | if (!$argsExist || |
|---|
| | 1361 | !exists($args{'work'}) || |
|---|
| | 1362 | !defined($args{'work'})) { |
|---|
| | 1363 | |
|---|
| | 1364 | # Croak if no valid argument is supplied. |
|---|
| | 1365 | $LOG->error("Error: No work argument supplied."); |
|---|
| | 1366 | Carp::croak "Error: No work argument supplied."; |
|---|
| | 1367 | } |
|---|
| | 1368 | |
|---|
| | 1369 | # TODO: Add more. |
|---|
| | 1370 | my $som; |
|---|
| | 1371 | my $result; |
|---|
| | 1372 | my $currentWork; |
|---|
| | 1373 | my $finishedWork = { |
|---|
| | 1374 | 'client_id' => $self->{'database_id'}, |
|---|
| | 1375 | 'links_visited' => {}, |
|---|
| | 1376 | 'links_timed_out' => {}, |
|---|
| | 1377 | 'links_ignored' => {}, |
|---|
| | 1378 | }; |
|---|
| | 1379 | my $numWorkInserted; |
|---|
| | 1380 | |
|---|
| | 1381 | while (scalar(%{$args{'work'}})) { |
|---|
| | 1382 | |
|---|
| | 1383 | # Extract the highest priority work. |
|---|
| | 1384 | $currentWork = _pop($args{'work'}); |
|---|
| | 1385 | |
|---|
| | 1386 | $LOG->info("(" . $self->{'name'} . ") - " . $self->{'driver_name'} . " - Driving To Resource: " . $currentWork); |
|---|
| | 1387 | $som = $self->{'_agent_handle'}->drive(driver_name => $self->{'driver_name'}, |
|---|
| | 1388 | parameters => encode_base64($currentWork)); |
|---|
| | 1389 | $result = thaw(decode_base64($som->result())); |
|---|
| | 1390 | |
|---|
| | 1391 | # XXX: Delete this, eventually. |
|---|
| | 1392 | print Dumper($result); |
|---|
| | 1393 | |
|---|
| | 1394 | # Figure out if there was a compromise found. |
|---|
| | 1395 | if (scalar(@{$result->{'fingerprint'}->{os_processes}})) { |
|---|
| | 1396 | $LOG->warn("(" . $self->{'name'} . ") - " . $self->{'driver_name'} . " - Integrity Check: FAILED"); |
|---|
| | 1397 | # XXX: Test this. |
|---|
| | 1398 | _dumpFingerprint($result->{'fingerprint'}); |
|---|
| | 1399 | } else { |
|---|
| | 1400 | $LOG->info("(" . $self->{'name'} . ") - " . $self->{'driver_name'} . " - Integrity Check: PASSED"); |
|---|
| | 1401 | } |
|---|
| | 1402 | |
|---|
| | 1403 | $finishedWork->{'links_visited'}->{$currentWork} = $result->{'time_at'}; |
|---|
| | 1404 | |
|---|
| | 1405 | $numWorkInserted = HoneyClient::Manager::Database::insert_history_urls($finishedWork); |
|---|
| | 1406 | $LOG->info($numWorkInserted . " URL(s) Inserted."); |
|---|
| | 1407 | |
|---|
| | 1408 | # Flush the work history, after committing to the database. |
|---|
| | 1409 | $finishedWork->{'links_visited'} = {}; |
|---|
| | 1410 | |
|---|
| | 1411 | } |
|---|