Analyzing Golang Executables [UPDATED]
The Go Reverse Engineering Tool Kit (go-re.tk) is a new open-source toolset foranalyzing Go binaries. The tool is designed to extract as much metadata aspossible from stripped binaries to assist in both reverse engineering andmalware analysis.
Analyzing Golang Executables
Since C++ type names are usually stored in their mangled form, we've also added a MSVC symbol demangler to Malcat. Virtual methods, as well as PE imports and exports names will be demangled for MSVC-compiled executables.
But starting from version 1.16, Golang slightly changed the format of the PcLn table, which made Malcat miss this useful information for recent Golang binaries. Well, this problem has now been fixed. If you had issues analyzing recent Golang binaries, try reanalyzing with Malcat 0.8.0.
edit: the question is about executables programmed in go language in general and how to automatically discover transitive dependencies of those executables as part of executing vulnerability scan for a target system.
I understand that you want some vulnerability scanning/auditing that is capable to find vulnerabilities on Go executables by inspecting it. I already read some articles that fit on keywords such as "golang vulnerable function" expecting to encountering some lack of security functions alike in C language that fight against stack overflow (i.g., strcpy, gets, sprintf, ...), memory adjacent overflow (i.g., strncpy, strncat, ...) and on and on. However, I haven't found ways to discover flaws this way, but as you aforementioned on several CVE listed in CVEDetails, these known vulnerabilities are possible to detect using NIST National Vulnerability Database (usually used into an unauthenticated vulnerability scanning, that's why some vulnerability scanning can found some flaws without requires credentials - i.e., Nmap and Nessus) and you can also use the vulnerability auditing method such thing like Open Vulnerability Assessment Language (aka OVAL Language - An open and publicly available security content, and to standardize the transfer of this information across the entire spectrum of security tools and services.1 -, usually used in authenticated scanning [i.e., OpenSCAP]), namely, you can read about that and create your own "rules" to detect those known vulnerabilities.
Those signatures, that support Go runtimes versions 1.10 through 1.16 (for x64 architectures, on Windows, Linux & Mac), can greatly improve the workflow of users as they allow them to quickly identifylibrary functions (which can usually be ignored). And, since Go executables are statically linked, large parts of the binaries can quickly be marked as library code.
Tracing is a way to instrument code to analyze latency throughout thelifecycle of a chain of calls. Go providesgolang.org/x/net/tracepackage as a minimal tracing backend per Go node and provides a minimalinstrumentation library with a simple dashboard. Go also providesan execution tracer to trace the runtime events within an interval.
If you're interested in analyzing or visualizing the dependencies for your application, then you might want to also check out the go mod graph tool. There's a great tutorial and example code for generating visualizations here.
There are a couple of experimental analyzers in golang.org/x/tools which you might want to try: nilness (which checks for redundant or impossible nil comparisons) and shadow (which check for possible unintended shadowing of variables). If you want to use these, you'll need to install and run them separately. For example, to install nilness you would run:
To my knowledge, no open-source golang projects exist to perform full memory dumps or even process memory dumps. Therefore, this Osquery-go extension leverages pre-existing tools such as DumpIT to perform full memory captures and ProcDump to perform process memory captures. The first iteration of this extension required the machine to have DumpIt and ProcDump on the machine and in a specific location. This approach causes a lot of headaches to ensure the following were all correct: Osquery is installed, Osquery extension is on the machine, Osquery is configured to use the extension, ProcDump and DumpIt are in the correct locations, and the machine has the required versions of DumpIt and ProcDump. All of these requirements create a logistical NIGHTMARE so I did some Googling and found the following golang project go-bindata.
This golang project allows you to compile static content such as binaries into your golang binary. So, now the logistical nightmare is reduced to Osquery is installed, Osquery extension is on the machine and Osquery is configured to use the extension. When the extension is loaded by Osquery, it unpacks the binaries for DumpIt and ProcDump to disk (See figure below). This means the maintainer of the Osquery extension controls what versions of DumpIt and ProcDump are used. When the binaries are written to disk there is a verification check to ensure the binaries on disk match the binaries being shipped with the Osquery extension. EVERY TIME this Osquery extension is used it does a verification check to ensure the binaries on disk have NOT been modified. If the binaries have been modified the extension will overwrite the binaries with the appropriate binary.
As the security team, you are in control of the applications being used for memory dumping and analysis so you should know the SHA256 hashes of those binaries. The golang byteexec package has a default location of C:\Users\\AppData\Roaming\byteexec to store binaries to disk. You may modify this location but the main point is that knowing the directory path is important for auditing. Lastly, the only process that should be invoking these memory tools is osqueryD. If these memory tools are invoked in any way that does not meet the criteria above, then you should generate an alert.
Mach-O files can contain a CODE_SIGNATURE segment, which contains all the information required to verify the integrity and origin of the file. In fact, all current versions of iOS require all executables to be signed, and this is now the case for Apple silicon macs running Big Sur:
The sample we will be analyzing in this post is named anabolic.exe (SHA256: 46d340eaf6b78207e24b6011422f1a5b4a566e493d72365c6a1cace11c36b28b). This file is a 64-bit executable compiled with Golang version 1.18.3.
## Part 1 - decrypting the trafficThe initial strategy was to look at the binary, looking for a key to decrypt traffic from the pcap. As said before, binary turned out to be a compiled GoLang. I wasn't experienced with reversing golang binaries, so initially I spent a lot of time learning about golang (I will link few useful sources on the bottom). There were few issues I was dealing with: * Golang compiler is passing all functions' arguments on the stack, while Ghidra insists since it is x64 binary it must follow an x64 callign convention. Due to this, arguments are all messed up in Ghidra both in disassembly and decompiler. I couldn't find easy and fast way to solve it during CTF so I was just making notes, what functions have what arguments. * Golang has a huge concurrency focus, related to so called goroutines. Not sure if this is directly related, but my x64dbg loved to switch context, even during single-stepping, which was quite annoying. In the end, I learned to not use single-stepping and just put a lot of breakpoint whenever I saw an interesting code. * On the bright side, Ghidra did well on recovering all function names and strings, which I read was an issue for some disassemblers in the past. So this at least made analyzis a little bit more convinent.
## ConclusionThis was a really well thought-through challenge, and kudos to the author. I appriciate a depth to this challenge, from analyzing GO biary, via decrypting traffic to analyzin a .NET binary and writing a decryptor. It all required a really broad set of reversing skills. I also liked an attention to little details like decryption key being derived from earlier saved registry keys etc. This put more challenge into this task, because once I thought I got this, there was always another issue to tackle.
A useful step in analyzing a solution with many projects would be to visualize the dependencies to understand which subset of assemblies depend on what. The general recommendation is to apply the results of the analysis in a bottom-up approach starting with the leaf nodes in a dependency graph.
An initial, static examination of the malware did not uncover much about its purpose as it was packed. There were a large number of portable executable (PE) sections in addition to odd section names, which is fairly common in packed executables. There were also a low number of imports and few meaningful strings; this is also common in packed executables.
So it seems that go tool pprof noticed that the filename in profile.pb was /home/bork/work/experiments/golang-pprof/leak_simplest, and then it just opened up that file on my computer and used that to get the function names. Neat!