Visualização de leitura

Linux Kernel 7.1 Reaches End of Life

The Linux Kernel 7.1 EOL has officially arrived. Discover the final updates and learn why you must upgrade to the latest stable LTS releases immediately.

Related Posts:

The post Linux Kernel 7.1 Reaches End of Life appeared first on Daily CyberSecurity.

Debian 11 Reaches End of Long Term Support

Debian 11 LTS ends on August 31, 2026. Discover upgrade options and extended paid support details for enterprises still running the older Linux version.

Related Posts:

The post Debian 11 Reaches End of Long Term Support appeared first on Daily CyberSecurity.

Debian AI Policy: Responsible Generative AI Use Wins Vote

Debian's AI policy vote picked "Responsible Use of Generative AI": AI is neither banned nor endorsed, with full accountability left to contributors.

Related Posts:

The post Debian AI Policy: Responsible Generative AI Use Wins Vote appeared first on Daily CyberSecurity.

OpenClaw Unleashes Massive Update

The open-source OpenClaw AI agent project just released its largest update ever. Discover how this accidental 2.0 upgrade transforms the user experience.

Related Posts:

The post OpenClaw Unleashes Massive Update appeared first on Daily CyberSecurity.

California Exempts Linux from Age Verification

California passes AB-1856, exempting open-source operating systems like Linux from the burdensome age verification mandates of the Digital Age Assurance Act.

Related Posts:

The post California Exempts Linux from Age Verification appeared first on Daily CyberSecurity.

GoResolver: Using Control-flow Graph Similarity to Deobfuscate Golang Binaries, Automatically

Volexity-Blog-GoResolver-Using Control-flow-Graph-Similarity-to-Deobfuscate-Golang-Automatically

KEY TAKEAWAYS
  • Go language (Golang) is increasing in popularity with developers of both legitimate and malicious tooling.
  • Volexity frequently encounters malware samples written in Golang that apply obfuscators to hinder analysis.
  • Obfuscated Golang malware samples are significantly harder to statically analyze for reverse engineers.
  • Volexity has developed an open-source tool, GoResolver, to retrieve obfuscated functions names.
  • GoResolver’s control-flow graph similarity techniques offer a significant advantage in recovering symbol information.

In the course of its investigations, Volexity frequently encounters malware samples written in Golang. Binaries written in Golang are often challenging to analyze because of the embedded libraries and the sheer size of the resulting binaries. This issue is amplified when samples are obfuscated using tools such as Garble, an open-source Golang obfuscation tool.

The popularity of Golang amongst malware developers, and the use of obfuscators to make reverse-engineering harder, raised the need for better tooling to assist in reverse-engineering efforts. Volexity developed GoResolver, an open-source tool that uses control-flow graph similarities to retrieve obfuscated functions names. GoResolver is available for download on GitHub here.

Note that throughout this blog post, Garble obfuscation is used to demonstrate GoResolver’s effectiveness. However, the same principles apply to other closed-source Golang obfuscators observed by Volexity.

Garble Obfuscation Properties Analysis

One of the obfuscators commonly encountered by Volexity is Garble. Its functionality is described in the README, a screenshot of which is shown below:

Despite these listed features, all of which significantly hinder manual static analysis, binaries obfuscated using Garble present interesting properties that weaken the overall apparent strength of its obfuscation.

For example, the randomization employed by Garble for function and package names is not truly random. Due to how Golang resolves function names, randomized names must stay consistent across all functions of a package, so they are highly reused:

As shown in the image above, the “E2AKV7TQjQ” string is reused across many functions as it represents the package name. Manually looking at the functions called by this garbled string, it can be inferred that this represents the os/exec package. Consequently, if one function from a package is identified, the package can be identified for the entire binary. All other obfuscated functions can then be associated with this package. This logic greatly improves the symbol recovery.

Existing Go Tools

Some tools already exist to help retrieve lost symbol information, the most well-known of which is Mandiant’s GoReSym. GoReSym works by bypassing the symbol table entirely. Instead, it extracts function names and type information from Go’s internal runtime structures, ModuleData and PcLineTab, in the same way as the Golang runtime would, using the Golang runtime’s own parser whenever possible. As these structures are necessary for Golang binaries to work properly, Garble cannot strip them.

