⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psa-chapter09.txt

📁 perl语言的经典文章
💻 TXT
📖 第 1 页 / 共 2 页
字号:
Example code from Perl for System Administration by David N. Blank-Edelman
O'Reilly and Associates, 1st Edition, ISBN 1-56592-609-9

Chapter Nine
============

#*
#* two ways to scan a log file for the word "error"
#*

open(LOG,"logfile") or die "Unable to open logfile:$!\n";
while(<LOG>){
	print if /\berror\b/i;
}
close(LOG);

### OR ###

# from the command line
$ perl -ne 'print if /\berror\b/i' logfile
-------
#*
#* read wtmp on SunOS and dump entries found there
#*

# this is the template we're going to feed to unpack()
$template = "A8 A8 A16 l";
# this uses pack() to help us determine the size (in bytes)
# of a single record
$recordsize = length(pack($template,()));

# open the file
open(WTMP,"/var/adm/wtmp") or die "Unable to open wtmp:$!\n";

# read it in one record at a time
while (read(WTMP,$record,$recordsize)) {
    # unpack it, using our template
    ($tty,$name,$host,$time)=unpack($template,$record);
    # handle the records with a null character specially 
    # (see below)
    if ($name and substr($name,0,1) ne "\0"){
        print "$tty:$name:$host:",scalar localtime($time),"\n"; 
    }
    else {
        print "$tty:(logout):(logout):",scalar localtime($time),"\n"; 
    }   
}

# close the file
close(WTMP);
-------
#*
#* show all the unique user names found in a wtmp file using "last"
#*

# location of the last command binary
$lastexec = "/usr/ucb/last";

open(LAST,"$lastexec|") or die "Unable to run $lastexec:$!\n";
while(<LAST>){
    $user = (split)[0];
    print "$user","\n" unless exists $seen{$user};
    $seen{$user}='';
}
close(LAST) or die "Unable to properly close pipe:$!\n";
-------
#*
#* dump the entries in the NT/2000 system event log
#*

use Win32::EventLog;

# each event has a type, this is a translation of the common types
%type = (1  => "ERROR",
         2  => "WARNING",
         4  => "INFORMATION",
         8  => "AUDIT_SUCCESS",
         16 => "AUDIT_FAILURE");


# if this is set, we also retrieve the full text of every 
# message on each Read()
$Win32::EventLog::GetMessageText = 1; 

# open the System event log
$log = new Win32::EventLog("System") or die "Unable to open system log:$^E\n";

# read through it one record at a time, starting with the first entry
while (
 $log->Read((EVENTLOG_SEQUENTIAL_READ|EVENTLOG_FORWARDS_READ),
             1,$entry)){
    print scalar localtime($entry->{TimeGenerated})." ";
    print $entry->{Computer}."[".($entry->{EventID} &
          0xffff)."] ";
    print $entry->{Source}.":".$type{$entry->{EventType}};
    print $entry->{Message};
}
-------
#*
#* log rotation using Logfile::Rotate
#*

use Logfile::Rotate;
$logfile = new Logfile::Rotate(
			       File   => "/var/adm/log/syslog",
			       Count  => 5,
			       Gzip   => "/usr/local/bin/gzip",
			       Signal => 
			       sub {
				   open PID, "/etc/syslog.pid" or
				     die "Unable to open pid file:$!\n";
				   chomp($pid = <PID>);
				   close PID;
				   # should check validity first
				   kill 'HUP', $pid; 
			       }
			      );

$logfile->rotate();
undef $logfile;
-------
#*
#* bigbuffy - handling log files with circular buffering
#*

$buffsize = 200; # default circular buffer size (in lines)

use Getopt::Long;

# parse the options
GetOptions("buffsize=i" => \$buffsize,
           "dumpfile=s" => \$dumpfile);

# set up the signal handler and initialize a counter
&setup;

# and away we go! (with just a simple 
# read line-store line loop)
while (<>){
    # insert line into data structure 
    # note, we do this first, even if we've caught a signal. 
    # Better to dump an extra line than lose a line of data if 
    # something goes wrong in the dumping process

    $buffer[$whatline] = $_;

    # where should the next line go? 
    ($what_line %= $buff_size)++;

    # if we receive a signal, dump the current buffer
    if ($dumpnow) {
	&dodump();
    }
}

sub setup {
    die "USAGE: $0 [--buffsize=<lines>] --dumpfile=<filename>"
      unless (length($dumpfile));

    $SIG{'USR1'} = \&dumpnow; # set a signal handler for dump

    $whatline = 1; # start line in circular buffer
}

