#!/usr/bin/env python # # Copyright 2015 by Konrad Kaczkowski (at) HP.COM [ konrad.kaczkowski@pheo.NET ] # # http://arcsight.pheo.NET/ # # HP ArcSight Active List Import script # Scrapes Open Source Intelligence data for import into ESM via CEF/Syslog # # THIS SCRIPT IS AFTER TESTS on RedHat 6.5 with Python 2.6 # # #---------------------------------------------------------------------------- # The MIT License # # #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is #furnished to do so, subject to the following conditions: # #The above copyright notice and this permission notice shall be included in #all copies or substantial portions of the Software. # #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. # # # Minimal reconfiguration require: # # # Place where are stored xml files for import: line 63 # export_dlobal_dir = "/opt/asset_import/active list" # # Device interface name: line 86 # CEF_dvc = get_ip('eth0') import re, socket, sys, time, os, string, getpass, tempfile, datetime, hashlib import csv import datetime import subprocess import commands from optparse import OptionParser #XML parse from xml.etree import ElementTree import glob def modification_date(filename): t = os.path.getmtime(filename) return datetime.datetime.fromtimestamp(t) date_now = time.strftime("%Y%m%d%H%M") al_time = str(time.mktime(datetime.datetime.strptime(date_now, "%Y%m%d%H%M").timetuple())) export_dlobal_dir = "/opt/asset_import/active list" export_dir = time.strftime("%Y%m%d%H%M") # get deviceHostName if socket.gethostname().find('.')>=0: CEF_dvchost = socket.gethostname() else: CEF_dvchost = socket.gethostbyaddr(socket.gethostname())[0] # get IP address for interface import socket, struct, fcntl sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sockfd = sock.fileno() SIOCGIFADDR = 0x8915 def get_ip(iface = 'eth0'): ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) try: res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq) except: return None ip = struct.unpack('16sH2x4s8x', res)[2] return socket.inet_ntoa(ip) CEF_dvc = get_ip('eth0') VERSION = "v0.6 2015-03-10" USAGE = """Usage: parameters.py [ Options description ] -r 10 [ numers of rows per single import ] -l Actve List [ avtive list full URI in format "/All Avtive Lists/customer/malware" ] -f filename [ if file contains space - use filename in " QUITAS " ] -m ESM manager [ HP ArcSight ESM manager FQDN ] -u ESM user [ HP ArcSight ESM import user ] -p ESM user pass [ HP ArcSoght ESM user password ] -s Syslog Server [ Syslog server ] -P Syslog Port [ Syslog server port ] -c [ clean (delete) imported files ] -d [ debugging - display detailed information from processing ] """ parser = OptionParser(USAGE) #definition of parameter parsing parser.add_option("-r", action="store", type="string", dest="AL_ROWS", default = "", help="number of rows per one import") parser.add_option("-l", action="store", type="string", dest="AL_URI", default = "", help="Active list URI - in format \"/All Actve List/import\"") parser.add_option("-f", action="store", type="string", dest="INPUT_FILE", default = "", help="Active List csv file") parser.add_option("-m", action="store", type="string", dest="ESM_MANAGER", default = "", help="HP ArcSight ESM manager") parser.add_option("-u", action="store", type="string", dest="ESM_USER", default = "", help="HP ArcSight ESM import user") parser.add_option("-p", action="store", type="string", dest="ESM_PASS", default = "", help="HP ArcSight ESM user Password") parser.add_option("-s", action="store", type="string", dest="SYSLOG_SERVER", default = "", help="Syslog server") parser.add_option("-P", action="store", type="string", dest="SYSLOG_SERVER_PORT", default = "", help="Syslog server port") parser.add_option("-v", action="store_true", dest="version", default=False, help="show version") parser.add_option("-c", action="store_true", dest="CLEAN", default=False, help="clean imported files") parser.add_option("-d", action="store_true", dest="DEBUG", default=False, help="debugging") (options, args) = parser.parse_args() if options.version: print "Active List import tool", VERSION sys.exit() if (not (options.INPUT_FILE and options.AL_URI and options.ESM_USER and options.ESM_USER)): parser.print_help() sys.exit() # check if password is defined in command line if len(options.ESM_PASS) == 0: # read password from stdin print "Please type password for user ",options.ESM_USER, "on ",options.ESM_MANAGER ESM_PASS = getpass.getpass() # loop untill passwoerd length will be different than 0 (pressing ENTER key) while len(ESM_PASS) == 0: print "Please type password different than pressing ENTER" ESM_PASS = getpass.getpass() else: ESM_PASS=str(options.ESM_PASS) #parameter assignment AL_ROWS=int(options.AL_ROWS) AL_URI=str(options.AL_URI) INPUT_FILE=str(options.INPUT_FILE) ESM_MANAGER=str(options.ESM_MANAGER) ESM_USER=str(options.ESM_USER) if options.SYSLOG_SERVER: SYSLOG_SERVER=str(options.SYSLOG_SERVER) if not options.SYSLOG_SERVER_PORT: SYSLOG_SERVER_PORT=514 else: SYSLOG_SERVER_PORT=int(options.SYSLOG_SERVER_PORT) # print parameters if options.DEBUG: print " " print " PARAMETERS: " print " " if AL_ROWS: print " Rows per import : ", AL_ROWS if AL_URI: print " Active List URI : ", AL_URI if INPUT_FILE: print " Input csv file : ", INPUT_FILE if ESM_MANAGER: print " HP ESM manager : ", ESM_MANAGER if ESM_USER: print " HP ESM user : ", ESM_USER #if ESM_PASS: print " HP ESM pass : ", ESM_PASS if options.SYSLOG_SERVER: print " Syslog Server : ", SYSLOG_SERVER,":",SYSLOG_SERVER_PORT print " " ########################################################### ## Syslog module - send syslog message about import ## ########################################################### ## Syslog definition START if options.SYSLOG_SERVER or options.SYSLOG_SERVER_PORT: FACILITY = { 'kern': 0, 'user': 1, 'mail': 2, 'daemon': 3, 'auth': 4, 'syslog': 5, 'lpr': 6, 'news': 7, 'uucp': 8, 'cron': 9, 'authpriv': 10, 'ftp': 11, 'local0': 16, 'local1': 17, 'local2': 18, 'local3': 19, 'local4': 20, 'local5': 21, 'local6': 22, 'local7': 23, } LEVEL = { 'emerg': 0, 'alert':1, 'crit': 2, 'err': 3, 'warning': 4, 'notice': 5, 'info': 6, 'debug': 7 } def syslog(message, level=LEVEL['notice'], facility=FACILITY['daemon'], host=SYSLOG_SERVER, port=SYSLOG_SERVER_PORT): """ Send syslog UDP packet to given host and port. """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = '<%d>%s' % (level + facility*8, message) sock.sendto(data, (host, port)) sock.close() ## Syslog definition END arc_archive_header = '\n\n\n \n insert\n default\n \n \n' arc_archive_footer = '' # check if file exist and is readable if not (os.path.isfile(INPUT_FILE) and os.access(INPUT_FILE, os.R_OK)): print "no such file", INPUT_FILE sys.exit() else: #print "file exist" # import file to array print "Loading file to memory" AL_IMPORT_CSV = [line.split(',') for line in open(INPUT_FILE)] AL_IMPORT_CSV_ROWS = int(len(AL_IMPORT_CSV)) ESM_ARCHIVE_LOG_FILE = "/opt/arcsight/manager/logs/archive.log" ESM_ARCHIVE_FILE_RIGHTS = os.stat(ESM_ARCHIVE_LOG_FILE) if(os.access(ESM_ARCHIVE_LOG_FILE,os.R_OK)): ESM_LOG_RIGHTS_READ="ALLOWED" else: ESM_LOG_RIGHTS_READ="DENIED" if(os.access(ESM_ARCHIVE_LOG_FILE, os.W_OK)): ESM_LOG_RIGHTS_WRITE="ALLOWED" else: ESM_LOG_RIGHTS_WRITE="DENIED" if options.DEBUG: print " -=================================================================================================================================================================-" print "ESM_LOG_RIGHTS_READ : "+ESM_LOG_RIGHTS_READ print "ESM_LOG_RIGHTS_WRITE : "+ESM_LOG_RIGHTS_WRITE print "\n\n\n" if ( ESM_LOG_RIGHTS_READ == "DENIED" or ESM_LOG_RIGHTS_WRITE == "DENIED" ): print "\n !!!! WARNING !!!!\n" print "Please verify owner of file : "+ESM_ARCHIVE_LOG_FILE+"\n" print "Please do one of option:\n" print " - EXECUTE SCRIPT as owner of file : "+ESM_ARCHIVE_LOG_FILE+" - typically it's arcsight" print " - change rights to file\n" print "Exiting ...." sys.exit() print "Validating if Active List : ",AL_URI, "is valid" TEMP_FILE="/tmp/AL_IN_ESM_INVALID" if(os.access(TEMP_FILE,os.R_OK)): TEMP_FILE_RIGHTS_READ="ALLOWED" os.remove(TEMP_FILE) else: TEMP_FILE_RIGHTS_READ="DENIED" if(os.access(TEMP_FILE, os.W_OK)): TEMP_FILE_RIGHTS_WRITE="ALLOWED" else: TEMP_FILE_RIGHTS_WRITE="DENIED" if os.path.isfile(TEMP_FILE): os.remove(TEMP_FILE) if ( TEMP_FILE_RIGHTS_WRITE == "DENIED" ): print "\nYou don't have rights to TEMP_FILE : "+TEMP_FILE print "\nUsing autogenerated temp file\n" # Generate STRING that will be md5 hash for tem file suffix - current date in format [ 2015-01-29 09:59:27.625175 ] MD5_STRING_TO_HASH = str(datetime.datetime.now()) # generate md5 hash in format [ 2864f8a44d6fc5a0d6f0740ebd9ddceb ] MD5_SUFFIX_FILE_NAME = str(hashlib.md5(MD5_STRING_TO_HASH).hexdigest()) # set new TEMP_FILE variable TEMP_FILE="/tmp/ARC_AL_"+MD5_SUFFIX_FILE_NAME AL_IN_ESM_INVALID = "is invalid" AL_IN_ESM_UNKNOWN_TYPE = "Unknown type" AL_IN_ESM_DISABLED_USER="Your user account has been disabled temporarily" AL_IN_ESM_INVALID_USER_PASS="The authentication failed. Please verify your credentials and try again." AL_IN_ESM_CANNOT_CONNECT="Connection refused" AL_IN_ESM_CANNOT_CONNECT1="Connection timed out" AL_IN_ESM_NO_RIGHTS_TO_LOG_FILE="Unable to open log file" command_to_execute = '/opt/arcsight/manager/bin/arcsight archive -action export -m '+ESM_MANAGER+' -u '+ESM_USER+' -p '+ESM_PASS+' -uri "'+AL_URI+'" -f "'+TEMP_FILE+'"' if options.DEBUG: print " -=================================================================================================================================================================-" print command_to_execute command_status, command_output = commands.getstatusoutput(command_to_execute) AL_IN_ESM_EXIST = command_output.find(AL_IN_ESM_INVALID) AL_IN_ESM_UNKNOWN = command_output.find(AL_IN_ESM_UNKNOWN_TYPE) AL_IN_ESM_DISABLED_USER_TEMPORARY = command_output.find(AL_IN_ESM_DISABLED_USER) AL_IN_ESM_INVALID_PASS = command_output.find(AL_IN_ESM_INVALID_USER_PASS) AL_IN_ESM_CONNECTION_REFUSED = command_output.find(AL_IN_ESM_CANNOT_CONNECT) AL_IN_ESM_CONNECTION_TIMEOUT = command_output.find(AL_IN_ESM_CANNOT_CONNECT1) AL_IN_ESM_NO_RIGHTS_TO_LOG = command_output.find(AL_IN_ESM_CANNOT_CONNECT) if options.DEBUG: print "Active List Exist :", AL_IN_ESM_EXIST print "User disabled temporary :", AL_IN_ESM_DISABLED_USER_TEMPORARY print "User password invalid :", AL_IN_ESM_INVALID_PASS print "Connection refused :", AL_IN_ESM_CONNECTION_REFUSED print "Connection timeout :", AL_IN_ESM_CONNECTION_TIMEOUT print "No rights to arcive.log :", AL_IN_ESM_NO_RIGHTS_TO_LOG print " -=================================================================================================================================================================-" if AL_IN_ESM_EXIST > 0: print "\n !!!! WARNING !!!!\n" print "Active List "+AL_URI+" does not exist in ESM Manager :"+ESM_MANAGER+"\n" print "Please specify valid Active List\n" print "Exiting ...." sys.exit() if AL_IN_ESM_UNKNOWN > 0: print "\n !!!! WARNING !!!!\n" print "Active List "+AL_URI+" is NOT VALID RESOURCE ob ESM Manager : "+ESM_MANAGER+"\n" print "Please specify valid Active List\n" print "Exiting ...." sys.exit() if AL_IN_ESM_DISABLED_USER_TEMPORARY > 0: print "\n !!!! WARNING !!!!\n" print "You have temporary disabled user!!!!\n" print "Please enable user and use correct password\n" print "Exiting ...." sys.exit() if AL_IN_ESM_INVALID_PASS > 0: print "\n !!!! WARNING !!!!\n" print "The authentication failed.\n" print "Please verify your credentials and try again.\n" print "Exiting ...." sys.exit() if AL_IN_ESM_CONNECTION_REFUSED > 0 or AL_IN_ESM_CONNECTION_TIMEOUT > 0: print "\n !!!! WARNING !!!!\n" print "Connection Refused.\n" print "Please verify that ESM Manager is running and You have access to Manager port [ 8443 ].\n" print "Exiting ...." sys.exit() else: tree = ElementTree.parse(TEMP_FILE) olp_name = tree.findall("//columnName") olp_type = tree.findall("//typeName") AL_ESM_ALL_COLUMNS_NAME = [t.text for t in olp_name] AL_ESM_ALL_COLUMNS_TYPE = [t.text for t in olp_type] AL_ESM_AVAILABLE_COLUMNS=len(AL_ESM_ALL_COLUMNS_NAME)-4 if options.DEBUG: print " Available Active List columns for import: ",AL_ESM_AVAILABLE_COLUMNS print " Available Active List columns:" for i in range (AL_ESM_AVAILABLE_COLUMNS): print "\t\t\t\t",AL_ESM_ALL_COLUMNS_NAME[i], " | ", AL_ESM_ALL_COLUMNS_TYPE[i] os.remove(TEMP_FILE) # Verifying if CSV file have same number of column than Active List for i in range(AL_IMPORT_CSV_ROWS): if len(AL_IMPORT_CSV[i]) != AL_ESM_AVAILABLE_COLUMNS: print "\n WARNING !!!!!\n" print " Import CSV field have different number of columns than Active List" print " Import CSV file : "+INPUT_FILE print " Active List : "+AL_URI sys.exit() ACTIVE_LIST = AL_URI.split('/') ACTIVE_LIST_BASE_URI="" for i in range(1, len(ACTIVE_LIST)-1): ACTIVE_LIST_BASE_URI += "/"+ACTIVE_LIST[i] ACTIVE_LIST_BASE_URI = str(ACTIVE_LIST_BASE_URI) ACTIVE_LIST_NAME = str(ACTIVE_LIST[len(ACTIVE_LIST)-1]) # count number of output xml files - for format X_files_ftom_Y.xml j=0 m=0 for i in range(AL_IMPORT_CSV_ROWS): if str(str(AL_IMPORT_CSV[i][0]).startswith( '#' )) == "False": rest = (j % AL_ROWS) if rest == 0: m=m+1 j=j+1 NUMBER_OF_XML_FILES=m # generating xml files j=0 m=0 for i in range(AL_IMPORT_CSV_ROWS): EXPORT_SUBDIR = export_dlobal_dir+"/"+export_dir+"/" try: os.makedirs(EXPORT_SUBDIR) except OSError: if not os.path.isdir(EXPORT_SUBDIR): raise if str(str(AL_IMPORT_CSV[i][0]).startswith( '#' )) == "False": rest = (j % AL_ROWS) data=str(AL_IMPORT_CSV[i]) if rest == 0: if j!=0: XML_OUTPUT_FILE = str(EXPORT_SUBDIR)+"AL_"+str(ACTIVE_LIST_NAME)+"_"+str(m)+"_of_"+str(NUMBER_OF_XML_FILES)+".xml" XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(arc_archive_footer) if options.DEBUG: print " execute file "+XML_OUTPUT_FILE m=m+1 XML_OUTPUT_FILE = str(EXPORT_SUBDIR)+"AL_"+str(ACTIVE_LIST_NAME)+"_"+str(m)+"_of_"+str(NUMBER_OF_XML_FILES)+".xml" XML_FILE = file(XML_OUTPUT_FILE, "w") XML_FILE.write(arc_archive_header) XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' 1\n') XML_FILE.write(' '+al_time[:10]+'000\n') XML_FILE.write(' '+al_time[:10]+'000\n') XML_FILE.write(' \n') XML_FILE.write(' \n') for l in range(len(AL_IMPORT_CSV[i])): data = str(AL_IMPORT_CSV[i][l]).replace('\n', '').replace('"', '"').replace("&", "\A").replace(",", "\C").replace("<", "\L").replace(">", "\G").replace('\\', '\\\\').replace('\|', '\\|') XML_FILE.write(' '+data+'\n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') else: XML_FILE.write(' \n') XML_FILE.write(' 1\n') XML_FILE.write(' '+al_time[:10]+'000\n') XML_FILE.write(' '+al_time[:10]+'000\n') XML_FILE.write(' \n') XML_FILE.write(' \n') for l in range(len(AL_IMPORT_CSV[i])): data = str(AL_IMPORT_CSV[i][l]).replace('\n', '').replace('"', '"').replace("&", "\A").replace(",", "\C").replace("<", "\L").replace(">", "\G").replace("\\", "\\\\").replace("\|", "\\|") XML_FILE.write(' '+data+'\n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') if (AL_ROWS - j) == 0: XML_FILE = file(XML_OUTPUT_FILE, "a") XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(arc_archive_footer) XML_FILE.close() j=j+1 XML_FILE = file(XML_OUTPUT_FILE, "a") XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(' \n') XML_FILE.write(arc_archive_footer) XML_FILE.close() time.sleep(3) # list directory and put *.xml files list to array if options.DEBUG: print " execute file "+XML_OUTPUT_FILE XML_DIR=export_dlobal_dir+"/"+export_dir+"/*.xml" XML_FILES_TO_IMPORT = glob.glob(XML_DIR) if options.DEBUG: print XML_FILES_TO_IMPORT # walk array and execute import for i in range(len(XML_FILES_TO_IMPORT)): file = XML_FILES_TO_IMPORT[i] command_to_execute = '/opt/arcsight/manager/bin/arcsight archive -action import -m '+ESM_MANAGER+' -u '+ESM_USER+' -p '+ESM_PASS+' -f \"'+file+'\"' if options.DEBUG: print "Iteration :"+str(i) print "Import file :"+file print command_to_execute command_status, command_output = commands.getstatusoutput(command_to_execute) # Command output checking - for better view if some import stage fail string_import_stage1 = "Stage 1 Complete" string_import_stage2 = "Stage 2 Complete" string_import_stage3 = "Stage 3 Complete" string_import_finished = "Import Complete" string_import_failed1 = "For help use" string_import_failed2 = "Import Failed" string_import_failed3 = "Failure During Archive Process" import_status_stage1 = command_output.find(string_import_stage1); import_status_stage2 = command_output.find(string_import_stage2); import_status_stage3 = command_output.find(string_import_stage3); import_status_fisned = command_output.find(string_import_finished); if import_status_stage1 > 0: import_stage1=1 if import_status_stage2 > 0: import_stage2=1 if import_status_stage3 > 0: import_stage3=1 if import_status_fisned > 0: import_status=1 else: import_status=0 import_status_level = 'all 3 stages' else: import_stage3=0 import_status_level = 'Stage 3' else: import_stage2=0 import_status_level = 'Stage 2' else: import_stage1 = 0 import_status_level = 'Stage 1' # if all stages was correct if ( import_stage1 == 1 ) and ( import_stage2 == 1 ) and ( import_stage3 == 1 ) and ( import_status == 1 ): file_new = file+'.done' if options.CLEAN: os.remove(file) else: os.rename(file, file_new) print 'Import completed successfully for file : ',file_new CEF_end = time.strftime("%b %d %Y %H:%M:%S") CEF_message = 'CEF:0|HP ESS|Active List Import Script|'+VERSION+'|Active List inport susccessfull|Active List import susccessfull|3|end='+CEF_end+' act=import fname='+file_new+' filepath='+XML_DIR+' msg='+ACTIVE_LIST_NAME+' cs1='+ACTIVE_LIST_BASE_URI+' cs2='+ACTIVE_LIST_NAME+' dvchost='+CEF_dvchost+' dvc='+CEF_dvc+'' if options.SYSLOG_SERVER: syslog(CEF_message, level=5, facility=3, host=SYSLOG_SERVER, port=SYSLOG_SERVER_PORT) if options.DEBUG: print CEF_message # if was some errors and list wasn't imported elif ( import_stage1 != 1 ) or ( import_stage2 != 1 ) or ( import_stage3 != 1 ) or ( import_status != 1 ): print 'Import failed for file : ',file CEF_end = time.strftime("%b %d %Y %H:%M:%S") CEF_message = 'CEF:0|HP ESS|Active List Import Script|'+VERSION+'|Active List import failed|Active List import failed|7|end='+CEF_end+' act=import fname='+file+' filepath='+XML_DIR+' msg=Import Failed after '+import_status_level+' cs1='+ACTIVE_LIST_BASE_URI+' cs2='+ACTIVE_LIST_NAME+' dvchost='+CEF_dvchost+' dvc='+CEF_dvc+'' if options.SYSLOG_SERVER: syslog(CEF_message, level=5, facility=3, host=SYSLOG_SERVER, port=SYSLOG_SERVER_PORT) if options.DEBUG: print CEF_message print command_output