Order Of Six Angles

Main Logo

Х.Р.А.М Сатаны

Home | RU | Translations | Art | Feed.xml

9 July 2022

tags: linux - malware analysis

Calculation of approximate (minimum) timestamp for golang elf malware


Timestamp (or compilation date) is one of the main characteristics of malware. It allows you to understand whether the sample is new, whether the sample has been used in other attacks and give an idea of when the attack was approximately prepared. But what if the malware sample has ELF format, which, as you know, does not save the compilation date?

Golang malware has become very popular over the past few years.

1. Sandworm-Team (Exaramel-Linux)
2. APT28 Zebrocy
3. Ekans
4. Kinsing (miner)
5. Mustang Panda 
6. Rocke
7. APT29 WellMess/WellMail
8. Gobot
9. rocke
10. htran
11. goodor
12. FritzFrog
13. Gobrut
14. Geacon
15. Kaiji
17. Carbanak
18. Veil
19. AgeLocker
20. Notrobin
21. r2r2
22. Blackrota
23. IPStorm
24. RobbinHood
25. TinyBanker
27. NEsha
28. Hercules
29. Gandalf
30. RDW
31. hershell
33. braincrypt
34. Klingon RAT

The universality of the language allows you to compile the same source code for different architectures and operating systems, including Linux (as an ELF file).

I recently watched a video Golang Malware: Using the attackers force against them which has an interesting point. The point is that it is possible to calculate an approximate timestamp of a binary using dependencies. The calculation algorithm from the video is as follows:

  1. We take golang ELF malware
  2. Get a list of dependencies
  3. Get the dependency version
  4. Get the date of a specific version (release) of the dependency
  5. Create a list of dates
  6. We take the latest date, it will be the approximate (minimum) timestamp


I decided to implement this idea in the code. The gore project was used to get the dependencies. Keep in mind that dependencies can only be obtained from a binary if it has a gopclntab section. We will consider the Kinsing malware sample as an example. Kinsing is a golang linux malware that runs the miner. gore returns a list of dependencies like this:


If you look closely, you’ll find that Golang represents dependency versions in three ways:




In the first form, the version of the dependency is always v0.0.0, that is, the dependency has no releases, which means that the version string itself contains the creation date. Therefore, we simply take the date from the string.

In the second form, incompatible means that the dependency does not have a go.mod file and has a version greater than 2. We discard the word incompatible and take only the version.

In the third form, we have nothing but a version, so we move on to the next step.

Knowing only the version of the dependency, we can try to get the release date using the golang library for working with GithubAPI. Let’s look at the dependency \go\pkg\mod\github.com\tklauser\go-sysconf@v0.3.10 as an example. Since not all repositories have releases but only tags, the ListTags method is used. owner and repo in this case will be tklauser and go-sysconf

tags, resp, err := client.Repositories.ListTags(context.Background(), owner, repo, nil)

The response has info about each tag (release)

The tag has a commit field with a SHA field. Using the Github Commit API we get commit information

commit, resp, err := client.Repositories.GetCommit(context.Background(), owner, repo, sha, nil)

The response will contain the date of the commit.

Now we have specific date for a specific dependency. We find the latest date among result. This date is the approximate (minimum) timestamp of the sample:

Source Code Link