# simple signal handler that just sets an exception flag, 
# see perlipc(1)
sub dumpnow {
    $dumpnow = 1;
}

# dump the circular buffer out to a file, appending to file if
# it exists
sub dodump{
    my($line);     # counter for line dump
    my($exists);   # flag, does the output file exist already?
    my(@firststat,@secondstat); # to hold output of lstats

    $dumpnow = 0;  # reset the flag and signal handler
    $SIG{'USR1'} = \&dumpnow;

    if (-e $dumpfile and (! -f $dumpfile or -l $dumpfile)) {
	warn "ALERT: dumpfile exists and is not a plain file,skipping dump.\n";
	return undef;
    }

    # we have to take special precautions when we're doing an 
    # append. The next set of "if" statements perform a set of 
    # security checks while opening the file for append
    if (-e $dumpfile) {
	$exists = 1;
	unless(@firststat = lstat $dumpfile){
	    warn "Unable to lstat $dumpfile,skipping dump.\n";
	        return undef;
	}
	if ($firststat[3] != 1) {
	    warn "$dumpfile is a hard link, skipping dump.\n";
	    return undef;
	}
    }

    unless (open(DUMPFILE,">>$dumpfile")){
	warn "Unable to open $dumpfile for append,skipping dump.\n";
	return undef;
    }
    if ($exists) {
	unless (@secondstat = lstat DUMPFILE){
	    warn "Unable to lstat opened $dumpfile,skipping dump.\n";
	    return undef;
	}

	if ($firststat[0] != $secondstat[0] or # check dev num
	    $firststat[1] != $secondstat[1] or # check inode
	    $firststat[7] != $secondstat[7])   # check sizes
	  {
	      warn "SECURITY PROBLEM: lstats don't match,skipping dump.\n";
	      return undef;
	  }
    }

    $line = $whatline;
    print DUMPFILE "-".scalar(localtime).("-"x50)."\n";
    do {
        # in case buffer was not full
	last unless (defined $buffer[$line]);
	print DUMPFILE $buffer[$line];
	$line = ($line == $buffsize) ? 1 : $line+1;
    } while ($line != $whatline);

    close(DUMPFILE);

    # zorch the active buffer to avoid leftovers 
    # in future dumps
    $whatline = 1;
    $buffer = ();
    
    return 1;
}
-------
#*
#* count the total number of reboots on a Solaris 2.6 machine
#*

# template for Solaris 2.6 wtmpx, see the pack() doc 
# for more information
$template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x"; 

# determine the size of a record
$recordsize = length(pack($template,()));

# open the file
open(WTMP,"/var/adm/wtmpx") or die "Unable to open wtmpx:$!\n";

# read through it one record at a time
while (read(WTMP,$record,$recordsize)) {
    ($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,
     $ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen,$ut_host)=
       unpack($template,$record);

    if ($ut_line eq "system boot"){
        print "rebooted ".scalar localtime($tv_sec)."\n";
        $reboots++;
    }
}

close(WTMP);
print "Total reboots: $reboots\n";
-------
#*
#* summarize the events in the NT/2000 System event log
#*

use Win32::EventLog;

my %event=('Length',NULL,
           'RecordNumber',NULL, 
           'TimeGenerated',NULL,
           'TimeWritten',NULL, 
           'EventID',NULL, 
           'EventType',NULL,  
           'Category',NULL,
           'ClosingRecordNumber',NULL,
           'Source',NULL, 
           'Computer',NULL,
           'Strings',NULL,
           'Data',NULL,); 

# partial list of event types, i.e. Type 1 is "Error",
# 2 is "Warning", etc.
@types = ("","Error","Warning","","Information");

Win32::EventLog::Open($EventLog,'System','') or 
  die "Could not open System log:$^E\n";

$EventLog->Win32::EventLog::GetNumber($numevents);
$EventLog->Win32::EventLog::GetOldest($oldestevent); 

$EventLog->Win32::EventLog::Read((EVENTLOG_SEEK_READ |
                                  EVENTLOG_FORWARDS_READ),
                                  $numevents + $oldestevent, $event);

# loop through all of the events, recording the number of 
# Source and EventTypes
for ($i=0;$i<$numevents;$i++) {
    $EventLog->Read((EVENTLOG_SEQUENTIAL_READ | 
                     EVENTLOG_FORWARDS_READ),  
                     0, $event);
    $source{$event->{Source}}++;
    $types{$event->{EventType}}++;
}

