Core Impact Agent Transformation Scripts
What is the feature for?
You can configure specific Core Impact agent processing functions by leveraging this feature to increase their effectiveness. Some functions that can benefit from this feature are signing the implant with a custom certificate, processing the payload with an obfuscator, and customizing the implant loader to increase effectiveness.
Enabling Agent Transformations
To enable Agent Transformations, select Tools > Options > Agent Transformations.
When Core Impact executes Shellcode Transformations or Binary Transformations, it will log a message in the Module Log.
How the agent is created
Modules deploying agents will request a given artifact based on the configuration of the target under test and any configured parameters (for example, the connection method and connection port). First, the shellcode aligned with the configuration is created, and then, depending on the exploit or module itself, the shellcode could be wrapped in another artifact (for example, an executable, a library, or returned as a raw payload).
Considering this process, Core Impact includes two defined customizing hook points:
-
Shellcode generation - Shellcode Transformations
-
Binary wrapping - Binary Transformations
Shellcode Transformations
If configured, this script is applied to every module that deploys an agent. Whether the module is an Exploit, an Identity Verifier, a server exposing the agent to download, or an agent packer like Package and Register Agent, this script affects its execution.
Define a run function in the .py file with the following parameters:
-
shellcode
-
The original Core Impact agent shellcode.
-
Should be returned without modification to keep default behavior.
-
-
host_os
-
The operating system of the machine where the module is being executed: 'windows', 'linux', 'mac os x', 'solaris', 'aix', 'openbsd', 'freebsd', 'netbsd', 'hp-ux', 'ios', 'ibmi', 'unsupported', 'unknown'
-
-
host_ arch
-
The architecture of the machine where the module is being executed: 'i386', 'x86-64'
-
-
module_logger
-
The module's logger object. The following functions set visibility for messages logged in the Module Log:
-
logLow: Logged messages are only visible when Detail Level is set to High.
-
logMed: Logged messages are only visible when Detail Level is set to Medium or High.
-
logHi: Logged messages are always visible.
-
-
Binary Transformations
Define a run function in the .py file with the following parameters:
-
artifact_type
-
The type of artifact requested by the caller: 'library', 'executable'.
NOTE:'raw', is not an option for this parameter as it returns the actual shellcode without further wrapping.
-
-
artifact
-
The original artifact packed by Core Impact. Shellcode is packed as <artifact_type>.
-
Should be returned without modification to keep default behavior.
-
-
shellcode
-
The shellcode to pack. Returns the original Core Impact's agent shellcode or the one returned by the previous callback, if defined.
-
-
host_os
-
The operating system of the machine where the module is being executed: 'windows', 'linux', 'mac os x', 'solaris', 'aix', 'openbsd', 'freebsd', 'netbsd', 'hp-ux', 'ios', 'ibmi', 'unsupported', 'unknown'
-
-
host_ arch
-
The architecture of the machine where the module is being executed: 'i386', 'x86-64'
-
-
module_logger
-
The module's logger object. The following functions set visibility for messages logged in the Module Log:
-
logLow: Logged messages are only visible when Detail Level is set to High.
-
logMed: Logged messages are only visible when Detail Level is set to Medium or High.
-
logHi: Logged messages are always visible.
-
-
Binary Transformation Script Samples
Signing a Windows Implant
Script Parameters
Name | Description | Required | Example |
---|---|---|---|
USE_CORE_IMPACT_DEFAULT_CERTIFICATE | If True, uses the default Core Impact self-signed certificate to sign the files.
Possible values: True and False. |
Yes | |
CRT_CERTIFICATE_FILE | Path to the private key file associated with the CRT certificate. | No. This parameter is only required if you want to generate the PFX certificate automatically. | path/to/your/certificate.crt |
CRT_CERTIFICATE_KEY_FILE | Path to the private key file associated with the CRT certificate. | No. This parameter is only required if you want to generate the PFX certificate automatically. | path/to/your/private.key |
PFX_CERTIFICATE_FILE | Path to the PFX (certificate) file. | Yes. If configured, the existing file is used. Otherwise, the PFX file is created from CRT_CERTIFICATE_FILE and CRT_CERTIFICATE_KEY_FILE. | path/to/save/your/certificate.pfx |
PFX_CERTIFICATE_PASSWORD | Password to protect the generated PFX file. | No | yourPFXpassword |
SIGNATURE_TIMESTAMP_SERVER_URL | URL of the Timestamp Server to use during the signing process. This server provides a trusted timestamp, ensuring that the signature remains valid even after the certificate expires. You can set the value of this parameter to None if Core Impact is running in an air-gapped environment. | Yes | http://timestamp.digicert.com |
Script Example
You can find the following script in the UserModules\agent_transformations\examples folder.
When configuring this script, the generated agent artifact will be signed and timestamped using the provided certificate. This script also verifies the signature of the signed file, returning its thumbprint and certificate details.
Create a copy of this script before making edits to avoid overwriting it when you upgrade to a new version of Core Impact.
# -*- coding: utf-8 -*-
"""
Callback to apply Authenticode code signing signatures and timestamps to Windows Implants (exe and dll) using the native Microsoft APIs.
Copyright Fortra, LLC and its affiliated companies
All rights reserved.
This proprietary computer software is owned by Fortra, LLC and its affiliated companies and is protected by U.S. copyright laws and other laws and by
international treaties. This computer software is furnished by Fortra, LLC and its affiliated companies pursuant to a written license agreement and may
be used, copied, transmitted, and stored only in accordance with the terms of such license and with the inclusion of the above copyright notice.
This Computer software or any other copies thereof may not be provided or otherwise made available to any other person.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL FORTRA, LLC AND ITS AFFILIATED COMPANIES BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS SOFTWARE.
"""
"""
CONFIGURATION PARAMETERS
------------------------
Below are the parameters that can be configured by the end user.
Please provide appropriate values before running the callback.
"""
# If True, the default Core Impact self-signed certificate will be used to sign the files
# Default: False
USE_CORE_IMPACT_DEFAULT_CERTIFICATE = False
# Path to the existing CRT (certificate) file. [OPTIONAL- Only required if you want to generate the PFX certificate automatically]
# Example: "path/to/your/certificate.crt"
CRT_CERTIFICATE_FILE = ""
# Path to the private key file associated with the CRT certificate. [OPTIONAL- Only required if you want to generate the PFX certificate automatically]
# Example: "path/to/your/private.key"
CRT_CERTIFICATE_KEY_FILE = ""
# Path to the PFX (certificate) file should be saved. [REQUIRED - If CRT_CERTIFICATE_FILE and CRT_CERTIFICATE_KEY_FILE are not set, the file should exist]
# Example: "path/to/save/your/certificate.pfx"
PFX_CERTIFICATE_FILE = ""
# Password to protect the generated PFX file. [OPTIONAL]
# Example: "yourPFXpassword"
PFX_CERTIFICATE_PASSWORD = ""
# URL of the Timestamp Server to be used during the signing process. [REQUIRED]
# This server provides a trusted timestamp, ensuring that the signature remains valid even after the certificate expires.
# The value for that parameter can be None if Core Impact is running in an air-gapped environment
# Example: "http://timestamp.digicert.com"
SIGNATURE_TIMESTAMP_SERVER_URL = "http://timestamp.digicert.com"
"""
END OF CONFIGURATION PARAMETERS
-------------------------------
No further modifications are necessary below this line.
"""
import os
import time
from impact import config
from impact import signing
def run(artifact_type, artifact, shellcode, host_os, host_arch, module_logger):
if USE_CORE_IMPACT_DEFAULT_CERTIFICATE:
CRT_CERTIFICATE_FILE = os.path.join(config.getWebAppsInstallPath(),"data","impact-wa.crt")
CRT_CERTIFICATE_KEY_FILE = os.path.join(config.getWebAppsInstallPath(),"data","impact-wa.key")
try:
pfx_password = PFX_CERTIFICATE_PASSWORD.encode()
except:
raise Exception("PFX_CERTIFICATE_PASSWORD is a required parameter.")
file_path = os.path.join(config.getTempPath(), "temporary_agent_{timestamp}".format(timestamp=int(time.time())))
with open(file_path, "wb") as f:
f.write(artifact)
module_logger.logMed("[+] Artifact copied to: {}".format(file_path))
if not PFX_CERTIFICATE_FILE:
raise Exception("PFX_CERTIFICATE_FILE is a required parameter.")
if not os.path.isfile(PFX_CERTIFICATE_FILE):
signing.create_cert(CRT_CERTIFICATE_FILE,CRT_CERTIFICATE_KEY_FILE,PFX_CERTIFICATE_FILE,pfx_password)
if not os.path.isfile(file_path):
raise Exception("Error: Executable file not found: {}".format(file_path))
if not os.path.isfile(PFX_CERTIFICATE_FILE):
raise Exception("Error: Certificate file not found: {}".format(PFX_CERTIFICATE_FILE))
# Sign file
signing.sign_file(filename=file_path, certificate=PFX_CERTIFICATE_FILE, password=pfx_password, timestamp=SIGNATURE_TIMESTAMP_SERVER_URL, use_rfc3161=True, use_sha256=True)
# Validate the certificate information
cert_info = signing.get_certificate_info(file_path)
if cert_info is not None:
pretty_cert_info = "[+] Signer Certificate Information:\n"
pretty_cert_info += "\tThumbprint : {thumbprint}\n".format(thumbprint=cert_info["thumbprint"])
pretty_cert_info += "\tSubject : {subject}\n".format(subject=cert_info["subject"])
pretty_cert_info += "\tIssuer : {issuer}\n".format(issuer=cert_info["issuer"])
pretty_cert_info += "\tSerial Number: {serial}\n".format(serial=cert_info["serial"])
pretty_cert_info += "\tValid From : {not_before}\n".format(not_before=cert_info["not_before"])
pretty_cert_info += "\tValid To : {not_after}".format(not_after=cert_info["not_after"])
module_logger.logLow(pretty_cert_info)
# Read signed binary file
if file_path:
with open(file_path, "rb") as f:
signed_exe_binary = f.read()
# Cleanup
if os.path.exists(file_path):
os.remove(file_path)
module_logger.logHi("[+] Cleanup")
return signed_exe_binary
Inceptor
Setting Up Inceptor
-
Go to https://www.python.org/downloads/, and then download and install Python3.
-
Go to https://git-scm.com/downloads, and then download and install Git.
-
Using GIt, clone the inceptor project at https://github.com/klezVirus/inceptor.
git clone --recursive https://github.com/klezVirus/inceptor.git
-
Go to https://visualstudio.microsoft.com/visual-cpp-build-tools/, and then download and install the Microsoft C++ Build Tools. This will download the vs_BuildTools.exe installer file.
-
Double-click vs_BuildTools.exe.
-
When prompted by the Visual Studio Installer, do the following:
-
Under the Workloads tab, select Desktop development with C++.
-
Under the Individual components tab, select the following:
-
MSBuild support for LLVM (clang-cl) toolset
-
C++ Clang Compiler for Windows (latest version)
-
-
-
Select Install.
-
Run the following Python command to install the requirements.txt file:
-
python -m pip install -r requirements.txt
-
-
Using the C++ Build Tools, configure Inceptor using the following:
-
cd inceptor
-
python update-config.py
-
Script Parameters
Name | Description | Required | Example |
---|---|---|---|
PYTHON_PATH | Path to the Python interpreter. | Yes | C:\Python313\python.exe |
INCEPTOR_PATH | Path to the Inceptor tool's main script. | Yes | C:\Tools\Inceptor\inceptor.py |
Script Example
You can find the following script in the UserModules\agent_transformations\examples folder.
When configuring this script, the generated Windows agent will be processed using the klezVirus/inceptor tool you cloned in step 3 of Setting Up Inceptor, applying advanced obfuscation techniques to make the artifact more resistant to detection by AV/EDR solutions.
Create a copy of this script before making edits to avoid overwriting it when you upgrade to a new version of Core Impact.
# -*- coding: utf-8 -*-
"""
Callback to generate a transformed payload through Inceptor.
Inceptor is a template-based PE packer for Windows, designed to help penetration testers and red teamers bypass common AV and EDR solutions. Inceptor has been designed with a focus on usability, and to allow extensive user customization.
Copyright Fortra, LLC and its affiliated companies
All rights reserved.
This proprietary computer software is owned by Fortra, LLC and its affiliated companies and is protected by U.S. copyright laws and other laws and by
international treaties. This computer software is furnished by Fortra, LLC and its affiliated companies pursuant to a written license agreement and may
be used, copied, transmitted, and stored only in accordance with the terms of such license and with the inclusion of the above copyright notice.
This Computer software or any other copies thereof may not be provided or otherwise made available to any other person.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL FORTRA, LLC AND ITS AFFILIATED COMPANIES BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS SOFTWARE.
Credits: Inceptor: https://github.com/klezVirus/inceptor
Copyright (c) 2021, Alessandro Magnosi (d3adc0de)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Alessandro Magnosi (d3adc0de).
4. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
"""
CONFIGURATION PARAMETERS
------------------------
Below are the parameters that can be configured by the end user.
Please provide appropriate values before running the callback.
"""
# Path to the Python interpreter (python.exe) [REQUIRED]
# Example: "C:\Python313\python.exe"
PYTHON_PATH = r'C:\Python313\python.exe'
# Path to the Inceptor tool's main script (inceptor.py) [REQUIRED]
# Example: "C:\Tools\Inceptor\inceptor.py"
INCEPTOR_PATH = r'C:\Tools\inceptor\inceptor.py'
"""
END OF CONFIGURATION PARAMETERS
-------------------------------
No further modifications are necessary below this line.
"""
import os
from impact import config
from impact.post.cmdexec import WinCmd
def run(artifact_type, artifact, shellcode, host_os, host_arch, module_logger):
if host_os != 'windows':
module_logger.logHi('[-] Inceptor can only target Windows systems')
return artifact
# 1: write binary blob in a temp file
module_logger.logHi('[*] Preparing temporal files')
shellcode_path = os.path.join(config.getTempPath(), "temp_shellcode")
with open(shellcode_path, "wb") as tempfile:
tempfile.write(shellcode)
output_path = os.path.join(config.getTempPath(), "temp_agent.{}".format("dll" if artifact_type == "library" else "exe"))
inceptor_args = [
"\"{}\"".format(PYTHON_PATH),
"\"{}\"".format(INCEPTOR_PATH),
'native',
'-t loader',
'-C cl',
'-hw',
'--arch {}'.format('x86' if host_arch == 'i386' else 'x64'),
"-o \"{}\"".format(output_path),
"\"{}\"".format(shellcode_path),
]
env = os.environ.copy()
env.pop('PYTHONHOME',None)
env_list = ["{}={}".format(k, v) for k, v in env.items()]
# 2: call inceptor
module_logger.logHi('[*] Calling inceptor')
the_command = ' '.join(inceptor_args)
module_logger.logLow('[+] {}'.format(the_command))
cmd = WinCmd(the_command, environment=env_list, sync=True)
for line in cmd.readlines():
module_logger.logLow("[+] {}".format(line))
# 3: read output file content and return it as a buffer
module_logger.logHi('[*] Reading artifact to return')
with open(output_path, "rb") as outputfile:
output = outputfile.read()
# 4: remove files
module_logger.logHi("[*] Cleanup")
if os.path.exists(shellcode_path):
os.remove(shellcode_path)
if os.path.exists(output_path):
os.remove(output_path)
return output