Repository: google/turbinia
Pull request #1073 (2022-06-17 01:20:36)

Evidence names
Adding descriptive evidence names

Fixes: #468 

dfjxs: @aarontp This should cover the evidence names, but I was also thinking about how we could include the evidence name in the final report.

We could record the input evidence name along with the task in Datastore and then query it in `client.format_task_status` when compiling the final report. What do you think?

Patch:
diff --git a/k8s/gcp-pubsub/turbinia-server.yaml b/k8s/gcp-pubsub/turbinia-server.yaml
index 297bfbb..de2a354 100644
--- a/k8s/gcp-pubsub/turbinia-server.yaml
+++ b/k8s/gcp-pubsub/turbinia-server.yaml
@@ -17,6 +17,7 @@ spec:
       labels:
         app: turbinia-server
     spec:
+      serviceAccountName: <SA_NAME>
       initContainers:
         - name: init-filestore
           image: busybox:1.28
diff --git a/k8s/gcp-pubsub/turbinia-worker.yaml b/k8s/gcp-pubsub/turbinia-worker.yaml
index 032b16f..5bc2f10 100644
--- a/k8s/gcp-pubsub/turbinia-worker.yaml
+++ b/k8s/gcp-pubsub/turbinia-worker.yaml
@@ -17,6 +17,7 @@ spec:
       labels:
         app: turbinia-worker
     spec:
+      serviceAccountName: <SA_NAME>
       # The grace period needs to be set to the largest task timeout as
       # set in the turbinia configuration file.
       terminationGracePeriodSeconds: 86400
diff --git a/k8s/tools/.clusterconfig b/k8s/tools/.clusterconfig
index d822be9..c0fbdb4 100644
--- a/k8s/tools/.clusterconfig
+++ b/k8s/tools/.clusterconfig
@@ -18,6 +18,7 @@ DEPLOYMENT_FOLDER="deployment/$INSTANCE_ID"
 # not currently support multi-zone operation.
 ZONE='us-central1-f'
 REGION='us-central1'
+DATASTORE_REGION='us-central'
 
 # VPC network to configure the cluster in.
 VPC_NETWORK='default'
diff --git a/k8s/tools/cleanup-pubsub-gke.sh b/k8s/tools/cleanup-pubsub-gke.sh
index 30985ea..5184882 100755
--- a/k8s/tools/cleanup-pubsub-gke.sh
+++ b/k8s/tools/cleanup-pubsub-gke.sh
@@ -100,9 +100,14 @@ if [[ "$*" != *--no-filestore* ]] ; then
   echo "Deleting Filestore instance $FILESTORE_NAME"
   gcloud -q --project $DEVSHELL_PROJECT_ID filestore instances delete $FILESTORE_NAME --zone $ZONE
 fi
+# Delete the dfDewey Filestore instance
 if [[ "$*" != *--no-dfdewey* ]] ; then
-  echo "Deleting Filestore instance $FILESTORE_DFDEWEY_NAME"
-  gcloud -q --project $DEVSHELL_PROJECT_ID filestore instances delete $FILESTORE_DFDEWEY_NAME --zone $ZONE
+  if [[ -z "$(gcloud -q --project $DEVSHELL_PROJECT_ID filestore instances list --format='value(name)' --filter=name:$FILESTORE_DFDEWEY_NAME)" ]] ; then
+    echo "Filestore instance $FILESTORE_DFDEWEY_NAME does not exist"
+  else
+    echo "Deleting Filestore instance $FILESTORE_DFDEWEY_NAME"
+    gcloud -q --project $DEVSHELL_PROJECT_ID filestore instances delete $FILESTORE_DFDEWEY_NAME --zone $ZONE
+  fi
 fi
 
 # Remove cloud functions
diff --git a/k8s/tools/deploy-pubsub-gke.sh b/k8s/tools/deploy-pubsub-gke.sh
index ee22936..b3adf31 100755
--- a/k8s/tools/deploy-pubsub-gke.sh
+++ b/k8s/tools/deploy-pubsub-gke.sh
@@ -20,10 +20,11 @@ cd $DIR/..
 if [[ "$*" == *--help ]] ; then
   echo "Turbinia deployment script for Kubernetes environment"
   echo "Options:"
