/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#
|