blog.xlab.qianxin.com
Open in
urlscan Pro
121.32.243.76
Public Scan
URL:
https://blog.xlab.qianxin.com/a-deep-dive-into-the-zergeca-botnet/
Submission: On July 08 via api from IL — Scanned from IL
Submission: On July 08 via api from IL — Scanned from IL
Form analysis
0 forms found in the DOMText Content
奇安信 X 实验室 * Home * About * EN DDoS NEW THREAT: A DEEP DIVE INTO THE ZERGECA BOTNET * * ALEX.TURING, ACEY9 2024年6月19日 • 13 min read 1. Background 2. Sample & C2 Detection 3. Profile of 84.54.51.82 1. Scanner 2. Mirai Downloader&C2 3. Zergeca C2 4. Exploits 5. DDoS Statistics 4. Reverse Analysis 1. 0x00: String Decryption 2. 0x01: Persistence Module 1. Experiment A 3. 0x2: Silivaccine Module 1. Experiment B 4. 0x3: Zombie Module 1. Communication Protocol 2. Experiment C 5. Summary 6. IOC 1. Sample 2. Domain 3. IP 7. Appendix 1. IdaPython Script BACKGROUND On May 20, 2024, while everyone was happily celebrating the holiday, the tireless XLab CTIA(Cyber Threat Insight Analysis) system captured a suspicious ELF file around 2 PM, located at /usr/bin/geomi. This file was packed with a modified UPX, had a magic number of 0x30219101, and was uploaded from Russia to VirusTotal, where it was not detected as malicious by any antivirus engine. Later that evening at 10 PM, another geomi file using the same UPX magic was uploaded to VT from Germany. The suspicious file path, modified UPX, and multi-country uploads caught our attention. After analysis, we confirmed that this is a botnet implemented in Golang. Given that its C2 used the string "ootheca," reminiscent of the swarming Zerg in StarCraft, we named it Zergeca. Functionally, Zergeca is not just a typical DDoS botnet; besides supporting six different attack methods, it also has capabilities for proxying, scanning, self-upgrading, persistence, file transfer, reverse shell, and collecting sensitive device information. From a network communication perspective, Zergeca also has the following unique features: * Supports multiple DNS resolution methods, prioritizing DOH for C2 resolution. * Uses the uncommon Smux library for C2 communication protocol, encrypted via XOR. During the investigation of Zergeca's infrastructure, we found that its C2 IP address, 84.54.51.82, has been serving at least two Mirai botnets since September 2023. We speculate that the author behind Zergeca accumulated experience operating the Mirai botnets before creating Zergeca. On June 10, XLab command tracking system captured a vector 7 DDoS command that the current samples did not support, indicating that Zergeca's author is actively developing and updating, with new samples yet to be discovered. Our persistence paid off when we captured a new sample on the 19th that supports the vector 7. Currently, the detection rates for Zergeca samples and C2 are very low. Considering Zergeca's potential threat in DDoS attacks, we have decided to release this article to share our findings with the community. SAMPLE & C2 DETECTION From the sample perspective, we captured a total of 5 Zergeca samples. While their functions are nearly identical, there is a significant discrepancy in their detection rates. How can this anomaly be explained? Most antivirus vendors have categorized the sample 23ca4ab1518ff76f5037ea12f367a469 as Generic Malware. We speculate that the detection of Zergeca by antivirus software is based on file hash. Therefore, as long as the hash changes, the detection effectiveness diminishes. MD5 Detection First Seen Telemetry 23ca4ab1518ff76f5037ea12f367a469 28/64 2024.05.20 Russian 9d96646d4fa35b6f7c19a3b5d3846777 0/67 2024.05.20 Germany d78d1c57fb6e818eb1b52417e262ce59 1/67 2024.05.22 China 604397198f291fa5eb2c363f7c93c9bf 1/66 2024.06.11 France 60f23acebf0ddb51a3176d0750055cf8 0/67 2024.06.18 France To verify our hypothesis, we appended the 4-byte string "Xlab" to the end of the file 23ca4ab1518ff76f5037ea12f367a469 and re-uploaded it to VirusTotal. The detection rate changed to 9/67, partially confirming our speculation. Additionally, the current detection is based on the packed samples, after unpacking, the detection rate drops to 0. From the Domain Perspective, the four samples share two C2 domains that were created on the same day. The samples prioritize using DOH (DNS over HTTPS) for C2 resolution, which obscures the relationship between the samples and the C2 domains to some extent. Because of this, VirusTotal couldn't even associate the C2 domains with the samples, resulting in a naturally low detection rate. Domain Detection Create date ootheca.pw 1/93 2024.04.28 ootheca.top 1/93 2024.04.28 PROFILE OF 84.54.51.82 The two C2 servers of Zergeca point to the same IP address, 84.54.51.82. According to our data, this IP has been in use since September 2023, serving a variety of roles. During this period, it has acted as a Scanner, Downloader, Mirai botnet C2, and Zergeca botnet C2. SCANNER Starting from September 18, 2023, scanning activities commenced, primarily targeting protocols such as Telnet, HTTP, and socks4. The main ports scanned include23, 8080, 3128, 80, and 8888. MIRAI DOWNLOADER&C2 From September and October 2023 to April 2024, 84.54.51.82 was primarily used as the Loader IP and Downloader IP for the Mirai botnet. * 2023.09 - 2023.10, it was used as the Loader and Downloader IP to implant the following related samples. #Downloader http://84.54[.51.82/jaws http://84.54[.51.82/bin http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.x86 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.spc http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.sh4 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.ppc http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.mpsl http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.mips http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.m68k http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.i686 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.arm7 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.arm6 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.arm5 http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.arm http://84.54[.51.82/596a96cc7bf9108cd896f33c44aedc8a/db0fa4b8db0333367e9bda3ab68b8042.arc #CC mirai://bot.hamsterrace.space:59666 * 2024.04, it was used as the Loader IP to implant the following related samples. #Downloader http://145.239[.108.150/Fantazy.sh http://145.239[.108.150/Fantazy/Fantazy.arm5 http://145.239[.108.150/Fantazy/Fantazy.arm6 http://145.239[.108.150/Fantazy/Fantazy.mpsl http://145.239[.108.150/Fantazy/Fantazy.sh4 http://145.239[.108.150/Please-Subscribe-To-My-YT-Channel-VegaSec/1isequal9.x86 http://145.239[.108.150/cache # CC mirai://145.239.108.150:63645 ZERGECA C2 Starting from April 29, 2024, 84.54.51.82 began being used as the C2 server for Zergeca. The relevant C2 domains and their resolution records are as follows: EXPLOITS In our observation, the primary methods used by 84.54.51.82 to propagate samples are Telnet weak passwords and certain known vulnerabilities. The relevant vulnerability identifiers are as follows: Telnet Weak Password CVE-2022-35733 CVE-2018-10562 CVE-2018-10561 CVE-2017-17215 CVE-2016-20016 DDOS STATISTICS From early to mid-June 2024, the Zergeca botnet primarily targeted regions such as Canada, the United States, and Germany. The main type of attack was ackFlood (atk_4), with victims distributed across multiple countries and different ASNs. REVERSE ANALYSIS The four Zergeca samples in our observation are all designed for the x86-64 CPU architecture and target the Linux platform. The presence of strings like "android," "darwin," and "windows" in the samples, along with Golang's inherent cross-platform capabilities, suggests that the author may eventually aim for full platform support. This article focuses on the earliest captured sample for detailed analysis. The sample is packed with UPX and has a magic number of 0x30219101. For this type of modified UPX packer, simply changing the magic back to the standard "UPX!" allows for unpacking with the command upx -d. MD5:23ca4ab1518ff76f5037ea12f367a469 Mgaic:ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, corrupted section header size Packer: UPX Version:0.0.01c After unpacking, it becomes evident that Zergeca is a botnet implemented in Go language. The symbols are not obfuscated, making reverse analysis relatively straightforward. The figure above shows a code snippet of the main_main function. Functionally, it can be broken down into four distinct modules. The persistence and proxy modules are self-explanatory, with the former ensuring persistence and the latter handling proxying. The silivaccine module is used to remove competing malware, ensuring exclusive control over the device. The most crucial module is zombie, which implements the full botnet functionality. It reports sensitive information from the compromised device to the C2 and awaits commands from the C2, supporting six types of DDoS attacks, scanning, reverse shell, and other functions. 0X00: STRING DECRYPTION Zergeca uses XOR encryption for many sensitive strings. Using IDA, we found that the XOR key is referenced 240 times across various functions. Each decryption involves two uses of the XOR key: one for initialization and one for decryption. So there are 120 decryption operations needed. The XOR key is initially set to EC 22 2B A9 F3 DD DF 1C CD 46 AC 1E, but only the first six bytes (EC 22 2B A9 F3 DD) are used. Manually decrypting 120 times is impractical. Although the decryption process isn't confined to a single function, CFG analysis revealed a specific pattern in most decryption-related code blocks: 1. The XOR block has one predecessor and one successor. 2. The predecessor block's first instruction is mov, with the first operand being an address pointing to the original length of the XOR key. 3. The successor block's first instruction is cmp, with the first operand being a number indicating the ciphertext's length. 4. The predecessor block's predecessor's first instruction is lea, with the first operand being an address pointing to the ciphertext's starting address. By identifying these patterns, we can automate the decryption process and restore all encrypted strings efficiently.We implemented IdaPython decryption script in the Appendix with the following results: 111 successful decryptions and 9 mismatches. The 9 mismatched codes are distributed across six functions. Among them, the packets__Cursor Read/WriteString functions handle network packet encryption/decryption and can be ignored. gomi_bot_zombie__Zombie_Connect geomi_common_utils_init_0_func1, geomi_bot_discovery_Run, geomi_common_packets__Cursor_WriteString, geomi_common_packets__Cursor_ReadString, geomi_common_utils_RandomUserAgent For the remaining four functions, the issue was that the ciphertexts were arrays rather than single entries, causing the pattern match to fail. For example, in the RandomUserAgent function, the user_agent_list contains 1000 encrypted user agents. For such cases, we can use the manual_decode function, where the first parameter is the starting address of the ciphertext array and the second parameter is the number of array elements. ey=b"\xEC\x22\x2B\xA9\xF3\xDD" def manual_decode(base,cnt): for i in range(cnt): start=idc.get_qword(base) addr=idc.get_qword(start+i*16) size=idc.get_qword(start+8+i*16) buff=idc.get_bytes(addr,size) out=bytearray() for k,v in enumerate(buff): out.append(v ^ key[k%6]) print(out.decode()) manual_decode(0x000000000C56FA0,1000) #user agent manual_decode(0x0000000000C56F80,0xc) #opennic dns manual_decode(0x000000000C56C40,2) # c2 Decrypted examples include various user agents, OpenNIC DNS server, and C2s. With all strings successfully decrypted, we can now begin reverse-engineering Zergeca's various functionalities. 0X01: PERSISTENCE MODULE Zergeca achieves persistence on compromised devices by adding a system service geomi.service. This service ensures that the Zergeca sample automatically generates a new geomi process if the device restarts or the process is terminated. [Unit] Description= Requires=network.target After=network.target [Service] PIDFile=/run/geomi.pid ExecStartPre=/bin/rm -f /run/geomi.pid ExecStart=/usr/bin/geomi Restart=always [Install] WantedBy=multi-user.target EXPERIMENT A When running the Zergeca sample on a virtual machine and restarting the device, geomi.service automatically launches the Zergeca sample. The resulting process named geomi had a PID of 897. Terminating this process with kill -9 897 immediately spawned a new geomi process with PID 8460. When network administrators discover a geomi process and suspicious traffic on a device, they can attempt the following cleanup steps: 1. Delete /etc/systemd/system/geomi.service 2. Delete the sample file referenced by the ExecStart parameter 3. Terminate the geomi process 0X2: SILIVACCINE MODULE To monopolize the device, Zergeca includes a list of competitor threats, covering miners, backdoor trojans, botnets, and more. Some familiar names on the list include mozi, kinsing, and various mining pools. Zergeca continuously monitors the system and terminates any process whose name or runtime parameters match those on the list, deleting the corresponding binary files. Mozi.a com.ufo.miner kinsing kthreaddi kaiten srv00 meminitsrv .javae solr.sh monerohash minexmr c3pool crypto-pool.fr f2pool.com xmrpool.eu ......... EXPERIMENT B We renamed the system program /bin/sleep to Mozi.a and ran it. The Mozi.a process was killed, and the corresponding binary file was deleted. 0X3: ZOMBIE MODULE Zergeca resolves the C2 IP address using the geomi_common_utils_Resolve function, which supports four resolvers: Public DNS, Local DNS, DoH (DNS over HTTPS), and OpenNIC. Zergeca prioritizes two DoH resolvers, masking C2 domain resolution in DNS traffic. https://cloudflare-dns.com/dns-query https://dns.google/resolve After obtaining the C2 IP, the bot reports device sensitive information encapsulated in a DeviceInfo structure, including details like "country, public IP, OS, user groups, runtime directory, and reachability". struct DeviceInfo { Country string PlucAddress byte[] MAC string OS string ARCH string Name string MachineId string Numcpu uint32 CPUMODEL string username string uid string gid string Users []string Uptime time.Duration PID uitn32 Path string checksum []uint8 version string Reachable bool } The bot then awaits commands from the C2, processing them with different handlers. The supported functions are as follows: ID Task 0x01 Proxy 0x02 Reverse Shell 0x03 FileTransfer 0x05 Self-update 0xa0 DDoS 0xb0 Stop Discovery 0xb1 Start Discovery The DDoS functionality supports the following seven attack vectors: Sub-ID Attack Vector 1 minecraft 2 httpPPS 3 synFlood 4 ackFlood 5 pushFlood 6 rstFlood 7 pushOVHFlood COMMUNICATION PROTOCOL Zergeca uses smux for Bot-C2 communication. Smux(Simple MUltipleXing) is a Golang multiplexing library that relies on underlying connections like TCP or KCP for reliability and ordering, providing stream-oriented multiplexing. Smux packets feature an 8-byte header: VERSION(1B) | CMD(1B) | LENGTH(2B) | STREAMID(4B) | DATA(LENGTH). From an analysis perspective, only the LENGTH and DATA fields are of primary concern. The captured traffic includes various messages such as online status, device information reporting, command 0xb0, and heartbeat messages. Online Message: * Length: 0x04 bytes * Content: Hardcoded 13 3a 12 79 Device Info Report: * Length: 0xd5 bytes (varies by device) * Content (excluding IP): XOR encrypted with key EC 22 2B A9 F3 DD * Decrypted DeviceInfo as follows pos: 0x4 len: 0x2 <----> b'JP' pos 0x7 len: 4 <----> 45.14.XX.XX pos: 0xc len: 0x11 <----> b'72:ba:29:e9:b8:08' pos: 0x1f len: 0x5 <----> b'linux' pos: 0x26 len: 0x5 <----> b'amd64' pos: 0x2d len: 0x6 <----> b's22262' pos: 0x35 len: 0x20 <----> b'b19642a3c672d4f20cbdb5b1569bf98f' pos: 0x5b len: 0x29 <----> b'Intel(R) Xeon(R) CPU E5-2678 v3 @ 2.50GHz' pos: 0x86 len: 0x4 <----> b'root' pos: 0x86 len: 0x4 <----> b'root' pos: 0xa2 len: 0x2 <----> b'\x92\xf1' pos: 0xa6 len: 0xe <----> b'/usr/bin/geomi' pos: 0xb6 len: 0x14 <----> b'r\xbd>\xcfY\x15[\xd9]\xa4\xe7m\x86\x9f\xbf\x895\xaa\x19\xe8' pos: 0xcc len: 0x7 <----> b'0.0.01c' Command 0xb0 Message: * Length: 0x08 bytes * Function: Stop scanning Heartbeat Message: * Length: 0x03 bytes * Content: ff 00 00 Let's take a look at the DDoS-related packets. The format is cmd (1 byte) + length (2 bytes) + sub_cmd (1 byte) + target_info (length-1), where cmd is 0xa0, indicating a DDoS command, and sub_cmd is 0x4, indicating an ACK flood attack. The target_info field focuses on the first 4 bytes, which represent the target IP. For example, 1f 06 10 21 corresponds to the IP address 31.6.16.33. When the Bot receives the aforementioned command, the resulting attack traffic aligns perfectly with our analysis. EXPERIMENT C Based on our network protocol analysis, we implemented a fake C2 to control the Bot and observe its behavior upon receiving different commands. In this experiment, we sent the Bot a 0xb1 command, which is to "start scanning." Upon receiving this command, the Bot immediately began scanning 16 ports on randomly generated IP addresses. SUMMARY Through reverse analysis, we gained initial insights into Zergeca's author. The built-in competitor list shows familiarity with common Linux threats. Techniques like modified UPX packing, XOR encryption for sensitive strings, and using DoH to hide C2 resolution demonstrate a strong understanding of evasion tactics. Implementing the network protocol with Smux showcases their development skills. Given this combination of operational knowledge, evasion tactics, and development expertise, encountering more of their work in the future would not be surprising. This is our basic intelligence of Zergeca. We welcome unique insights from other companies, such as Init Access. And readers can contact us on Twitter for more details. IOC SAMPLE 23ca4ab1518ff76f5037ea12f367a469 9d96646d4fa35b6f7c19a3b5d3846777 d78d1c57fb6e818eb1b52417e262ce59 604397198f291fa5eb2c363f7c93c9bf f68139904e127b95249ffd40dfeedd21 d7b5d45628aa22726fd09d452a9e5717 6ac8958d3f542274596bd5206ae8fa96 pathced with "xlab" at the end of file 980cad4be8bf20fea5c34c5195013200 sample captured on 2024.06.19, support ddos vector 7 60f23acebf0ddb51a3176d0750055cf8 DOMAIN ootheca.pw ootheca.top bot.hamsterrace.space IP 84.54.51.82 The Netherlands|None|None AS202685|Aggros Operations Ltd. APPENDIX IDAPYTHON SCRIPT # Test script, only for 23ca4ab1518ff76f5037ea12f367a469 # Modidy keyaddr,sizeaddr in your case def decode(buf): key=b"\xEC\x22\x2B\xA9\xF3\xDD" out=bytearray() for i in range(len(buf)): out.append(buf[i]^key[i%6]) return out count=0 notcount=0 failedfunc=[] successedfunc=[] keyaddr=0x0000000000C56FC0 sizeaddr=0x0000000000C56FC8 refs=XrefsTo(keyaddr, flags=0) for ref in refs: f_blocks = idaapi.FlowChart(idaapi.get_func(ref.frm), flags=idaapi.FC_PREDS) for blk in f_blocks: if blk.start_ea!=ref.frm: continue if len(list(blk.preds()))!=1 and len(list(blk.succs()))!=1: continue predblk=list(blk.preds())[0] succsblk=list(blk.succs())[0] if idc.get_operand_value(predblk.start_ea,1)!=sizeaddr: continue if idc.get_operand_type(succsblk.start_ea,1)!=0x5: print(idc.get_func_name(ref.frm),hex(ref.frm),"not matched") notcount+=1 failedfunc.append(idc.get_func_name(ref.frm)) continue ppredblk=list(predblk.preds()) if len(ppredblk)!=1: continue addr=idc.get_operand_value(ppredblk[0].start_ea,1) size=idc.get_operand_value(succsblk.start_ea,1) buf=idc.get_bytes(addr,size) out=decode(buf) count+=1 print(idc.get_func_name(ref.frm),hex(ppredblk[0].start_ea),"matched, ciphertext at", hex(addr), "<---->",bytes(out)) successedfunc.append(idc.get_func_name(ref.frm)) print("\n--------------------Statistic--------------------") print(f'Success:{count},Failed:{notcount}\n') print("---------Success Function---------") print(set(successedfunc),'\n') print("---------Failed Function---------") print(set(failedfunc),'\n') Please enable JavaScript to view the comments powered by Disqus. 奇安信 X 实验室 © 2024 * RSS Powered by Ghost