[0:01]So, first off, I just want to thank Botcom for having me here as the first time uh presenter. I'm I'm very honored to be here. So, today I'll be talking about uh meeting Gopher Whisper, uncovering an APT secrets through its own words. So, hello everyone. My name is Eric Howard. I'm also known as a gentle giant. Uh, I'm a Mawer researcher for the ESET Montreal Office in Canada and I have been a part of the ESET team for just a little over a year now, focusing on China aligned APTs. Before getting started, uh I just want to provide everyone with a quick overview of what will be talked about today. First, we will cover uh we will start off with a quick introduction uh and overview of Gopher Whisper. Then I will go into details about the first back door, Lax Gopher, and how we came to identify the tool, Compact Gopher. Afterwards, three other back doors will be covered, uh Rat Gopher, Box of Friends, and SSL Lordor. Lastly, the talk will conclude providing recommendations and summarizing our observations.
[1:10]So, Gopher Whisper is a China aligned group, and I know what you must be thinking, what makes them China aligned? Well, throughout this presentation, I will go into details from data we acquired from the CNC servers, along with messages we were able to retrieve using their very own hard coded credentials that will demonstrate our justification. It was from these very same CNC messages that we were able to confirm that the group has been active since at least 2023. Additionally, from the backdoors we've seen and used by the group, we know that the group makes use of publicly available services like Discord, Slack, Microsoft Graph, and the follow sharing service, file.io. And throughout this presentation, we will come to know that the group really enjoys using Golang, which based on the Golang mascot, inspired part of the name for Gopher Whisper.
[2:04]So why the new group? So, based on how the group operates with their use of Slack, Discord, and Microsoft Graph, along with the significant use of tools built with the Golang programming language, uh we weren't able to make any attributions to any existing groups. We were also unable to link any of the new and custom backdoors, as well as injectors, to any known groups. Adding to the group, uh new group reasoning is the victimology. Gopher Whisper was first discovered through our telemetry in early 2025 on a victim in Mongolia.
[2:41]It was later identified that the victim of these attacks is a government entity within Mongolia, and we were also able to confirm through CNC messages that Mongolia was the single and only targeted country of this activity. Now, going to a quick timeline of the first victim occurrences, uh seen through our telemetry, on January 2nd of 2025, we first observed the injector Jab Gopher and the backdoor Lax Gopher, which has which was the spark to ignite our initial investigations. A few days later, through CNC messages recovered from Lax Gopher, we discovered an exfiltration tool that we call Compact Gopher.
[3:24]On January 22nd, we saw first activity of the Rat Gopher backdoor, and a couple of months later, on March 5th, we detected friend delivery, which injects the Box of Friends backdoor. And finally on March 24th, we identified the final backdoor, SSL Ord door.
[3:46]So let's take a look at Lax Gopher. So before diving deep into the details of the Lax Gopher back door, I just want to briefly cover the execution chain we observed with Lax Gopher. It was found that a legitimate executable, which is an open source wrapper to Open AI's automatic speak recognition model, that is a mouthful, uh side loads a tool we've called Jab Gopher. Jab Gopher decrypts bytes from within its own resource section, which results in the whisper.dll for the Lax Gopher backdoor. The Lax Gopher DLL is then injected into a newly created SVC host process where the backdoor continues to execute and communicates with a private Slack server. So Lax Gopher is a backdoor written in Go, using a private Slack server for communications, and it only has five commands. Uh COOM is used with a Boolean flag to start an instance of a Windows command prompt on the impacted host, which can then be used in combination with the command command to pass a string to execute on the command prompt. Upload, which is pretty standard in this case, uh takes an absolute path and uploads the uh a file to the Slack server, and download, which takes only a Boolean, signals the backdoor to reach out to the Slack server channel and download a hosted file. And lastly, uh change, which is an interesting command that I'll get into here shortly, uh to modify the token and Slack channel, uh the backdoor is using for a specific victim. When Lax Gopher first executes, it decrypts a hard-coded Slack API token and a channel ID to establish a connection to the private Slack server. And once it once it connects, it will sit in a loop waiting for a How are you message uh from the main channel.
[5:43]After the initial initial message of How are you is processed by the backdoor, a response is sent back to the server containing the victim host name using Win API. So where does this change come in?
[5:58]After Lax Gopher uh successfully alerts the operators that a new victim has connected by receiving the host name, a change command can be issued. Issuing a command focuses on a specific victim so that operators can isolate that victim into their own channel, which is useful for things like obtaining uploaded and downloaded files, as well as issuing commands or reviewing command history without impacting other connected victim machines. Before going into some of the messages, uh we followed one of the change commands using the updated Slack token to enumerate metadata about one of the configured channels. And by enumerating that Slack server channel, the metadata JSON object returned a display name that belonged to a host who is part of the government entity in Mongolia. Further into the JSON metadata, uh we can also see the locale set to a value of CH-CN, which is used for simplified Chinese.
[7:00]This is important because by default Slack does not use server locals. Uh, the locale is taken from the user itself, or it is configured in the Slack workspace, meaning that the user or Slack server associated with the hard coded token we used is actually configured to format messages as simplified Chinese.
[7:20]After finding the locale and analyzing all the messages, uh we found that there were only two instances where Chinese was actually used. Uh, these were likely messages from Slack making a notification in the channel that a user has joined the channel and that the channel name has changed. Everything else from the standpoint of commands was done completely in English.
[8:00]And since I already gave it away that we were able to access the Slack server, uh we recovered just a little over 6,000 messages. Slack by default keeps message timestamps in UTC, but since we know the expected locale and assuming timestamps are formatted within the time zone used in mainland China, we can adjust for the China standard time UTC + 8. Funny enough, uh as we can see, uh when we uh apply CST, uh we found that most activity occurred between 9:00 a.m. and 9:00 p.m. This follows the 996 working hour system implemented in China, where workers are active between 9:00 a.m. to 9:00 p.m., six days a week.
[8:46]And from the messages, I'm sure we've all done this in the past where we use our messaging platforms to send either messages or files to ourselves. Well, I don't believe operators are much different here. Um, from early CNC messages and files, we came across several links relating to how to create a service, how to perform injections, various utilities and encryptions, all in Golang, likely used as references and libraries during Mauer development phases.
[9:16]Digging further into some of the recovered messages, we saw early on that operators were having a hard time from their machines getting network connectivity to Slack. But what's interesting is that the IP that was resolved for Slack points to the closest server out of Tokyo, Japan, increasing the likelihood that operators reside in countries nearby, like China.
[9:38]But what is also great is that operators were nice enough to leave behind old testing activities including enumerating their machine through system info commands. As we can see, operators are using VMware host machines. And we can also find the time zone is set to Pacific UTC - 8 and the locale as ENS, which is likely due to using default configuration values when installing Windows. This enumeration was actually super helpful to identify host names that connected to the Slack server, uh that belong to operators and which ones were belonging to victims. We also found that operators listed their IP configurations, which is as a result revealed that they were using a VPN. This is likely due to the fact that countries like China block certain uh services like Slack by default and require a VPN to circumvent these blocks. And of course, the enumeration doesn't end there. Maybe because they were testing the upload function of large files, we found that operators created a file which contained a recursive directory call listing their entire C drive. As a result, in their downloads directory, contained some interesting file names including how to write rat, uh, which leads us to believe that these operators might be new to developing malware. From further testing coming from an operator connected machine, we also observed testing activities of a service called Keylogger. Uh, this was done after downloading a key logger, which of course is written in Go, by the way. Through the back door. And as we can see from the name, it appears that operators were attempting it to make make it look like some sort of .net application. Shortly after the service creation on the operator machine, uh the same key logger was also found under a different name and was found being persisted through the use of registry keys.
[11:43]Some other tools that we found in addition to the key logger is the rp.exe application that can be found from many download locations online, known to be a run as tool using token impersonation to execute a command. The command in this case was to make use of a dropped web browser pass view, which is a public tool to reveal passwords stored in several browsers and dump them into a file on disk. Also during operator testing activity, we found a der command that had some interesting results. And I say interesting because unfortunately, redacted for privacy, some of the executables contain user names of the targeted victims. This is likely due to operators customizing payloads to specific hosts within Mongolia. We did come across the compressed archives that contain these executables on their respective victims, but unfortunately could not extract the contents for analysis because the archives were password protected.
[12:44]One tool that really caught our attention, uh was uploaded as a zip archive to a victim machine containing a single executable. After extracting the executable into a temporary location, it was executed with a few arguments provided. And during its execution, output can be seen written to the terminal that a zip file was successfully created, then encryption was a success and that upload to file IO was complete, which was then finally proceeded with a successful delete message. Now you know the history of how we were able to identify Compact Gopher. Compact Gopher is a collection and exfiltration tool, seen uh deployed by Lax Gopher as we just saw. It too is written in Go and has a few command line arguments to get it started. Sourcedir is used to specify the directory in which to collect files and does so recursively. Outputdir is the location of the compressed archive that's expected. Starttime and endtime are used to specify what date range should be should the tool uh collect files for based on the creation time of that file. Based on the arguments provided to Compact Gopher on the command line, uh Compact Gopher sets forth with the filtering criteria to find any files recursively in the specified directory, matching hard coded extensions for documents, spreadsheets, PDFs, PowerPoints, and text files. After collecting these files, they are compressed into a zip archive that is then encrypted and uploaded to file.io. Finally, if file.io responds with a successful upload, the temp files are deleted from disk. And for those who don't know about file IO, it's a file sharing service that provides not only a front-end application, but an API as well, making it easy to use through HTTP requests. File IO advertises that they are like Snapchat for files, where once a file is downloaded, it is removed from their servers, which will invalidate the link. An expiry can also be configured to retain the download uh for a period of time, but after expiry or if the file is downloaded, the file is again deleted from the service servers with no chance of recovery. This makes a great tool for operators to use because it requires no registration, and once an operator successfully downloads their file, it's gone from the system, making it unrecoverable and less work for them to have to deal with cleanup.
[15:25]Let's now take a look into Rat Gopher, uh which is inspired by the internal package name used by the backdoor called Rat 0813. Rat Gopher is a backdoor and, surprise, surprise, it's written in Go, and uses Discord this time for CNC. Each CNC message is a JSON object that comprises of a type, also known as the command, and the content containing the arguments uh for a command. The backdoor shares some similarities with Lax Gopher commands. Uh first creates an instance of command prompt through the command 1001, and uses sub calls of 1002 to provide the arguments to be executed on open command prompt instance. Commands 2001 and 3001 are commands for uploading and downloading files directly to file.io, which in this case removes the need to deploy tools like Compact Gopher for data exfiltration, streamlining the process. And this has may have also been an an alternative to avoid upload size limitations that are set by Discord.
[16:37]Rat Gopher also has a series of types that are used for response messages only. Uh these are used to alert the operator of any ongoing activities that may have failed or succeeded. Some of these, as you can find, are repeats. However, uh many of the response codes are found in specific regions of the backdoor, which operators are likely aware of, giving them an idea of where they had actually occurred.
[17:05]Now Rat Gopher has a somewhat complex initialization uh method. Uh first it uses a hard coded key and base 64 encoded string, which the backdoor decrypts to reveal the channel and user ID along with the Discord token used to contact the the operator ran Discord server. Once a connection is established, uh operators send the message, hello, this is name speaking with a base 64 encoded string between pipes. This is where things get a little bit confusing, uh but by using the previously decrypted user and channel ID, both of which get processed as MD5 sums, are set as AES CFB keys and IV. The MD5 sum used as the key and IV are then used against the ba the decoded base 64 bytes, which results in yet another key and IV, but this time for AES CPC, which is used only for message decryption.
[18:04]After that, uh successfully obtaining the new AES CBC key and IV, uh the back door notifies operators that it is ready to receive a commands by sending the message, hello everyone, I'm coming. Very polite back door.
[18:36]So by using the um credentials and encryption keys, we successfully collected all messages from the Discord server at the time, uh which recovered just a little over 3,000 uh messages. By applying the same China standard time to the messages as we did with Lax Gopher backdoor, we observed similar time frames. Again, operators were most active actively issuing commands during 996 working hours, uh so between 9:00 a.m. and 9:00 p.m., with what appears to be some sort of lunch break between 12:00 and 1:00. I guess operators have to eat as well.
[19:15]From the earliest messages uh we observed, there are three distinct users participating in message activity, Cardinal, Bot, uh Bot Manager and Bot Test one. And Cardinal is the user who we believe uh owns the server, and as we can see from their message history, they really wanted to pick a fight with the back door for some reason. Uh so we're not certain if this may have been early signs of developer exhaustion or the beginning of some sort of uh some kind of existential crisis. Later messages active uh message activity did not include Cardinal, uh as this user played no role in the activity against Mongolia. However, we know that from the CNC messages that Bot Manager is the bot who provides CNC commands to the back door, and Bot Test one is the configured user with their token hard coded in the back door responding to the operators.
[20:12]So by using the unique IDs, which we found in the Discord channel, uh which are known as Snowflake IDs by Discord, uh for each user, we can extract the creation date and even uh determine if the account is a bot. The date time stamps, as we can see on the slide, uh and in correlation with what we observed in the messages, gives us a great time frame that the operators first began working on this back door as early as November 2023.
[20:43]From decrypting messages in Discord, we came across more enumeration performed by operators, likely testing functionality. And again, operators are using VMware hosts.
[20:57]And they also appear to be using a VPN again, likely to be able to access Discord outside of countries like China where it is generally blocked.
[21:09]From the decrypted messages, we also uncovered that early on in testing, operators were using a Linux host, uh which later we saw that they migrated to a Windows machine, as we can see based off uh on both images, listing directories at the project folder level.
[21:38]As a result of the dump, we found that this was actually early stages for Rat Gopher. However, as we know, coming from a Linux host, the first iterations were likely developed as a proof of concept running on Linux only. So, for example, we can see that the uh Shell Start function, um only supported the Linux Bash shell at this time. Later additions of Rat Gopher that were found on Windows hosts in Mongolia, kept the same data packet seen here for the command and argument structure. Moving on now to Box of Friends, uh again inspired by a package name containing malicious code. But before we dive into uh the back door, um much like Lax Gopher, Box of Friends makes use of an injection process we call friend delivery. By using a legitimate word fault that is validated through a CRC 32 check, uh malicious word.dll is side loaded. During execution of friend delivery, a copy of the executable and DLL is made to a fake Bit Defender directory in app data. This directory is used as the execution path for the persistent Windows service uh created by friend delivery. When the service executes, it performs the same side loading process as previously seen, uh but with a slight modification uh to the command line arguments in order to launch the back door.
[23:14]So, as we can see based on the configured Windows service, uh the path uh the path to the executable has new argument appended to it, dash S. Uh this dash S argument argument notifies the friend delivery uh that the back door can be started. To do so, friend delivery reads bytes from its overlay in search for a specific string of bytes. Once successfully finds the offset located by the string marker, all remaining bytes are decrypted resulting in the bytes that make up Box of Friends. These bytes are then used to inject into a newly created process, help.exe, where Box of Friends is executed. And I'm sure you've all guessed it by now, that Box of Friends is a backdoor written in Golang. The backdoor uses Microsoft Graph API, but more specifically API end points for creating and modifying draft emails. Draft emails are used to control the behavior of the backdoor with commands appearing as recipients and arguments within message bodies. So for example, there are only four uh different command type recipients that perform the activity of updating an internal RC4 uh encryption key, uploading a large file, which is actually done by chunking the file into multiple draft updates, followed by a sleep allowing the operators time to um ingest that file, and then a single file upload. There is also some sub command processing. And some of the sub command processing performed include a self delete, which will delete the file used in the injection process from disk, but it will not remove the persistence created through the service. So since this is running under help.exe, which is a known Windows executable, it will actually delete that help.exe from the disk. There's also CD to change or display the working directory. Download, which uses the contents of the draft email body to write to a file. Sleep, which obviously just pauses the execution. Interval specifies how long to wait until a heart beat is sent. Um there's also port forwarding, which is used to establish new forwarding ports, exposing services or applications. And any command that isn't hard coded as you see above is executed directly on a Windows command prompt, which kind of begs the question, why did they have to hard code these arguments in? Along with various command recipients, we also found response recipients. Uh so when Box of Friends first launches, it will use Adam 930 uh to create a new draft with enumeration results of the victim machine to the operator. Periodically, Seth 912 will be seen providing heartbeats along with the same enumeration data as Adam at configured uh intervals. And anytime the internal RC4 key is rotated for encryption, Caan 910 can be found notifying that the to the operators that the operation completed successfully. And lastly as a catch all, uh Maliyah 895 provides all other responses performed by various activities across the backdoor.
[26:32]As we know, uh commands are performed by the recipient for each updated draft email. However, in certain cases of specific recipients, either a base 64 or base 58 encoding will be used. When a base 58 encoding is used, uh messages are decrypted with an XOR key that is stored in the subject of the email. This key is created during first launch of Box of Friends, where it is derived from an MD5 sum of the first network interface's Mac address. However, if base 64 is used, RC4 is then used with a key that is capable of being rotated as I explained previously. During each uh during communication, each request makes use of a bear token that is uh generated from using the hard coded client ID, secret, and refresh token uh for Microsoft graph. And as I previously mentioned, draft emails are used to pass the CNC messages between victims and operators and vice versa. The issue with this is that it makes it impossible to recover uh any historical messages unless you're actively grabbing them at the same time operators are. This is because Box of Friends overwrites each draft email by saving a new recipient and message body every time a communication occurs. Using the hard coded credentials, we were able to obtain 43 draft messages. But because of this message uh method of updating draft emails, we can only say that there is a possibility a possible total of up to 43 infections. We can't confirm the number because of lacking details and due to the fact that Box of Friend also creates a new draft if the backdoor was restarted from the machine or process being restarted. Luckily for us though, draft emails have a creation and modified date associated with them, uh which gives us a sense of when these infections first occurred and when they were last updated. And based on the earliest draft messages we could find, we know that CNC activity began as early as April 1st of 2025. From one of the five emails in the inbox, uh we also came across a welcome to Outlook email, which shows that the account was created sometime in July of 2024, and gives us a sense that it took almost a year to see first activity of the back door.
[29:10]All right, uh the last backdoor I have to share for with you today is SSL Ord door. Now, again, I know what you must be thinking, great, another go backdoor. Well, I've tricked you, this one's written in C++. And for the amount of times I've had to say SSL Ord door, I've started to feel like I'm on some uh some form of cyber spin-off of Game of Thrones. But uh SSL Ord door makes use of the Open SSL BIO library to securely create a connection to the operator own infrastructure and decrypts all messages using RC4.
[29:52]SSL Ord door has several commands, some of which, like we've seen with previous backdoors, share a purpose. The backdoor is capable of executing commands directly against a Windows command prompt. Enumerate drives specifically from A to Z. Searches for a file and provides the metadata results back if it exists. Uh it's capable of uploading a file and deleting files or directories. There's also commands to open a file for writing where bytes can be streamed in as content from the C2. Uh it's also able to execute a file on disk and can manage a socket proxy connection.
[30:37]Since SSL Ord door has been found as an only as an executable, its execution chain is relatively simple. However, during execution, it does try to locate a DLL, and if that DLL does exist, it will halt any further execution. We believe that this may have been left over during development or testing to prevent self-infection on a operator machine. And communication to the server is also pretty straightforward. Uh using the Open SSL library to manage the socket, operators also use a simple XOR operation on top of already RC4 encrypted bytes. And depending on if the messages are seen as commands, uh they will be passed as a buffer length of 4,088 bytes, whereas the response will be sent back to the operators as a buffer of 4,096 bytes.
[31:32]The RC4 that's used in uh the case of communication was likely custom made uh to add a layer of obfuscation to avoid uh detection and prevent static analysis. I won't go into significant details about every single operation, but to start off, we have a strange buffer size of 528 bytes. In the init section, uh additional operations are performed to make the initial identity permutation appear more complex uh than needed to be, uh and can also be seen using a weird offset starting at 16.
[32:25]In the pseudo pseudo random uh generation algorithm, we again find the strange uh start offset of 16 with an index, uh which is being used uh in an XOR operation with the buffer that was passed to the function.
[33:02]All right, so now on to the conclusion. So from what we've covered in this presentation, we know that Gopher Whisper Group uses an arsenal of tool, uh most of which are written in Go. It was found that back doors communicate to Slack, Discord or Microsoft graph and have been seen deploying tools to exfiltrate data and obtain credentials.
[33:28]As a result of the back door using publicly and well documented services, along with hard coded credentials, we successfully recovered a total of 9,098 CNC messages, containing testing activity and targeted activity against Mongolia.
[33:54]Before parting today, I'll leave with uh some advice. And I know it's difficult to implement, but applications like Discord may be out of the scope of the workplace policy and as such should be properly monitored for activity. Leading to my next point that noisy chat applications or even post requests to the API of chat applications seen uploading large number of bytes may indicate a bigger issue like data exfiltration. So it's important to look into these situations. Finally, access to web and non-web-based applications that could lead to exfill should be blocked, as an example in this infection, the use of file.io can be an easy method for anyone to upload critical data from internal systems if not properly managed. And lastly, if you're still interested into even more details about the backdoor and injectors, a blog post accompanied by a white paper and all the IOCs will be published on April 23rd. Thank you.
[35:09]Okay, time for questions.
[35:16]Who's got a question?
[35:20]Balcony, yeah.
[35:24]Hello. Um thank you for the talk. I wanted to ask what kind of tools and plugins did you use to reverse engineer the Golang binaries? Honestly, it was just Ida. So newer newer versions of Ida have, um, Golang disassembler is kind of built in. Uh previously I used to use Go Analyzer, uh which was a plug-in for Ida 8.4 or something like that, but uh, yeah, now you can just use Ida. Okay, thank you. One here.
[35:57]Thank you, very good presentation. Did you see any hint as that the developers were directly from Chinese hacker teams, uh sponsored by uh various uh governments there or by um hacker for hire, meaning organizations, development organizations that would uh build that tool set for them. Yeah, so there's no evidence that would support that they're part of some sort of team or not, but I'd have to assume that they are just because the number of tools that they're working on, uh and the number of tools that they're deploying all at the same time. As you saw that this was all deployed within a very short time frame, so of course they're they're doing a lot of testing activities, uh by uh implicating victims. So I do believe that there is some sort of team that's behind it.
[36:56]Thank you.
[37:00]Uh in the front. You said the victims were in Mongolia, is that right? Um were they not also suffering from the the great firewall of China blocking their access to places like Discord or or Telegram or or Slack or whatever? So That's a great question. I have not actually looked into that. Um so it is possible that Mongolia might be blocking those activities, but from what we saw based on how they were able to communicate with the CNCs, uh and there's also additional enumerations that I could not share about the IP configurations of the victims, uh we did not see any VPNs that were assigned to these users, so chances are they had some way of being able to access the Slack and Discord. Okay.



