Changeset 937

Show
Ignore:
Timestamp:
10/16/07 17:10:14 (11 months ago)
Author:
kindlund
Message:

Merged xeno-realtime_integrity into trunk.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • honeyclient/trunk/bin/StartManager.pl

    r769 r937  
    2828my $driver = "HoneyClient::Agent::Driver::Browser::IE"; 
    2929my $config = undef; 
    30 my $maxrel = -1
     30my $maxrel = 4
    3131my $nexturl = ""; 
    3232my $urllist= ""; 
  • honeyclient/trunk/bin/run.sh

    r783 r937  
    1919done 
    2020 
    21 ping www.honeyclient.org 
     21ping pingu.honeyclient.org 
    2222cd ~/honeyclient && svn update 
    2323 
     24~/honeyclient/Capture2/capture-client-xeno-mod/install/CaptureBAT.exe -c -l "C:\cygwin\tmp\realtime-changes.txt"& 
     25 
    2426while [ true ] ; do 
    25     sleep 5 && \ 
    26     perl -Ilib bin/StartAgent.pl 
     27    perl -Ilib bin/StartAgent.pl && sleep 1 
    2728done 
  • honeyclient/trunk/etc/honeyclient.xml

    r827 r937  
    5151        3600 
    5252    </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"> 
    5454        etc/honeyclient_log.conf 
    5555    </log_config> 
     
    154154                /tmp/changes.txt 
    155155            </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> 
    156159            <!-- HoneyClient::Agent::Integrity::Filesystem Options --> 
    157160            <Filesystem> 
     
    332335        </host> 
    333336        <dbname description="The name of the HoneyClient database." default="HoneyClient"> 
    334             HoneyClient 
     337            HcNewSchema 
    335338        </dbname> 
    336339        <user description="The username to use, when connecting to the HoneyClient database."> 
    337             honeyclient_user 
     340            hc_user 
    338341        </user> 
    339342        <pass description="The password to use, when connecting to the HoneyClient database."> 
    340             honeyclient_password  
     343            hc_pass 
    341344        </pass> 
    342345        <port description="The default TCP port number used to communicate with the database." default="3306"> 
     
    459462        <VM> 
    460463            <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-23/winXPPro.cfg 
     464                /vm/master-vms/Agent.Master-25/winXPPro.cfg 
    462465            </master_vm_config> 
    463466            <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  
    6363# Screen Logging Settings 
    6464#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 
    6667# Suppress Parser Debugging Messages 
    6768#log4perl.logger.HoneyClient.Agent.Integrity.Registry.Parser=INFO, Screen 
  • honeyclient/trunk/lib/HoneyClient/Agent.pm

    r796 r937  
    948948            $LOG->info($driverName . " - Performing Integrity Checks."); 
    949949            $changes = $integrity->check(); 
    950             if (scalar(@{$changes->{registry}}) ||  
    951                 scalar(@{$changes->{filesystem}})) { 
     950            if (scalar(@{$changes->{processes}})) {  
    952951                $LOG->warn($driverName . " - Integrity Check: FAILED"); 
    953952                $isCompromised = 1; 
  • honeyclient/trunk/lib/HoneyClient/Agent/Integrity.pm

    r796 r937  
    6161  } 
    6262 
    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 
     64each hashtable has the format given in the METHODS IMPLEMENTED section related to 
     65check(). 
    11466 
    11567=head2 INITIALIZATION 
    11668 
    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. 
     69No initialization is currently necessary, as realtime changes are read in from 
     70a list exported by the Capture C code. However, in the future it may become  
     71deisrable to perform an initial baseline of the system in order to automatically 
     72determine the original value for things which were changed. This is because the 
     73mechanisms that Capture code uses to record events, may in some cases be unable 
     74to record the initial value for a registry key for instance. 
    16075 
    16176=cut 
     
    17287 
    17388# Include the Registry Checking Library 
    174 use HoneyClient::Agent::Integrity::Registry; 
     89#use HoneyClient::Agent::Integrity::Registry; 
    17590 
    17691# Include the Filesystem Checking Library 
    177 use HoneyClient::Agent::Integrity::Filesystem; 
     92#use HoneyClient::Agent::Integrity::Filesystem; 
    17893 
    17994# Use Storable Library 
     
    187102# Include Logging Library 
    188103use Log::Log4perl qw(:easy); 
     104 
     105# Use MD5 
     106use Digest::MD5; 
     107 
     108# Use SHA 
     109use Digest::SHA; 
     110 
     111# Use IO::File Library 
     112use IO::File; 
     113 
     114# Use File::Type Library 
     115use File::Type; 
    189116 
    190117####################################################################### 
     
    278205 
    279206# 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; 
    284211 
    285212# 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; 
    290217 
    291218# Make sure HoneyClient::Agent::Integrity loads. 
     
    318245=over 4 
    319246 
    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  
     247Currently defaults to 1, whereby the object will forgo any type of initial baselining 
     248process, upon initialization.  If set to 0, baselining will occur upon initialization. 
     249Baselining is currently deprecated. 
    324250=back 
    325251 
     
    330256    # process, upon initialization.  Otherwise, baselining will occur 
    331257    # 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, 
    333261 
    334262    # Contains the Registry object, once initialized. 
     
    342270    # XXX: comment this 
    343271    _changes_found_file => getVar(name => 'changes_found_file'), 
     272 
     273    # XXX: comment this 
     274    _realtime_changes_file => getVar(name => 'realtime_changes_file'), 
     275 
    344276); 
    345277 
     
    471403 B<$changes>, which is an array of hashtable references, where each 
    472404hashtable 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
    518474 
    519475I<Notes>: 
     
    550506    }); 
    551507 
    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  
    557713    # If any changes were found, write them out to the 
    558714    # filesystem. 
    559     if (scalar(@{$changes->{registry}}) || 
    560         scalar(@{$changes->{filesystem}})) { 
     715    if (scalar($changes{'processes'})){ 
    561716        if (!open(CHANGE_FILE, ">>" . $self->{_changes_found_file})) { 
    562717            $LOG->error("Unable to write changes to file '" . $self->{_changes_found_file} . "'."); 
     
    564719            $Data::Dumper::Terse = 1; 
    565720            $Data::Dumper::Indent = 1; 
    566             print CHANGE_FILE Dumper($changes); 
     721            print CHANGE_FILE Dumper(\%changes); 
     722            print Dumper(\%changes); 
    567723            close CHANGE_FILE; 
    568724        } 
    569725    } 
    570726 
    571     return $changes; 
     727    return \%changes; 
    572728} 
     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 
     737sub 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 
    573756 
    574757# TODO: Comment this. 
     
    612795=head1 BUGS & ASSUMPTIONS 
    613796 
    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 
     797We assume that because of the short time in which malware is allowed to run 
     798we can never see the same name:pid pair twice, because there will not have been 
     799enough processes created in order to wrap the pid numbers back around. 
    631800 
    632801=head1 SEE ALSO 
     
    640809=head1 ACKNOWLEDGEMENTS 
    641810 
    642 XXX: Fill this in. 
     811The Capture client-side honeypot team is responsible for creating the code which outputs 
     812the system events that this reads in in the event of a compromise. 
    643813 
    644814=head1 AUTHORS 
     
    648818Xeno Kovah, E<lt>xkovah@mitre.orgE<gt> 
    649819 
     820Darien Kindlund, E<lt>kindlund@mitre.orgE<gt> 
     821 
     822Brad Stephenson, E<lt>stephenson@mitre.orgE<gt> 
     823 
    650824Thanh 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> 
    655825 
    656826=head1 COPYRIGHT & LICENSE 
  • honeyclient/trunk/lib/HoneyClient/DB.pm

    r830 r937  
    368368# To be used ONLY INTERNALLY! 
    369369our ( %_types, %_check, %_required, %_init_val, %_keys, %defaults ); 
    370 our (%display_rank)
     370our %display_rank
    371371 
    372372# %fields must be defined by all children classes 
    373373our %fields; 
     374 
     375our $last_error_code; 
    374376 
    375377#constants 
     
    380382# Option for get_fields() 
    381383our ( $FIELDS_ALL, $FIELDS_SEARCH, $FIELDS_DISPLAY ) = ( 0 , 1, 2); 
    382 our $debug = 0; 
     384# Error Codes 
     385our ($ERROR_NONE,$ERROR_INSERT_FAILED,$ERROR_DUPLICATE_FOUND,$ERROR_DUPLICATE_UNRESOLVED) 
     386    = (0,1,2,3); 
     387our @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); 
     393our $LAST_ERROR = $ERROR_NONE; 
    383394 
    384395# Initialize Connection 
     
    415426For Example: 
    416427 
    417   $my_obj = new HoneyClient::DB::SomeObj->new({ 
     428  $my_obj = HoneyClient::DB::SomeObj->new({ 
    418429          field_a => "foo", 
    419430          field_b => "bar" 
     
    424435sub new { 
    425436    my ( $class, $self ) = @_; 
    426  
    427437    bless( $self, $class ); 
    428438 
    429439    # Check if Schema has been imported 
    430     _import_schema($class) if ( !exists( $_types{$class} ) ); 
     440    import_schema($class) if ( !exists( $_types{$class} ) ); 
    431441 
    432442    # Make sure required Attributes are set. Fail if not. 
    433443    my @missing = $self->_check_required(); 
    434444    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 
    444452    foreach my $key ( keys %$self ) { 
    445453        eval { 
     
    454462        } 
    455463        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 
    459467            if ( $childClass->can('new') ) { 
    460                 if ( $ref eq 'HASH' and $childType eq 'ref' ) { 
     468                if ( $childType eq 'ref' ) { 
    461469                    $self->{$key} = $childClass->new( $self->{$key} ); 
    462470                } 
     
    482490    my $class = ref $self; 
    483491 
    484     # make sure field is not undef if 'required' option is set 
     492    # make sure field is not undefined if 'required' option is set 
    485493    if ( exists $_required{$class} ) { 
    486494        my @missing; 
     
    494502} 
    495503 
    496 sub _import_schema { 
     504sub import_schema { 
    497505    my $class  = shift; 
    498506    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); 
    501508    my $MAX_RANK = 10000; 
    502509 
     
    525532            while ( my ( $a, $opts ) = each %$attrib ) { 
    526533                $_types{$class}{$a} = $type; 
    527                 if ( $opts->{required} ) { 
     534                if ( exists $opts->{required} && $opts->{required}) { 
    528535                    $_required{$class}{$a} = 1; 
    529536                } 
     
    536543                    } 
    537544                    if ( !exists $_types{ $opts->{objclass} } ) { 
    538                         _import_schema( $opts->{objclass} ); 
     545                        import_schema( $opts->{objclass} ); 
    539546                    } 
    540547                    $_types{$class}{$a} .= ':' . $opts->{objclass}; 
     
    559566                #DEBUG: Test new code 
    560567                if( $opts->{searchable} ) { 
    561                     1;#TODO: $_search_fields{$class} 
     568                    #TODO: $_search_fields{$class} 
    562569                } 
    563570                if( exists $opts->{display_rank} ) { 
    564                     #TODO: Add logic to handle inappropriatly ranked items 
    565571                    my $rank = $opts->{display_rank}; 
    566572                    if ($opts->{display_rank}) { 
    567                         while (exists $rank_me_display{$rank}) { 
     573                        while (exists $rank_display{$rank}) { 
    568574                                $rank++; 
    569575                        } 
    570                         $rank_me_display{$rank} = $a; 
     576                        $rank_display{$rank} = $a; 
    571577                    } 
    572578                } 
    573579                elsif ($type =~ m/^(array|ref)$/) {} 
    574580                else { 
    575                     #TODO: Eliminate Constant here: 
    576                     $rank_me_display{$MAX_RANK++} = $a; 
     581                    $rank_display{$MAX_RANK++} = $a; 
    577582                } 
    578583            } 
     
    582587        } 
    583588    } 
    584     my @temp = map $rank_me_display{$_}, sort( keys( %rank_me_display ) ); 
     589    my @temp = map $rank_display{$_}, sort( keys( %rank_display ) ); 
    585590    $display_rank{$class} = \@temp; 
    586     use Data::Dumper; 
    587     print "Rank $class: ".Dumper($display_rank{$class})."\n"; 
    588591 
    589592    # Add the table to the DB if necessary 
    590     # TODO: Move to install script?? 
    591593    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"); 
    594596    } 
    595597} 
     
    622624    my $obj = shift; 
    623625    my $id  = undef;