Even though it cannot be said that Go is a new programming language (it is already more than ten years old), it does belong to that new batch of languages that, together with Rust, Typescript, Zig, etc., are becoming more and more popular in current times. Go was born, in a way, from Google’s need to find a substitute for the efficient but immensely complex C++. This complexity produced two undesirable effects in a company: very long compilation times and a shortage of engineers with a high level of knowledge, very necessary if you want to take advantage of the language (and not generate security flaws).
Thus, well-known names such as Rob Pike, Ken Thompson and others designed a programming language that would cover the needs described above. A language that would be secure, without memory errors that would result in security vulnerabilities, with reduced compilation times, multiplatform, Internet-oriented and concurrent programming. A priori, the task seemed like an insurmountable challenge, the squaring of a perfect circle.
But it worked, Go was (and is) simple, secure, powerful and modern. Its success is beyond doubt. It is already an ecosystem that has produced projects such as Docker, Kubernetes or CoreOS. Its syntax, which inherits the simplicity of the C language, has opened the doors to a huge number of programmers with its gentle learning curve and automatic memory management.
Is it this ease of use that has caused malware to adopt it as an “official” language?
One of the first opportunities to see Go used as part of a malware infrastructure was with the Mirai botnet (whose source code was released and can be read here). If you recall, Mirai focused on finding and detecting devices with easy or default passwords. It was a tremendous success and within days of going live it had millions of nodes under its control.
Although Mirai was written primarily in the venerable C language, its control centre (C2) was written in Go:
Those who design and program malware are not much different from a developer except for the obviously malicious intentionality. In the end, it is a well-defined evolutionary process that includes updates, improvements and bug fixes with the continuous release of new versions. We also cannot forget that the life of malware is short and ends when the anti-virus industry deploys the signatures necessary for detection. New versions of the same malware can increase that window of infection by slipping under the antivirus radar, if only momentarily.
Since the creation of malware is not very different from that of ordinary software, tools remain common and are no stranger to changing trends. Moreover, in Go they have found a tool with highly desirable features: cross-platform, automatic memory management, unit tests integrated into the language, etc.
Not only did they find a good tool, but in Go the binaries produced statically carry the libraries necessary for their execution, i.e., they do not need the system to have a specific library, they already include it embedded in the executable. This, however, causes the binaries to reach “abnormal” sizes, of several megabytes, a circumstance that can be ambivalent: it allows them to be characterised and, on the other hand, a large size hinders the automatic inspection of the binaries.
Is this enough for the relative success Go is having in its adoption of malware?
When an analyst is interested in a particular sample, he or she uses a set of tools to start to get an idea of what is in front of him or her. Between the static and dynamic analysis, a picture emerges that eventually paints a picture of a malware’s intentions.
Analysts have decades of experience dealing with executables produced by the usual compilers and overwhelmingly made in C or C++. Go binaries are structured differently and when opening them for inspection, the analyst encounters unfamiliar territory. The tools used therefore need to adapt to this new canon in order to find an agile analysis process.
While this is happening, malware writers see an added benefit in the fact that producing a Go binary allows them to slow down analysis and increase the window of malware activity.
A small sample, two basic programs, two “Hello World” in C and Go. Let’s look at their sizes:
Now, we will look at the number of functions (symbols) carried by each of the binaries produced:
As we can see, the Go binary not only carries the program, but also a group of functions from its standard library that allow us to print the classic “Hello World” sentence on the terminal. This behaviour can be reproduced by C if we had statically compiled everything necessary to perform the same function, but this is not common.
However, the number of functions should not daunt an experienced analyst. It is only chaff that needs to be removed until the true root of the binary, the behaviour coded by its authors, is reached. Thus, it is just a matter of adapting the already available reverse engineering and analysis tools to the new landscape.
By the way, if we stripe (delete debug information and symbols (function names, etc.)) from a binary in Go, the symbols (just like their C counterpart) disappear and make analysis even more difficult:
This is only the tip of the iceberg. There are many more problems for analysts to unravel: string detection, memory reservations, and so on. It all “looks” familiar to the binaries produced by other compilers, but it is different in the way that normal operations are performed. It’s like speaking assembler, but with a noticeably different accent.
Is this a strong trend to follow?
The number of malware samples grows daily in enormous proportions. Obviously, many are variants of the same family and there is a melting pot of programming languages on which they are designed and released.
As early as 2019, a study by PaloAlto Networks’ UNIT42 reported 13,000 unique malware samples created on Go. A couple of years later, the trend was being confirmed by other labs, with Intezer’s report, published last March, representing a 2000% growth since a few years ago
No only Go
Another modern programming language is Rust, born in the heart of Mozilla, now independent of the Firefox browser organisation. Nor is it free from being used by cybercriminals to include it in their arsenal of tools.
Interestingly enough, Rust, which is a language destined to be the replacement for the complex and enormous C++, has a meme called “Rewrite it in Rust”, which consists of asking projects that are not written in Rust to rewrite them in this language. Evidently, in a playful and mocking tone.
Well, it has happened for real in the malware world with “Buer”. This malware became known written in C language… until a few months, when they found a complete rewrite in Rust.
Malware is an industry, no wonder, and the processes that are inherent to industry eventually permeate it. The design, assembly, deployment, and quality chains are all modelled on those used by organisations. As we have seen, anything that gives a competitive advantage will be used using the latest trends in development.