Operator On The Wire
← Back to Knowledge Base
Research / Evading Elastic EDR via Static String Obfuscation in Sliver

Evading Elastic EDR and Yara Rules via Static String Obfuscation in Sliver

Lab note: This research was performed inside Shinra ProLab on Hack The Box. The objective was to understand exactly why Elastic detected a stock Linux Sliver beacon and to validate that conclusion experimentally.


Overview

I wanted to play around with static string obfuscations.

This started with a simple observation: a stock Sliver beacon was removed as soon as it was transferred to an Elastic-protected Linux host.

Rather than treating the EDR verdict as a black box, I traced the detection back to its public YARA rule, more specifically - Multi_Trojan_Sliver.yar. I reproduced the match locally, identified the exact strings responsible, changed one of them in the Sliver source tree to satisfy the rule condition, rebuilt the project, and tested the result again.

The modified beacon no longer matched the original Sliver YARA rule, transferred successfully, executed, called back, and accepted tasking. Elastic still generated a separate high-severity behavioral alert because the binary was launched from /dev/shm, but that alert did not terminate the running beacon and was outside the scope of the current test.

This was not a broad EDR bypass. It was a controlled demonstration that one specific detection depended on a two-string condition that could be invalidated with a minimal source-level change.


1. Establishing The Baseline

I first generated a stock Linux amd64 Sliver beacon and transferred it to the target host.

The transfer was immediately intercepted by Elastic. The alert identified the file as malicious and showed that wget, running under bash as root on web01, had attempted to create the beacon under /dev/shm.

01-elastic-detection

The file transfers successfully, and in about ~1 second it is deleted:

02-immediate-delete

What exactly was Elastic matching?


2. Finding The Public Sliver Rule

Elastic publishes its protection artifacts in the elastic/protections-artifacts repository. Searching the repository for Sliver led to the following rule file:

yara/rules/Multi_Trojan_Sliver.yar

One of the rules contained several Sliver-related strings and used the following condition:

2 of them

The two strings that mattered for my stock beacon were:

  • ).RequestResend
  • ).GetPrivInfo

03-yara-rule

The condition was the important part.

The rule did not require every listed string; any two were sufficient.


3. Reproducing The Detection Locally

Before changing anything, I validated the rule against the original beacon on my Kali system.

I searched the binary for every string listed by the rule. The stock beacon contained two relevant matches:

  • RequestResend
  • GetPrivInfo

Running Elastic's YARA rule locally against the same binary produced a positive match and identified those two strings as the matching conditions.

04-local-yara-reproduction

This was the key confirmation.

I could reproduce the same detection independently and see the exact bytes responsible.


4. Tracing The Strings Into The Sliver Source Tree

I then searched the Sliver source tree for both identifiers.

GetPrivInfo appeared in generated protobuf code. I had not worked with that code-generation path before, and modifying it would have introduced unnecessary complexity.

RequestResend, by contrast, appeared as a normal method name in the transport and server code, together with its call sites.

Because the YARA condition required two matches, removing either one would be enough to invalidate this specific rule.

I therefore chose the smaller and more controlled change: rename RequestResend consistently while leaving GetPrivInfo untouched.

I applied the rename across the source tree and rebuilt Sliver from source.

05-source-change

The replacement also affected identifiers in vendor OpenTelemetry code where RequestResend appeared as part of a longer name. The underlying telemetry string remained unchanged, and the project rebuilt successfully. It was not intentional but it also did not introduce errors in the current scope of my research.


5. Verifying The Rebuilt Beacon

After rebuilding, I generated a fresh Linux beacon from the modified Sliver build.

I repeated the same checks against the new binary:

  • GetPrivInfo was still present.
  • The original RequestResend string was gone.
  • The renamed identifier was present instead.
  • Elastic's Sliver YARA rule did not produce a match.

06-verification

This was the expected result. The rule required two listed strings, but the rebuilt beacon now exposed only one of the two strings that had matched previously.


6. Testing The Modified Beacon Against Elastic

With the local result confirmed, I started an HTTPS listener on port 443 and generated a new Linux amd64 beacon using the rebuilt Sliver binaries.

07-listener-and-generation

I transferred the new beacon to the same target host, placed it in /dev/shm, marked it executable, and launched it.

Unlike the stock beacon, the modified file remained present and executed successfully.

08-transfer-and-execution

(The reason you see two beacon files present is because I put in the wrong listener settings when regenerating the first time.. disregard it as it's not relevant, the important one is beacon_fix)

The Sliver server received a callback. I then issued an ls task through the beacon and received the contents of the target directory, confirming that the beacon was alive and accepting commands.

09-callback-and-tasking

This completes the chain:

  1. The stock beacon triggered the public Sliver YARA rule and was prevented.
  2. The same rule was reproduced locally.
  3. One matching source identifier was changed.
  4. The project was rebuilt.
  5. The rebuilt beacon no longer matched the rule.
  6. The beacon transferred, executed, called back, and accepted tasking.

7. The Remaining High-Severity Alert

I left the beacon running and monitored Elastic for another five to ten minutes.

The original malware-prevention alert did not return. The only new detection was:

Binary Executed from Shared Memory Directory

Elastic raised this because bacon_fix was executed by root from /dev/shm, a location commonly abused for temporary or fileless execution on Linux systems.

10-shared-memory-alert

This alert was unrelated to the Sliver YARA signature. It was based on runtime behavior and execution location rather than embedded strings in the binary.

It was still classified as High, with a risk score of 73, but it did not kill the beacon. It also fired only once for the process execution event; subsequent commands issued through the existing beacon did not repeatedly trigger the same rule.

That distinction was one of the most useful lessons from the exercise:

  • The original alert was a high-confidence malware-prevention decision tied to static content.
  • The remaining alert was a behavioral anomaly that generated telemetry without automatically terminating the process.

Key findings

  • Public detections can be reproduced precisely

Finding the public rule and running it locally turned an EDR verdict into a testable condition. Instead of guessing, I could identify the exact matching strings and verify every change before touching the target again.

  • Go binaries expose useful detection material

The stock Sliver beacon retained method names that were specific enough to support a YARA signature. In this case, two embedded Go identifiers were sufficient to identify the sample.

  • Minimal changes make conclusions stronger

I changed only one matching identifier because the rule required two. Leaving GetPrivInfo untouched made the result easier to interpret: the rule stopped matching because one required element was removed, not because the entire binary had been heavily transformed.

  • Detection and prevention are separate outcomes

Elastic prevented the stock beacon based on the malware signature, but only alerted when the rebuilt binary executed from /dev/shm. A high-severity alert does not necessarily imply automatic process termination.

  • Static and behavioral detections complement each other

Removing one static signature match did not make the activity invisible. Elastic still observed the execution context and raised a separate alert for the shared-memory directory.


Conclusion

This was my first hands-on experiment with an EDR.

The real lesson was the workflow:

  • observe the alert;
  • locate the detection logic;
  • reproduce it independently;
  • identify the exact matching evidence;
  • make the smallest possible change;
  • rebuild and retest;
  • validate both offensive functionality and defensive telemetry.

I started with a stock binary that was immediately prevented and ended with a working beacon that no longer matched the specific public YARA rule. At the same time, the remaining behavioral alert made it clear that bypassing one detection is not the same as disappearing from the EDR.

That interaction between static signatures, runtime behavior, severity, and prevention policy is what made the exercise genuinely interesting—and why this probably will not be my last EDR lab.