As the retrieved symbols are still randomized, Volexity recognized an opportunity to go further by using control-flow graph similarities to identify the original package and function names.

Control-flow Graph Similarities

Control-flow graphs can be used to represent different paths a binary may take during execution. Even when recompiled across different compiler versions, the resulting control-flow graph of a given algorithm will remain similar. By measuring the similarity between the control-flow graph of two functions in two different binaries, it is sometimes possible to assert if they result from the same algorithm.

A paper published in 2020 describes an efficient technique to compute the normalized similarity (0.0 to 1.0) between two control-flow graphs by computing the weighted ratio of similar assembly instructions across nodes of the control-flow graph. By implementing this technique and comparing Garbled samples against generated clean template Golang samples, it could then be possible to fully resolve the randomized symbol names to their original form.

An illustration of this process is below:

Two graphs are compared, and the similarity between each set of two blocks in the graph is computed. In the illustration above, the red and blue blocks contain the exact same instructions but in a different order, and thus have a similarity of 1.0.

GoResolver Installation

The GoResolver toolchain is composed of four projects:

Project Description
GoResolver A Golang symbol recovery tool through symbol extraction and control-flow graph similarity
GoGrapher A binary similarity tool that computes the control-flow graph similarity between two binaries
GoStrap A Golang reference sample bootstrapping tool that allows users to generate Go samples of any Golang version and feature the requested set of libraries
GitToolFetcher A simple tool to install, manage, and run multiple, concurrent versions of GitHub-hosted projects

An overview of the interactions within the projects of the GoResolver toolchain is shown below:

Image3

To install the GoResolver toolchain, please ensure your system’s dependencies match the following minimum requirements:

Language Version
Go 1.20.6+
Python 3.12+

Each Python-based component of the toolchain is available on pypi, so you can simply run the following command to install:

pip install goresolver

GoResolver also provides plugins for IDA Pro and Ghidra. The following versions are supported:

Tool Version Python Version
IDA Pro (IDAPython) 9+ Python 3.12+
Ghidra (PyGhidra) 11.3+ Python 3.12+

In Volexity’s experience, analysis of Golang binaries is significantly faster in IDA Pro.

Case Study

To illustrate usage of the GoResolver toolchain, Volexity built the Stowaway agent using Garble. The sample (1df2cd0d12e5028d5dbda33a4e4404e0) is available on VirusTotal.

When the sample is disassembled using IDA Pro, most functions have generic names using the format sub_OFFSET. This is to be expected, since Garble stripped the symbol table. Performing a complete analysis would be tedious; instead, the sample is submitted to GoResolver.

GoResolver will first try to identify the version of Golang used to build the malware sample. This is usually done by parsing the BuildInfo or identifying Golang version string fragments in the binary. For garbled Golang binaries, however, neither approach works, since Garble ensures no version fragments or BinaryInfo remain in the compiled executable.

While Garble removes all directly identifiable information, it is still bundled with the Golang runtimes. Since the Golang runtime changes between different versions, GoResolver can use this information to fingerprint the runtime version. By generating reference data for each major Golang version and computing the similarity of each runtime with the malware sample, the tool can pinpoint the Golang version used to compile the malware sample. Volexity has identified that testing only 2% of the Golang runtime was sufficient to discriminate between major versions. This improves both efficiency and resource usage when computing the similarity of each major Golang version of the malware sample.

To submit a sample to GoResolver, simply call the tool with the path to the sample as argument, for example:

goresolver /path/to/sample.exe

The submission of the malware sample to GoResolver is shown below:

Once the Golang version of the malware sample is identified, the template compiled with this specific version will be used as a reference. GoResolver then computes the full binary similarity, which is combined with the symbols extracted similarly to those used by GoReSym. This results in the final symbol report, which can then be imported into your SRE tool of choice.

The before-and-after import comparison of resolved symbols is illustrated below:

As shown above, numerous symbols have been resolved to more meaningful names, even though they are still partially obfuscated. Even in cases where symbols haven’t been fully resolved by the similarity algorithm, statistical analysis helps resolve the package and modules names, as can be seen with the “os” package shown below:

