{
	"id": "22ecc4e3-f511-46eb-9369-d69cc49cba8e",
	"created_at": "2026-04-06T00:11:05.701669Z",
	"updated_at": "2026-04-10T13:12:21.756645Z",
	"deleted_at": null,
	"sha1_hash": "df6bbcf3b05769922f5565357fb9052a2d6ff638",
	"title": "Analyzing KSL0T (Turla’s Keylogger), Part 2 – Reupload | 0ffset Training Solutions",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1684002,
	"plain_text": "Analyzing KSL0T (Turla’s Keylogger), Part 2 – Reupload | 0ffset\r\nTraining Solutions\r\nBy 0verfl0w_\r\nPublished: 2019-07-08 · Archived: 2026-04-05 22:02:14 UTC\r\n(This post is a reupload from my old site which is no longer available – you may have seen it before)\r\nIf you haven’t read the first post, go check it out here. You can download this keylogger off of VirusBay. So far\r\nwe have decrypted a whole lot of text using a simple XOR method, which revealed information on how different\r\nkeys could be logged, file names in which the data could be logged to, and a possible name for the\r\nkeylogger: KSL0T. If you’ve got no clue what I’m talking about, you should most definitely check out the last\r\npost. Anyway, let’s go further down the rabbit hole.\r\nMD5: 59b57bdabee2ce1fb566de51dd92ec94\r\nIf you’re following along with this analysis, make sure you rename the decryption function, so it confuses things\r\nless. After the return of the decryption function, GetModuleHandleW and GetProcAddress are called, using the\r\nrecently decrypted values, which are the last two strings to be decrypted. These values\r\nare kernel32.dll and GetProcAddress.\r\nThe return value of GetProcAddress will be stored in the rax register, which is then moved into the\r\nlocation [rsp+48h+var_28], so to simplify matters, we can rename var_28 to GetProcessAddress, so whenever it\r\nis moved into another register (as long as it hasn’t been changed), we can identify what is happening if that\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 1 of 21\n\nregister is called by the program. Sure enough, it is moved into the rdx register, just before a handle\r\nto kernel32.dll gets moved into the rcx register – and then a function at 0x1800039C0 is called.\r\nWe can easily identify the arguments passed to this function, as it is using the mov operation again. We already\r\nknow rcx contains a handle to kernel32.dll, and rdx contains the GetProcAddress function, and it\r\nseems r8 contains an address to an empty region of memory: 0x1800105A0, which is filled with zeroes.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 2 of 21\n\nIf you are viewing the function in graph mode, you’ll be able to see that the flow is simply one long “line”, with\r\nno if’s or for statements until the end. You can also see that there are a lot of variables that are declared before the\r\narguments are filled – as we are analyzing this binary using static analysis, this function alone will require a lot of\r\nwork to understand (because it is a possible anti-static analysis method used by Turla to prevent easy analysis).\r\nHint: It’s more data decryption, except this time, the encrypted data is loaded during runtime – hence why there\r\nare so many mov operations in a row. Due to this, we will have to manually extract those bytes, figure out how\r\nthey are decrypted, and find a way to decrypt them, through automation or writing a script. Let’s get stuck into it!\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 3 of 21\n\nThere is most definitely a better way to decrypt the data, although I am unaware of it, so I took the long route.\r\nHighlight the mov instructions and copy it to a file. We will be stripping this down so it only contains the second\r\nargument to the instruction – the encrypted data.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 4 of 21\n\nNow we need to parse the data and format it correctly, so that we only have the value being moved into the\r\ndestination. Below is a script that removes everything but the digit, including the h specifying the hexadecimal\r\nformat. For singular digits, a zero is prepended onto the value, to make an understandable hex value.\r\ndef main():\r\nf = open(\"data.txt\", \"r\")\r\ndata = f.readlines()\r\nf.close()\r\nf = open(\"data_2.txt\", \"w\")\r\nfor lines in data:\r\n lines = lines.split(\"], \")[1]\r\n if \"h\" in lines:\r\n lines = lines.split(\"h\")[0]\r\n lines = lines + \" \"\r\n else:\r\n lines = \"0\" + lines\r\n lines = lines.split(\"\\n\")[0]\r\n lines = lines + \" \"\r\n f.write(lines)\r\nf.close()\r\nif name == “main”:\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 5 of 21\n\nmain()\r\nAfter executing the script, we get this output in data_2.txt. This is the extracted encrypted data, so we need to\r\nidentify the decryption method used, to understand what it is encrypted with.\r\nBack to the assembly, after the individual bytes have been moved into the correct locations, a function\r\nat 0x180001000 is called repeatedly in a similar fashion to the first decryption function, except this time with 2\r\narguments.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 6 of 21\n\nAs you’ve probably guessed, this is another algorithm, although it is a lot less complex than the last one – this is\r\ndue to the fact that each section of data is XORed using 0x55, meaning we don’t need to write some sort of\r\ndecryption script, and we can simply put it into CyberChef and perform a basic XOR decryption, and then\r\nconvert it from hexadecimal format. If you haven’t used CyberChef before, you should check it out, as it is\r\nextremely useful in situations like these.\r\nAs you can see, the data contains multiple API calls and DLL’s that are loaded during runtime – in this function.\r\nAs we scroll down the graph, there are several calls to GetProcAddress, as well as calls to variables, such\r\nas var_290. There are two ways we can approach this to figure out what is being stored in variable 290 – using a\r\ndebugger, or in this case through static analysis (the more complex method). To do so, we need to trace\r\nbackwards. We can see that the value in rax is stored in var_290, just after a GetProcAddress call, and as one of\r\nthe arguments is kernel32.dll, the other must be the function that is called – this is stored in var_58.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 7 of 21\n\nJust above the GetProcAddress, the decryption function is used to decrypt 13 bytes of data at var_58, so lets go\r\nto the x-ref of  var_58 in this function, and count out 13 bytes of data: var_58 -\u003e var_4C.\r\nCopy those bytes and put them into CyberChef, and XOR with 0x55. You should get LoadLibraryA.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 8 of 21\n\nFrom then on, only GetProcAddress and LoadLibraryA are called by this function – and we can assume that\r\neach of the API functions in the decrypted text are imported. Obviously we could do that all manually, but if you\r\nhave access to a debugger it would be much quicker.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 9 of 21\n\nAs all of the imports have been resolved, we can move on, out of the function, where the program\r\ncalls GetUserNameExW twice. In my case, the call will return Reversing\\RE – the domain name and username.\r\nThe malware then moves it to a different location using wcscat, and checks to see if there is a backslash in the\r\nreturned value, using wcsstr. If there is, a pointer to it will be returned. The backslash is then replaced with a full\r\nstop, leaving us with Reversing.RE. The formatted string is used to create a mutex. The program first checks to\r\nsee if a mutex has been created under that value by calling OpenMutexW, and if it hasn’t been\r\ncreated, CreateMutexW is called. We are able to double check that this mutex is created by using a tool\r\ncalled SysAnalyzer, which is useful for analyzing malicious programs whilst performing dynamic analysis.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 10 of 21\n\nOnce a mutex has been created, a function at 0x180003960 is called, which creates a new thread pointing\r\nto 0x180001B70. When the created thread exits, the malware exits as well.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 11 of 21\n\nSo, let’s take a look at the newly created thread. It seems that immediately after the thread executes, a function\r\nlocated at 0x180001B00 is called, containing the ‘meat’ of the keylogger. I have labelled this as Set_Hooks, based\r\noff of the method used by the keylogger.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 12 of 21\n\nThe two most common Windows API calls used in malware and ‘legitimate’ software to perform keylogging\r\nis GetAsyncKeyState or SetWindowsHookEx. Due to the number of issues with using GetAsyncKeyState,\r\nmost keyloggers utilize SetWindowsHookEx nowadays. In this case, SetWindowsHookEx is used to capture\r\nkeystrokes. Whilst we are unable to use the pseudo code function in IDA, we can use MSDN to understand what\r\nis being called and how.\r\nHHOOK SetWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId);\r\nWhen we input all of the arguments into the function, we get:\r\nHHOOK SetWindowsHookExA(13, 0x1800022C0 , 0x180010720, 0);\r\nHHOOK SetWindowsHookExA(WH_KEYBOARD_LL, LowLevelKeyboardProc, DLL_Handle, NULL);\r\nSo a hook is installed that ‘monitors low level keyboard input events‘, allowing the malware to gather each\r\nkeystroke. After, the function returns back to the previous function, where\r\na Get, Translateand DispatchMessage loop is created. While the program is keylogging, GetMessage will gather\r\neach key press and pass it to TranslateMessage, which translates virtual key messages into character messages.\r\nThis is then passed to DispatchMessage, and this redirects it to another window procedure. If you want to learn\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 13 of 21\n\nmore about the inner workings of keylogging, check out this site here, it goes into the very low levels of keystroke\r\nlogging.\r\nNow lets take a look at the function called by SetWindowsHookExA, located at 0x1800022C0. As you can see\r\nfrom the graph overview, this function is a huge mess. The section at the bottom of the graph is in fact\r\na switch statement – we can see there are multiple case values, and a default value as well. Furthermore, IDA also\r\ntells us this is a switch statement. Here is an overview of switch statements in C. To sum it up, it is another\r\nmethod of comparing one variable to several different variables, instead of using multiple if statements.\r\nIn order to find the values of the case variables, we need to perform some simple addition. Looking at each box,\r\nthere is a lea rdx, Encrypted_Keys and then add rdx, …h, where the … indicates a certain hexadecimal value.\r\nIn one particular case, the value 13C is being added to the memory address of the Encrypted Keys, which\r\nis 0x18000F2F0. After adding them together, we get 0x18000F42C, which points to ‘\u003c‘. The next instruction after\r\nthe add, a value is moved into r8d. This indicates the size of the string, which is 4. Therefore, the 3 bytes\r\nafter 0x18000F42C are also included, meaning the full value is \u003cr0\u003e.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 14 of 21\n\nTo speed up the process, I wrote a simple script to *automate* the process, so all you have to do is input the\r\naddition value and the string length, and the corresponding key is output to the terminal. I have uploaded it to\r\npastebin and you can view it here.\r\nThis value is concatenated, using wcsncat, into the address 0x1800115B0. We can rename this\r\nto Captured_Char, as that is what it is. If the captured keystroke does not equal any of the hardcoded values,\r\nthe default case is used, however they all lead to the same logging function. Before examining the rest of this\r\nfunction, lets take a look at how the data is logged.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 15 of 21\n\nSo this function is quite long, although we just need to see the WriteFile part, to see if the data is encrypted or not\r\nwhen being stored – which is right at the bottom of the function.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 16 of 21\n\nAs assumed, the data is encrypted before being written to the file. As you can see, there is a for loop, where on\r\none side data is being written using WriteFile, and on the other side data is being XORed using the original XOR\r\nkeys. First, it seems that the value in var_34 is being compared to the value in var_20. We can deduce\r\nthat var_34 is the length of the data to be XORed, due to it being the third argument in the WriteFile call:\r\nWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped)\r\nTherefore, we can rename that to NumberOfBytesToWrite. While doing so, we can also rename the other\r\nvariables used in the call, so it is easier to understand the function. You might also have noticed that var_20 is\r\nbeing incremented each loop as well, so we can simply rename that as i. So, lets take a look at the actual XOR\r\npart.\r\nSo the value in i is moved into rcx, and the value in the Buffer (highly likely the captured keystrokes plus any\r\nadditional data) is moved into rax. Once again – similar to both decryption routines – the first character that will\r\nbe encrypted is found by adding the value in i to the address of the Buffer. This is moved into edi, and then div is\r\ncalled. If you remember the first post on the keylogger, div divides the value in rax with the passed operand,\r\nwhich is rcx. The value in rcx is 100 (0x64), and therefore rax will be divided by 100. The question is, what is the\r\nvalue in rax? We can see dword_180010738 is being moved into the register – but it is empty. We have to locate\r\nthe section where a value is moved into the dword.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 17 of 21\n\nSearching for xrefs, there is only one mention of this variable before the encryption routine, which is\r\nat 0x1800013F1. It seems that the malware gets the file size of the file which the keystrokes will be logged to, and\r\nthen performs another div operation, with the remainder being stored in the dword. Let’s imagine that the file size\r\nis 0, as the logger has just started up. 0 is then divided by 100, which is obviously 0. This means that the value\r\nin edx is 0, and therefore the value in the dword is, you guessed it, also 0. So we can jump back to the encryption\r\nroutine and work through the rest.\r\nIn order to get a byte from the key to XOR the data with, rdx and rax are used. The value in rdx on the first loop\r\nis zero – this is the result of the div using the value in dword_180010738. The address of the original XOR key is\r\nmoved into rax, and a byte is stored in eax using the same byte ptr [rax+rdx] used throughout. edi (the keystroke\r\ndata) is moved into edx, which is XORedby eax (the key). The encrypted character is used to overwrite the\r\ncharacter in the keystroke data, based off of the value in i. Next, the value of dword_180010738 is incremented\r\nby 1, meaning the key used to XOR the first character of the buffer is different to the key used to XOR the second\r\ncharacter of the buffer. Finally, i is also incremented by 1, and the loop continues until the buffer is completely\r\noverwritten.\r\nThe data is then written to the file, the buffer is freed, the file handle is closed, and the function returns.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 18 of 21\n\nNow we have cracked the algorithm, we need to find where the data is being logged. We already know which\r\nvariable contains the handle to the file, so lets find the first instance of it being used. Sure enough, there is a mov\r\n[rsp+928h+File], rax just after a call to CreateFileW. When looking at the arguments CreateFile takes, we can\r\nsee that the very first argument is the file name:\r\nHANDLE CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposit\r\nIn this case, the first argument is a variable containing msimm.dat – one of the original strings we decrypted. As\r\nthere is no file path connected to it, it seems that this file is written in the current directory, so wherever the\r\nkeylogger is run.\r\nWe know almost everything about how the file is logged and how the data is stored, so let’s see if we can get a\r\nsample of the encrypted data in order to analyze it. Open up a VM and run the DLL. In order to run it, I am using\r\nx64Dbg, as I couldn’t seem to get rundll32.exe to run it – maybe due to the lack of exports. Eventually, the file I\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 19 of 21\n\nwanted was created on the Desktop, msimm.dat. Upon opening it, there is a lot of what seems to be text in a\r\ndifferent language, although this is just the encrypted text being displayed by Notepad. Open the file in something\r\nlike CFF Explorer in order to view the hex data of the file, so that we can XOR it back to plain text. Copy this\r\ninto a text file on your host machine, and get your favourite text formatting tool up.\r\nThe reason for this is because the script I have written is quite ‘hacky’. I tried several different things in order for\r\npython to read hex bytes as hex bytes into an array – all failed. If you guys have any ideas on how to improve it,\r\nlet me know! Anyway, the text needs to be formatted in this way:\r\n0x..., 0x..., 0x...\r\nAnd as CFF explorer copies the hex in one long string, we need to split it every second character and convert\r\nspaces to , 0x. I personally used this to do so. Now my script doesn’t work 100% of the time – I’m mainly using it\r\nas an example here to show you how to replicate the algorithm in Python. It only seems to work on one section of\r\nthe text, but I’m sure those of you with a higher level of Pythonic knowledge and malware analysis knowledge\r\nwill be able to re purpose it so it works flawlessly. Anyway, here it is. When we run the script, it will decrypt the\r\nsection of hex data using the keys and output the plaintext. There is also a legend that shows you which part\r\nmeans what. As I mentioned, there are so many better ways to do this so that it works for different logs, however I\r\ndidn’t have much time to work on it and make it pristine.\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 20 of 21\n\nThat pretty much wraps up this analysis, as there isn’t much else to analyze. There is no method of extracting the\r\nlog files in the keylogger, so I believe Turla only use it when they have remote access to the machine, and extract\r\nthe logs through a remote access tool or a backdoor. So I hope you enjoyed the two part analysis, and I should\r\nhopefully have the Hancitor part two write up soon. Thanks!\r\nIOCs:\r\nKeylogger: 59b57bdabee2ce1fb566de51dd92ec94\r\nSource: https://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nhttps://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/\r\nPage 21 of 21\n\nJust above the GetProcAddress, https://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/ the decryption function is used to decrypt 13 bytes of data at var_58, so lets go\nto the x-ref of var_58 in this function, and count out 13 bytes of data: var_58 -\u003e var_4C.\nCopy those bytes and put them into CyberChef, and XOR with 0x55. You should get LoadLibraryA.\n   Page 8 of 21",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://0ffset.net/reverse-engineering/malware-analysis/analyzing-turlas-keylogger-2/"
	],
	"report_names": [
		"analyzing-turlas-keylogger-2"
	],
	"threat_actors": [
		{
			"id": "8aaa5515-92dd-448d-bb20-3a253f4f8854",
			"created_at": "2024-06-19T02:03:08.147099Z",
			"updated_at": "2026-04-10T02:00:03.685355Z",
			"deleted_at": null,
			"main_name": "IRON HUNTER",
			"aliases": [
				"ATK13 ",
				"Belugasturgeon ",
				"Blue Python ",
				"CTG-8875 ",
				"ITG12 ",
				"KRYPTON ",
				"MAKERSMARK ",
				"Pensive Ursa ",
				"Secret Blizzard ",
				"Turla",
				"UAC-0003 ",
				"UAC-0024 ",
				"UNC4210 ",
				"Venomous Bear ",
				"Waterbug "
			],
			"source_name": "Secureworks:IRON HUNTER",
			"tools": [
				"Carbon-DLL",
				"ComRAT",
				"LightNeuron",
				"Mosquito",
				"PyFlash",
				"Skipper",
				"Snake",
				"Tavdig"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "a97cf06d-c2e2-4771-99a2-c9dee0d6a0ac",
			"created_at": "2022-10-25T16:07:24.349252Z",
			"updated_at": "2026-04-10T02:00:04.949821Z",
			"deleted_at": null,
			"main_name": "Turla",
			"aliases": [
				"ATK 13",
				"Belugasturgeon",
				"Blue Python",
				"CTG-8875",
				"G0010",
				"Group 88",
				"ITG12",
				"Iron Hunter",
				"Krypton",
				"Makersmark",
				"Operation Epic Turla",
				"Operation Moonlight Maze",
				"Operation Penguin Turla",
				"Operation Satellite Turla",
				"Operation Skipper Turla",
				"Operation Turla Mosquito",
				"Operation WITCHCOVEN",
				"Pacifier APT",
				"Pensive Ursa",
				"Popeye",
				"SIG15",
				"SIG2",
				"SIG23",
				"Secret Blizzard",
				"TAG-0530",
				"Turla",
				"UNC4210",
				"Venomous Bear",
				"Waterbug"
			],
			"source_name": "ETDA:Turla",
			"tools": [
				"ASPXSpy",
				"ASPXTool",
				"ATI-Agent",
				"AdobeARM",
				"Agent.BTZ",
				"Agent.DNE",
				"ApolloShadow",
				"BigBoss",
				"COMpfun",
				"Chinch",
				"Cloud Duke",
				"CloudDuke",
				"CloudLook",
				"Cobra Carbon System",
				"ComRAT",
				"DoublePulsar",
				"EmPyre",
				"EmpireProject",
				"Epic Turla",
				"EternalBlue",
				"EternalRomance",
				"GoldenSky",
				"Group Policy Results Tool",
				"HTML5 Encoding",
				"HyperStack",
				"IcedCoffee",
				"IronNetInjector",
				"KSL0T",
				"Kapushka",
				"Kazuar",
				"KopiLuwak",
				"Kotel",
				"LOLBAS",
				"LOLBins",
				"LightNeuron",
				"Living off the Land",
				"Maintools.js",
				"Metasploit",
				"Meterpreter",
				"MiamiBeach",
				"Mimikatz",
				"MiniDionis",
				"Minit",
				"NBTscan",
				"NETTRANS",
				"NETVulture",
				"Neptun",
				"NetFlash",
				"NewPass",
				"Outlook Backdoor",
				"Penquin Turla",
				"Pfinet",
				"PowerShell Empire",
				"PowerShellRunner",
				"PowerShellRunner-based RPC backdoor",
				"PowerStallion",
				"PsExec",
				"PyFlash",
				"QUIETCANARY",
				"Reductor RAT",
				"RocketMan",
				"SMBTouch",
				"SScan",
				"Satellite Turla",
				"SilentMoon",
				"Sun rootkit",
				"TTNG",
				"TadjMakhal",
				"Tavdig",
				"TinyTurla",
				"TinyTurla Next Generation",
				"TinyTurla-NG",
				"Topinambour",
				"Tunnus",
				"Turla",
				"Turla SilentMoon",
				"TurlaChopper",
				"Uroburos",
				"Urouros",
				"WCE",
				"WITCHCOVEN",
				"WhiteAtlas",
				"WhiteBear",
				"Windows Credential Editor",
				"Windows Credentials Editor",
				"Wipbot",
				"WorldCupSec",
				"XTRANS",
				"certutil",
				"certutil.exe",
				"gpresult",
				"nbtscan",
				"nbtstat",
				"pwdump"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a97fee0d-af4b-4661-ae17-858925438fc4",
			"created_at": "2023-01-06T13:46:38.396415Z",
			"updated_at": "2026-04-10T02:00:02.957137Z",
			"deleted_at": null,
			"main_name": "Turla",
			"aliases": [
				"TAG_0530",
				"Pacifier APT",
				"Blue Python",
				"UNC4210",
				"UAC-0003",
				"VENOMOUS Bear",
				"Waterbug",
				"Pfinet",
				"KRYPTON",
				"Popeye",
				"SIG23",
				"ATK13",
				"ITG12",
				"Group 88",
				"Uroburos",
				"Hippo Team",
				"IRON HUNTER",
				"MAKERSMARK",
				"Secret Blizzard",
				"UAC-0144",
				"UAC-0024",
				"G0010"
			],
			"source_name": "MISPGALAXY:Turla",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "d11c89bb-1640-45fa-8322-6f4e4053d7f3",
			"created_at": "2022-10-25T15:50:23.509601Z",
			"updated_at": "2026-04-10T02:00:05.277674Z",
			"deleted_at": null,
			"main_name": "Turla",
			"aliases": [
				"Turla",
				"IRON HUNTER",
				"Group 88",
				"Waterbug",
				"WhiteBear",
				"Krypton",
				"Venomous Bear",
				"Secret Blizzard",
				"BELUGASTURGEON"
			],
			"source_name": "MITRE:Turla",
			"tools": [
				"PsExec",
				"nbtstat",
				"ComRAT",
				"netstat",
				"certutil",
				"KOPILUWAK",
				"IronNetInjector",
				"LunarWeb",
				"Arp",
				"Uroburos",
				"PowerStallion",
				"Kazuar",
				"Systeminfo",
				"LightNeuron",
				"Mimikatz",
				"Tasklist",
				"LunarMail",
				"HyperStack",
				"NBTscan",
				"TinyTurla",
				"Penquin",
				"LunarLoader"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434265,
	"ts_updated_at": 1775826741,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/df6bbcf3b05769922f5565357fb9052a2d6ff638.pdf",
		"text": "https://archive.orkl.eu/df6bbcf3b05769922f5565357fb9052a2d6ff638.txt",
		"img": "https://archive.orkl.eu/df6bbcf3b05769922f5565357fb9052a2d6ff638.jpg"
	}
}