{
	"id": "b19021c1-046c-47c6-ad11-cd1c33234dc6",
	"created_at": "2026-04-06T01:32:08.785964Z",
	"updated_at": "2026-04-10T03:30:30.894073Z",
	"deleted_at": null,
	"sha1_hash": "df4cab4f217485602ef6e5aa3a0c6b061bfd151d",
	"title": "Unpacking Colibri Loader: A Russian APT linked Campaign",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 442710,
	"plain_text": "Unpacking Colibri Loader: A Russian APT linked Campaign\r\nBy André Tavares\r\nPublished: 2022-11-30 · Archived: 2026-04-06 01:13:28 UTC\r\nBetween July and October 2022 Bitsight observed a ColibriLoader malware campaign being distributed by\r\nPrivateLoader, which was identified as being utilized by the threat actor UAC-0113, a group linked to Sandworm\r\nby CERT-UA. Sandworm is known to be a Russian advanced persistent threat (APT) group affiliated with The\r\nMain Directorate of the General Staff of the Armed Forces of the Russian Federation (GRU). In this research, we\r\npresent how to manually “unpack” a sample from a recent campaign. Unpacking means reaching the final stage of\r\nthe malware, which contains its main functionality. We also share some threat-hunting signatures and indicators of\r\ncompromise which can be utilized in defense and tracking efforts.\r\nColibriLoader is a Malware-as-a-Service family, first advertised on XSS.is cybercrime forum in August 2021 to\r\n\"people who have large volumes of traffic and lack of time to work out the material\" (Fig. 1). For $150/week or\r\n$400/month, it offers a small, unpacked, obfuscated loader written in C and assembly, along with a control panel\r\nwritten in PHP. As its name suggests, it’s meant to deliver and manage payloads onto infected computers.\r\nMoreover, the malware ignores systems from Commonwealth of Independent States countries (Armenian,\r\nAzerbaijani, Belarusian, Hungarian, Kazakh, Kyrgyz, Romanian, Russian, Tajik, Turkmen, Uzbek).\r\nFig. 1 - Post on XSS.is cybercrime forum by user “c0d3r_0f_shr0d13ng3r”\r\nPrivateLoader is a loader from a pay-per-install malware distribution service that has been utilized to distribute\r\ninfo stealers, banking trojans, loaders, spambots, rats, miners and ransomware on Windows machines. While\r\nmonitoring PrivateLoader malware distribution activity, we spotted ColibriLoader being distributed between July\r\nand October. Many security products automatically classified these samples and we noticed that all of them have\r\nthe tag “Build1”, which may represent the botnet or campaign id. Contradicting the author's advertisements, we\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 1 of 11\n\nnoticed some indicators suggesting that the samples are packed, such as their size, which should be around 20KB,\r\nand the fact that it contains only two sections, the .text and .reloc, which was not the case.\r\nIn order to evade antivirus security products and frustrate malware reverse engineering, malware operators\r\nleverage encryption and compression via executable packing to protect their malicious code. Malware packers are\r\nsoftware programs that either encrypt or compress the original binary, making it unreadable until it’s placed in\r\nmemory. In general, malware packers consist of two components, a packed buffer, the actual malicious code, and\r\nan unpacking stub responsible for unpacking and executing the packed buffer. Threat Actors make use of packers\r\nwhen distributing their malware as they remain an effective way to evade detection and make the malware harder\r\nto analyze. Manual analysis can defeat these protections and help develop tools that aid in this costly task.\r\nLet’s have a look at a sample dropped by PrivateLoader on September 4, 2022. First, we tried to use unpac.me\r\nservice to try to unpack it automatically but we were unlucky. So, let’s dive deep into this sample.\r\nResolving the Windows API\r\nOpening it on IDA Pro, on the main function (Fig. 3), we can see a pattern that seems to be a way of dynamically\r\nresolving some Windows API functions, which are usually crucial to understand the code behavior quickly. The\r\nmalware walks the process environment block (PEB), looking for the in-memory loaded modules base addresses\r\non the current process, finds the functions exported by each, hashes them, and compares it with the hash of\r\nLoadLibrary. Then, it calls LoadLibraryA to load kernel32.dll to get a module handle for it, but does not actually\r\nload it since it is already loaded by default, and then searches for the target export function (a more detailed\r\nexplanation can be found here). By searching on Google for the constants in the code that generates the hash, we\r\nconfirmed the hashing algorithm in use is Fowler–Noll–Vo.\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 2 of 11\n\nFig. 3 - Example of Windows API resolution.\r\nEncrypted Shellcode and Executable\r\nLooking a bit further through the code, we can spot what seems to be an XOR decryption of 520 bytes of\r\nshellcode at 0x454708, where the key is “2760”, and also the change in the protection of that region\r\n(VirtualProtect) to PAGE_EXECUTE_READWRITE (0x40), as well as four calls of a function within that region\r\n(Fig. 4). \r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 3 of 11\n\nFig. 4 - Shellcode decryption.\r\nWe can confirm it by disassembling the shellcode function at 0x4547A8 after running it on x32dbg (Fig. 5)\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 4 of 11\n\nFig. 5 - Decrypted shellcode #1 function at 0x4547A8.\r\nThis function allocates memory on the heap and copies some data to it. The size of the region to be allocated is on\r\nthe second argument. Going back to the main code, there’s XOR decryption done on each piece of data, and\r\nsubsequently a call to VirtualProtect to enable execution of the newly decrypted shellcode (Fig. 6). Their\r\narguments are what seems to be a file path, a pointer to an executable, what seems to be an XOR key, and\r\nprobably the size of the executable (0x12C00 bytes, or 76.8KB)\r\nFig. 6 - Decrypted executable at 0x78ECA80.\r\nAfter saving to file that executable and sending it to VirusTotal, we can see that it was already uploaded. Again, no\r\nluck on unpacking it with unpac.me. Entering the last decrypted shellcode, it seems to dynamically resolve some\r\nWindows API functions by passing a hash and then it creates a file at C:\\ProgramData\\conhost.exe (Fig. 7).\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 5 of 11\n\nFig. 7 - Decrypted shellcode #2.\r\nAfter running it, a file was indeed dropped at the expected location, which turns out to be the same file we\r\nmanually dumped. VirusTotal shows 173 executables dropping this file, most with compilation and first-seen\r\ntimestamps from September 2022. \r\nLet's have a look at the dropped file. Opening again on IDA Pro, looking at the main function, it seems very\r\nsimilar to the previous stage, almost a copy, with some minor changes. In the end, we can quickly spot the same\r\npattern of resolving VirtualProtect, calling it, and then calling the decrypted shellcode, just as seen before. After\r\nrunning on x32dbg with a breakpoint at that last call, we can see as before that the pointer to the newly decrypted\r\nexecutable is the second argument (Fig. 8). However, this time the size is not being passed as an argument, but we\r\ncan get it from other places, such as the call to a function that decrypts the executable, where the size to be\r\ndecrypted is passed on the first argument.\r\nFig. 8 - Decrypted executable at 0x7DCC838.\r\nGoing back, by putting a breakpoint on the call to decrypt the executable, we can see that the size is 0x5000 bytes\r\n(or 20KB). We can now extract the executable from memory and have a look at it. The file seems to be a valid\r\nexecutable with only two sections, .text and .reloc. There’s sufficient evidence to conclude that we have\r\nsuccessfully unpacked the ColibriLoader. \r\nAt the time of this research, this last stage was not yet on VirusTotal. Later, we found a quicker way of unpacking\r\nthe malware. We used this script to extract executables from memory dumps (from a sandbox run for example)\r\nand then the YARA rule we share below was used to find the Colibri sample.\r\nFinally, let’s have a very quick look at the actual malware. The first anti-analysis trick we encounter is called\r\nopaque predicates (Fig. 9); It’s a commonly used technique in program obfuscation, intended to add complexity to\r\nthe control flow. There are many patterns of this technique but in this case, the malware author simply takes an\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 6 of 11\n\nabsolute jump (JMP) and transforms it into two conditional jumps, jump if zero (JZ) and jump if not zero (JNZ).\r\nDepending on the value of the Zero flag (ZF), the execution will follow the first or second branch. However,\r\ndisassemblers are tricked into thinking that there is a fall-through branch if the second jump is not taken (which is\r\nimpossible as one of them must be taken) and try to disassemble the unreachable instructions (often invalid)\r\nresulting in garbage code.\r\nFig. 9 - Example of ColibriLoader opaque predicates anti-analysis technique.\r\nIn order for IDA Pro to load it properly, we need to patch the first conditional jump to an absolute jump and NOP\r\nout the second jump (Fig. 10). We’ve automated this task using myrtus0x0’s code since SmokeLoader also uses\r\nthis technique.\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 7 of 11\n\nFig. 10 - Patched ColibriLoader.\r\nThe last analysis we did was trying to extract the strings the malware uses, which will contain indicators of\r\ncompromise, such as command and control servers. After looking a bit through the code, it wasn’t hard to find the\r\nstring decryption function at 0x40594B since there are 71 cross-references for it, so it’s probably the most used\r\nfunction (Fig. 11 and 12).\r\nFig. 11 - Example call to the string decryption function.\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 8 of 11\n\nFig. 12 - String decryption loop from function at 0x40594B.\r\nThis code seems straightforward enough. Strings are encrypted with an XOR key passed as an argument to the\r\nfunction. Yet, we didn’t need to script this out because we’ve found a working IDA script from Casperinous. Here\r\nare the results:\r\n0x401faf %s\\\\%s\r\n0x401fd4 \\\\Microsoft\\\\WindowsApps\r\n0x401ffa Get-Variable.exe\r\n0x402020 powershell.exe -windowstyle hidden\r\n0x402046 %s:Zone.Identifier\r\n0x40229c %s\\\\%s\r\n0x4022c1 \\\\WindowsPowerShell\r\n0x4022e7 dllhost.exe\r\n0x40230d %s:Zone.Identifier\r\n0x402579 %s\\\\%s\r\n0x40259e \\\\Microsoft\\\\WindowsApps\r\n0x4025c4 Get-Variable.exe\r\n0x402706 %s\\\\%s\r\n0x40272b \\\\WindowsPowerShell\r\n0x402751 dllhost.exe\r\n0x4028e5 %s:Zone.Identifier\r\n0x402999 runas\r\n0x4029bf cmd.exe\r\n0x4029e5 /c %s%s%s %s\r\n0x402b49 %s\\\\rundll32.exe %s,%s\r\n0x402c4e %s /s\r\n0x402c74 runas\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 9 of 11\n\n0x402ca8 %s\\\\System32\\\\regsrv32.exe\r\n0x402cff %s\\\\SysWOW64\\\\regsrv32.exe\r\n0x402e48 /c %s%s%s %s\r\n0x402e6e cmd.exe\r\n0x402e94 open\r\n0x403041 %s%s\r\n0x403612 6rmUi1hRdfbV0QyXqAoT\r\n0x4037c0 /c chcp 65001 \u0026\u0026 ping 127.0.0.1 \u0026\u0026 DEL /F /S /Q /A %s%s%s\r\n0x4037e5 cmd.exe\r\n0x4038db Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\r\n0x403903 ProductName\r\n0x4039cc Unknown\r\n0x403c07 %08lX%04lX%lu\r\n0x403c81  /create /tn COMSurrogate /st 00:00 /du 9999:59 /sc once /ri 1 /f /tr \r\n0x403ca7 %s\\\\schtasks.exe\r\n0x403e4b %s\\\\schtasks.exe\r\n0x403e71  /delete /tn COMSurrogate /f\r\n0x404058 Content-Type: application/x-www-form-urlencoded\r\n0x404488 zpltcmgodhvvedxtfcygvbgjkvgvcguygytfigj.cc\r\n0x4044ad yugyuvyugguitgyuigtfyutdtoghghbbgyv.cx\r\n0x404582 /gate.php\r\n0x4045a8 hf9qkeO66MP7WJXkg9rp\r\n0x4045ce 2OrnJZG6Wtbzd4bKJoS0\r\n0x4045f4 %s?type=%s\u0026uid=%s\r\n0x40461a check\r\n0x404640 GET\r\n0x404666 HTTP/1.1\r\n0x40489d 1.2.0\r\n0x4048c3 Build1\r\n0x4048e9 /gate.php\r\n0x40490f hf9qkeO66MP7WJXkg9rp\r\n0x404934 2OrnJZG6Wtbzd4bKJoS0\r\n0x40495a %s?type=%s\u0026uid=%s\r\n0x404980 update\r\n0x4049a6 POST\r\n0x4049cc HTTP/1.1\r\n0x4049f2 %s|%s|%s|%s|%s|%s|%s\r\n0x404a18 32bit\r\n0x404a3e 64bit\r\n0x404d9c Build1\r\n0x404dc3 /gate.php\r\n0x404dec hf9qkeO66MP7WJXkg9rp\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 10 of 11\n\n0x404e13 2OrnJZG6Wtbzd4bKJoS0\r\n0x404e3a %s?type=%s\u0026uid=%s\r\n0x404e61 ping\r\n0x404e88 POST\r\n0x404eaf HTTP/1.1\r\n0x404ed6 %s|%s|%s|%s|%s|%s|%s\r\n0x4054d3 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\nThese decrypted strings also allow us to further reverse the malware more quickly if we need to. \r\nWe presented a way to manually unpack the ColibriLoader samples from a campaign linked to the threat actor\r\nUAC-0113. Later, we found a quicker way of unpacking the malware using the pe_extract.py script combined\r\nwith a YARA rule which detects unpacked samples of ColibriLoader, which we share below. All indicators of\r\ncompromise and threat-hunting rules can be found at https://github.com/bitsight-research/threat_research\r\nHere’s a YARA rule to detect packed ColibriLoader samples based on a typo:\r\nThe following YARA rule detects unpacked ColibriLoader samples based on the string decryption function. This\r\nrule was tested on VirusTotal and it returned few results with first-seen timestamps between September 2021 and\r\nNovember 2022.\r\nHere’s a Suricata rule to detect the ColibriLoader network traffic, specifically its C2 check-in request, tested with\r\na PCAP generated from a sandbox run of the malware:\r\nSource: https://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nhttps://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.bitsight.com/blog/unpacking-colibri-loader-russian-apt-linked-campaign"
	],
	"report_names": [
		"unpacking-colibri-loader-russian-apt-linked-campaign"
	],
	"threat_actors": [
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-10T02:00:02.959797Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"IRIDIUM",
				"Blue Echidna",
				"VOODOO BEAR",
				"FROZENBARENTS",
				"UAC-0113",
				"Seashell Blizzard",
				"UAC-0082",
				"APT44",
				"Quedagh",
				"TEMP.Noble",
				"IRON VIKING",
				"G0034",
				"ELECTRUM",
				"TeleBots"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "7bd810cb-d674-4763-86eb-2cc182d24ea0",
			"created_at": "2022-10-25T16:07:24.1537Z",
			"updated_at": "2026-04-10T02:00:04.883793Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"APT 44",
				"ATK 14",
				"BE2",
				"Blue Echidna",
				"CTG-7263",
				"FROZENBARENTS",
				"G0034",
				"Grey Tornado",
				"IRIDIUM",
				"Iron Viking",
				"Quedagh",
				"Razing Ursa",
				"Sandworm",
				"Sandworm Team",
				"Seashell Blizzard",
				"TEMP.Noble",
				"UAC-0082",
				"UAC-0113",
				"UAC-0125",
				"UAC-0133",
				"Voodoo Bear"
			],
			"source_name": "ETDA:Sandworm Team",
			"tools": [
				"AWFULSHRED",
				"ArguePatch",
				"BIASBOAT",
				"Black Energy",
				"BlackEnergy",
				"CaddyWiper",
				"Colibri Loader",
				"Cyclops Blink",
				"CyclopsBlink",
				"DCRat",
				"DarkCrystal RAT",
				"Fobushell",
				"GOSSIPFLOW",
				"Gcat",
				"IcyWell",
				"Industroyer2",
				"JaguarBlade",
				"JuicyPotato",
				"Kapeka",
				"KillDisk.NCX",
				"LOADGRIP",
				"LOLBAS",
				"LOLBins",
				"Living off the Land",
				"ORCSHRED",
				"P.A.S.",
				"PassKillDisk",
				"Pitvotnacci",
				"PsList",
				"QUEUESEED",
				"RansomBoggs",
				"RottenPotato",
				"SOLOSHRED",
				"SwiftSlicer",
				"VPNFilter",
				"Warzone",
				"Warzone RAT",
				"Weevly"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775439128,
	"ts_updated_at": 1775791830,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/df4cab4f217485602ef6e5aa3a0c6b061bfd151d.pdf",
		"text": "https://archive.orkl.eu/df4cab4f217485602ef6e5aa3a0c6b061bfd151d.txt",
		"img": "https://archive.orkl.eu/df4cab4f217485602ef6e5aa3a0c6b061bfd151d.jpg"
	}
}