def test_rules_namespace( oid, key ): lc = limacharlie.Manager( oid, key ) testRuleName = 'test-lc-python-sdk-rule' testNamespace = 'managed' if testRuleName in lc.rules(): assert( {} == lc.del_rule( testRuleName ) ) if testRuleName in lc.rules( namespace = testNamespace ): assert( {} == lc.del_rule( testRuleName, namespace = testNamespace ) ) assert( {} == lc.add_rule( testRuleName, { 'op' : 'is tagged', 'tag' : 'test-tag-python-sdk', }, [ { 'action' : 'report', 'name' : 'test-sdk-detection', } ], isReplace = True, namespace = testNamespace ) ) try: rules = lc.rules( namespace = testNamespace ) assert( testRuleName in rules ) rules = lc.rules( namespace = None ) assert( testRuleName not in rules ) finally: assert( {} == lc.del_rule( testRuleName, namespace = testNamespace ) ) assert( testRuleName not in lc.rules( namespace = testNamespace ) )
def test_spout(oid, key): lc = limacharlie.Manager(oid, key, inv_id='test-lc-python-sdk-inv', is_interactive=True) try: # First we need to make sure we have a sensor to test against. sensors = lc.sensors() assert (0 != len(sensors)) # We will pick the first sensor in the list that is online. targetSensor = None for sensor in sensors: if sensor.isOnline(): targetSensor = sensor print("Found sensor %s online, using it for test." % (sensor, )) break assert (targetSensor is not None) resp = targetSensor.simpleRequest('os_version') assert (resp is not None) assert (resp.get('event', None) is not None) finally: try: lc.shutdown() except: # In Python3 the underlying http client has issues # with this call being reentrant. It should not be # an issue for us here. pass
def test_batch_object_information(oid, key): lc = limacharlie.Manager(oid, key) objects = lc.getBatchObjectInformation( {'domain': ['www.google.com', 'www.apple.com']}) assert (isinstance(objects, dict))
def main(): parser = argparse.ArgumentParser( prog = 'python -m lcservice.simulator' ) parser.add_argument( 'url', type = str, help = 'the URL of the service to call.' ) parser.add_argument( 'action', type = str, help = 'action to run, one of supported callbacks (see doc).' ) parser.add_argument( '-s', '--secret', type = str, required = False, dest = 'secret', default = '', help = 'optionally specify the shared secret, you can omit if the service was started with secret disabled.' ) parser.add_argument( '-d', '--data', type = eval, default = {}, dest = 'data', help = 'data to include in the request, this string gets evaluated as python code' ) args = parser.parse_args() if args.url.startswith( 'https://' ) and args.url.startswith( 'http://' ): print( "url must start with http or https." ) sys.exit( 1 ) lc = limacharlie.Manager() lc.whoAmI() oid = lc._oid jwt = lc._jwt secret = args.secret print( json.dumps( postData( args.url, secret, oid, jwt, args.action, data = args.data ), indent = 2 ) )
def test_api_keys(oid, key): lc = limacharlie.Manager(oid, key) keyName = 'automated-test-key-name' perms = ['org.get', 'sensor.task', 'sensor.get'] perms.sort() keys = lc.getApiKeys() assert (0 != len(keys)) response = lc.addApiKey(keyName, perms) assert (response) assert (response['success']) assert (response['api_key']) assert (response['key_hash']) keys = lc.getApiKeys() assert (response['key_hash'] in keys) tmpKey = keys[response['key_hash']] assert (keyName == tmpKey['name']) tmpKey['priv'].sort() assert (tmpKey['priv'] == perms) lc.removeApiKey(response['key_hash']) keys = lc.getApiKeys() assert (response['key_hash'] not in keys)
def test_credentials(oid, key): lc = limacharlie.Manager(oid, key) assert (lc.testAuth([ 'org.get', 'sensor.get', 'sensor.list', 'replicant.get', 'replicant.task', ]))
def test_credentials(oid, key): lc = limacharlie.Manager(oid, key) assert (lc.testAuth([ 'org.get', 'sensor.list', 'sensor.get', 'output.list', 'output.set', 'output.del', ]))
def test_detections(oid, key): lc = limacharlie.Manager(oid, key) detections = lc.getHistoricDetections(int(time.time()) - (60 * 60 * 24), int(time.time()), limit=10) # The return is a generator so we # will unravel it. detections = list(detections) assert (isinstance(detections, list))
def test_credentials(oid, key): lc = limacharlie.Manager(oid, key) assert (lc.testAuth([ 'org.get', 'sensor.get', 'sensor.list', 'insight.evt.get', 'insight.det.get', 'insight.list', 'insight.stat', ]))
def test_ingestion_keys( oid, key ): lc = limacharlie.Manager( oid, key ) testIngestionKeyName = 'test-python-sdk-key' assert( {} == lc.setIngestionKey( testIngestionKeyName ) ) try: assert( testIngestionKeyName in lc.getIngestionKeys() ) finally: assert( {} == lc.delIngestionKey( testIngestionKeyName ) ) assert( testIngestionKeyName not in lc.getIngestionKeys() )
def test_isolation(oid, key): lc = limacharlie.Manager(oid, key) for sensor in lc.sensors(): if sensor.isChrome(): continue if not (sensor.isMac() or sensor.isWindows()): continue if not sensor.isOnline(): continue assert (not sensor.isIsolatedFromNetwork()) sensor.isolateNetwork() assert (sensor.isIsolatedFromNetwork()) sensor.rejoinNetwork() assert (not sensor.isIsolatedFromNetwork()) break
def test_fps( oid, key ): lc = limacharlie.Manager( oid, key ) testRuleName = 'test-lc-python-sdk-fp' assert( {} == lc.add_fp( testRuleName, { 'op' : 'is', 'path' : 'cat', 'value' : 'test-sdk-detection' }, isReplace = True ) ) try: rules = lc.fps() assert( testRuleName in rules ) finally: assert( {} == lc.del_fp( testRuleName ) ) assert( testRuleName not in lc.fps() )
def test_rules(oid, key): lc = limacharlie.Manager(oid, key) testRuleName = 'test-lc-python-sdk-rule' assert ({} == lc.add_rule(testRuleName, { 'op': 'is tagged', 'tag': 'test-tag-python-sdk', 'event': 'NEW_PROCESS', }, [{ 'action': 'report', 'name': 'test-sdk-detection', }], isReplace=True)) try: rules = lc.rules() assert (testRuleName in rules) finally: assert ({} == lc.del_rule(testRuleName)) assert (testRuleName not in lc.rules())
def test_outputs( oid, key ): lc = limacharlie.Manager( oid, key ) testOutputName = 'test-lc-python-sdk-out' testDest = '1.1.1.1:22' assert( lc.add_output( testOutputName, 'syslog', 'event', dest_host = testDest, is_tls = True, is_strict_tls = True, is_no_header = True, ) ) try: outputs = lc.outputs() assert( outputs.get( testOutputName, {} ).get( 'dest_host', None ) == testDest ) finally: assert( {} == lc.del_output( testOutputName ) ) assert( testOutputName not in lc.outputs() )
def test_credentials( oid, key ): lc = limacharlie.Manager( oid, key ) assert( lc.testAuth( [ 'org.get', 'sensor.get', 'sensor.list', 'dr.list', 'dr.set', 'dr.del', 'dr.list.managed', 'dr.set.managed', 'dr.del.managed', 'ikey.list', 'ikey.set', 'ikey.del', 'output.list', 'output.set', 'output.del', 'org.conf.get', 'ingestkey.ctrl', 'audit.get', 'fp.ctrl', ] ) )
def test_hosts( oid, key ): lc = limacharlie.Manager( oid, key ) hosts = lc.hosts( 'a' ) assert( isinstance( hosts, list ) )
def test_sensors( oid, key ): lc = limacharlie.Manager( oid, key ) sensors = lc.sensors() assert( isinstance( sensors, list ) )
def test_whoami( oid, key ): lc = limacharlie.Manager( oid, key ) who = lc.whoAmI() assert( 0 != len( who.get( 'perms', [] ) ) ) assert( 0 != len( who.get( 'orgs', [] ) ) )
def test_object_informaton(oid, key): lc = limacharlie.Manager(oid, key) objects = lc.getObjectInformation('domain', 'www.google.com', 'summary') assert (isinstance(objects, dict))
def test_org_config( oid, key ): lc = limacharlie.Manager( oid, key ) val = lc.getOrgConfig( 'vt' ) assert( val )
def test_org_urls( oid, key ): lc = limacharlie.Manager( oid, key ) urls = lc.getOrgURLs() assert( isinstance( urls, dict ) )
def _processEvent(self, data): version = data.get('version', None) jwt = data.get('jwt', None) oid = data.get('oid', None) msgId = data.get('mid', None) deadline = data.get('deadline', None) eType = data.get('etype', None) data = data.get('data', {}) if version is not None and version > PROTOCOL_VERSION: return self.response(isSuccess=False, isDoRetry=False, data={ 'error': 'unsupported version (> %s)' % (PROTOCOL_VERSION, ) }) if self._isTraceComms: dataNoJwt = data.copy() dataNoJwt.pop('jwt', None) self.log("REQ (%s): %s => %s" % (msgId, eType, json.dumps(dataNoJwt))) request = Request(eType, msgId, data) # If the eType is 'request' and the service specifies # some request parameter definitions we'll do some # validation on the parameters. if 'request' == eType and 0 != len(self._supportedRequestParameters): for k, v in request.data.items(): if v is None: continue definition = self._supportedRequestParameters.get(k, None) if definition is None: continue validationResult = self._validateRequestParameter( definition, v) if validationResult is None: continue return self.response(isSuccess=False, error="invalid parameter %s: %s" % (k, validationResult)) for k, v in self._supportedRequestParameters.items(): if not v.get('is_required', False): continue if request.data.get(k, None) is None: return self.response(isSuccess=False, error="missing parameter %s" % (k, )) handler = self._handlers.get(eType, None) if handler is None: return self.responseNotImplemented() lcApi = None if oid is not None and jwt is not None: invId = str(uuid.uuid4()) # We support a special function to wrap the LC API # if needed to provide some added magic. if hasattr(self, 'wrapSdk'): lcApi = getattr(self, 'wrapSdk')(oid=oid, jwt=jwt, inv_id=invId) else: lcApi = limacharlie.Manager(oid=oid, jwt=jwt, inv_id=invId) try: with self._lock: self._nCallsInProgress += 1 resp = handler(lcApi, oid, request) if resp is True: # Shotcut for simple success. resp = self.response(isSuccess=True) elif resp is False: # Shortcut for simple failure no retry. resp = self.response(isSuccess=False, isDoRetry=False) elif resp is None: # Shortcut for simple failure with retry. resp = self.response(isSuccess=False, isDoRetry=True) elif not isinstance(resp, dict): self.logCritical( 'no valid response specified in %s, assuming success' % (eType, )) resp = self.response(isSuccess=True, isDoRetry=False, data={}) if self._isTraceComms: self.log("REP (%s): %s" % (msgId, json.dumps(resp))) return resp except: exc = traceback.format_exc() self.logCritical(exc) return self.response(isSuccess=False, isDoRetry=True, data={'exception': exc}) finally: with self._lock: self._nCallsInProgress -= 1 now = time.time() if deadline is not None and now > deadline: self.logCritical('event %s over deadline by %ss' % (eType, now - deadline))
def test_host_count_platform(oid, key): lc = limacharlie.Manager(oid, key) counts = lc.getInsightHostCountPerPlatform() assert (isinstance(counts, dict))
def test_replicants_available(oid, key): lc = limacharlie.Manager(oid, key) replicants = lc.getAvailableReplicants() assert (isinstance(replicants, list))
import json import uuid import getpass if __name__ == "__main__": def debugPrint(msg): print msg # This example uses interactive credentials, but see the README for alternative # ways of getting credentials. print("We are starting in interactive mode.") man = limacharlie.Manager( oid=raw_input('Enter OID: '), secret_api_key=getpass.getpass(prompt='Enter secret API key: '), print_debug_fn=None, inv_id=str(uuid.uuid4()), is_interactive=True) # Starting the Manager with is_interactive = True means that Sensors accessed # through this Manager will support the .request() API which behaves similarly # to .task(), but instead of being unidirectional, it returns a FutureResponses # object which can be used to get the response to the task. print("Getting a list of sensors.") sensors = man.sensors() print("Got %s sensors." % len(sensors)) # This is a very naive way to proceed. We could issue all tasks, accumulate the # futures and then wait on all of them, that would be MUCH faster.
import limacharlie from limacharlie.utils import parallelExec import argparse from datetime import datetime if __name__ == "__main__": parser = argparse.ArgumentParser( description = 'Delete duplicate sensors.' ) parser.add_argument( '--dry-run', action = 'store_true', default = False, dest = 'isDryRun' ) args = parser.parse_args() if args.isDryRun: print( "---=== DRY RUN ===---" ) # Instantiate the SDK lc = limacharlie.Manager() # We will accumulate sensors by hostname. sensorsByHostname = {} allSensors = [] # Get all the sensor info. Do this in parallel since it # could take a while on a large organization. def _getSensorInfo( s ): sensorInfo = s.getInfo() sensorsByHostname.setdefault( sensorInfo[ 'hostname' ], [] ).append( sensorInfo ) allSensors.append( sensorInfo ) print( "Getting all sensor info..." ) parallelExec( _getSensorInfo, lc.sensors(), maxConcurrent = 5 )
def test_artifact_lifecycle(oid, key): lc = limacharlie.Manager(oid, key) assert (lc.testAuth([ 'org.get', 'insight.evt.get', 'insight.list', 'ingestkey.ctrl', ])) # Create a new ingestion key. keyName = "test_ingestion_%s" % (uuid.uuid4(), ) keyVal = lc.setIngestionKey(keyName) assert (keyVal.get('key', False)) keyVal = keyVal['key'] source = "test-%s" % (uuid.uuid4(), ) try: artifactService = limacharlie.Artifacts(lc, keyVal) # Create 3 test artifacts locally. assert (0 == os.system("echo 'test file 1' > test1.txt")) assert (0 == os.system("echo 'test file 2' > test2.txt")) assert (0 == os.system("echo 'test file 3' > test3.txt")) # Upload 3 test artifacts. uploadTime = int(time.time()) for filePath in ('test1.txt', 'test2.txt', 'test3.txt'): resp = artifactService.upload(filePath, source=source, hint='txt', originalPath=filePath, nDaysRetention=2) assert (resp) # Give it a few seconds to make sure the new artifacts # have made it through ingestion. time.sleep(10) # Iterate over them to make sure we see them. nArtifacts = 0 for artifactInfo, artifactTmpFile in artifactService.listArtifacts( type='txt', source=source, after=uploadTime - 60, before=int(time.time()) + 60, withData=True): try: nArtifacts += 1 assert (artifactInfo) artifactData = open(artifactTmpFile, 'rb').read().decode() assert (artifactData.startswith('test file ')) finally: os.remove(artifactTmpFile) assert (3 == nArtifacts) finally: lc.delIngestionKey(keyName)
'--category', type=str, dest='cat', default=None, help='spout should only receive detections from this category.') parser.add_argument( '-s', '--sid', type=lambda x: str(uuid.UUID(x)), dest='sid', default=None, help='spout should only receive detections or events from this sensor.' ) args = parser.parse_args() secretApiKey = getpass.getpass(prompt='Enter secret API key: ') _printToStderr("Registering...") man = limacharlie.Manager(oid=args.oid, secret_api_key=secretApiKey) sp = limacharlie.Spout(man, args.data_type, inv_id=args.inv_id, tag=args.tag, cat=args.cat, sid=args.sid) _printToStderr("Starting to listen...") while True: data = sp.queue.get() print(json.dumps(data, indent=2)) _printToStderr("Exiting.")
import signal import sys import getpass if __name__ == "__main__": def signal_handler(): global sp print('You pressed Ctrl+C!') sp.shutdown() sys.exit(0) gevent.signal(signal.SIGINT, signal_handler) def debugPrint(msg): print msg # This example uses interactive credentials, but see the README for alternative # ways of getting credentials. man = limacharlie.Manager( oid=raw_input('Enter OID: '), secret_api_key=getpass.getpass(prompt='Enter secret API key: '), print_debug_fn=debugPrint) sp = limacharlie.Spout(man, 'event') while True: data = sp.queue.get() print(json.dumps(data, indent=2) + "\n\n")
def test_insight_status(oid, key): lc = limacharlie.Manager(oid, key) assert (lc.isInsightEnabled())