Even though these symbols are only partially resolved, knowing their package name helps understand the binary layout. This also helps the analyst avoid reversing runtime and library methods, allowing them to instead focus on the malware’s actual core logic.

SRE Plugins

To ease the integration of the GoResolver toolchain into analyst workflows, Volexity has made plugins available for both IDA Pro and Ghidra. Both plugins allow easy import of recovered symbol data generated by the GoResolver CLI tool into their respective symbol databases. While their interface differs, both plugins rely on the same codebase and thus provide the same capabilities.

When using IDA Pro, the following dialog is shown:

The GoResolver plugin features two modes of operation, depending on how you want the GoResolver toolchain to integrate into your workflow: “Analyze the current file” or “Import a previous report”. These options are selectable on the left-hand side.

The Analyze option lets you run GoResolver directly within IDA Pro. Once the analysis is complete the generate report file will be automatically imported into the symbol database.

The Import option requires you to generate a report file using the standalone GoResolver CLI beforehand. This can then be imported into the symbol database by selecting the path to the previously generated report file.

When using Ghidra, the following dialogs are shown:

These dialogs offer the same options as the IDA Pro plugin; the Analyze and Import modes behave the same way.

Both plugins are available in the “Plugin” directory within GoResolver’s repository.

Conclusion

Golang is more often the language of choice for many malware authors, due to embedded libraries and the size of the resulting binaries. To add additional complexity, malware written in Golang is often obfuscated. The ability to reverse engineer obfuscated malware written in Golang is an important part of digital forensic investigations.

Volexity has developed GoResolver, an open-source tool that uses control-flow graph similarities to retrieve obfuscated functions names. The use of control-flow graph similarity, in conjunction with pre-existing symbol extraction techniques, allows the resolution of more complete symbols than previously achievable. This ensures a better understanding of the binary, and helps analysts focus on reversing the core malware logic. Volexity plans to integrate more features, such as automatic Golang strings parsing and various improvements to facilitate the Golang binaries reversing, so watch for updates in the GoResolver repository on GitHub.

Acknowledgements

Volexity would like to thank Mandiant’s threat intelligence division for its documentation of the Golang runtime’s symbol-parsing mechanism, as well as their work on GoReSym.

Volexity also thanks Mr. Hyun-il Lim from the Kyungnam University for the research and paper on control-flow graph similarity algorithms.

The post GoResolver: Using Control-flow Graph Similarity to Deobfuscate Golang Binaries, Automatically appeared first on Volexity.

Forging a Better Operator Quality of Life

A new Mythic add-on for Windows Agents

Mythic provides flexibility to agent developers for how they want to describe and execute techniques. While this is great, it also means that when operators hop from agent to agent, they can have issues with slight differences between similar commands. Because of this, there have been some requests within the Mythic community to provide a feature similar to Sliver’s amazing Armory project so that, if desired, there can be a more standardized way of executing beacon object files (BOFs) and .NET assemblies.

Introducing Forge

Forge in Mythic

Mythic uses Docker to provide a plug-and-play framework of adding/removing agents and communication profiles dynamically. This means that adding a new Docker container to Mythic simply adds that new agent. You can use that agent to build payloads, get callbacks, and run commands, but that’s all specific to that one agent. The commands from Apollo are not available to another agent like Poseidon, so how can Mythic provide some standardized command across multiple agents?

Mythic 3.3 introduced the concept of a “Command Augmentation” container that in many ways acts the same as a normal agent container. This container brings along new commands to Mythic; however, instead of having them tied to a specific agent, they’re automatically added to all callbacks that meet certain criteria. This criteria can be callbacks on certain operating systems or callbacks based on certain other agents. These “Command Augmentation” containers process the command like normal, but instead of handing that finished command to the agent for execution, it’s handed to another agent’s container for further processing.

Forge is the first “Command Augmentation” container released on the MythicAgents GitHub organization. The Forge Docker image is built with all of Flangvik’s SharpCollection compiled assemblies and Sliver’s Armory of compiled BOFs. Forge offers a few management commands that allow you to list out collections of commands, register assemblies/BOFs within your callbacks, add support for other agents, and more. Let’s look at two examples of what Forge can do.

.NET Assembly Support

Forge Collections SharpCollection

