After the disruption of the Trickbot botnet by Microsoft and “allies”, it had become quiet about Trickbot. At least for a couple of days. Just a few days after the partial takedown, comrade Emotet came to the rescue and executed Trickbot on infected systems  .
If you work on Trickbot, especially extracting Trickbot configs, you probably haven’t missed that something has changed in the last weeks. I recently downloaded some newer samples from Malware Bazaar and was wondering, why my config extraction did not work. So I started debugging my code and fixed it but something was strange.
Let’s take 6ca141e8ed2443113c9e497d231b93cf41d86b224993c48f589b375a830cd27c for example.
The extracted config looks like this:
<mcconf> <ver>100001</ver> <gtag>rob3</gtag> <servs> <srva>22.214.171.124:1273</srva> <srva>126.96.36.199:39938</srva> <srva>188.8.131.52:25317</srva> <srva>184.108.40.206:10616</srva> <srva>220.127.116.11:58232</srva> </servs> <autorun> <module name="pwgrab"/> </autorun> </mcconf>
Normally, the port number looks different and there are usually much more C2’s inside the config. When I looked into a sandbox report, I could also see a C2 IP which is not included in the config.
As usual, the Trickbot config blob is XOR and AES encrypted so we have to find new functions which are executed after the config decryption and ideally taking the config decryption output as an argument. If you are using BinDiff, you should be able to spot it quite fast, just watch out for this beauty:
I reimplemented the function in python and it looks like its working fine.
# e.g. 18.104.22.168 def convert_to_real_ip(ip_str): result_octets =  octets = ip_str.split(".") o1 = int(octets) o2 = int(octets) o3 = int(octets) o4 = int(octets) x = ((~o1 & 0xFF) & 0xb8 | (o1 & 0x47)) ^ ((~o2 & 0xFF) & 0xb8 | (o2 & 0x47)) result_octets.append(str(x)) o = (o3 & (~o2 & 0xFF)) | ((~o3 & 0xff) & o2) result_octets.append(str(((~o & 0xff) & o4) | (o & (~o4 & 0xff)))) result_octets.append(str(o)) result_octets.append(str(((~o2 & 0xFF) & o4) | ((~o4 & 0xff) & o2))) return ".".join(result_octets) + ":443" fake_ips = ["22.214.171.124", "126.96.36.199", "188.8.131.52", "184.108.40.206", "220.127.116.11"] for item in fake_ips: print(convert_to_real_ip(item))
The output and thus the correct C2 IPs look as follows:
18.104.22.168:443 22.214.171.124:443 126.96.36.199:443 188.8.131.52:443 184.108.40.206:443
I hardcoded port
443 into my function because I could also see it hardcoded in the Trickbot code but there might be
other ports in the future as well. So far I only found the group tags
identical configs using those fake IPs.
If any of you have more samples using fake C2 IPs with other group tags or other configs, I would appreciate a hint.
220.127.116.11:443 18.104.22.168:443 22.214.171.124:443 126.96.36.199:443 188.8.131.52:443 6ca141e8ed2443113c9e497d231b93cf41d86b224993c48f589b375a830cd27c fc3da2468a121aff5433ea738221b5e9fd962c87041654b2c88f5291e0e15f22