What the Bin? Nim, Golang, C++
We've seen offensive tools and/or malware written in Golang and Nim, it's no new news. However, recently we've seen a lot of people in the infosec community discussing Nim and that sparked our interest.
We asked the following questions:
- How do the binaries differ during initial analysis?
- Is it possible to quickly detect if a binary was written in Nim or Golang?
We found that there was a Yara rule written by SentinelLabs on Github which detects Golang bins. We couldn't find anything for Nim binaries at the time of this writing and we attempt to see if we can build one.
Process
We will go into the following process shortly:
- Produce test binaries using default configs
- Analyze the binaries
- Attempt to produce Yara rule(s)
- Run rule(s) against test binaries and malware
- Additional Nim Testing:
- Release Build
- DLLs
Test Bins
Code
The picture above contains the code which was compiled to produce the test binaries. They achieve the same simple goal of printing "hello world".
Compilation
"The /EHsc command-line option instructs the compiler to enable standard C++ exception handling behavior.Without it, thrown exceptions can result in undestroyed objects and resource leaks. For more information, see /EH (Exception Handling Model)." - Microsoft docs
Analyzing the Binaries
Bin Sizes
Golang is known to produce large binaries, and that can be seen below:
Lang | Arch | Size |
---|---|---|
C++ | 32bit | 174KB |
C++ | 64bit | 223KB |
Go | 64bit | 1,848KB |
Nim | 64bit | 181KB |
A Look at the Sections
We noticed that the Golang and Nim bins we produced contain much more sections than the C++ bin.
While C++'s bin contained 6 sections the Nim bin contained 16 and Golang's contained 13:
A Look at the File Header
We found that the "IMAGE_FILE_LINE_NUMS_STRIPPED" flag in the nim bin's characteristics field to be interesting and took note of it.
A Look at the Imports
We noticed that only the Nim binary was importing the msvcrt.dll. Surely we can't use this for detection, it is just interesting.
A Look at Nim’s Strings
That's a lotta Nims. Note that we used choosenim to install Nim.
Attempt to Produce Yara Rule
Putting everything interesting we found thus far which is:
- IMAGE_FILE_LINE_NUMS_STRIPPED flag in the characteristics field
- Multiple occurrences of ".nim" in the strings
We wrote and tested the following Yara rule
import "pe"
rule IsNim : Nim{
meta:
desc = Identify windows Nim binaries (PE)"
author = "Humoud Al Saleh"
version = "1.0"
last_modified = "11.06.2022"
strings:
$a1 = ".nim" ascii
condition:
pe.is_pe and $a1 and pe.characteristics & pe.LINE_NUMS_STRIPPED
}
We also added Sentinel Lab's rule from Github to our rules file, and added the "Go" tag to it:
// https://github.com/SentineLabs
rule TTP_GoBuildID : Go
{
meta:
desc = "Quick rule to identify Golang binaries (PE,ELF,Macho)"
author = "JAG-S @ SentinelLabs"
version = "1.0"
last_modified = "10.06.2021"
strings:
$GoBuildId = /Go build ID: \"[a-zA-Z0-9\/_-]{40,120}\"/ ascii wide
condition:
(
(uint16(0) == 0x5a4d) or
(uint32(0)==0x464c457f) or
(uint32(0) == 0xfeedfacf) or
(uint32(0) == 0xcffaedfe) or
(uint32(0) == 0xfeedface) or
(uint32(0) == 0xcefaedfe)
)
and
#GoBuildId == 1
}
Run Rule Against Test Binaries and Malware
We gathered a collection of binaries written in Nim and Golang from:
- https://bazaar.abuse.ch/browse/tag/golang
- https://bazaar.abuse.ch/browse/tag/Nim
- https://github.com/HuskyHacks/the-crown-defcon615 (Nim bins)
Many thanks to them!
We threw all the bins in one directory in preparation for testing the rule:
Now, the directory contains C++ binaries, zip archives, Nim binaries, and Golang binaries.
For reference and convenience, the following image contains of a list of binaries in the directory:
Yara scan
We filtered the results to make them more readable:
TTP_GoBuildID [Go]:
all_bins\1c55d4144572be0ee5f5f95d9ce655549a7d0f55c74d576f649a85c323b31a63.go
all_bins\8b6d63b2b7829c89877231c11bbcb8984abab9a344e918780bea6d0cf4632bc5.go
all_bins\af5e6a5e0d4c63665c642e7c6f82345c77e05c67ea7efb8fc881c46117248765.go
all_bins\e6d6100cc97057cd00751ef5ac18261f7796868a420b4507144e9de0a7e80784.go
all_bins\golang_helloworld.exe
IsNim [Nim]:
all_bins\a3af3d7e825daeffc05e34a784d686bb9f346d48a92c060e1e901c644398d5d7.nim
all_bins\07e0b509288c501c57cc8f11b88ac8c06e379b01b74cd910d93cfdff1f9dd7ec.nim
all_bins\397e4dc12d48fb0c4d80980643581c9416a4bed022d4676f30218fb1f1e1811c.nim
all_bins\nim_helloworld.exe
all_bins\nim_shellexec.exe
all_bins\socket.exe
No misses or false positives.
Additional Nim Testing
Release Build
Compile options and arguments can be passed to the Nim compiler, we decided to take a look at the compilation options and generated a release build.
We noticed that it included less "nim"s in the strings:
Characteristics field still had the IMAGE_FILE_LINE_NUMS_STRIPPED flag:
Thus the Yara rule would detect it as a Nim Bin.
DLL
Decided to test the Yara rule against a DLL release build. For the source code we went with byt3bl33d3r's offensive Nim repo on Github, we took the source code from the examples:
We noticed the generated DLL contained both the strings and the IMAGE_FILE_LINE_NUMS_STRIPPED flag.
Running the Yara rule against Nim bins dir:
Thus far the rule detected debug and release Nim Windows bins, exe's and dll's.
Concerns
We will list concerns in the form of questions:
- What if obfuscation was used?
- Can the IMAGE_FILE_LINE_NUMS_STRIPPED flag be unset during the compilation of a nim binary?
Sources
The following is a Github repo with the Yara rule and source code used to generate the test bins
Resource
This is a nice resource for those that wish to do further reading:
Author
Humoud Al Saleh:
- Twitter
- Github
- More posts...