The forge_collections command allows you to list out the available commands that are part of a collection. The SharpCollection and SliverArmory collections exist by default, but you can add new ones at any time. In the output above, we can see the ability to re-download the command (this fetches the .NET versions again from GitHub and can be helpful if there’s a new version released), to register the command (make it available to execute), and some information about the command name and what the assembly does. Clicking the download or register buttons will register the command within this callback and all callbacks that have support with Forge. Let’s say we click the register button for the Rubeus entry. We’ll get a new command we can issue called forge_net_Rubeus; the name of this command allows you to easily identify commands added as part of Forge and if this is a .NET command or a BOF command.

New assembly commands always have the same arguments: the argument string that’s passed to the .NET assembly, the version of the assembly to use, and if this should be executed via execute_assembly (fork-and-run) or inline_assembly (in process).

Forge .NET Parameters

These parameters are always the same for each .NET assembly because in the offensive security community, .NET assemblies are made to take in a single string and do the parsing themselves instead of using named parameters.

BOF Support

Forge Collections Sliver Armory

BOF support in Forge works a little differently thanks to the amazing work that the Sliver team did for their Armory plugins. Unlike .NET assemblies, BOFs have a very specific set of arguments they take, in a specific order, and with specific formats. Many people use BOFs with Cobalt Strike, so they have Aggressor Scripting files created for them that describe these parameters. Unfortunately, this format isn’t usable outside of Cobalt Strike, but the Sliver team went above and beyond to convert many of these to JSON. As part of this, the Sliver team has forked versions many common BOF projects (e.g., https://github.com/sliverarmory/CS-Situational-Awareness-BOF) where they store compiled versions of the BOFs and this converted JSON data in tagged releases.

Forge hooks into their work by fetching the latest tagged release for the command you want to register and extracts the object files along with the extension.json file that describes the BOF’s arguments. Since Mythic already supports defining commands with named parameters, their types, and their orders, Mythic can use the extension.json file to dynamically create Mythic styled parameters.

BOF Argument Support

In this example, the BOF command forge_bof_sa-netgroup , takes three parameters: a number (0 or 1 based on the description) and two strings. Due to Sliver’s format, we can even identify which arguments are required and which ones are optional. Unfortunately, we miss additional context about default values that could be pre-populated, so that’s still up to the individual BOFs or for them to call out in their parameter descriptions.

When an operator submits this task, Forge looks up the associated extension.json file and converts these named parameters back into a normal Mythic TypedArray format that is then passed to a supporting agent’s command (like Apollo’s execute_coff ) for processing before a callback picks it up.

Normally, BOF execution requires an operator to upload the right object file, know the exact types and orderings of parameters for the bof (ex: zisZZZ), and provide the right values in that order. This would require execution like some_bof_command zisZZZ test 3 0 bob testing.com Mozilla. Naturally, this is error prone and not very operator friendly. With Forge, you could instead issue a task like forge_bof_myBof -location test -loops 3 -useAdmin 0 -user bob -domain testing.com -useragent Mozilla. Notice how, especially with all of the parameters being tab-completable, it’s much more operator friendly, especially if you don’t already know all of the parameters needed for the BOF.

Forging Forward

Forge is based on a series of JSON files on disk that describe things like what agents work with Forge, what collections are available, and what commands are available in each collection. You aren’t limited to SharpCollection and SliverArmory though. With the forge_create command, you can upload your own .NET assembly or BOF files (including extension.json) and have those turned into new commands on the fly. If you want to set this up ahead of time though, you can always edit the JSON files directly on disk or through the Mythic UI.

Forge comes with default support for the Apollo and Athena agents, but pull requests are always welcome to provide default support for other agents as well. Additionally, only Flangvik’s SharpCollection and Sliver’s Armory are pre-installed in the container. If the community has other sources of tooling they’d like to see pre-installed, PRs are also welcome.

Mythic has many different kinds of containers and features available, so hopefully Forge will inspire the community about other kinds of “Command Augmentation” containers they can make.

If you aren’t already aware, the BloodHound slack has open invites with a thriving community that discusses Mythic in the #mythic channel. I’m also available on Twitter, BlueSky, and Mastodon if you want to reach out.


Forging a Better Operator Quality of Life was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