This file is indexed.

/usr/share/perl5/Anomy/Sanitizer/MacroScanner.pm is in sanitizer 1.76-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/perl
#
my $revision = '$Id: MacroScanner.pm,v 1.2 2001/12/22 02:47:58 bre Exp $';
my $version = 'Anomy 0.0.0 : sanitizer.pl';
#
##  Copyright (c) 2001 Bjarni R. Einarsson. All rights reserved.
##  Based on code by John Hardin.
##
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 2 of the License, or
##  (at your option) any later version.
#
##############################################################################
#
# NOTE:  Sanitizer development is for the most part sponsored by
#        FRISK Software International, http://www.frisk.is/.  Please
#        consider buying their anti-virus products to show your 
#        appreciation.
#
##############################################################################
#
# This is the built in macro scanner, based on John D. Hardin's code.
#
# It has been improved to use only a fixed, small amount of memory
# even when reading binary data.  The scanner checks a sliding 256-byte
# window - first for a sign that this is an MS document, then for stuff 
# that looks like macros.
#
# When macro stuff is seen, a score is incremented by an amount hopefully
# reflecting how "dangerous" it is.  If the total score exceeds a user 
# defined value, the attachment is considered poisoned and the scan 
# terminates immediately with a nonzero return value.
#
# Usage:
#
#  # Macro scanner configuration - this doesn't make sense within the 
#  # Sanitizer.pm module, since the Sanitizer.pm module knows nothing 
#  # about the macro scanner.
#  my @MACROSCAN = ('file_list_5_scanner = 0:1:2:builtin/macro 25',
#                  'file_list_5_policy  = unknown:mangle:mangle:defang',
#                  'file_list_5 = (?i)\.(do[tc]|xl[aswct]|p[po]t|pps|rtf|md[abw])$');
#
#  # WARNING: For brevity, error handling is omitted in this example, see
#  #          sanitizer.pl for a proper example.
#  #
#  $engine = new Anomy::Sanitizer;
#  $engine->register_scanner("macro", \&MacroScan);
#  $engine->configure(@MACROSCAN);
#
##[ Package definition ]######################################################

package Anomy::Sanitizer::MacroScanner;
use strict;
use IO::File;
use Anomy::Log;
 
BEGIN {
    use Exporter ();
    use vars         qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
    $VERSION         = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
    @ISA             = qw(Exporter);
    @EXPORT          = qw(MacroScanner);
    @EXPORT_OK       = qw( );
}

use vars @EXPORT_OK;

##[ Package implementation ]##################################################

sub MacroScanner
{
    my $self = shift;
    my $plog = shift;
    my $fh = shift;
    my $md5x2 = shift;
    my $poison_score = shift;

    my $score = 0;
    my $msapp = 0;  
    
    # Read relatively small chunks at a time, to minimize the extra
    # work done by the pattern maching.  We just trust the OS to make
    # this efficient...
    #
    my $chunksize = 128;
    local $/ = \$chunksize;
    
    # Initialize buffer.
    $fh->seek(0, SEEK_SET);
    my $buff = <$fh> . <$fh>;

    my $log = $plog->sublog("MacroScan", SLOG_TRACE, undef);

    while ($buff)
    {   
        unless ($msapp) 
        {
            if ($buff =~ /\000(Microsoft (Word Document|PowerPoint|Excel( (Spread|Work)sheet)?)|MSWordDoc|Word\.Document\.[0-9]+|Excel\.Sheet\.[0-9]+)\000/)
            {
                $msapp = 1;

                $log->entry("is-MS-document", SLOG_DEBUG, undef,
                    "This appears to be an MS document, restarting scan.");
                
                # Restart scan
                $fh->seek(0, SEEK_SET);
                $buff = <$fh> . <$fh>;
                next;
            }
        }
        else
        {
            # Lots of while loops here - we replace the leading \000 boundary
            # with 'x' characters to ensure this eventually completes.
            #
            $score += 99 while ($buff =~ s/\000(VirusProtection)/x$1/i);
            $score += 99 while ($buff =~ s/\000(select\s[^\000]*shell\s*\()/x$1/i);
            $score +=  9 while ($buff =~ s/\000(regedit|SaveNormalPrompt|Outlook.Application\000)/x$1/i);
            $score +=  4 while ($buff =~ s/\000(ID="{[-0-9A-F]+)$/x$1/i);
            $score +=  4 while ($buff =~ s/\000(CreateObject)/x$1/i);
            $score +=  4 while ($buff =~ s/(?:\000|\004)(([a-z0-9_]\.)*(Autoexec|Workbook_(Open|BeforeClose)|Document_(Open|New|Close)))/x$1/i);
            $score +=  4 while ($buff =~ s/(?:\000|\004)(Logon|AddressLists|AddressEntries|Recipients|Subject|Body|Attachments|Logoff)/x$1/i);
            $score +=  2 while ($buff =~ s/\000(Shell|Options|CodeModule)/x$1/i);
            $score +=  2 while ($buff =~ s/\000(([a-z]+\.)?Application\000)/x$1/i);
            $score +=  2 while ($buff =~ s/(?:\000|\004)(stdole|NormalTemplate)/x$1/i);
            $score +=  1 while ($buff =~ s/\000(ID="{[-0-9A-F]+}"|ThisWorkbook\000|PrivateProfileString)/x$1/i);
            $score +=  1 while ($buff =~ s/(?:\000|\004)(ActiveDocument|ThisDocument)/x$1/i);
            $score +=  1 while ($buff =~ s/\000(\[?HKEY_(CLASSES_ROOT|CURRENT_USER|LOCAL_MACHINE))/x$1/);

            # Save cycles!  Return early!
            if ($score > $poison_score) 
            {
                $log->entry("bad-score", SLOG_INFO, 
                    { score => $score, bytes => $chunksize * $. },
                    "Score (%score%) exceeded $poison_score after ".
                    "scanning %bytes% bytes!");
                return 1;
            }
        }

        # Read on...
        $buff = substr($buff, $chunksize, $chunksize) . <$fh>;
    }

    $log->entry("bad-score", SLOG_INFO, { score => $score }, 
                "Attachment passed macro scan with a score of %score%."); 
    return 0;
}

1;
#EOF#