{
	"id": "dd7f96bc-09dd-4828-8eaf-dc7e6d759715",
	"created_at": "2026-04-06T00:19:56.561203Z",
	"updated_at": "2026-04-10T03:31:24.481585Z",
	"deleted_at": null,
	"sha1_hash": "dc1829ae46f0b77dcf26243e1326038221b7a31d",
	"title": "A New Look at Old Dragonfly Malware (Goodor) – One Night in Norfolk",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1036423,
	"plain_text": "A New Look at Old Dragonfly Malware (Goodor) – One Night in\r\nNorfolk\r\nPublished: 2020-03-30 · Archived: 2026-04-05 15:02:41 UTC\r\nFrom time to time, new tools emerge that make it significantly easier to examine older malware. In 2017,\r\nSymantec’s threat intelligence team published research regarding the Dragonfly group, an adversary with an\r\napparent interest in performing reconnaissance against energy sector companies. One of the reported malware\r\nfamilies, “Backdoor.Goodor,” is written in Golang and the blog post states that it “provides the attackers with\r\nremote access to the victim’s machine.”\r\nIn recent years, several free options have become available to help reverse engineer these types of Golang\r\nbinaries, replacing premium (but extremely well documented) methods and making this type of analysis\r\nparticularly more accessible.\r\nThis post walks through the reverse engineering of a Goodor file, examining its capabilities and discussing key\r\nprinciples of these types of files.\r\nKey Concepts\r\nThis blog notes that there are a few key concepts relevant to understanding Golang binaries:\r\n– When first disassembled, Golang binaries will have a nearly unreadable number of unlabeled functions\r\n– Golang binaries contain a section referred to as “gopclntab” that stores function information.\r\n– For Linux/Unix binaries, this is an actual named section. For Windows binaries, it is not.\r\n– This section has the same “magic bytes” in both types of binaries and follows a uniform structure.\r\nIn particular, this blog recommends that those interested in a deeper understand of the subject start by watching\r\nJoakim Kennedy’s two presentations which provide significant detail regarding the structure of Golang binaries.\r\nMr. Kennedy’s tool, Redress, is a key part of current Golang reverse engineering and is used in this analysis.\r\nFinally, this analysis uses Cutter, a GUI-based implementation of the Radare2 framework. When a Golang Linux\r\nbinary is opened in Radare2 or Cutter, both tools automatically identify the gopclntab section, parse function\r\nnames from this section, and relabel the assembly as needed. However, this blog noted that they did not behave\r\nthis way for Windows binaries, where this section is not explicitly created. Redress provides a workaround for this\r\nissue.\r\nThis post relies on a Linux VM for Cutter, Radare2, and Redress, as the Windows version of Cutter didn’t allow\r\nfor the execution of Redress in the command line and the Windows version of Radare2 functioned poorly with\r\n#!pipe commands. The debugging itself takes place in a Windows VM.\r\nTechnical Analysis – Initial File\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 1 of 13\n\nFile: ntdll_installer.exe\r\nMD5: f2edff3d0e5a909c8d05b04905642105\r\nSHA1: c8c8329449c18445330903dd6a59d0b4098d9670\r\nSHA256: 5a7ace894461c2432fe9b52254cbc5c3f5bbce0c91a416154511a554dba6f913\r\nThis blog revisits an older malware family with newer tools to obtain a better understanding of the file. One place\r\nto start is Symantec’s original write-up, which stated:\r\n1. “Backdoor.Goodor… opens a backdoor on the compromised computer”\r\n2. “When the Trojan is executed, it copies itself to the following location…”\r\n3. It “creates the following registry entry…”\r\n%AppData%\\NT\\ntdll.exe ddd-073d7bac5d624bb40adbb25f55eb693d\r\nThis blog notes that the current Google-indexed page for this malware leads to a Broadcom page that states, “You\r\nhave arrived at this page either because you have been alerted by your Symantec product about a risk, or you are\r\nconcerned that your computer has been affected by a risk.” As neither statement is true, this blog has linked to the\r\narchived version instead.\r\nAs this analysis will show, Symantec’s write-up is a close approximation that’s not quite forensically accurate. The\r\n“copied” file is actually a dropped embedded file, and the registry entry changes slightly from device to device.\r\nIdentify Function Names\r\nThe first step for this analysis is to use the Redress tool with the -src switch to identify function names. When run\r\nagainst this file, the tool produces the following output:\r\nPackage main: C:\\Users\\User\\go\\src\\i\r\nFile: i_main.go\r\nmain Lines: 15 to 19 (4)\r\nTryDoMain Lines: 19 to 29 (10)\r\nTryDoMainfunc1 Lines: 20 to 24 (4)\r\nDoMain Lines: 29 to 61 (32)\r\nGetFn Lines: 61 to 76 (15)\r\nCreateBat Lines: 76 to 110 (34)\r\nStartA Lines: 110 to 113 (3)\r\nFile: r.go.template.impl.go\r\ninit Lines: 6 to 6 (0)\r\nPackage e: C:\\Users\\User\\go\\src\\e\r\nFile: e.go\r\nDecode Lines: 53 to 93 (40)\r\nDecodefunc1 Lines: 70 to 155 (85)\r\nFromB64 Lines: 93 to 121 (28)\r\nDecrypt Lines: 121 to 144 (23)\r\nHashStr Lines: 144 to 150 (6)\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 2 of 13\n\nRandomHashString Lines: 150 to 153 (3)\r\ninit Lines: 155 to 155 (0)\r\nThis output represents the author-added functions to a Golang binary. Golang binaries are large as they also\r\nincorporate dozens (or hundreds) of additional library functions, and so this output separates the most important\r\nsections.\r\nThe output also provides some hints: we can postulate that the malware likely performs some sort of Base64\r\ndecoding and decryption (FromB64, Decode, Decrypt) and may also create a .bat file (CreateBat). Notably, we\r\ndon’t see anything indicative of command-and-control (C2) traffic.\r\nCreate a Function Map\r\nWith the primary functions identified, we can map them out. Open the binary in Cutter with the slider for analysis\r\nall the way to the left, indicating no analysis. Using #!pipe, run the Redress tool. Finally, run “aaaa” to perform\r\nanalysis and go to View-\u003e Refresh Contents.\r\n#!pipe command used within the Cutter console to launch Redress. Note that some error\r\nmessages were cropped for readability. These can be ignored.\r\nWith the function names populated, we can begin mapping out a smaller call-tree. As with other disassemblers, we\r\ncan select each function name in graph mode or use the cross-referencing features to identify function\r\nrelationships. For example, DoMain makes several additional calls in the following order:\r\n– Decode\r\n– GetFn\r\n– RandomHashString\r\n– StartA\r\n– CreateBat\r\nDecode, in turn, calls “FromB64” and “Decrypt.” Using this information, we can construct a simple call map.\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 3 of 13\n\nDoMain calling StartA\r\nSimplified function map. Calls are ordered from left-to-right and top-to-bottom.\r\nThis particular sample only uses each of these functions one time, providing an easy-to-understand workflow. This\r\nis of course not necessarily typical for all malware. The graph above may also be too simple, as it omits several\r\nimportant native Golang calls that could provide a broader understanding of some of these functions.\r\nConsider the GetFN function: within this function are calls such as “GetEnv,” “TempDir,” and “MkdirAll” that\r\nstrongly suggest that a file and/or folder is being written to a specific path. Without this information, one might\r\nhave assumed “GetFN” was simply obtaining the name of a file (or the file running). With that in mind, we can\r\ncreate a more complete graph, with boxes differentiating the native calls.\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 4 of 13\n\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 5 of 13\n\nGetFN function with native calls\r\nFunction call graph with native calls added in as rectangles.\r\nWith these functions mapped out, we can hypothesize a workflow such as:\r\n1. The malware Base64 decodes and then decrypts something.\r\n2. The malware creates a filename and/or directory somewhere, possibly in the Temp directory.\r\n3. The malware writes something to the disk.\r\n4. The malware calls StartA, which executes something.\r\n5. The malware creates and runs a .bat file.\r\nIt’s time to begin debugging to test these hypotheses.\r\nDebugging\r\nI prefer the x96 suite for debugging. The most important thing to do before actually running the debugger is to\r\nrename the key functions we’ve identified. These include the author-added Golang functions plus any other\r\ninteresting ones, such as those within the GetFN call. There are a few options here; in this case, I opted to do this\r\nmanually, but you can also use Radare/Cutter + Redress + the “aaaa” and “afl” commands to get an address-function pair list (copying it to a file), and then create a comment or label script for x96dbg. For a larger file, that\r\nmight be the most practical approach.\r\nThe first order of business is to examine the decoding hypothesis. The malware contains a large block of Base64-\r\nencoded data, visible in the strings via Process Hacker. As the string is several thousand characters long, it is easy\r\nto stop in a single memory section. After stepping over the Decode function (which in turn triggers the FromB64\r\nand Decrypt calls), this section will populate with the decoded and then decrypted data:\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 6 of 13\n\nDecoding and Decrypting\r\nExecutable decrypted in memory\r\nNext, is the GetFN function call. Earlier, we hypothesized that this should create a file path or directory in the\r\nuser’s Temp folder. Stepping through this function, we can see it creates a directory at AppData\\Roaming\\NT\\\r\nDirectory creation within GetFN function.\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 7 of 13\n\nThe malware will also create a filename, ntdll.exe, and append it to this path. When the function exits, it uses the\r\nWriteFile call to write the decoded executable to this location. The StartA function then issues a system command\r\nto run this. For the purposes of this analysis, I copied the executable to the desktop and replaced it with a renamed\r\nFakeNet Mini executable to examine the CreateBat function.\r\nFrom a static perspective, CreateBat demonstrates a string load. The program identifies the address and length (in\r\nthis case, 25 characters) of a string containing a ping command. The rest of the function also performs a string\r\nreplacement for a registry key value to be added. The end result is a .bat file written to disk:\r\n.bat file written to disk\r\nThis file creates an HKCU runkey that will cause the dropped payload to execute any time the user logs in. It will\r\nalso silently delete the initial dropper and delete itself. Following the execution of this batch file, the program\r\nterminates itself. At this point, we can look at the dropped payload.\r\nTechnical Analysis – Dropped Payload\r\nThe dropped payload is a UPX-packed Windows executable.\r\nFilename: ntdll.exe\r\nMD5 (packed): 8943E71A8C73B5E343AA9D2E19002373\r\nMD5 (unpacked): ca818c14f69bef7695c0e2ff127e6d9b\r\nSHA1 (unpacked): 115d12e0fb73445a788ebe7bdf3cab552b3cb9af\r\nSHA256 (unpacked): b5278301da06450fe4442a25dda2d83d21485be63598642573f59c59e980ad46\r\nFollowing the same steps as above, we can identify the author-created functions.\r\nPackage e: C:\\Users\\User\\go\\src\\e\r\nFile: e.go\r\nDecode Lines: 53 to 93 (40)\r\nDecodefunc1 Lines: 70 to 155 (85)\r\nFromB64 Lines: 93 to 121 (28)\r\nDecrypt Lines: 121 to 144 (23)\r\nHashStr Lines: 144 to 150 (6)\r\nRandomHashString Lines: 150 to 153 (3)\r\ninit Lines: 155 to 155 (0)\r\nPackage main: C:\\Users\\User\\go\\src\\m\r\nFile: m_main.go\r\nmain Lines: 17 to 21 (4)\r\nTryDoMain Lines: 21 to 31 (10)\r\nTryDoMainfunc1 Lines: 22 to 44 (22)\r\nDoMain Lines: 31 to 43 (12)\r\nTryDoIter Lines: 43 to 57 (14)\r\nTryDoIterfunc1 Lines: 44 to 166 (122)\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 8 of 13\n\nDoIter Lines: 57 to 100 (43)\r\nGetU Lines: 100 to 117 (17)\r\nOnData Lines: 117 to 146 (29)\r\nExecute Lines: 146 to 151 (5)\r\nGetHttp Lines: 151 to 160 (9)\r\nCreateTempFileName Lines: 160 to 164 (4)\r\ninit Lines: 166 to 166 (0)\r\nA few things should stand out. First, the “e” package appears to be reused, alongside all of the decoding and\r\ndecryption functions. However, this is clearly not a “copy” of the initial dropper. The primary package has new\r\nfunctions, such as GetHttp, OnData, CreateTempFileName, and execute. Using the same strategy as before, we\r\ncan map some key functions out.\r\nFunction tree for dropped Goodor payload\r\nAs with the previous graph, the code structure (for this particular example – again, most samples are less linear) is\r\nsuch that we can read left-to-right and top-to-bottom. We might expect that:\r\n1. The malware runs GetU. Perhaps this obtains the username (it does not, but that was my initial guess).\r\n2. The malware establishes an HTTP connection.\r\n3. The malware checks to see if it gets a response, and if so, Base64 decodes and then decrypts that response.\r\n4. The malware creates a filename for a target in the Temp directory.\r\n5. The malware writes the decoded data to this file.\r\n6. The malware executes this file.\r\nFor this example, I opted to use radare2 + redress, followed by piping the output of the “afl” function to a file.\r\nWith some Notepad++ regex, I used the function addresses to make a basic x96dbg script to re-label all of the\r\naddresses. See here for an example from another analyst (replacing cmt with lbl). I mainly did this for\r\nperformance reasons, and to demonstrate an additional option readers.\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 9 of 13\n\nRedress and dumping a function list\r\nExample of a labeling script for x96dbg\r\nDebugging the malware, we can get through the GetU function before we start to run into some obstacles that will\r\nhinder a full analysis. Recall that we hypothesized that GetU could return the username. It actually creates the\r\nstring for the GET request sent to the C2 server:\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 10 of 13\n\nC2 string building function\r\nRight click and open in a new tab to zoom in a bit. The GetU function pulls one of five hardcoded C2 servers and\r\nappends an identifier string to it:\r\nhxxp: // 176.53.11[.]130/aspnet_client/system_web/4_0_30319/update/DefaultForm.txt\r\nhxxp: // 82.222.188[.]18/aspnet_client/system_web/4_0_30319/update/DefaultForm.txt\r\nhxxp: // 130.25.10[.]158/aspnet_client/system_web/4_0_30319/update/DefaultForm.aspx\r\nhxxp: // 41.205.61[.]221/aspnet_client/system_web/4_0_30319/update/DefaultForm.aspx\r\nhxxp: // 5.150.143[.]107/aspnet_client/system_web/4_0_30319/update/DefaultForm.aspx\r\nOne of these values, boxed in red above, remained consistent through different runs of the malware. This value,\r\n881456fc, also appears in VirusTotal runs of the malware in the behavior tab. If the file is run with a command\r\nline argument (as the runkey would cause), this value is appended with that argument. If not, the value is\r\nappended with “no” instead. One possibility is that this serves as a campaign ID and a device identifier.\r\nAt this stage, the analysis ran into some hurdles that could not be overcome. The malware didn’t appear to call out\r\nto the C2 server during the GetHTTP call, limiting confirmation of the remainder of the suspected functionality.\r\nStill, we can make some pretty strong inferences from the final call of the workflow, OnData:\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 11 of 13\n\nOnData workflow\r\nThe workflow strongly suggests that something is Base64 decoded and decrypted, written to disk at a generated\r\nlocation, and then executed. Symantec’s original report suggested that several other backdoors were deployed\r\nagainst victims. It is therefore possible that Goodor was used to deliver a tool such as a screen grabber, the\r\nKaragany backdoor, or one of several other payloads.\r\nConcluding Thoughts\r\nA few simple contemporary tools make analyzing Golang malware significantly easier than it was in the past,\r\nparticularly for those lacking access to premium tools such as IdaPro. Radare2, Cutter, and Redress can combine\r\nto create a workflow where the user can rename Golang functions, navigate a graph, and debug malware\r\nsignificantly easier than in the past.\r\nDuring this research, I ran a retrohunt to try to identify additional samples that contained the same encoding\r\nfunctions or matched other function names from the dropper and payload. Unfortunately, while I found other\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 12 of 13\n\nhashes, none were “new.” This may have been a one-time use tool from the threat actor, or the function names\r\nmay have been renamed in different versions.\r\nSource: https://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nhttps://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/\r\nPage 13 of 13",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://norfolkinfosec.com/a-new-look-at-old-dragonfly-malware-goodor/"
	],
	"report_names": [
		"a-new-look-at-old-dragonfly-malware-goodor"
	],
	"threat_actors": [
		{
			"id": "649b5b3e-b16e-44db-91bc-ae80b825050e",
			"created_at": "2022-10-25T15:50:23.290412Z",
			"updated_at": "2026-04-10T02:00:05.257022Z",
			"deleted_at": null,
			"main_name": "Dragonfly",
			"aliases": [
				"TEMP.Isotope",
				"DYMALLOY",
				"Berserk Bear",
				"TG-4192",
				"Crouching Yeti",
				"IRON LIBERTY",
				"Energetic Bear",
				"Ghost Blizzard"
			],
			"source_name": "MITRE:Dragonfly",
			"tools": [
				"MCMD",
				"Impacket",
				"CrackMapExec",
				"Backdoor.Oldrea",
				"Mimikatz",
				"PsExec",
				"Trojan.Karagany",
				"netsh"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "1a76ed30-4daf-4817-98ae-87c667364464",
			"created_at": "2022-10-25T16:47:55.891029Z",
			"updated_at": "2026-04-10T02:00:03.646466Z",
			"deleted_at": null,
			"main_name": "IRON LIBERTY",
			"aliases": [
				"ALLANITE ",
				"ATK6 ",
				"BROMINE ",
				"CASTLE ",
				"Crouching Yeti ",
				"DYMALLOY ",
				"Dragonfly ",
				"Energetic Bear / Berserk Bear ",
				"Ghost Blizzard ",
				"TEMP.Isotope ",
				"TG-4192 "
			],
			"source_name": "Secureworks:IRON LIBERTY",
			"tools": [
				"ClientX",
				"Ddex Loader",
				"Havex",
				"Karagany",
				"Loek",
				"MCMD",
				"Sysmain",
				"xfrost"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-10T02:00:04.679488Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434796,
	"ts_updated_at": 1775791884,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/dc1829ae46f0b77dcf26243e1326038221b7a31d.pdf",
		"text": "https://archive.orkl.eu/dc1829ae46f0b77dcf26243e1326038221b7a31d.txt",
		"img": "https://archive.orkl.eu/dc1829ae46f0b77dcf26243e1326038221b7a31d.jpg"
	}
}