Leveraging Splunk Enterprise Security threat intelligence features to increase detection capabilities.

Threat hunters, especially malware hunters, often rely on reputation feeds or categorization to start an investigation. In their Enterprise Security product, Splunk has a great threat intelligence feeds feature that allows you to download and use all kinds of threat intel feeds to correlate data and increase detection capability.

When a domain/IP from a datamodel correlates with an IOC from these, they will appear in the “Threat Activity” section of Enterprise Security. Threat Activity is a datamodel by itself which means we can use it to build dashboards and reports and customize to achieve the results we want.

Here I will share some examples that analysts could find useful using feeds from Emerging Threats. I mostly use these queries to quickly see if there is anything relevant to investigate.

This query is using the Threat_Activity datamodel combined with the ET app macro to show all firewall connections to an IP categorized as CnC.

| tstats latest(_time) as _time,values(Threat_Activity.orig_sourcetype) as sourcetype,values(Threat_Activity.src) as src,values(Threat_Activity.dest) as dest, values(Threat_Activity.dest_port) as dest_port from datamodel=Threat_Intelligence.Threat_Activity where * Threat_Activity.orig_sourcetype="<sourcetype_name_here>" Threat_Activity.src="10.*.*.*" Threat_Activity.threat_key=iprepdata by Threat_Activity.threat_collection,Threat_Activity.threat_match_field,Threat_Activity.threat_match_value,Threat_Activity.src,Threat_Activity.dest,Threat_Activity.threat_key | `drop_dm_object_name("Threat_Activity")` | `get_threat_attribution("threat_key")` | `per_panel_filter("ppf_threat_activity","threat_match_field,threat_match_value")` | rename ppf_filter as filter | stats count by _time,threat_match_value,src,dest,threat_key | sort - filter,_time | table _time,src,dest,threat_key | `et_ip_lookup(IP=dest)` | search rep_category_name="CnC" | fields - threat_key

First, what I did was taking an already built query from Enterprise Security and modified it to fit my needs. I first precise that I only want firewall activity by adding Threat_Activity.orig_sourcetype=”<sourcetype_name_here>” and only from the 10.0.0.0/8 subnet with Threat_Activity.src=”10.*.*.*” (I could have used the CIDR but it didn’t work for some reason). Then I precise the specific threat feed I wish to use to eliminate noise from the free ones by adding Threat_Activity.threat_key=iprepdata (which is the ET one). Finally, I use the macro from the ET app to limit the results to the CnC category using | `et_ip_lookup(IP=dest)` | search rep_category_name=”CnC”

This is what it looks like after:

Capture1

From there, some modifications can be done to have more accurate results if desired, which has showing results only if the destination port from the log and the one observed by the feed matches and a score equal to or above 67.

| tstats latest(_time) as _time,values(Threat_Activity.orig_sourcetype) as sourcetype,values(Threat_Activity.src) as src,values(Threat_Activity.dest) as dest, values(Threat_Activity.dest_port) as dest_port from datamodel=Threat_Intelligence.Threat_Activity where * Threat_Activity.orig_sourcetype="<sourcetype_name_here>" Threat_Activity.src="10.*.*.*" Threat_Activity.threat_key=iprepdata by Threat_Activity.threat_collection,Threat_Activity.threat_match_field,Threat_Activity.threat_match_value,Threat_Activity.src,Threat_Activity.dest,Threat_Activity.threat_key | `drop_dm_object_name("Threat_Activity")` | `get_threat_attribution("threat_key")` | `per_panel_filter("ppf_threat_activity","threat_match_field,threat_match_value")` | rename ppf_filter as filter | stats count by _time,threat_match_value,src,dest_port,dest,threat_key | sort - filter,_time | table _time,src,dest,dest_port,threat_key | `et_ip_lookup(IP=dest)` | search rep_category_name=CnC rep_score >= 67 | fields - threat_key rep_cat_description | where dest_port=ports

From there, if you have an IDS, I suggest adding matching results from an IDS alert for increased confidence as we all know that IP-based IOCs are often unreliable and results are hard to contextualize.

By the way, the same can be done with proxy logs:

| tstats latest(_time) as _time,values(Threat_Activity.orig_sourcetype) as sourcetype,values(Threat_Activity.src) as src,values(Threat_Activity.dest) as dest from datamodel=Threat_Intelligence.Threat_Activity where * Threat_Activity.orig_sourcetype="<sourcetype_name_here>" Threat_Activity.threat_key="domainrepdata" by Threat_Activity.threat_collection,Threat_Activity.threat_match_field,Threat_Activity.threat_match_value,Threat_Activity.src,Threat_Activity.dest,Threat_Activity.threat_key | `drop_dm_object_name("Threat_Activity")` | `get_threat_attribution("threat_key")` | `per_panel_filter("ppf_threat_activity","threat_match_field,threat_match_value")` | rename ppf_filter as filter | stats count by _time,src,dest,threat_key | sort - filter,_time | table _time,src,dest,threat_key | `et_domain_lookup(DOMAIN=dest)` | search threat_level=Malicious rep_category_name=CnC | fields - threat_key

 

Analyzing code injected in a remote process via CreateRemoteThread

This is a commonly used technique in advanced malwares. This is from recent Sality sample submitted to VirusTotal. This code injection method is from the packer and not the malware itself. I won’t dive deep into the actual malware but want to simply show this method to analyze the injected code.

  1. The packer allocates memory in the space of taskhost.exe, changes protection as PAGE_EXECUTE_READWRITE.1
  2. Then it writes code in the memory space recently allocated.2
  3. Finally, it creates a thread in taskhost.exe that will execute the code.3-e1499696046540.png

Now, there is code that will be executed by a new thread spawned in taskhost.exe, we need to do the following to analyze it:

  1. In the hex dump, go to the buffer address pushed before calling WriteProcessMemory  (0130D10B here).
  2. Change the CALL instruction for a JMP that will loop on endlessly by replacing the E8 instruction with EB FE.4
  3. Step over and execute the call to CreateRemoteThread.
  4. Open a new debugger instance attach to taskhost.exe.
  5. In the CPU window, go the the address previously allocated by WriteProcesMemory (either by using “Go to Expression, checking the latest thread created or using the Memory Map).
  6. Change the JMP back to a CALL by changing EB FE back to E8 00. 6-e1499696098280.png
  7. Set a break point then on the call, resume execution, step over and have fun.