Changeset 937
- Timestamp:
- 10/16/07 17:10:14 (11 months ago)
- Files:
-
- honeyclient/trunk/Capture-Client-1.1.0-5324-src (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/Capture-Client-1.1.0-5324-src)
- honeyclient/trunk/Capture2 (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/Capture2)
- honeyclient/trunk/bin/StartManager.pl (modified) (1 diff)
- honeyclient/trunk/bin/capture_out2exclude.pl (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/bin/capture_out2exclude.pl)
- honeyclient/trunk/bin/run.sh (modified) (1 diff)
- honeyclient/trunk/etc/honeyclient.xml (modified) (4 diffs)
- honeyclient/trunk/etc/honeyclient_log.conf (modified) (1 diff)
- honeyclient/trunk/lib/HoneyClient/Agent.pm (modified) (1 diff)
- honeyclient/trunk/lib/HoneyClient/Agent/Integrity.pm (modified) (13 diffs)
- honeyclient/trunk/lib/HoneyClient/DB.pm (modified) (36 diffs)
- honeyclient/trunk/lib/HoneyClient/DB/Analyst (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Analyst)
- honeyclient/trunk/lib/HoneyClient/DB/Analyst.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Analyst.pm)
- honeyclient/trunk/lib/HoneyClient/DB/Client.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Client.pm)
- honeyclient/trunk/lib/HoneyClient/DB/File (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/File)
- honeyclient/trunk/lib/HoneyClient/DB/File.pm (modified) (2 diffs)
- honeyclient/trunk/lib/HoneyClient/DB/Fingerprint.pm (modified) (6 diffs)
- honeyclient/trunk/lib/HoneyClient/DB/Note.pm (modified) (2 diffs)
- honeyclient/trunk/lib/HoneyClient/DB/Process.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Process.pm)
- honeyclient/trunk/lib/HoneyClient/DB/Regkey.pm (modified) (2 diffs)
- honeyclient/trunk/lib/HoneyClient/DB/Server.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Server.pm)
- honeyclient/trunk/lib/HoneyClient/DB/SystemConfig (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/SystemConfig)
- honeyclient/trunk/lib/HoneyClient/DB/SystemConfig.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/SystemConfig.pm)
- honeyclient/trunk/lib/HoneyClient/DB/Time.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Time.pm)
- honeyclient/trunk/lib/HoneyClient/DB/Url (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Url)
- honeyclient/trunk/lib/HoneyClient/DB/Url.pm (copied) (copied from honeyclient/branches/exp/xeno-realtime_integrity/lib/HoneyClient/DB/Url.pm)
- honeyclient/trunk/lib/HoneyClient/Manager.pm (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
honeyclient/trunk/bin/StartManager.pl
r769 r937 28 28 my $driver = "HoneyClient::Agent::Driver::Browser::IE"; 29 29 my $config = undef; 30 my $maxrel = -1;30 my $maxrel = 4; 31 31 my $nexturl = ""; 32 32 my $urllist= ""; honeyclient/trunk/bin/run.sh
r783 r937 19 19 done 20 20 21 ping www.honeyclient.org21 ping pingu.honeyclient.org 22 22 cd ~/honeyclient && svn update 23 23 24 ~/honeyclient/Capture2/capture-client-xeno-mod/install/CaptureBAT.exe -c -l "C:\cygwin\tmp\realtime-changes.txt"& 25 24 26 while [ true ] ; do 25 sleep 5 && \ 26 perl -Ilib bin/StartAgent.pl 27 perl -Ilib bin/StartAgent.pl && sleep 1 27 28 done honeyclient/trunk/etc/honeyclient.xml
r827 r937 51 51 3600 52 52 </timeout> 53 <log_config description="The global Log4perl configuration file, used throughout all modules. " default="etc/honeyclient_log.conf">53 <log_config description="The global Log4perl configuration file, used throughout all modules. This setting should not need to be changed." default="etc/honeyclient_log.conf"> 54 54 etc/honeyclient_log.conf 55 55 </log_config> … … 154 154 /tmp/changes.txt 155 155 </changes_found_file> 156 <realtime_changes_file description="When an integrity check fails, all changes will be written to this file within the compromized honeyclient VM's filesystem." default="/tmp/realtime-changes.txt"> 157 /tmp/realtime-changes.txt 158 </realtime_changes_file> 156 159 <!-- HoneyClient::Agent::Integrity::Filesystem Options --> 157 160 <Filesystem> … … 332 335 </host> 333 336 <dbname description="The name of the HoneyClient database." default="HoneyClient"> 334 H oneyClient337 HcNewSchema 335 338 </dbname> 336 339 <user description="The username to use, when connecting to the HoneyClient database."> 337 h oneyclient_user340 hc_user 338 341 </user> 339 342 <pass description="The password to use, when connecting to the HoneyClient database."> 340 h oneyclient_password343 hc_pass 341 344 </pass> 342 345 <port description="The default TCP port number used to communicate with the database." default="3306"> … … 459 462 <VM> 460 463 <master_vm_config description="The full absolute path to the VM configuration file on the host system that will be used by all subsequent cloned VMs."> 461 /vm/master-vms/Agent.Master-2 3/winXPPro.cfg464 /vm/master-vms/Agent.Master-25/winXPPro.cfg 462 465 </master_vm_config> 463 466 <port description="The TCP port number that the SOAP server of the VM daemon will listen on for requests. Note: This port should be unique and not already be used by other modules, services, or daemons running on the host system." default="8089"> honeyclient/trunk/etc/honeyclient_log.conf
r601 r937 63 63 # Screen Logging Settings 64 64 #log4perl.logger.HoneyClient.Agent.Integrity.Registry=DEBUG, Screen 65 #log4perl.logger.HoneyClient.DB=DEBUG, Screen 65 #log4perl.logger.HoneyClient.Manager=INFO, Screen, Syslog 66 #log4perl.logger.HoneyClient.DB=DEBUG, Screen, Syslog 66 67 # Suppress Parser Debugging Messages 67 68 #log4perl.logger.HoneyClient.Agent.Integrity.Registry.Parser=INFO, Screen honeyclient/trunk/lib/HoneyClient/Agent.pm
r796 r937 948 948 $LOG->info($driverName . " - Performing Integrity Checks."); 949 949 $changes = $integrity->check(); 950 if (scalar(@{$changes->{registry}}) || 951 scalar(@{$changes->{filesystem}})) { 950 if (scalar(@{$changes->{processes}})) { 952 951 $LOG->warn($driverName . " - Integrity Check: FAILED"); 953 952 $isCompromised = 1; honeyclient/trunk/lib/HoneyClient/Agent/Integrity.pm
r796 r937 61 61 } 62 62 63 # $changes refers to an array of hashtable references, where 64 # each hashtable has the following format: 65 # 66 # $changes = { 67 # registry => [ { 68 # # The registry directory name. 69 # 'key' => 'HKEY_LOCAL_MACHINE\Software...', 70 # 71 # # Indicates if the registry directory was deleted, 72 # # added, or changed. 73 # 'status' => 'deleted' | 'added' | 'changed', 74 # 75 # # An array containing the list of entries within the 76 # # registry directory that have been deleted, added, or 77 # # changed. If this array is empty, then the corresponding 78 # # registry directory in the original and new hives contained 79 # # no entries. 80 # 'entries' => [ { 81 # 'name' => "\"string\"", # A (potentially) quoted string; 82 # # "@" for default 83 # 'new_value' => "string", # New string; maybe undef, if deleted 84 # 'old_value' => "string", # Old string; maybe undef, if added 85 # }, ], 86 # }, ], 87 # 88 # filesystem => [ { 89 # # Indicates if the filesystem entry was deleted, 90 # # added, or changed. 91 # 'status' => 'deleted' | 'added' | 'changed', 92 # 93 # # If the entry has been added/changed, then this 94 # # hashtable contains the file/directory's new information. 95 # 'new' => { 96 # 'name' => 'C:\WINDOWS\SYSTEM32...', 97 # 'size' => 1263, # in bytes 98 # 'mtime' => 1178135092, # modification time, seconds since epoch 99 # }, 100 # 101 # # If the entry has been deleted/changed, then this 102 # # hashtable contains the file/directory's old information. 103 # 'old' => { 104 # 'name' => 'C:\WINDOWS\SYSTEM32...', 105 # 'size' => 802, # in bytes 106 # 'mtime' => 1178135028, # modification time, seconds since epoch 107 # }, 108 # }, ], 109 # } 110 111 =head1 DESCRIPTION 112 113 # TODO: This text needs to change. 63 $changes refers to an array of hashtable references, where 64 each hashtable has the format given in the METHODS IMPLEMENTED section related to 65 check(). 114 66 115 67 =head2 INITIALIZATION 116 68 117 # TODO: This text needs to change. 118 119 In order to properly check the system, a snapshot must be taken of a known-good 120 state. 121 122 For the filesystem this means a listing is created which contains 123 cryptographic hashes of files in their start state. The only files what are 124 checked are those which are explicitly specified in the checklist file (or are 125 found in a specified directory) and are not in the exclusion list will be checked. 126 Initialization of the filesystem is done with the initFileSystem() function, 127 described later. 128 129 For the registry a similar logic applies in that the only the specified keys are 130 checked and only if they are not in the exclusion list. The desired registry keys 131 are exported to a text file via the command line functionality of regedit. This 132 is done via initRegistry(). 133 134 135 =head2 CHECKING 136 137 # TODO: This text needs to change. 138 139 Checking the filesystem entails running mostly the same code as the initialization 140 piece in order to obtain a snapshot of the current state of the filesystem. At that 141 point additional checks are performed to look for additions, deletions, and 142 modifications to the filesystem. These checks are done with checkFileSystem(). 143 144 A speed-optimized check of the registry is performed by first dumping the current 145 state, again with the command line version of regedit. Then the unix "diff" 146 utility is used to compare the clean registry dump to the current one. The output 147 from a diff is in a format which shows the minimum possible changes which can be 148 done to the first file in order to yield the same content as the second file. 149 Therefore this format must be parsed in order to determine what specific additions, 150 deletions, and modifications were made to the clean registry. Further, because 151 the output of diff need not exactly reflect changes (for instance when the same 152 content would be the first line of the previous value and the last line of the new 153 value) this requires some cases to re-consult the original and current state in order 154 to disambiguate the changes which were made. These tests are done in checkRegistry(). 155 156 NOTE: Because these are simple, static, user-space checks, they can fail in the 157 presense of even user-space rootkits. Therefore these checks should not be taken as 158 definitive proof of the absense of malicious software until they are integrated more 159 tightly with the system. 69 No initialization is currently necessary, as realtime changes are read in from 70 a list exported by the Capture C code. However, in the future it may become 71 deisrable to perform an initial baseline of the system in order to automatically 72 determine the original value for things which were changed. This is because the 73 mechanisms that Capture code uses to record events, may in some cases be unable 74 to record the initial value for a registry key for instance. 160 75 161 76 =cut … … 172 87 173 88 # Include the Registry Checking Library 174 use HoneyClient::Agent::Integrity::Registry;89 #use HoneyClient::Agent::Integrity::Registry; 175 90 176 91 # Include the Filesystem Checking Library 177 use HoneyClient::Agent::Integrity::Filesystem;92 #use HoneyClient::Agent::Integrity::Filesystem; 178 93 179 94 # Use Storable Library … … 187 102 # Include Logging Library 188 103 use Log::Log4perl qw(:easy); 104 105 # Use MD5 106 use Digest::MD5; 107 108 # Use SHA 109 use Digest::SHA; 110 111 # Use IO::File Library 112 use IO::File; 113 114 # Use File::Type Library 115 use File::Type; 189 116 190 117 ####################################################################### … … 278 205 279 206 # Make sure HoneyClient::Agent::Integrity::Registry loads 280 BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry')281 or diag("Can't load HoneyClient::Agent::Integrity::Registry package. Check to make sure the package library is correctly listed within the path."); }282 require_ok('HoneyClient::Agent::Integrity::Registry');283 use HoneyClient::Agent::Integrity::Registry;207 #BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry') 208 # or diag("Can't load HoneyClient::Agent::Integrity::Registry package. Check to make sure the package library is correctly listed within the path."); } 209 #require_ok('HoneyClient::Agent::Integrity::Registry'); 210 #use HoneyClient::Agent::Integrity::Registry; 284 211 285 212 # Make sure HoneyClient::Agent::Integrity::Filesystem loads 286 BEGIN { use_ok('HoneyClient::Agent::Integrity::Filesystem')287 or diag("Can't load HoneyClient::Agent::Integrity::Filesystem package. Check to make sure the package library is correctly listed within the path."); }288 require_ok('HoneyClient::Agent::Integrity::Filesystem');289 use HoneyClient::Agent::Integrity::Filesystem;213 #BEGIN { use_ok('HoneyClient::Agent::Integrity::Filesystem') 214 # or diag("Can't load HoneyClient::Agent::Integrity::Filesystem package. Check to make sure the package library is correctly listed within the path."); } 215 #require_ok('HoneyClient::Agent::Integrity::Filesystem'); 216 #use HoneyClient::Agent::Integrity::Filesystem; 290 217 291 218 # Make sure HoneyClient::Agent::Integrity loads. … … 318 245 =over 4 319 246 320 When set to 1, the object will forgo any type of initial baselining 321 process, upon initialization. Otherwise, baselining will occur 322 as normal, upon initialization. 323 247 Currently defaults to 1, whereby the object will forgo any type of initial baselining 248 process, upon initialization. If set to 0, baselining will occur upon initialization. 249 Baselining is currently deprecated. 324 250 =back 325 251 … … 330 256 # process, upon initialization. Otherwise, baselining will occur 331 257 # as normal, upon initialization. 332 bypass_baseline => 0, 258 # XXX: Bypass static baselining, for now. 259 # XXX: Baselining will not be used with the current version which includes Capture 260 bypass_baseline => 1, 333 261 334 262 # Contains the Registry object, once initialized. … … 342 270 # XXX: comment this 343 271 _changes_found_file => getVar(name => 'changes_found_file'), 272 273 # XXX: comment this 274 _realtime_changes_file => getVar(name => 'realtime_changes_file'), 275 344 276 ); 345 277 … … 471 403 B<$changes>, which is an array of hashtable references, where each 472 404 hashtable has the following format: 473 474 $changes = { 475 registry => [ { 476 # The registry directory name. 477 'key' => 'HKEY_LOCAL_MACHINE\Software...', 478 479 # Indicates if the registry directory was deleted, 480 # added, or changed. 481 'status' => 'deleted' | 'added' | 'changed', 482 483 # An array containing the list of entries within the 484 # registry directory that have been deleted, added, or 485 # changed. If this array is empty, then the corresponding 486 # registry directory in the original and new hives contained 487 # no entries. 488 'entries' => [ { 489 'name' => "\"string\"", # A (potentially) quoted string; 490 # "@" for default 491 'new_value' => "string", # New string; maybe undef, if deleted 492 'old_value' => "string", # Old string; maybe undef, if added 493 }, ], 494 }, ], 495 496 filesystem => [ { 497 # Indicates if the filesystem entry was deleted, 498 # added, or changed. 499 'status' => 'deleted' | 'added' | 'changed', 500 501 # If the entry has been added/changed, then this 502 # hashtable contains the file/directory's new information. 503 'new' => { 504 'name' => 'C:\WINDOWS\SYSTEM32...', 505 'size' => 1263, # in bytes 506 'mtime' => 1178135092, # modification time, seconds since epoch 507 }, 508 509 # If the entry has been deleted/changed, then this 510 # hashtable contains the file/directory's old information. 511 'old' => { 512 'name' => 'C:\WINDOWS\SYSTEM32...', 513 'size' => 802, # in bytes 514 'mtime' => 1178135028, # modification time, seconds since epoch 515 }, 516 }, ], 517 } 405 406 $changes = { 407 #A reference to an anonymous array of process objects 408 processes => [ { 409 'name' => "C:\WINDOWS\system32\Notepad.exe", # The process name as a full path 410 'pid' => 1000, # The Windows system process ID 411 'parent_name' => "C:\WINDOWS\system32\explorer.exe", # The process name as 412 # a full path for the process which created this process 413 'parent_pid' => 999, # The Windows system process ID for the 414 # process which created this process 415 416 #The absence of both a created and terminated time implies that the enclosed 417 #filesystem and/or registry events are related to a process which was running 418 #when the realtime checks were started, and was still running when they ended 419 420 #OPTIONAL, its existence signifies that we saw this process be created 421 'created_time' => ISO 8601 Timestamp (yyyy-mm-dd hh24:mi:ss.uuuuuu) 422 423 #OPTIONAL, its existence signifies that we saw this process be terminated 424 'terminated_time' => ISO 8601 Timestamp 425 426 #A reference to an anonymous array of registry objects 427 registry => [ { 428 # The registry directory name in regedit 429 'key_name' => 'HKEY_LOCAL_MACHINE\Software...', 430 431 'time' => ISO 8601 Timestamp, 432 433 #The specific registry event type which took place, as given by it's Windows name 434 'event_type' => { CreateKey | OpenKey | CloseKey | Query Key | 435 QueryValueKey, EnumerateKey | EnumerateValueKey | 436 SetValueKey | DeleteValueKey | DeleteKey }, 437 438 #The "name" which shows up in regedit 439 'value_name' => "my key", 440 441 #The "type" which shows up in regedit. It is only possible to create the first 442 # 6 types by manually using regedit (and REG_NONE is only indirect, for instance 443 # on a DeleteValueKey event_type). 444 'value_type' => { REG_NONE | REG_SZ | REG_BINARY | REG_DWORD | 445 REG_EXPAND_SZ | REG_MULTI_SZ | REG_LINK | 446 REG_DWORD_BIG_ENDIAN | REG_RESOURCE_LIST | 447 REG_FULL_RESOURCE_DESCRIPTOR | 448 REG_RESOURCE_REQUIREMENTS_LIST | 449 REG_QWORD_LITTLE_ENDIAN}, 450 #The "value" which shows up in regedit 451 'value' => many possible data types, but converted into a string, 452 453 }, ], 454 455 #A reference to an anonymous array of file system objects 456 file_system => [ { 457 #The full path and name of the file which was effected 458 'name' => 'C:\WINDOWS\SYSTEM32...', 459 460 'event_type' => { Deleted | Read | Write }, #TODO: add created & renamed/moved 461 462 'time' => ISO 8601 Timestamp, 463 464 #OPTIONAL, this will not exist for deleted files 465 'content' => { 466 'size' => 1234, # size of new content 467 'type' => 'application/octect-stream', # type of new content 468 'md5' => 'b1946ac92492d2347c6235b4d2611184', # md5 of new content 469 'sha1' => 'f572d396fae9206628714fb2ce00f72e94f2258f', # sha1 of new content 470 }, 471 },] 472 },] 473 } 518 474 519 475 I<Notes>: … … 550 506 }); 551 507 552 my $changes = { 553 'registry' => $self->{'_registry'}->check(), 554 'filesystem' => $self->{'_filesystem'}->check(), 555 }; 556 508 # my $changes = { 509 # 'registry' => $self->{'_registry'}->check(), 510 # 'filesystem' => $self->{'_filesystem'}->check(), 511 # }; 512 #XENO - BEGIN REPLACEMENT WITH CAPTURE-READING CODE 513 my $change_file_name = $self->{_realtime_changes_file}; 514 my %changes; 515 my @capdump; 516 if(-s $change_file_name > 0 ){ 517 open(CAP, $change_file_name) or die "Can't open $change_file_name"; 518 @capdump = <CAP>; 519 close(CAP); 520 } 521 else{ 522 %changes = ( 523 'processes' => [], 524 ); 525 526 return \%changes; 527 } 528 529 my @reg_list = (); 530 my @reg_lines = (); 531 my @file_list = (); 532 my @file_lines = (); 533 my @proc_list = (); 534 my @proc_lines = (); 535 my @bad_line_list = (); 536 my $key; 537 my $status; 538 my @proc_and_file_list; 539 my @proc_objs = (); 540 my %names = (); 541 #Indices in the string for different types of information 542 my $ENTRY_TYPE = 1; 543 my $R_TIME = 0; 544 my $R_EVENT_TYPE = 2; 545 my $R_PROC_PID = 3; 546 my $R_PROC_NAME = 4; 547 my $R_KEY_NAME = 5; 548 my $R_VALUE_NAME = 6; 549 my $R_VALUE_TYPE = 7; 550 my $R_VALUE = 8; 551 my $F_TIME = 0; 552 my $F_EVENT_TYPE = 2; 553 my $F_PROC_PID = 3; 554 my $F_PROC_NAME = 4; 555 my $F_NAME = 5; 556 my $P_TIME = 0; 557 my $P_EVENT_TYPE = 2; 558 my $P_PARENT_PID = 3; 559 my $P_PARENT_NAME = 4; 560 my $P_PID = 5; 561 my $P_NAME = 6; 562 my $TOTAL_PROC_TOKENS = 7; 563 my $TOTAL_FILE_TOKENS = 6; 564 my $TOTAL_REG_TOKENS = 9; 565 my $STATUS_DELETED = 0; 566 my $STATUS_ADDED = 1; 567 my $STATUS_MODIFIED = 2; 568 569 570 #Get the time of the first event from the first entry and used it for compromise_time 571 my @tmp_toks = split("\",\"",$capdump[0]); 572 $tmp_toks[0] =~ s/^"(.*)/$1/; 573 %changes = ('compromise_time' => $tmp_toks[0]); 574 575 foreach my $line (@capdump){ 576 my $ret = undef; 577 #Get rid of the windows carriage return and newline (sometimes looks like ^M) 578 $line =~ s/\r\n$//; 579 #Get rid of first and last quotes 580 $line =~ s/^\"(.*)/$1/; 581 chop($line); 582 583 my @toks = split("\",\"", $line, $TOTAL_REG_TOKENS+1); 584 my $index = undef; 585 my $proc_obj = undef; 586 my $proc_push; 587 if($toks[$ENTRY_TYPE] eq "process"){ 588 $proc_push = 1; 589 if($toks[$P_EVENT_TYPE] eq "terminated"){ 590 ($ret, $index) = checkForExistingProcObj($toks[$P_PID], $toks[$P_NAME], @proc_objs); 591 #If the object already exists as something which didn't have anything filled in, then fill it in 592 if($ret == 1){ 593 $proc_objs[$index]->{"$toks[$P_EVENT_TYPE]_time"} = $toks[$P_TIME]; 594 $proc_push = 0; 595 } 596 } 597 #create this object 598 $proc_obj = { 599 'pid' => $toks[$P_PID], 600 'name' => $toks[$P_NAME], 601 'parent_pid' => $toks[$P_PARENT_PID], 602 'parent_name' => $toks[$P_PARENT_NAME], 603 "$toks[$P_EVENT_TYPE]_time" => $toks[$P_TIME], 604 'file_system' => [], 605 'registry' => [], 606 }; 607 } 608 else{ 609 $proc_push = 0; 610 611 ($ret, $index) = checkForExistingProcObj($toks[$R_PROC_PID], $toks[$R_PROC_NAME], @proc_objs); 612 if($ret == 1){ 613 $proc_obj = $proc_objs[$index]; 614 } 615 else{ 616 #First build an empty proc object 617 $proc_obj = { 618 'pid' => $toks[$R_PROC_PID], 619 'name' => $toks[$R_PROC_NAME], 620 'registry' => [], 621 'file_system' => [], 622 }; 623 $proc_push = 1; 624 } 625 626 if($toks[$ENTRY_TYPE] eq "registry"){ 627 #Build the registry object and put it in to the proc object 628 my $reg_obj = { 629 'time' => $toks[$R_TIME], 630 'event_type' => $toks[$R_EVENT_TYPE], 631 'key_name' => $toks[$R_KEY_NAME], 632 'value_name' => $toks[$R_VALUE_NAME], 633 'value_type' => $toks[$R_VALUE_TYPE], 634 'value' => $toks[$R_VALUE], 635 }; 636 push @{$proc_obj->{'registry'}}, $reg_obj; 637 } 638 elsif($toks[$ENTRY_TYPE] eq "file"){ 639 640 #Build the filesystem object and put it in to the proc object 641 my $fs_ref = $proc_obj->{'file_system'}; 642 if(scalar(@{$fs_ref}) == 0 || $fs_ref->[-1]->{'name'} ne $toks[$F_NAME] || 643 $fs_ref->[-1]->{'event_type'} ne $toks[$F_EVENT_TYPE]){ 644 645 my $file_obj = { 646 'name' => $toks[$F_NAME], 647 'event_type' => $toks[$F_EVENT_TYPE], 648 'time' => $toks[$F_TIME], 649 }; 650 if($toks[$F_EVENT_TYPE] ne "Delete"){ 651 #Fill in the default values, incase the file can't be found due to a rename rather than delete 652 $file_obj->{'contents'} = { 653 'size' => 0, 654 'type' => "UNKNOWN", 655 'md5' => "$toks[$F_NAME]$toks[$F_TIME]", 656 'sha1' => "$toks[$F_NAME]$toks[$F_TIME]", 657 }; 658 my $tmp_name = $toks[$F_NAME]; 659 if(-f $tmp_name){ 660 my $md5_ctx = Digest::MD5->new(); 661 my $sha1_ctx = Digest::SHA->new("1"); 662 my $type_ctx = File::Type->new(); 663 my $md5 = 'UNKNOWN'; 664 my $sha1 = 'UNKNOWN'; 665 my $type = 'UNKNOWN'; 666 my $size = 0; 667 my $fh = IO::File->new($tmp_name, "r"); 668 #print "md5ing $tmp_name\n"; 669 # Compute MD5 Checksum. 670 $md5_ctx->addfile($fh); 671 $md5 = $md5_ctx->hexdigest(); 672 673 # Rewind file handle. 674 seek($fh, 0, 0); 675 676 #print "sha1ing $tmp_name\n"; 677 # Compute SHA1 Checksum. 678 $sha1_ctx->addfile($fh); 679 $sha1 = $sha1_ctx->hexdigest(); 680 681 #Compute file size 682 $size = -s $tmp_name; 683 684 # Compute File Type. 685 $type = $type_ctx->mime_type($tmp_name); 686 687 # Close the file handle. 688 undef $fh; 689 $file_obj->{'contents'}->{'size'} = $size; 690 $file_obj->{'contents'}->{'md5'} = $md5; 691 $file_obj->{'contents'}->{'sha1'} = $sha1; 692 $file_obj->{'contents'}->{'type'} = $type; 693 } 694 push @{$proc_obj->{'file_system'}},$file_obj; 695 } 696 697 } 698 } 699 } 700 if($proc_push){ 701 push @proc_objs, $proc_obj; 702 } 703 }#end foreach 704 705 $changes{'processes'} = \@proc_objs; 706 # $Data::Dumper::Terse = 1; 707 # $Data::Dumper::Indent = 1; 708 # print Dumper(\%changes); 709 710 711 #XENO - END REPLACEMENT WITH CAPTURE-READING CODE 712 557 713 # If any changes were found, write them out to the 558 714 # filesystem. 559 if (scalar(@{$changes->{registry}}) || 560 scalar(@{$changes->{filesystem}})) { 715 if (scalar($changes{'processes'})){ 561 716 if (!open(CHANGE_FILE, ">>" . $self->{_changes_found_file})) { 562 717 $LOG->error("Unable to write changes to file '" . $self->{_changes_found_file} . "'."); … … 564 719 $Data::Dumper::Terse = 1; 565 720 $Data::Dumper::Indent = 1; 566 print CHANGE_FILE Dumper($changes); 721 print CHANGE_FILE Dumper(\%changes); 722 print Dumper(\%changes); 567 723 close CHANGE_FILE; 568 724 } 569 725 } 570 726 571 return $changes;727 return \%changes; 572 728 } 729 730 # This function looks for if there is already a process object with the given pid and name 731 # and if it exists, returns its index in the processes array 732 # This function is used to find process objects for merging 733 # NOTE: In the future, we may want to make it be a hash, keyed by name:pid rather than an 734 # array, so that lookups are not O(n) 735 # Also, this function is predicated on the assumption that we will not see the same name:pid 736 # pair during our run 737 sub checkForExistingProcObj { 738 my $pid = shift; 739 my $name = shift; 740 my $index = 0; 741 my @proc_objs = @_; 742 743 foreach my $obj (@proc_objs){ 744 #Check if the object already exists 745 #&& !defined $obj->{'terminated_time'} 746 if($obj->{'pid'} eq $pid && $obj->{'name'} eq $name){ 747 #object already exists 748 return (1, $index); 749 } 750 $index++; 751 } 752 return (0, $index); 753 } 754 755 573 756 574 757 # TODO: Comment this. … … 612 795 =head1 BUGS & ASSUMPTIONS 613 796 614 # XXX: Fill this in. 615 616 =head1 TODO 617 618 Need to add sub-modules that support the following capabilities: 619 620 =over 4 621 622 =item * 623 624 Static or real-time rogue process detection. 625 626 =item * 627 628 Static or real-time memory alteration detection. 629 630 =back 797 We assume that because of the short time in which malware is allowed to run 798 we can never see the same name:pid pair twice, because there will not have been 799 enough processes created in order to wrap the pid numbers back around. 631 800 632 801 =head1 SEE ALSO … … 640 809 =head1 ACKNOWLEDGEMENTS 641 810 642 XXX: Fill this in. 811 The Capture client-side honeypot team is responsible for creating the code which outputs 812 the system events that this reads in in the event of a compromise. 643 813 644 814 =head1 AUTHORS … … 648 818 Xeno Kovah, E<lt>xkovah@mitre.orgE<gt> 649 819 820 Darien Kindlund, E<lt>kindlund@mitre.orgE<gt> 821 822 Brad Stephenson, E<lt>stephenson@mitre.orgE<gt> 823 650 824 Thanh Truong, E<lt>ttruong@mitre.orgE<gt> 651 652 Darien Kindlund, E<lt>kindlund@mitre.orgE<gt>653 654 Brad Stephenson, E<lt>stephenson@mitre.orgE<gt>655 825 656 826 =head1 COPYRIGHT & LICENSE honeyclient/trunk/lib/HoneyClient/DB.pm
r830 r937 368 368 # To be used ONLY INTERNALLY! 369 369 our ( %_types, %_check, %_required, %_init_val, %_keys, %defaults ); 370 our (%display_rank);370 our %display_rank; 371 371 372 372 # %fields must be defined by all children classes 373 373 our %fields; 374 375 our $last_error_code; 374 376 375 377 #constants … … 380 382 # Option for get_fields() 381 383 our ( $FIELDS_ALL, $FIELDS_SEARCH, $FIELDS_DISPLAY ) = ( 0 , 1, 2); 382 our $debug = 0; 384 # Error Codes 385 our ($ERROR_NONE,$ERROR_INSERT_FAILED,$ERROR_DUPLICATE_FOUND,$ERROR_DUPLICATE_UNRESOLVED) 386 = (0,1,2,3); 387 our @ERROR_MESSAGES = ( 388 "Success!", 389 "Failed with a fatal error", 390 "Duplicate object found. Non-fatal warning.", 391 "Duplicate object found. Unable to retrieve ID of duplicate record.", 392 ); 393 our $LAST_ERROR = $ERROR_NONE; 383 394 384 395 # Initialize Connection … … 415 426 For Example: 416 427 417 $my_obj = newHoneyClient::DB::SomeObj->new({428 $my_obj = HoneyClient::DB::SomeObj->new({ 418 429 field_a => "foo", 419 430 field_b => "bar" … … 424 435 sub new { 425 436 my ( $class, $self ) = @_; 426 427 437 bless( $self, $class ); 428 438 429 439 # Check if Schema has been imported 430 _import_schema($class) if ( !exists( $_types{$class} ) );440 import_schema($class) if ( !exists( $_types{$class} ) ); 431 441 432 442 # Make sure required Attributes are set. Fail if not. 433 443 my @missing = $self->_check_required(); 434 444 if ( scalar @missing ) { 435 $LOG->fatal( "Object missing required attribute(s): " 436 . join( ', ', @missing ) 437 . '.' ); 438 Carp::croak( "Object missing required attribute(s): " 439 . join( ', ', @missing ) 440 . '.\n' ); 441 } 442 443 # Check if ref and array objects have been initialized. If not call new 445 $LOG->fatal( "$class->new(): Object missing required attribute(s): " . 446 join( ', ', @missing ) . '.' ); 447 Carp::croak( "$class->new(): Object missing required attribute(s): " . 448 join( ', ', @missing ) . '.\n' ); 449 } 450 451 # Check data validity. Initialize uninitialized ref and array objects 444 452 foreach my $key ( keys %$self ) { 445 453 eval { … … 454 462 } 455 463 if ( $_types{$class}{$key} =~ m/(array|ref):(.*)/ ) { 456 my $ref = ref( $self->{$key} );457 my $childType = $1;458 my $childClass = $2; 464 my $ref = ref( $self->{$key} ); 465 my ($childType,$childClass) = ($1,$2); 466 459 467 if ( $childClass->can('new') ) { 460 if ( $ ref eq 'HASH' and $childType eq 'ref' ) {468 if ( $childType eq 'ref' ) { 461 469 $self->{$key} = $childClass->new( $self->{$key} ); 462 470 } … … 482 490 my $class = ref $self; 483 491 484 # make sure field is not undef if 'required' option is set492 # make sure field is not undefined if 'required' option is set 485 493 if ( exists $_required{$class} ) { 486 494 my @missing; … … 494 502 } 495 503 496 sub _import_schema {504 sub import_schema { 497 505 my $class = shift; 498 506 my $schema = \%{ $class . "::fields" }; 499 #TODO: Give better names for these: 500 my (%rank_me_display, %rank_me_search); 507 my (%rank_display, %rank_search); 501 508 my $MAX_RANK = 10000; 502 509 … … 525 532 while ( my ( $a, $opts ) = each %$attrib ) { 526 533 $_types{$class}{$a} = $type; 527 if ( $opts->{required}) {534 if ( exists $opts->{required} && $opts->{required}) { 528 535 $_required{$class}{$a} = 1; 529 536 } … … 536 543 } 537 544 if ( !exists $_types{ $opts->{objclass} } ) { 538 _import_schema( $opts->{objclass} );545 import_schema( $opts->{objclass} ); 539 546 } 540 547 $_types{$class}{$a} .= ':' . $opts->{objclass}; … … 559 566 #DEBUG: Test new code 560 567 if( $opts->{searchable} ) { 561 1;#TODO: $_search_fields{$class}568 #TODO: $_search_fields{$class} 562 569 } 563 570 if( exists $opts->{display_rank} ) { 564 #TODO: Add logic to handle inappropriatly ranked items565 571 my $rank = $opts->{display_rank}; 566 572 if ($opts->{display_rank}) { 567 while (exists $rank_ me_display{$rank}) {573 while (exists $rank_display{$rank}) { 568 574 $rank++; 569 575 } 570 $rank_ me_display{$rank} = $a;576 $rank_display{$rank} = $a; 571 577 } 572 578 } 573 579 elsif ($type =~ m/^(array|ref)$/) {} 574 580 else { 575 #TODO: Eliminate Constant here: 576 $rank_me_display{$MAX_RANK++} = $a; 581 $rank_display{$MAX_RANK++} = $a; 577 582 } 578 583 } … … 582 587 } 583 588 } 584 my @temp = map $rank_ me_display{$_}, sort( keys( %rank_me_display ) );589 my @temp = map $rank_display{$_}, sort( keys( %rank_display ) ); 585 590 $display_rank{$class} = \@temp; 586 use Data::Dumper;587 print "Rank $class: ".Dumper($display_rank{$class})."\n";588 591 589 592 # Add the table to the DB if necessary 590 # TODO: Move to install script??591 593 if (!$class->deploy_table()) { 592 $LOG->fatal("${class}-> _import_schema: " . "Failed to deploy table");593 Carp::croak("${class}-> _import_schema: " . "Failed to deploy table");594 $LOG->fatal("${class}->import_schema: " . "Failed to deploy table"); 595 Carp::croak("${class}->import_schema: " . "Failed to deploy table"); 594 596 } 595 597 } … … 622 624 my $obj = shift; 623 625 my $id = undef;