-  echo "--build-release-test           Deploy Turbinia release test docker image"
   echo "--build-dev                    Deploy Turbinia development docker image"
-  echo "--no-gcloud-auth               Create service key instead of using gcloud authentication"
+  echo "--build-experimental           Deploy Turbinia experimental docker image"
+  echo "--no-gcloud-auth               Use Turbinia service account instead of gcloud authentication"
   echo "--no-cloudfunctions            Do not deploy Turbinia Cloud Functions"
+  echo "--no-appengine                 Do not enable App Engine"
   echo "--no-datastore                 Do not configure Turbinia Datastore"
   echo "--no-filestore                 Do not deploy Turbinia Filestore"
   echo "--no-gcs                       Do not create a GCS bucket"
@@ -72,30 +73,31 @@ fi
 # Enable IAM services
 gcloud -q --project $DEVSHELL_PROJECT_ID services enable iam.googleapis.com
 
-# Use local `gcloud auth` credentials rather than creating new Service Account.
-if [[ "$*" == *--no-gcloud-auth* ]] ; then
-  SA_NAME="turbinia"
-  SA_MEMBER="serviceAccount:$SA_NAME@$DEVSHELL_PROJECT_ID.iam.gserviceaccount.com"
-
-  if ! gcloud --project $DEVSHELL_PROJECT_ID iam service-accounts list |grep $SA_NAME; then
-    # Create service account
-    gcloud --project $DEVSHELL_PROJECT_ID iam service-accounts create "${SA_NAME}" --display-name "${SA_NAME}"
-  fi
+# Create Turbinia service account.
+SA_NAME="turbinia"
+SA_MEMBER="serviceAccount:$SA_NAME@$DEVSHELL_PROJECT_ID.iam.gserviceaccount.com"
 
-  # Grant IAM roles to the service account
-  echo "Grant permissions on service account"
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/cloudfunctions.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/cloudsql.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/compute.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/container.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/datastore.indexAdmin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/editor'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/logging.logWriter'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/pubsub.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/redis.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/servicemanagement.admin'
-  gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/storage.admin'
+if [[ -z "$(gcloud -q --project $DEVSHELL_PROJECT_ID iam service-accounts list --format='value(name)' --filter=name:/$SA_NAME@)" ]] ; then
+  # Create service account
+  gcloud --project $DEVSHELL_PROJECT_ID iam service-accounts create "${SA_NAME}" --display-name "${SA_NAME}"
+fi
 
+# Grant IAM roles to the service account
+echo "Grant permissions on service account"
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/cloudfunctions.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/cloudsql.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/compute.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/container.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/datastore.indexAdmin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/editor'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/logging.logWriter'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/pubsub.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/redis.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/servicemanagement.admin'
+gcloud projects add-iam-policy-binding $DEVSHELL_PROJECT_ID --member=$SA_MEMBER --role='roles/storage.admin'
+
+# Use local `gcloud auth` credentials.
+if [[ "$*" == *--no-gcloud-auth* ]] ; then
   # Create and fetch the service account key
   echo "Fetch and store service account key"
   gcloud --project $DEVSHELL_PROJECT_ID iam service-accounts keys create ~/$INSTANCE_ID.json --iam-account "$SA_NAME@$DEVSHELL_PROJECT_ID.iam.gserviceaccount.com"
@@ -107,11 +109,14 @@ elif [[ $( gcloud -q --project $DEVSHELL_PROJECT_ID auth list --filter="status:A
   exit 1
 fi
 
+echo "Enabling Compute API"
+gcloud -q --project $DEVSHELL_PROJECT_ID services enable compute.googleapis.com
+
 # Check if the configured VPC network exists.
 networks=$(gcloud -q --project $DEVSHELL_PROJECT_ID compute networks list --filter="name=$VPC_NETWORK" |wc -l)
 if [[ "${networks}" -lt "2" ]]; then
-        echo "ERROR: VPC network $VPC_NETWORK not found, please create this first."
-        exit 1
+  echo "ERROR: VPC network $VPC_NETWORK not found, please create this first."
+  exit 1
 fi
 
 # Update Docker image if flag was provided else use default
@@ -159,26 +164,38 @@ fi
 if [[ "$*" != *--no-datastore* ]] ; then
   echo "Enabling Datastore API and deploying datastore index"
   gcloud -q --project $DEVSHELL_PROJECT_ID services enable datastore.googleapis.com
+  # Enable App Engine
+  if [[ "$*" != *--no-appengine* ]] ; then
+    echo "Enabling App Engine"
+    gcloud -q --project $DEVSHELL_PROJECT_ID app create --region=$DATASTORE_REGION
+  fi
+  gcloud -q --project $DEVSHELL_PROJECT_ID datastore databases create --region=$DATASTORE_REGION
   gcloud -q --project $DEVSHELL_PROJECT_ID datastore indexes create ../tools/gcf_init/index.yaml
 fi
 
 # Create GKE cluster and authenticate to it
 if [[ "$*" != *--no-cluster* ]] ; then
-  echo "Enabling GCP Compute and Container APIs"
-  gcloud -q --project $DEVSHELL_PROJECT_ID services enable compute.googleapis.com
+  echo "Enabling Container API"
   gcloud -q --project $DEVSHELL_PROJECT_ID services enable container.googleapis.com
   echo "Creating cluser $CLUSTER_NAME with $CLUSTER_NODE_SIZE node(s) configured with machine type $CLUSTER_MACHINE_TYPE and disk size $CLUSTER_MACHINE_SIZE"
-  gcloud -q --project $DEVSHELL_PROJECT_ID container clusters create $CLUSTER_NAME --machine-type $CLUSTER_MACHINE_TYPE --disk-size $CLUSTER_MACHINE_SIZE --num-nodes $CLUSTER_NODE_SIZE --master-ipv4-cidr $VPC_CONTROL_PANE --network $VPC_NETWORK --zone $ZONE --shielded-secure-boot --shielded-integrity-monitoring --no-enable-master-authorized-networks --enable-private-nodes --enable-ip-alias --scopes "https://www.googleapis.com/auth/cloud-platform" --labels "turbinia-infra=true"
+  gcloud -q --project $DEVSHELL_PROJECT_ID container clusters create $CLUSTER_NAME --machine-type $CLUSTER_MACHINE_TYPE --disk-size $CLUSTER_MACHINE_SIZE --num-nodes $CLUSTER_NODE_SIZE --master-ipv4-cidr $VPC_CONTROL_PANE --network $VPC_NETWORK --zone $ZONE --shielded-secure-boot --shielded-integrity-monitoring --no-enable-master-authorized-networks --enable-private-nodes --enable-ip-alias --scopes "https://www.googleapis.com/auth/cloud-platform" --labels "turbinia-infra=true" --workload-pool=$DEVSHELL_PROJECT_ID.svc.id.goog
 else
   echo "--no-cluster specified. Authenticating to pre-existing cluster $CLUSTER_NAME"
 fi
 
 # Authenticate to cluster
 gcloud -q --project $DEVSHELL_PROJECT_ID container clusters get-credentials $CLUSTER_NAME --zone $ZONE
+# Create Kubernetes service account
+kubectl get serviceaccounts $SA_NAME || kubectl create serviceaccount $SA_NAME --namespace default
+gcloud iam service-accounts add-iam-policy-binding $SA_NAME@$DEVSHELL_PROJECT_ID.iam.gserviceaccount.com --role roles/iam.workloadIdentityUser --member "serviceAccount:$DEVSHELL_PROJECT_ID.svc.id.goog[default/$SA_NAME]"
+kubectl annotate serviceaccount $SA_NAME --overwrite --namespace default iam.gke.io/gcp-service-account=$SA_NAME@$DEVSHELL_PROJECT_ID.iam.gserviceaccount.com
 
 # Go to deployment folder to make changes files
 cd $DEPLOYMENT_FOLDER
 
+# Add service account to deployments
+sed -i -e "s/<SA_NAME>/$SA_NAME/g" turbinia-server.yaml turbinia-worker.yaml
+
 # Disable some jobs
 echo "Updating $TURBINIA_CONFIG with disabled jobs"
 sed -i -e "s/^DISABLED_JOBS = .*$/DISABLED_JOBS = $DISABLED_JOBS/g" $TURBINIA_CONFIG
diff --git a/turbinia/config/logger.py b/turbinia/config/logger.py
index f15f397..d100d94 100644
--- a/turbinia/config/logger.py
+++ b/turbinia/config/logger.py
@@ -82,7 +82,7 @@ def setup(need_file_handler=True, need_stream_handler=True, log_file_path=None):
     file_handler.setLevel(logging.DEBUG)
     logger.addHandler(file_handler)
 
-  console_handler = logging.StreamHandler()
+  console_handler = logging.StreamHandler(sys.stdout)
   formatter = logging.Formatter(
       '%(asctime)s [%(levelname)s] %(message)s', "%Y-%m-%d %H:%M:%S")
   console_handler.setFormatter(formatter)
diff --git a/turbinia/config/recipes/triage-macos.yml b/turbinia/config/recipes/triage-macos.yml
index 0310777..0d569d3 100644
--- a/turbinia/config/recipes/triage-macos.yml
+++ b/turbinia/config/recipes/triage-macos.yml
@@ -16,35 +16,35 @@ plaso_base:
       'ChromeStorage',
       'MacOSAppleSystemLogFiles',
       'MacOSAtJobs',
-      'MacOSAuditLogFiles',
+      'MacOSAuditLogFile',
       'MacOSBashHistory',
       'MacOSBluetoothPlistFile',
       'MacOSCronTabs',
-      'MacOSFSEvents',
+      'MacOSFSEventsFile',
       'MacOSGlobalPreferencesPlistFile',
       'MacOSiOSBackupInfo',
       'MacOSiOSBackupManifest',
       'MacOSiOSBackupStatus',
       'MacOSLastlogFile',
-      'MacOSLaunchAgentsPlistFiles',
-      'MacOSLaunchDaemonsPlistFiles',
+      'MacOSLaunchAgentsPlistFile',
+      'MacOSLaunchDaemonsPlistFile',
       'MacOSLoginWindowPlistFile',
       'MacOSMailAccounts',
       'MacOSMailOpenedAttachments',
       'MacOSMailPreferences',
-      'MacOSRecentItems',
+      'MacOSRecentItemsPlistFile',
       'MacOSRemoteDesktopAdministratorSystem',
       'MacOSRemoteDesktopClientSystem',
-      'MacOSSidebarLists',
-      'MacOSStartupItemsPlistFiles',
+      'MacOSSidebarListsPlistFile',
+      'MacOSStartupItemsPlistFile',
       'MacOSSystemConfigurationPreferencesPlistFile',
-      'MacOSSystemLogFiles',
-      'MacOSSystemPreferencesPlistFiles',
+      'MacOSSystemLogFile',
+      'MacOSSystemPreferencesPlistFile',
       'MacOSSystemVersionPlistFile',
       'MacOSTimeMachinePlistFile',
-      'MacOSUserLoginItems',
-      'MacOSUserPasswordHashesPlistFiles',
-      'MacOSUserSocialAccounts',
+      'MacOSUserLoginItemsPlistFile',
+      'MacOSUserPasswordHashesPlistFile',
+      'MacOSUserAccountsSQLiteDatabaseFile',
       'MacOSUtmpFile',
       'MacOSUtmpxFile',
   ]
\ No newline at end of file
diff --git a/turbinia/config/recipes/triage-windows.yaml b/turbinia/config/recipes/triage-windows.yaml
index d23a4b1..7ffb3bb 100644
--- a/turbinia/config/recipes/triage-windows.yaml
+++ b/turbinia/config/recipes/triage-windows.yaml
@@ -12,31 +12,36 @@ plaso_base:
       'BrowserCache',
       'BrowserHistory',
       'ChromeStorage',
+      'ChromePreferences',
+      'ChromiumBasedBrowsersExtensions',
+      'ChromiumBasedBrowsersExtensionActivitySQLiteDatabaseFile',
+      'FirefoxAddOns',
       'MicrosoftAVQuarantine',
       'NTFSLogFile',
       'NTFSMFTFiles',
+      'WindowsActivitiesCacheDatabase',
       'WindowsAMCacheHveFile',
       'WindowsAppCompatCache',
+      'WindowsBITSQueueManagerDatabases',
       'WindowsEventLogs',
+      'WindowsFirewallLogFile',
+      'WindowsGroupPolicyScripts',
+      'WindowsHostsFiles',
       'WindowsMostRecentApplication',
+      'WindowsPersistenceMechanisms',
       'WindowsPrefetchFiles',
       'WindowsRecycleBin',
-      'WindowsRunKeys',
-      'WindowsRunServices',
       'WindowsScheduledTasks',
-      'WindowsServices',
       'WindowsSetupApiLogs',
-      'WindowsShellLoadAndRun',
       'WindowsShellRunasCommand',
       'WindowsStartupFolderModification',
+      'WindowsStartupFolders',
       'WindowsSuperFetchFiles',
       'WindowsTempDirectories',
-      'WindowsTerminalServerRunKeys',
+      'WindowsUserAccessLogging',
       'WindowsUserJumpLists',
       'WindowsUserRecentFiles',
       'WindowsUserRegistryFilesAndTransactionLogs',
+      'WindowsSystemRegistryFilesAndTransactionLogsBackup',
       'WindowsUserShellFolders',
-      'WindowsWinlogonShell',
-      'WindowsWinlogonSystem',
-      'WindowsWinlogonUserinit',
   ]
\ No newline at end of file
diff --git a/turbinia/config/rules/redis_replicaof.yar b/turbinia/config/rules/redis_replicaof.yar
new file mode 100644
index 0000000..f43a9a0
--- /dev/null
+++ b/turbinia/config/rules/redis_replicaof.yar
@@ -0,0 +1,16 @@
+rule redis_replicaof {
+    meta:
+        description = "Rule to find exploitation of Redis servers"
+        author = "Fry"
+        date = "2022-06-21"
+        score = 90
+    strings:
+        $attack1 = "REPLICAOF" ascii
+        $attack2 = "slaveof" ascii
+        $result1 = "SECURITY ATTACK" ascii
+        $result2 = "killall" ascii
+        $result3 = "xmrig" ascii
+        $result4 = "Saving to" ascii /* wget */
+   condition:
+      filename matches /redis.*\.log(.[0-9]+)?/ and any of ($attack*) and any of ($result*)
+}
\ No newline at end of file
diff --git a/turbinia/evidence.py b/turbinia/evidence.py
index 7626f99..376f4da 100644
--- a/turbinia/evidence.py
+++ b/turbinia/evidence.py
@@ -195,7 +195,7 @@ class Evidence:
     # List of jobs that have processed this evidence
     self.processed_by = []
     self.type = self.__class__.__name__
-    self.name = name if name else self.type
+    self._name = name
     self.saved_path = None
     self.saved_path_type = None
 
@@ -214,6 +214,21 @@ class Evidence:
   def __repr__(self):
     return self.__str__()
 
+  @property
+  def name(self):
+    if self._name:
+      return self._name
+    else:
+      return self.source_path if self.source_path else self.type
+
+  @name.setter
+  def name(self, value):
+    self._name = value
+
+  @name.deleter
+  def name(self):
+    del self._name
+
   @classmethod
   def from_dict(cls, dictionary):
     """Instantiate an Evidence object from a dictionary of attributes.
@@ -597,6 +612,16 @@ class DiskPartition(RawDisk):
     # This Evidence needs to have a parent
     self.context_dependent = True
 
+  @property
+  def name(self):
+    if self._name:
+      return self._name
+    else:
+      if self.parent_evidence:
+        return ':'.join((self.parent_evidence.name, self.partition_location))
+      else:
+        return ':'.join((self.type, self.partition_location))
+
   def _preprocess(self, _, required_states):
     # Late loading the partition processor to avoid loading dfVFS unnecessarily.
     from turbinia.processors import partitions
@@ -746,6 +771,13 @@ class GoogleCloudDiskRawEmbedded(GoogleCloudDisk):
     # This Evidence needs to have a GoogleCloudDisk as a parent
     self.context_dependent = True
 
+  @property
+  def name(self):
+    if self._name:
+      return self._name
+    else:
+      return ':'.join((self.disk_name, self.embedded_path))
+
   def _preprocess(self, _, required_states):
     # Need to mount parent disk
     if not self.parent_evidence.partition_paths:
@@ -900,6 +932,16 @@ class DockerContainer(Evidence):
 
     self.context_dependent = True
 
+  @property
+  def name(self):
+    if self._name:
+      return self._name
+    else:
+      if self.parent_evidence:
+        return ':'.join((self.parent_evidence.name, self.container_id))
+      else:
+        return ':'.join((self.type, self.container_id))
+
   def _preprocess(self, _, required_states):
     if EvidenceState.CONTAINER_MOUNTED in required_states:
       self._docker_root_directory = GetDockerPath(
diff --git a/turbinia/turbiniactl.py b/turbinia/turbiniactl.py
index 639e7aa..3809976 100644
--- a/turbinia/turbiniactl.py
+++ b/turbinia/turbiniactl.py
@@ -631,6 +631,8 @@ def process_args(args):
       source = args.source[i]
       if args.command == 'googleclouddiskembedded':
         embedded_path = args.embedded_path[i]
+        if not name:
+          name = ':'.join((disk_name, embedded_path))
         mount_partition = args.mount_partition[i]
       if ((project and project != config.TURBINIA_PROJECT) or
           (zone and zone != config.TURBINIA_ZONE)):
diff --git a/turbinia/workers/analysis/loki.py b/turbinia/workers/analysis/loki.py
index 8623834..2e17de9 100644
--- a/turbinia/workers/analysis/loki.py
+++ b/turbinia/workers/analysis/loki.py
@@ -75,9 +75,9 @@ class LokiAnalysisTask(TurbiniaTask):
     stderr_file = os.path.join(self.output_dir, 'loki_stderr.log')
 
     cmd = [
-        'sudo', 'python', '/opt/loki/loki.py', '-w', '0', '--csv', '--intense',
-        '--noprocscan', '--dontwait', '--noindicator', '--nolevcheck',
-        '--nolisten', '-l', log_file, '-p', evidence.local_path
+        'sudo', 'python', '/opt/loki/loki.py', '-s', '10000', '--csv',
+        '--intense', '--noprocscan', '--dontwait', '--noindicator',
+        '--nolevcheck', '--nolisten', '-l', log_file, '-p', evidence.local_path
     ]
 
     (ret, result) = self.execute(
@@ -96,7 +96,7 @@ class LokiAnalysisTask(TurbiniaTask):
       lokireader = csv.DictReader(
           loki_report_csv, fieldnames=['Time', 'Hostname', 'Level', 'Log'])
       for row in lokireader:
-        if row['Level'] == 'ALERT':
+        if row['Level'] == 'ALERT' or row['Level'] == 'WARNING':
           report_lines.append(row['Log'])
 
     if report_lines:


Test patch:
diff --git a/turbinia/evidence_test.py b/turbinia/evidence_test.py
index 246341a..5f2e98d 100644
--- a/turbinia/evidence_test.py
+++ b/turbinia/evidence_test.py
@@ -69,7 +69,7 @@ class TestTurbiniaEvidence(unittest.TestCase):
     collection_evidence = serialized_evidence['collection'][0]
 
     self.assertIsInstance(serialized_evidence, dict)
-    self.assertEqual(collection_evidence['name'], 'My Evidence')
+    self.assertEqual(collection_evidence['_name'], 'My Evidence')
 
   def testEvidenceSerializationBadType(self):
     """Test that evidence_decode throws error on non-dict type."""