# now print out the totals
print "-->Event Log Source Totals:\n";
for (sort keys %source) {
    print "$_: $source{$_}\n";
}
print "-"x30,"\n";
print "-->Event Log Type Totals:\n";
for (sort keys %types) {
    print "$types[$_]: $types{$_}\n";
}
print "-"x30,"\n";
print "Total number of events: $numevents\n";
-------
#*
#* summarize events in an NT/2000 System event log using an external program
#*

eldump = 'c:\bin\eldump';      # path to ElDump
# output data field separated by ~ and without full message
# text (faster)
$dumpflags = '-l system -c ~ -M'; 
      
open(ELDUMP,"$eldump $dumpflags|") or die "Unable to run $eldump:$!\n";

print STDERR "Reading system log.";

while(<ELDUMP>){    ($date,$time,$source,$type,$category,$event,$user,$computer) = 
    split('~');
    $$type{$source}++;
    print STDERR ".";
}
print STDERR "done.\n";

close(ELDUMP);

# for each type of event, print out the sources and number of 
# events per source
foreach $type (qw(Error Warning Information 
                  AuditSuccess AuditFailure)){
    print "-" x 65,"\n";
    print uc($type)."s by source:\n";
    for (sort keys %$type){
        print "$_ ($$type{$_})\n";
    }
}
print "-" x 65,"\n";
-------
#*
#* breach finder for SunOS 4.1.x - show all contacts from a particular
#* host involved in a security breach
#*

$template       = "A8 A8 A16 l"; # for SunOS 4.1.x
$recordsize     = length(pack($template,()));
($user,$ignore) = @ARGV;

print "-- scanning for first host contacts from $user --\n";
open(WTMP,"/var/adm/wtmp") or die "Unable to open wtmp:$!\n";
while (read(WTMP,$record,$recordsize)) {
    ($tty,$name,$host,$time)=unpack($template,$record);
    
    if ($user eq $name){
       next if (defined $ignore and $host =~ /$ignore/o);
       if (length($host) > 2 and !exists $contacts{$host}){
	   $connect = localtime($time);
	   $contacts{$host}=$time;
	   write;
       }
   }
}

print "-- scanning for other contacts from those hosts --\n";
die "Unable to seek to beginning of wtmp:$!\n"
  unless (seek(WTMP,0,0));

while (read(WTMP,$record,$recordsize)) {
    ($tty,$name,$host,$time)=unpack($template,$record);
    
    # if it is not a logout, and we're looking for this host,
    # and this is a connection from a user *other* than the 
    # compromised account, then record
    if (substr($name,1,1) ne "\0" andexists $contacts{$host} and 
 	$name ne $user){
	  $connect = localtime($time);
	  write;
    }
}
close(WTMP);

# here's the output format, may need to be adjusted based on template
format STDOUT = 
@<<<<<<<<    @<<<<<<<<<<<<<<  @<<<<<<<<<<<<<<<<<<
$name,$host,$connect
.
-------
#*
#* show the top transfers from a WU-FTPD xferlog file
#*

$xferlog = "/var/adm/log/xferlog";

open(XFERLOG,$xferlog) or die "Unable to open $xferlog:$!\n";

while (<XFERLOG>){
    $files{(split)[8]}++;
}

close(XFERLOG);

for (sort {$files{$b} <=> $files{$a}||$a cmp $b} keys %files){
    print "$_:$files{$_}\n";
}
-------
#*
#* breach finder II (adding tcp wrapper log file scanning)
#*

$template       = "A8 A8 A16 l"; # for SunOS 4.1.x
$recordsize     = length(pack($template,()));
($user,$ignore) = @ARGV;

# tcpd log file location
$tcpdlog        = "/var/log/tcpd/tcpdlog"; 
$hostlen        = 16;  # max length of hostname in wtmp file


print "-- scanning for first host contacts from $user --\n";
open(WTMP,"/var/adm/wtmp") or die "Unable to open wtmp:$!\n";
while (read(WTMP,$record,$recordsize)) {
    ($tty,$name,$host,$time)=unpack($template,$record);
    
    if ($user eq $name){
       next if (defined $ignore and $host =~ /$ignore/o);
       if (length($host) > 2 and !exists $contacts{$host}){
	   $connect = localtime($time);
	   $contacts{$host}=$time;
	   write;
       }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -