text: #!/usr/bin/python2
  
  import sys, os, types, collections, json, re, io, urllib2, dateutil, datetime, time, pytz
  
  import pprint, getpass
  
  from optparse import OptionParser
  from optparse import BadOptionError
  from optparse import AmbiguousOptionError
  
  from stix.core import STIXPackage
  from stix.utils.parser import EntityParser
  from stix.common import vocabs
  from stix.common.vocabs import IndicatorType
  
  import libtaxii as t
  import libtaxii.messages_11 as tm11
  import libtaxii.clients as tc
  
  import lxml.etree
  from xml.etree.ElementTree import XML, XMLParser, tostring, TreeBuilder
  
  def extractObservable(args, obs, values):
  	typ = obs["properties"]["xsi:type"]
  
  	if args[0].type and args[0].type != typ:
  		return
  
  	val = None
  	
  	if typ == "AddressObjectType":
  		
  		# Handle if Address_Value is a plain string or one with datatype
  		if isinstance(obs["properties"]["address_value"], basestring):
  			val = obs["properties"]["address_value"]
  		elif 'value' in obs["properties"]["address_value"]:
  			val = obs["properties"]["address_value"]["value"]
  
  	elif typ == "URIObjectType" or typ == "DomainNameObjectType" or typ == "HostnameObjectType":
  		val = obs["properties"]["value"]
  		
  	elif typ == "UserAccountObjectType":
  		val = obs["properties"]["username"]
  		
  	elif typ == "FileObjectType":
  		val = []
  		for myHash in obs["properties"]["hashes"]:
  			val.append( myHash["simple_hash_value"]["value"] )
  		
  	if val:
  		if ( not isinstance(val, basestring) ) and isinstance(val, collections.Iterable):
  			for addr in val:
  				values.append( addr )
  		else:
  			values.append( val )
  	else:
  		if args[0].strict:
  			raise Exception("Encountered unsupported CybOX observable type: " + typ)
  		else:
  			print >> sys.stderr, "Encountered unsupported CybOX observable type: " + typ + ", ignoring..."
  		
  		
  def extractObservables(args,indicators):
  	 
  	values = []
  
  	for indicator in indicators:
  		
  		#Check if we were passed a list of indicators, or observables
  		obs = indicator
  		if "observable" in indicator:
  			obs = indicator["observable"]
  			
  		try:
  			if 'object' in obs:
  				extractObservable( args, obs["object"], values )
  			elif 'observable_composition' in obs:
  				for observable in obs["observable_composition"]["observables"]:
  					if 'object' in observable:
  						extractObservable(args,observable["object"], values )
  
  		except:
  			
  			print >> sys.stderr, "Could not handle observable/indicator:\n"
  			pprint.pprint( indicator, sys.stderr )
  			raise
  
  	return values
  	 
  class PassThroughOptionParser(OptionParser):
  	def _process_args(self, largs, rargs, values):
  		while rargs:
  			try:
  				OptionParser._process_args(self,largs,rargs,values)
  
  			except (BadOptionError,AmbiguousOptionError) as e:
  				largs.append(e.opt_str)
  
  def get_parser():
  
  	parser = PassThroughOptionParser(add_help_option=False)
  	
  	parser.add_option('-h', '--help', help='Show help message', action='store_true')
  	parser.add_option('-r', '--referenceset', help='Name of the reference set to import into. This set must already exist. Either set or map is required', action='store')
  	parser.add_option('-i', '--ip', default="127.0.0.1", help='IP or Host of the QRadar console', action='store')
  	parser.add_option('-t', '--token', help='QRadar authorized service token', action='store')
  	parser.add_option('-f', '--file', help='STIX file to import. Either this parameter or a STIX file is required', action='store')
  	parser.add_option('-y', '--type', help='Only import this type of indicator', action='store')
  	parser.add_option('--strict', action="store_true", help="Raise an error on an unsupported indicator. Defaults to simply printing to stderr.")
  	parser.add_option('--verbose', action="store_true", help="Print various inputs and outputs to STDERR")
  	
  	parser.add_option('-x', '--taxii', help='TAXII Server Endpoint. Either this parameter or a STIX file is required.', action='store')
  	parser.add_option('-p', '--taxiiport', default="80", help='Port for the TAXII Server', action='store')
  	parser.add_option('-c', "--collection", default="default", help="TAXII Data Collection to poll. Defaults to 'default'.")
  	parser.add_option('--taxii_endpoint', help='TAXII Service Endpoint. Required if -x is provided.', action='store')
  	parser.add_option("--taxii_ssl", default=None, help="Set this to use SSL for the TAXII request")
  	parser.add_option("--taxii_username", default=None, help="Set this to the username for TAXII BASIC authentication, if any")
  	parser.add_option("--taxii_password", default=None, help="Set this to use password for TAXII BASIC authentication, if any")
  	
  	parser.add_option("--taxii_start_time", dest="begin_ts", default=None, help="The start timestamp (YYYY-MM-dd HH:MM:SS) in UTC " +
  		   "for the taxii poll request. Defaults to None.")
  	
  	parser.add_option("--taxii_end_time", dest="end_ts", default=None, help="The end timestamp (YYYY-MM-dd HH:MM:SS) in UTC " +
  		   "for the taxii poll request. Defaults to None.")
  	
  	return parser
  
  
  def print_help(parser):
  		print >> sys.stderr, "\nA utility that imports STIX documents from either a TAXII server collection or a file.\n"
  		print >> sys.stderr, "All indicators and observables in the STIX document(s) will be imported into the specified reference set.\n"
  		print >> sys.stderr, parser.format_help().strip()
  	 
  	 
  # Processes a STIX package dictionary and adds all indicators and observables to a QRadar reference set
  def process_package_dict(args,stix_dict):
  
  	values = []
  	if "observables" in stix_dict:
  		values.extend( extractObservables( args, stix_dict["observables"]["observables"] ) )
  		
  	if "indicators" in stix_dict:
  		values.extend( extractObservables( args, stix_dict["indicators"] ) )
  
  	if len(values) > 0:
  		if args[0].ip:
  			serverIP = args[0].ip
  		else:
  			serverIP = '127.0.0.1'
  
  		url = 'https://' + serverIP + '/api/referencedata/sets/bulkLoad/' + args[0].referenceset
  
  		headers = { 'Accept': 'application/json', 'Content-type':'application/json', 'version':'0.1', 'SEC':args[0].token }
  
  		data = json.dumps(values)
  		data = data.encode('utf-8')
  	
  		if args[0].verbose:
  			print >> sys.stderr, "POSTING DATA:\n" + data + "\n"
  	
  		req = urllib2.Request(url, data, headers)
  		try:
  			response = urllib2.urlopen(req)
  			body = response.read().decode('utf-8')
  			
  		except urllib2.HTTPError, err:
  			body = err.read()
  			print >> sys.stderr, "Error posting data " + data + "\n"
  			print >> sys.stderr, body
  			raise
  
  		response_json = json.loads(body)
  	
  		if args[0].verbose:
  			print >> sys.stderr, "RECIEVED RESPONSE:\n" + ( json.dumps(response_json, indent=2, separators=(',', ':')) ) + "\n"
  	
  	return len(values)
  		
  
  def main():
  	
  	# This is a work-around for the fact that the 1.0 indicator type was removed from the STIX python 
  	# library, even though it is the essentially the same as the 1.1 type. We want to still support 1.0
  	# indicators since they are out there, and there is no difference for the purposes of this script.
  	vocabs._VOCAB_MAP["stixVocabs:IndicatorTypeVocab-1.0"] = IndicatorType
  	
  	# Create XML parser that can strip namespaces
  	xmlParser = EntityParser()
  	
  	stix_package = None
  	
  	argParser = get_parser()
  	args = argParser.parse_args()
  
  	if args[0].help:
  		print_help(argParser)
  	
  	# Import from a TAXII server
  	elif args[0].referenceset and args[0].taxii:
  		begin_ts = None
  		end_ts = None
  		
  		try:
  			if args[0].begin_ts:
  				structTime = time.strptime(args[0].begin_ts,'%Y-%m-%d %H:%M:%S')
  				begin_ts = datetime.datetime(*structTime[:6])
  				begin_ts = begin_ts.replace(tzinfo=pytz.UTC)
  			else:
  				begin_ts = None	
  				
  
  
  			if args[0].end_ts:
  				structTime = time.strptime(args[0].end_ts,'%Y-%m-%d %H:%M:%S')
  				end_ts = datetime.datetime(*structTime[:6])
  				end_ts = end_ts.replace(tzinfo=pytz.UTC)
  			else:
  				end_ts = None
  					
  		except ValueError:
  			print >> sys.stderr, "Could not parse either start or end time"
  			raise
  
  		poll_req = tm11.PollRequest(message_id=tm11.generate_message_id(),
  		collection_name=args[0].collection,
  		exclusive_begin_timestamp_label=begin_ts,
  		inclusive_end_timestamp_label=end_ts,
  		poll_parameters=tm11.PollRequest.PollParameters())
  
  		poll_req_xml = poll_req.to_xml()
  		
  		client = tc.HttpClient()
  		
  		if args[0].taxii_ssl:
  			client.setUseHttps(True)
  		
  		if args[0].taxii_username:
  			client.setAuthType(1)
  
  			if not args[0].taxii_password:
  				args[0].taxii_password = getpass.getpass("Enter your taxii password: ")
  
  			client.setAuthCredentials({'username': args[0].taxii_username, 'password': args[0].taxii_password})
  
  		resp = client.callTaxiiService2(args[0].taxii, args[0].taxii_endpoint + "/poll/", t.VID_TAXII_XML_11, poll_req_xml, args[0].taxiiport)
  		
  		response_message = t.get_message_from_http_response(resp, '0')
  		
  		response_dict = response_message.to_dict();
  
  		indicators = 0
  		
  		if 'content_blocks' in response_dict:
  			for content in response_dict["content_blocks"]:
  				bindingId = content["content_binding"]["binding_id"]
  				
  				if bindingId and bindingId.startswith("urn:stix.mitre.org:xml"):
  					if args[0].verbose:
  						print >> sys.stderr, "RECIEVED STIX DATA:\n"
  						print >> sys.stderr, content["content"]
  			
  					try:
  						# This string replace is a workaround for some invalid documents in my test server, if you don't need it, remove it
  						xmlString = content["content"].replace('low','Low').replace('medium','Medium').replace('high','High')
  						stix_package = xmlParser.parse_xml(io.BytesIO(xmlString), False)
  						indicators += process_package_dict( args, stix_package.to_dict() )
  					
  					except ValueError:
  						print >> sys.stderr, "Could not parse STIX document: "
  						print >> sys.stderr, content["content"]
  						raise
  			
  			print "Imported", indicators, "indicators into reference set", args[0].referenceset
  		else:
  			print >> sys.stderr, "Invalid reponse from TAXII server"
  			pprint.pprint( response_dict, sys.stderr )
  			exit(255)
  
  	# Import from a XML file on disk
  	elif args[0].referenceset and args[0].file:
  		
  		stix_package = xmlParser.parse_xml(args[0].file, False)
  
  		indicators = process_package_dict( args, stix_package.to_dict() )
  		
  		print "Imported", indicators, "indicators into reference set", args[0].referenceset
  	
  	else:
  		print >> sys.stderr, "Invalid arguments. Type 'python stix_import.py --help' for usage.\n"
  						
  
  if __name__ == "__main__":
  	main()
  