def test_dbrules(self): """Test if db rules correctly override defaults""" testdata = u""" INSERT INTO attachmentrules(scope,checktype,action,regex,description,prio) VALUES ('*****@*****.**','contenttype','allow','application/x-executable','this user likes exe',1) """ self.session.execute(testdata) # copy file rules tmpfile = tempfile.NamedTemporaryFile( suffix='virus', prefix='fuglu-unittest', dir='/tmp') shutil.copy(TESTDATADIR + '/binaryattachment.eml', tmpfile.name) suspect = Suspect( '*****@*****.**', '*****@*****.**', tmpfile.name) result = self.candidate.examine(suspect) resstr = actioncode_to_string(result) self.assertEqual(resstr, "DUNNO") # another recipient should still get the block suspect = Suspect( '*****@*****.**', '*****@*****.**', tmpfile.name) result = self.candidate.examine(suspect) if type(result) is tuple: result, message = result resstr = actioncode_to_string(result) self.assertEqual(resstr, "DELETE") tmpfile.close()
def test_dbrules(self): """Test if db rules correctly override defaults""" testdata = u""" INSERT INTO attachmentrules(scope,checktype,action,regex,description,prio) VALUES ('*****@*****.**','contenttype','allow','application/x-executable','this user likes exe',1) """ self.session.execute(testdata) # copy file rules tempfilename = tempfile.mktemp(suffix='virus', prefix='fuglu-unittest', dir='/tmp') shutil.copy(TESTDATADIR + '/binaryattachment.eml', tempfilename) suspect = Suspect('*****@*****.**', '*****@*****.**', tempfilename) result = self.candidate.examine(suspect) resstr = actioncode_to_string(result) self.assertEquals(resstr, "DUNNO") # another recipient should still get the block suspect = Suspect('*****@*****.**', '*****@*****.**', tempfilename) result = self.candidate.examine(suspect) if type(result) is tuple: result, message = result resstr = actioncode_to_string(result) self.assertEquals(resstr, "DELETE") os.remove(tempfilename)
def test_result(self): """Test if EICAR virus is detected and message deleted""" suspect = Suspect('*****@*****.**', '*****@*****.**', '/dev/null') stream = """Date: Mon, 08 Sep 2008 17:33:54 +0200 To: [email protected] From: [email protected] Subject: test eicar attachment X-Mailer: swaks v20061116.0 jetmore.org/john/code/#swaks MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_MIME_BOUNDARY_000_12140" ------=_MIME_BOUNDARY_000_12140 Content-Type: text/plain Eicar test ------=_MIME_BOUNDARY_000_12140 Content-Type: application/octet-stream Content-Transfer-Encoding: BASE64 Content-Disposition: attachment UEsDBAoAAAAAAGQ7WyUjS4psRgAAAEYAAAAJAAAAZWljYXIuY29tWDVPIVAlQEFQWzRcUFpYNTQo UF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCoNClBLAQIU AAoAAAAAAGQ7WyUjS4psRgAAAEYAAAAJAAAAAAAAAAEAIAD/gQAAAABlaWNhci5jb21QSwUGAAAA AAEAAQA3AAAAbQAAAAAA ------=_MIME_BOUNDARY_000_12140--""" suspect.setMessageRep(email.message_from_string(stream)) result = self.candidate.examine(suspect) if type(result) is tuple: result, message = result strresult = actioncode_to_string(result) self.assertEqual(strresult, "DELETE")
def test_result(self): """Test if EICAR virus is detected and message deleted""" suspect = Suspect( '*****@*****.**', '*****@*****.**', '/dev/null') stream = """Date: Mon, 08 Sep 2008 17:33:54 +0200 To: [email protected] From: [email protected] Subject: test eicar attachment X-Mailer: swaks v20061116.0 jetmore.org/john/code/#swaks MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_MIME_BOUNDARY_000_12140" ------=_MIME_BOUNDARY_000_12140 Content-Type: text/plain Eicar test ------=_MIME_BOUNDARY_000_12140 Content-Type: application/octet-stream Content-Transfer-Encoding: BASE64 Content-Disposition: attachment UEsDBAoAAAAAAGQ7WyUjS4psRgAAAEYAAAAJAAAAZWljYXIuY29tWDVPIVAlQEFQWzRcUFpYNTQo UF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCoNClBLAQIU AAoAAAAAAGQ7WyUjS4psRgAAAEYAAAAJAAAAAAAAAAEAIAD/gQAAAABlaWNhci5jb21QSwUGAAAA AAEAAQA3AAAAbQAAAAAA ------=_MIME_BOUNDARY_000_12140--""" suspect.setMessageRep(email.message_from_string(stream)) result = self.candidate.examine(suspect) if type(result) is tuple: result, message = result strresult = actioncode_to_string(result) self.assertEqual(strresult, "DELETE")
def test_defaultcodes(self): """test actioncode<->string conversion""" conf = ConfigParser() conf.add_section('spam') conf.add_section('virus') conf.set('spam', 'defaultlowspamaction', 'REJEcT') conf.set('spam', 'defaulthighspamaction', 'REjECT') conf.set('virus', 'defaultvirusaction', 'rejeCt') self.assertEqual(string_to_actioncode('defaultlowspamaction', conf), REJECT) self.assertEqual(string_to_actioncode('defaulthighspamaction', conf), REJECT) self.assertEqual(string_to_actioncode('defaultvirusaction', conf), REJECT) self.assertEqual(string_to_actioncode('nonexistingstuff'), None) self.assertEqual(actioncode_to_string(REJECT), 'REJECT') self.assertEqual(actioncode_to_string(string_to_actioncode('discard')), 'DELETE')
def test_defaultcodes(self): """test actioncode<->string conversion""" conf = ConfigParser() conf.add_section('spam') conf.add_section('virus') conf.set('spam', 'defaultlowspamaction', 'REJEcT') conf.set('spam', 'defaulthighspamaction', 'REjECT') conf.set('virus', 'defaultvirusaction', 'rejeCt') self.assertEqual( string_to_actioncode('defaultlowspamaction', conf), REJECT) self.assertEqual( string_to_actioncode('defaulthighspamaction', conf), REJECT) self.assertEqual( string_to_actioncode('defaultvirusaction', conf), REJECT) self.assertEqual(string_to_actioncode('nonexistingstuff'), None) self.assertEqual(actioncode_to_string(REJECT), 'REJECT') self.assertEqual( actioncode_to_string(string_to_actioncode('discard')), 'DELETE')
def lint(self): viract = self.config.get(self.section, 'virusaction') print("Virusaction: %s" % actioncode_to_string( string_to_actioncode(viract, self.config))) allok = self.checkConfig() and self.lint_ping() and self.lint_eicar() if self.config.getboolean(self.section, 'clamscanfallback'): print('WARNING: Fallback to clamscan enabled') starttime = time.time() allok = self.lint_eicar('shell') if allok: runtime = time.time()-starttime print('clamscan scan time: %.2fs' % runtime) return allok
def lint(self): viract = self.config.get(self.section, 'virusaction') print("Virusaction: %s" % actioncode_to_string(string_to_actioncode(viract, self.config))) allok = self.checkConfig() and self.lint_ping() and self.lint_eicar() if self.config.getboolean(self.section, 'clamscanfallback'): print('WARNING: Fallback to clamscan enabled') starttime = time.time() allok = self.lint_eicar('shell') if allok: runtime = time.time() - starttime print('clamscan scan time: %.2fs' % runtime) return allok
def examine(self, suspect): scripts = self.get_scripts() retaction = DUNNO retmessage = '' for script in scripts: self.logger.debug("Executing script %s" % script) suspect.debug("Executing script %s" % script) sstart = time.time() action, message = self.exec_script(suspect, script) send = time.time() self.logger.debug("Script %s done in %.4fs result: %s %s" % ( script, send - sstart, actioncode_to_string(action), message)) if action != DUNNO: retaction = action retmessage = message break return retaction, retmessage
def process(self, suspect, decision): buffer = "%s.fuglu.decision.%s:1|c\n" % ( self.nodename, actioncode_to_string(decision)) if self.sock == None: self.sock = socket(AF_INET, SOCK_DGRAM) if suspect.is_virus(): buffer = "%s%s.fuglu.message.virus:1|c\n" % (buffer, self.nodename) elif suspect.is_highspam(): buffer = "%s%s.fuglu.message.highspam:1|c\n" % (buffer, self.nodename) elif suspect.is_spam(): buffer = "%s%s.fuglu.message.spam:1|c\n" % (buffer, self.nodename) else: buffer = "%s%s.fuglu.message.clean:1|c\n" % (buffer, self.nodename) addr = self.config.get(self.section, 'host'), self.config.getint( self.section, 'port') self.sock.sendto(buffer.encode('utf-8'), addr)
def examine(self, suspect): scripts = self.get_scripts() retaction = DUNNO retmessage = '' for script in scripts: self.logger.debug("Executing script %s" % script) suspect.debug("Executing script %s" % script) sstart = time.time() action, message = self.exec_script(suspect, script) send = time.time() self.logger.debug( "Script %s done in %.4fs result: %s %s" % (script, send - sstart, actioncode_to_string(action), message)) if action != DUNNO: retaction = action retmessage = message break return retaction, retmessage
def process(self, suspect, decision): buffer = "%s.fuglu.decision.%s:1|c\n" % ( self.nodename, actioncode_to_string(decision)) if self.sock == None: self.sock = socket(AF_INET, SOCK_DGRAM) if suspect.is_virus(): buffer = "%s%s.fuglu.message.virus:1|c\n" % (buffer, self.nodename) elif suspect.is_highspam(): buffer = "%s%s.fuglu.message.highspam:1|c\n" % ( buffer, self.nodename) elif suspect.is_spam(): buffer = "%s%s.fuglu.message.spam:1|c\n" % (buffer, self.nodename) else: buffer = "%s%s.fuglu.message.clean:1|c\n" % (buffer, self.nodename) addr = self.config.get(self.section, 'host'), self.config.getint( self.section, 'port') self.sock.sendto(buffer.encode('utf-8'), addr)
def process(self, suspect, decision): if not SQL_EXTENSION_ENABLED: self.logger.error("Fuglu SQL Extensions not enabled") return connstring = self.config.get(self.section, 'dbconnectstring') session = get_session(connstring) if session is None: self.logger.error("Could not create database session") return try: conn = session.connection() conn.connect() except Exception as e: self.logger.error("Database Connection failed: %s" % e) return statementlist = self.get_statements() for statement in statementlist: self.logger.debug("Template: %s" % statement) addvalues = { 'action': actioncode_to_string(decision), } from_header = suspect.get_message_rep()['from'] try: addvalues['header_from'] = self.stripAddress(from_header) except Exception: #use full from header addvalues['header_from'] = from_header replaced = apply_template(statement, suspect, values=addvalues, valuesfunction=self.sqlfix) self.logger.debug("Statement: %s" % replaced) try: result = session.execute(replaced) except Exception as e: self.logger.error("Statement failed: statement=%s , error=%s" % (replaced, str(e))) session.remove()
def process(self, suspect, decision): buffer = "%s.fuglu.decision.%s:1|c\n" % ( self.nodename, actioncode_to_string(decision)) host = self.config.get(self.section, 'host') port = int(self.config.get(self.section, 'port')) if self.sock is None: addr_f = socket.getaddrinfo(host, 0)[0][0] self.sock = socket.socket(addr_f, socket.SOCK_DGRAM) if suspect.is_virus(): buffer = "%s%s.fuglu.message.virus:1|c\n" % (buffer, self.nodename) elif suspect.is_highspam(): buffer = "%s%s.fuglu.message.highspam:1|c\n" % (buffer, self.nodename) elif suspect.is_spam(): buffer = "%s%s.fuglu.message.spam:1|c\n" % (buffer, self.nodename) else: buffer = "%s%s.fuglu.message.clean:1|c\n" % (buffer, self.nodename) self.sock.sendto(force_bString(buffer), (host, port))
def lint(self): viract = self.config.get(self.section, 'virusaction') print("Virusaction: %s" % actioncode_to_string(string_to_actioncode(viract, self.config))) allok = (self.checkConfig() and self.lint_eicar()) return allok
class SQLRunner(AppenderPlugin): """Run SQL statements after message scan is complete""" def __init__(self, config, section): AppenderPlugin.__init__(self, config, section) self.logger = self._logger() self.requiredvars = { 'dbconnectstring': { 'default': 'mysql://root@localhost/test', 'description': 'sqlalchemy connectstring', }, 'statementseparator': { 'default': ';', 'description': 'Separator used to separate mutliple statements', }, 'statements': { 'description': """SQL statements to run, can containt standard variables as described in http://gryphius.github.io/fuglu/plugins-index.html#template-variables \n ${action} contains the action as string, eg. DUNNO """, 'default': "", }, } def sqlfix(self, values): for k, v in values.copy().iteritems(): if type(v) == str: values[k] = re.sub("""['";]""", "", v) return values def process(self, suspect, decision): if not fuglu.extensions.sql.ENABLED: self.logger.error("Fuglu SQL Extensions not enabled") return connstring = self.config.get(self.section, 'dbconnectstring') session = fuglu.extensions.sql.get_session(connstring) if session == None: self.logger.error("Could not create database session") return try: conn = session.connection() conn.connect() except Exception, e: self.logger.error("Database Connection failed: %s" % e) return statementlist = self.get_statements() for statement in statementlist: self.logger.debug("Template: %s" % statement) addvalues = { 'action': actioncode_to_string(decision), } from_header = suspect.get_message_rep()['from'] try: addvalues['header_from'] = self.stripAddress(from_header) except Exception, e: #use full from header addvalues['header_from'] = from_header replaced = apply_template(statement, suspect, values=addvalues, valuesfunction=self.sqlfix) self.logger.debug("Statement: %s" % replaced) try: result = session.execute(replaced) except Exception, e: self.logger.error("Statement failed: statement=%s , error=%s" % (replaced, str(e)))
def lint(self): viract = self.config.get(self.section, 'virusaction') print "Virusaction: %s" % actioncode_to_string( string_to_actioncode(viract, self.config)) allok = (self.checkConfig() and self.lint_eicar()) return allok
scannerlist = resultset logging.info("Scanner plugin list is now: %s" % scannerlist) for pluginstance in scannerlist: logging.info("*** Running plugin: %s ***" % pluginstance) ans = pluginstance.examine(suspect) message = "" if type(ans) is tuple: result, message = ans else: result = ans if result == None: result = DUNNO logging.info("Result: %s %s", actioncode_to_string(result), message) suspect.tags['decisions'].append((pluginstance.section, result)) logging.info(suspect) for pluginstance in mc.appenders: logging.info("*** Running appender: %s ***" % pluginstance) pluginstance.process(suspect, DUNNO) message = "" logging.info(suspect) if suspect.is_modified(): outfilename = '/tmp/fuglu_dummy_message_out.eml' out = open(outfilename, 'wb') out.write(suspect.get_source()) out.close() logging.info(