Friday Squid Blogging: The Chinese Squid-Fishing Fleet off the Argentine Coast
The latest article on this topic.
As usual, you can also use this squid post to talk about the security stories in the news that I haven’t covered.
The latest article on this topic.
As usual, you can also use this squid post to talk about the security stories in the news that I haven’t covered.
For the third year in a row, Amazon Web Services (AWS) is named as a Leader in the Information Services Group (ISG) Provider LensTM Quadrant report for Sovereign Cloud Infrastructure Services (EU), published on January 9, 2026. ISG is a leading global technology research, analyst, and advisory firm that serves as a trusted business partner to more than 900 clients. This ISG report evaluates 19 providers of sovereign cloud infrastructure services in the multi-public-cloud environment and examines how they address the key challenges that enterprise clients face in the European Union (EU). ISG defines Leaders as providers who represent innovative strength and competitive stability.
ISG rated AWS ahead of other leading cloud providers on both the competitive strength and portfolio attractiveness axes, with the highest score on portfolio attractiveness. Competitive strength was assessed on multiple factors, including degree of awareness, core competencies, and go-to-market strategy. Portfolio attractiveness was assessed on multiple factors, including scope of portfolio, portfolio quality, strategy and vision, and local characteristics.
According to ISG, “AWS’s infrastructure provides robust resilience and availability, supported by a sovereign-by-design architecture that ensures data residency and regional independence.”
Read the report to:
AWS’s recognition as a Leader in this report for the third consecutive year underscores our commitment to helping European customers and partners meet their digital sovereignty and resilience requirements. We are building on the strong foundation of security and resilience that has underpinned AWS services, including our long-standing commitment to customer control over data residency, our design principal of strong regional isolation, our deep European engineering roots, and our more than a decade of experience operating multiple independent clouds for the most critical and restricted workloads.
Download the full 2025 ISG Provider Lens Quadrant report for Sovereign Cloud Infrastructure Services (EU).
If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, contact AWS Support.
Palo Alto’s crosswalk signals were hacked last year. Turns out the city never changed the default passwords.
Leaders of many organizations are urging their teams to adopt agentic AI to improve efficiency, but are finding it hard to achieve any benefit. Managers attempting to add AI agents to existing human teams may find that bots fail to faithfully follow their instructions, return pointless or obvious results or burn precious time and resources spinning on tasks that older, simpler systems could have accomplished just as well.
The technical innovators getting the most out of AI are finding that the technology can be remarkably human in its behavior. And the more groups of AI agents are given tasks that require cooperation and collaboration, the more those human-like dynamics emerge.
Our research suggests that, because of how directly they seem to apply to hybrid teams of human and digital workers, the most effective leaders in the coming years may still be those who excel at understanding the timeworn principles of human management.
We have spent years studying the risks and opportunities for organizations adopting AI. Our 2025 book, Rewiring Democracy, examines lessons from AI adoption in government institutions and civil society worldwide. In it, we identify where the technology has made the biggest impact and where it fails to make a difference. Today, we see many of the organizations we’ve studied taking another shot at AI adoption—this time, with agentic tools. While generative AI generates, agentic AI acts and achieves goals such as automating supply chain processes, making data-driven investment decisions or managing complex project workflows. The cutting edge of AI development research is starting to reveal what works best in this new paradigm.
There are four key areas where AI should reliably boast superhuman performance: in speed, scale, scope and sophistication. Again and again, the most impactful AI applications leverage their capabilities in one or more of these areas. Think of content-moderation AI that can scan thousands of posts in an instant, legislative policy tools that can scale deliberations to millions of constituents, and protein-folding AI that can model molecular interactions with greater sophistication than any biophysicist.
Equally, AI applications that don’t leverage these core capabilities typically fail to impress. For example, Google’s AI Overviews irritate many of its users when the overviews obscure information that could be more efficiently consumed straight from the web results that the AI attempted to synthesize.
Agentic AI extends these core advantages of AI to new tasks and scenarios. The most familiar AI tools are chatbots, image generators and other models that take a single action: ask one question, get one answer. Agentic systems solve more complex problems by using many such AI models and giving each one the capability to use tools like retrieving information from databases and perform tasks like sending emails or executing financial transactions.
Because agentic systems are so new and their potential configurations so vast, we are still learning which business processes they will fit well with and which they will not. Gartner has estimated that 40 per cent of agentic AI projects will be cancelled within two years, largely because they are targeted where they can’t achieve meaningful business impact.
To understand the collective behaviors of agentic AI systems, we need to examine the individual AIs that comprise them. When AIs make mistakes or make things up, they can behave in ways that are truly bizarre. But when they work well, the reasons why are sometimes surprisingly relatable.
Tools like ChatGPT drew attention by sounding human. Moreover, individual AIs often behave like individual people, responding to incentives and organizing their own work in much the same ways that humans do. Recall the counterintuitive findings of many early users of ChatGPT and similar large language models (LLMs) in 2022: They seemed to perform better when offered a cash tip, told the answer was really important or were threatened with hypothetical punishments.
One of the most effective and enduring techniques discovered in those early days of LLM testing was ‘chain-of-thought prompting,’ which instructed AIs to think through and explain each step of their analysis—much like a teacher forcing a student to show their work. Individual AIs can also react to new information similar to individual people. Researchers have found that LLMs can be effective at simulating the opinions of individual people or demographic groups on diverse topics, including consumer preferences and politics.
As agentic AI develops, we are finding that groups of AIs also exhibit human-like behaviors collectively. A 2025 paper found that communities of thousands of AI agents set to chat with each other developed familiar human social behaviors like settling into echo chambers. Other researchers have observed the emergence of cooperative and competitive strategies and the development of distinct behavioral roles when setting groups of AIs to play a game together.
The fact that groups of agentic AIs are working more like human teams doesn’t necessarily indicate that machines have inherently human-like characteristics. It may be more nurture than nature: AIs are being designed with inspiration from humans. The breakthrough triumph of ChatGPT was widely attributed to using human feedback during training. Since then, AI developers have gotten better at aligning AI models to human expectations. It stands to reason, then, that we may find similarities between the management techniques that work for human workers and for agentic AI.
So, how best to manage hybrid teams of humans and agentic AIs? Lessons can be gleaned from leading AI labs. In a recent research report, Anthropic shared the practical roadmap and published lessons learned while building its Claude Research feature, which uses teams of multiple AI agents to accomplish complex reasoning tasks. For example, using agents to search the web for information and calling external tools to access information from sources like emails and documents.
Advancements in agentic AI enabling new offerings like Claude Research and Amazon Q are causing a stir among AI practitioners because they reveal insights from the frontlines of AI research about how to make agentic AI and the hybrid organizations that leverage it more effective. What is striking about Anthropic’s report is how transparent it is about all the hard-won lessons learned in developing its offering—and the fact that many of these lessons sound a lot like what we find in classic management texts:
When Anthropic analyzed what factors lead to excellent performance by Claude Research, it turned out that the best agentic systems weren’t necessarily built on the best or most expensive AI models. Rather, like a good human manager, they need to excel at breaking down and distributing tasks to their digital workers.
Unlike human teams, agentic systems can enlist as many AI workers as needed, onboard them instantly and immediately set them to work. Organizations that can exploit this scalability property of AI will gain a key advantage, but the hard part is assigning each of them to contribute meaningful, complementary work to the overall project.
In classical management, this is called delegation. Any good manager knows that, even if they have the most experience and the strongest skills of anyone on their team, they can’t do it all alone. Delegation is necessary to harness the collective capacity of their team. It turns out this is crucial to AI, too.
The authors explain this result in terms of ‘parallelization’: Being able to separate the work into small chunks allows many AI agents to contribute work simultaneously, each focusing on one piece of the problem. The research report attributes 80 per cent of the performance differences between agentic AI systems to the total amount of computing resources they leverage.
Whether or not each individual agent is the smartest in the digital toolbox, the collective has more capacity for reasoning when there are many AI ‘hands’ working together. In addition to the quality of the output, teams working in parallel get work done faster. Anthropic says that reconfiguring its AI agents to work in parallel improved research speed by 90 per cent.
Anthropic’s report on how to orchestrate agentic systems effectively reads like a classical delegation training manual: Provide a clear objective, specify the output you expect and provide guidance on what tools to use, and set boundaries. When the objective and output format is not clear, workers may come back with irrelevant or irreconcilable information.
Edison famously tested thousands of light bulb designs and filament materials before arriving at a workable solution. Likewise, successful agentic AI systems work far better when they are allowed to learn from their early attempts and then try again. Claude Research spawns a multitude of AI agents, each doubling and tripling back on their own work as they go through a trial-and-error process to land on the right results.
This is exactly how management researchers have recommended organizations staff novel projects where large teams are tasked with exploring unfamiliar terrain: Teams should split up and conduct trial-and-error learning, in parallel, like a pharmaceutical company progressing multiple molecules towards a potential clinical trial. Even when one candidate seems to have the strongest chances at the outset, there is no telling in advance which one will improve the most as it is iterated upon.
The advantage of using AI for this iterative process is speed: AI agents can complete and retry their tasks in milliseconds. A recent report from Microsoft Research illustrates this. Its agentic AI system launched up to five AI worker teams in a race to finish a task first, each plotting and pursuing its own iterative path to the destination. They found that a five-team system typically returned results about twice as fast as a single AI worker team with no loss in effectiveness, although at the cost of about twice as much total computing spend.
Going further, Claude Research’s system design endowed its top-level AI agent—the ‘Lead Researcher’—with the decision authority to delegate more research iterations if it was not satisfied with the results returned by its sub-agents. They managed the choice of whether or not they should continue their iterative search loop, to a limit. To the extent that agentic AI mirrors the world of human management, this might be one of the most important topics to watch going forward. Deciding when to stop and what is ‘good enough’ has always been one of the hardest problems organizations face.
If you work in a manufacturing department, you wouldn’t rely on your division chief to explain the specs you need to meet for a new product. You would go straight to the source: the domain experts in R&D. Successful organizations need to be able to share complex information efficiently both vertically and horizontally.
To solve the horizontal sharing problem for Claude Research, Anthropic innovated a novel mechanism for AI agents to share their outputs directly with each other by writing directly to a common file system, like a corporate intranet. In addition to saving on the cost of the central coordinator having to consume every sub-agent’s output, this approach helps resolve the information bottleneck. It enables AI agents that have become specialized in their tasks to own how their content is presented to the larger digital team. This is a smart way to leverage the superhuman scope of AI workers, enabling each of many AI agents to act as distinct subject matter experts.
In effect, Anthropic’s AI Lead Researchers must be generalist managers. Their job is to see the big picture and translate that into the guidance that sub-agents need to do their work. They don’t need to be experts on every task the sub-agents are performing. The parallel goes further: AIs working together also need to know the limits of information sharing, like what kinds of tasks don’t make sense to distribute horizontally.
Management scholars suggest that human organizations focus on automating the smallest tasks; the ones that are most repeatable and that can be executed the most independently. Tasks that require more interaction between people tend to go slower, since the communication not only adds overhead, but is something that many struggle to do effectively.
Anthropic found much the same was true of its AI agents: “Domains that require all agents to share the same context or involve many dependencies between agents are not a good fit for multi-agent systems today.” This is why the company focused its premier agentic AI feature on research, a process that can leverage a large number of sub-agents each performing repetitive, isolated searches before compiling and synthesizing the results.
All of these lessons lead to the conclusion that knowing your team and paying keen attention to how to get the best out of them will continue to be the most important skill of successful managers of both humans and AIs. With humans, we call this leadership skill empathy. That concept doesn’t apply to AIs, but the techniques of empathic managers do.
Anthropic got the most out of its AI agents by performing a thoughtful, systematic analysis of their performance and what supports they benefited from, and then used that insight to optimize how they execute as a team. Claude Research is designed to put different AI models in the positions where they are most likely to succeed. Anthropic’s most intelligent Opus model takes the Lead Researcher role, while their cheaper and faster Sonnet model fulfills the more numerous sub-agent roles. Anthropic has analyzed how to distribute responsibility and share information across its digital worker network. And it knows that the next generation of AI models might work in importantly different ways, so it has built performance measurement and management systems that help it tune its organizational architecture to adapt to the characteristics of its AI ‘workers.’
Managers of hybrid teams can apply these ideas to design their own complex systems of human and digital workers:
Analyze the tasks in your workflows so that you can design a division of labour that plays to the strength of each of your resources. Entrust your most experienced humans with the roles that require context and judgment and entrust AI models with the tasks that need to be done quickly or benefit from extreme parallelization.
If you’re building a hybrid customer service organization, let AIs handle tasks like eliciting pertinent information from customers and suggesting common solutions. But always escalate to human representatives to resolve unique situations and offer accommodations, especially when doing so can carry legal obligations and financial ramifications. To help them work together well, task the AI agents with preparing concise briefs compiling the case history and potential resolutions to help humans jump into the conversation.
AIs will likely underperform your top human team members when it comes to solving novel problems in the fields in which they are expert. But AI agents’ speed and parallelization still make them valuable partners. Look for ways to augment human-led explorations of new territory with agentic AI scouting teams that can explore many paths for them in advance.
Hybrid software development teams will especially benefit from this strategy. Agentic coding AI systems are capable of building apps, autonomously making improvements to and bug-fixing their code to meet a spec. But without humans in the loop, they can fall into rabbit holes. Examples abound of AI-generated code that might appear to satisfy specified requirements, but diverges from products that meet organizational requirements for security, integration or user experiences that humans would truly desire. Take advantage of the fast iteration of AI programmers to test different solutions, but make sure your human team is checking its work and redirecting the AI when needed.
Make sure each of your hybrid team’s outputs are accessible to each other so that they can benefit from each others’ work products. Make sure workers doing hand-offs write down clear instructions with enough context that either a human colleague or AI model could follow. Anthropic found that AI teams benefited from clearly communicating their work to each other, and the same will be true of communication between humans and AI in hybrid teams.
Organizations should always strive to grow the capabilities of their human team members over time. Assume that the capabilities and behaviors of your AI team members will change over time, too, but at a much faster rate. So will the ways the humans and AIs interact together. Make sure to understand how they are performing individually and together at the task level, and plan to experiment with the roles you ask AI workers to take on as the technology evolves.
An important example of this comes from medical imaging. Harvard Medical School researchers have found that hybrid AI-physician teams have wildly varying performance as diagnosticians. The problem wasn’t necessarily that the AI has poor or inconsistent performance; what mattered was the interaction between person and machine. Different doctors’ diagnostic performance benefited—or suffered—at different levels when they used AI tools. Being able to measure and optimize those interactions, perhaps at the individual level, will be critical to hybrid organizations.
We are in a phase of AI technology where the best performance is going to come from mixed teams of humans and AIs working together. Managing those teams is not going to be the same as we’ve grown used to, but the hard-won lessons of decades past still have a lot to offer.
This essay was written with Nathan E. Sanders, and originally appeared in Rotman Management Magazine.
The New York City Wegman’s is collecting biometric information about customers.
We don’t have many details:
President Donald Trump suggested Saturday that the U.S. used cyberattacks or other technical capabilities to cut power off in Caracas during strikes on the Venezuelan capital that led to the capture of Venezuelan President Nicolás Maduro.
If true, it would mark one of the most public uses of U.S. cyber power against another nation in recent memory. These operations are typically highly classified, and the U.S. is considered one of the most advanced nations in cyberspace operations globally.
Wired is reporting on Chinese darknet markets on Telegram.
The ecosystem of marketplaces for Chinese-speaking crypto scammers hosted on the messaging service Telegram have now grown to be bigger than ever before, according to a new analysis from the crypto tracing firm Elliptic. Despite a brief drop after Telegram banned two of the biggest such markets in early 2025, the two current top markets, known as Tudou Guarantee and Xinbi Guarantee, are together enabling close to $2 billion a month in money-laundering transactions, sales of scam tools like stolen data, fake investment websites, and AI deepfake tools, as well as other black market services as varied as pregnancy surrogacy and teen prostitution.
The crypto romance and investment scams regrettably known as “pig butchering”—carried out largely from compounds in Southeast Asia staffed with thousands of human trafficking victims—have grown to become the world’s most lucrative form of cybercrime. They pull in around $10 billion annually from US victims alone, according to the FBI. By selling money-laundering services and other scam-related offerings to those operations, markets like Tudou Guarantee and Xinbi Guarantee have grown in parallel to an immense scale.
Probably a college prank.
As usual, you can also use this squid post to talk about the security stories in the news that I haven’t covered.
404 Media has the story:
Unlike many of Flock’s cameras, which are designed to capture license plates as people drive by, Flock’s Condor cameras are pan-tilt-zoom (PTZ) cameras designed to record and track people, not vehicles. Condor cameras can be set to automatically zoom in on people’s faces as they walk through a parking lot, down a public street, or play on a playground, or they can be controlled manually, according to marketing material on Flock’s website. We watched Condor cameras zoom in on a woman walking her dog on a bike path in suburban Atlanta; a camera followed a man walking through a Macy’s parking lot in Bakersfield; surveil children swinging on a swingset at a playground; and film high-res video of people sitting at a stoplight in traffic. In one case, we were able to watch a man rollerblade down Brookhaven, Georgia’s Peachtree Creek Greenway bike path. The Flock camera zoomed in on him and tracked him as he rolled past. Minutes later, he showed up on another exposed camera livestream further down the bike path. The camera’s resolution was good enough that we were able to see that, when he stopped beneath one of the cameras, he was watching rollerblading videos on his phone.
Interesting article on the variety of LinkedIn job scams around the world:
In India, tech jobs are used as bait because the industry employs millions of people and offers high-paying roles. In Kenya, the recruitment industry is largely unorganized, so scamsters leverage fake personal referrals. In Mexico, bad actors capitalize on the informal nature of the job economy by advertising fake formal roles that carry a promise of security. In Nigeria, scamsters often manage to get LinkedIn users to share their login credentials with the lure of paid work, preying on their desperation amid an especially acute unemployment crisis.
These are scams involving fraudulent employers convincing prospective employees to send them money for various fees. There is an entirely different set of scams involving fraudulent employees getting hired for remote jobs.
Scammers are generating images of broken merchandise in order to apply for refunds.
I’ve worked in cybersecurity long enough to see that our biggest challenge isn’t a technical one, it’s motivational. We can build the strongest firewalls, design the smartest detection systems, and run endless awareness campaigns, but none of it matters if people don’t want to care. That’s the uncomfortable truth; cyber security has a motivation problem. […]
The post Cybersecurity Has a Motivation Problem appeared first on Heimdal Security Blog.

Authored by Joshua Kamp
The authors behind Android banking malware Vultur have been spotted adding new technical features, which allow the malware operator to further remotely interact with the victim’s mobile device. Vultur has also started masquerading more of its malicious activity by encrypting its C2 communication, using multiple encrypted payloads that are decrypted on the fly, and using the guise of legitimate applications to carry out its malicious actions.
Vultur is one of the first Android banking malware families to include screen recording capabilities. It contains features such as keylogging and interacting with the victim’s device screen. Vultur mainly targets banking apps for keylogging and remote control. Vultur was first discovered by ThreatFabric in late March 2021. Back then, Vultur (ab)used the legitimate software products AlphaVNC and ngrok for remote access to the VNC server running on the victim’s device. Vultur was distributed through a dropper-framework called Brunhilda, responsible for hosting malicious applications on the Google Play Store [1]. The initial blog on Vultur uncovered that there is a notable connection between these two malware families, as they are both developed by the same threat actors [2].
In a recent campaign, the Brunhilda dropper is spread in a hybrid attack using both SMS and a phone call. The first SMS message guides the victim to a phone call. When the victim calls the number, the fraudster provides the victim with a second SMS that includes the link to the dropper: a modified version of the McAfee Security app.
The dropper deploys an updated version of Vultur banking malware through 3 payloads, where the final 2 Vultur payloads effectively work together by invoking each other’s functionality. The payloads are installed when the infected device has successfully registered with the Brunhilda Command-and-Control (C2) server. In the latest version of Vultur, the threat actors have added a total of 7 new C2 methods and 41 new Firebase Cloud Messaging (FCM) commands. Most of the added commands are related to remote access functionality using Android’s Accessibility Services, allowing the malware operator to remotely interact with the victim’s screen in a way that is more flexible compared to the use of AlphaVNC and ngrok.
In this blog we provide a comprehensive analysis of Vultur, beginning with an overview of its infection chain. We then delve into its new features, uncover its obfuscation techniques and evasion methods, and examine its execution flow. Following that, we dissect its C2 communication, discuss detection based on YARA, and draw conclusions. Let’s soar alongside Vultur’s smarter mobile malware strategies!
In order to deceive unsuspecting individuals into installing malware, the threat actors employ a hybrid attack using two SMS messages and a phone call. First, the victim receives an SMS message that instructs them to call a number if they did not authorise a transaction involving a large amount of money. In reality, this transaction never occurred, but it creates a false sense of urgency to trick the victim into acting quickly. A second SMS is sent during the phone call, where the victim is instructed into installing a trojanised version of the McAfee Security app from a link. This application is actually Brunhilda dropper, which looks benign to the victim as it contains functionality that the original McAfee Security app would have. As illustrated below, this dropper decrypts and executes a total of 3 Vultur-related payloads, giving the threat actors total control over the victim’s mobile device.

Figure 1: Visualisation of the complete infection chain. Note: communication with the C2 server occurs during every malware stage.
The latest updates to Vultur bring some interesting changes worth discussing. The most intriguing addition is the malware’s ability to remotely interact with the infected device through the use of Android’s Accessibility Services. The malware operator can now send commands in order to perform clicks, scrolls, swipe gestures, and more. Firebase Cloud Messaging (FCM), a messaging service provided by Google, is used for sending messages from the C2 server to the infected device. The message sent by the malware operator through FCM can contain a command, which, upon receipt, triggers the execution of corresponding functionality within the malware. This eliminates the need for an ongoing connection with the device, as can be seen from the code snippet below.

Figure 2: Decompiled code snippet showing Vultur’s ability to perform clicks and scrolls using Accessibility Services. Note for this (and upcoming) screenshot(s): some variables, classes and method names were renamed by the analyst. Pink strings indicate that they were decrypted.
While Vultur can still maintain an ongoing remote connection with the device through the use of AlphaVNC and ngrok, the new Accessibility Services related FCM commands provide the actor with more flexibility.
In addition to its more advanced remote control capabilities, Vultur introduced file manager functionality in the latest version. The file manager feature includes the ability to download, upload, delete, install, and find files. This effectively grants the actor(s) with even more control over the infected device.

Figure 3: Decompiled code snippet showing part of the file manager related functionality.
Another interesting new feature is the ability to block the victim from interacting with apps on the device. Regarding this functionality, the malware operator can specify a list of apps to press back on when detected as running on the device. The actor can include custom HTML code as a “template” for blocked apps. The list of apps to block and the corresponding HTML code to be displayed is retrieved through the vnc.blocked.packages C2 method. This is then stored in the app’s SharedPreferences. If available, the HTML code related to the blocked app will be displayed in a WebView after it presses back. If no HTML code is set for the app to block, it shows a default “Temporarily Unavailable” message after pressing back. For this feature, payload #3 interacts with code defined in payload #2.

Figure 4: Decompiled code snippet showing part of Vultur’s implementation for blocking apps.
The use of Android’s Accessibility Services to perform RAT related functionality (such as pressing back, performing clicks and swipe gestures) is something that is not new in Android malware. In fact, it is present in most Android bankers today. The latest features in Vultur show that its actors are catching up with this trend, and are even including functionality that is less common in Android RATs and bankers, such as controlling the device volume.
A full list of Vultur’s updated and new C2 methods / FCM commands can be found in the “C2 Communication” section of this blog.
Like a crafty bird camouflaging its nest, Vultur now employs a set of new obfuscation and detection evasion techniques when compared to its previous versions. Let’s look into some of the notable updates that set apart the latest variant from older editions of Vultur.
In October 2022, ThreatFabric mentioned that Brunhilda started using string obfuscation using AES with a varying key in the malware samples themselves [3]. At this point in time, both Brunhilda and Vultur did not encrypt its HTTP requests. That has changed now, however, with the malware developer’s adoption of AES encryption and Base64 encoding requests in the latest variants.

Figure 5: Example AES encrypted and Base64 encoded request for bot registration.
By encrypting its communications, malware can evade detection of security solutions that rely on inspecting network traffic for known patterns of malicious activity. The decrypted content of the request can be seen below. Note that the list of installed apps is shown as Base64 encoded text, as this list is encoded before encryption.
{"id":"6500","method":"application.register","params":{"package":"com.wsandroid.suite","device":"Android/10","model":"samsung GT-I900","country":"sv-SE","apps":"cHQubm92b2JhbmNvLm5iYXBwO3B0LnNhbnRhbmRlcnRvdHRhLm1vYmlsZXBhcnRpY3VsYXJlcztzYS5hbHJhamhpYmFuay50YWh3ZWVsYXBwO3NhLmNvbS5zZS5hbGthaHJhYmE7c2EuY29tLnN0Y3BheTtzYW1zdW5nLnNldHRpbmdzLnBhc3M7c2Ftc3VuZy5zZXR0aW5ncy5waW47c29mdGF4LnBla2FvLnBvd2VycGF5O3RzYi5tb2JpbGViYW5raW5nO3VrLmNvLmhzYmMuaHNiY3VrbW9iaWxlYmFua2luZzt1ay5jby5tYm5hLmNhcmRzZXJ2aWNlcy5hbmRyb2lkO3VrLmNvLm1ldHJvYmFua29ubGluZS5tb2JpbGUuYW5kcm9pZC5wcm9kdWN0aW9uO3VrLmNvLnNhbnRhbmRlci5zYW50YW5kZXJVSzt1ay5jby50ZXNjb21vYmlsZS5hbmRyb2lkO3VrLmNvLnRzYi5uZXdtb2JpbGViYW5rO3VzLnpvb20udmlkZW9tZWV0aW5nczt3aXQuYW5kcm9pZC5iY3BCYW5raW5nQXBwLm1pbGxlbm5pdW07d2l0LmFuZHJvaWQuYmNwQmFua2luZ0FwcC5taWxsZW5uaXVtUEw7d3d3LmluZ2RpcmVjdC5uYXRpdmVmcmFtZTtzZS5zd2VkYmFuay5tb2JpbA==","tag":"dropper2"}
The dropper is a modified version of the legitimate McAfee Security app. In order to masquerade malicious actions, it contains functionality that the official McAfee Security app would have. This has proven to be effective for the threat actors, as the dropper currently has a very low detection rate when analysed on VirusTotal.

Figure 6: Brunhilda dropper’s detection rate on VirusTotal.
Next to modding the legitimate McAfee Security app, Vultur uses the official Android Accessibility Suite package name for its Accessibility Service. This will be further discussed in the execution flow section of this blog.

Figure 7: Snippet of Vultur’s AndroidManifest.xml file, where its Accessibility Service is defined with the Android Accessibility Suite package name.
Native code is typically written in languages like C or C++, which are lower-level than Java or Kotlin, the most popular languages used for Android application development. This means that the code is closer to the machine language of the processor, thus requiring a deeper understanding of lower-level programming concepts. Brunhilda and Vultur have started using native code for decryption of payloads, likely in order to make the samples harder to reverse engineer.
In this blog post we show how Brunhilda drops a total of 3 Vultur-related payloads: two APK files and one DEX file. We also showcase how payload #2 and #3 can effectively work together. This fragmentation can complicate the analysis process, as multiple components must be assembled to reveal the malware’s complete functionality.
While previous versions of Brunhilda delivered Vultur through a single payload, the latest variant now drops Vultur in three layers. The Brunhilda dropper in this campaign is a modified version of the legitimate McAfee Security app, which makes it seem harmless to the victim upon execution as it includes functionality that the official McAfee Security app would have.

Figure 8: The modded version of the McAfee Security app is launched.
In the background, the infected device registers with its C2 server through the /ejr/ endpoint and the application.register method. In the related HTTP POST request, the C2 is provided with the following information:
com.wsandroid.suite package name);sv-SE);dropper2).The server response is decrypted and stored in a SharedPreference key named 9bd25f13-c3f8-4503-ab34-4bbd63004b6e, where the value indicates whether the registration was successful or not. After successfully registering the bot with the dropper C2, the first Vultur payload is eventually decrypted and installed from an onClick() method.

Figure 9: Decryption and installation of the first Vultur payload.
In this sample, the encrypted data is hidden in a file named 78a01b34-2439-41c2-8ab7-d97f3ec158c6 that is stored within the app’s “assets” directory. When decrypted, this will reveal an APK file to be installed.
The decryption algorithm is implemented in native code, and reveals that it uses AES/ECB/PKCS5Padding to decrypt the first embedded file. The Lib.d() function grabs a substring from index 6 to 22 of the second argument (IPIjf4QWNMWkVQN21ucmNiUDZaVw==) to get the decryption key. The key used in this sample is: QWNMWkVQN21ucmNi (key varies across samples). With this information we can decrypt the 78a01b34-2439-41c2-8ab7-d97f3ec158c6 file, which brings us another APK file to examine: the first Vultur payload.
The first Vultur payload also contains the application.register method. The bot registers itself again with the C2 server as observed in the dropper sample. This time, it sends the package name of the current payload (se.accessibility.app in this example), which is not a modded application. The “tag” that was related to the dropper campaign is also removed in this second registration request. The server response contains an encrypted token for further communication with the C2 server and is stored in the SharedPreference key f9078181-3126-4ff5-906e-a38051505098.

Figure 10: Decompiled code snippet that shows the data to be sent to the C2 server during bot registration.
The main purpose of this first payload is to obtain Accessibility Service privileges and install the next Vultur APK file. Apps with Accessibility Service permissions can have full visibility over UI events, both from the system and from 3rd party apps. They can receive notifications, list UI elements, extract text, and more. While these services are meant to assist users, they can also be abused by malicious apps for activities, such as keylogging, automatically granting itself additional permissions, monitoring foreground apps and overlaying them with phishing windows.
In order to gain further control over the infected device, this payload displays custom HTML code that contains instructions to enable Accessibility Services permissions. The HTML code to be displayed in a WebView is retrieved from the installer.config C2 method, where the HTML code is stored in the SharedPreference key bbd1e64e-eba3-463c-95f3-c3bbb35b5907.

Figure 11: HTML code is loaded in a WebView, where the APP_NAME variable is replaced with the text “McAfee Master Protection”.
In addition to the HTML content, an extra warning message is displayed to further convince the victim into enabling Accessibility Service permissions for the app. This message contains the text “Your system not safe, service McAfee Master Protection turned off. For using full device protection turn it on.” When the warning is displayed, it also sets the value of the SharedPreference key 1590d3a3-1d8e-4ee9-afde-fcc174964db4 to true. This value is later checked in the onAccessibilityEvent() method and the onServiceConnected() method of the malicious app’s Accessibility Service.
ANALYST COMMENT
An important observation here, is that the malicious app is using thecom.google.android.marvin.talkbackpackage name for its Accessibility Service. This is the package name of the official Android Accessibility Suite, as can be seen from the following link: https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback.
The implementation is of course different from the official Android Accessibility Suite and contains malicious code.
When the Accessibility Service privileges have been enabled for the payload, it automatically grants itself additional permissions to install apps from unknown sources, and installs the next payload through the UpdateActivity.

Figure 12: Decryption and installation of the second Vultur payload.
The second encrypted APK is hidden in a file named data that is stored within the app’s “assets” directory. The decryption algorithm is again implemented in native code, and is the same as in the dropper. This time, it uses a different decryption key that is derived from the DXMgKBY29QYnRPR1k1STRBNTZNUw== string. The substring reveals the actual key used in this sample: Y29QYnRPR1k1STRB (key varies across samples). After decrypting, we are presented with the next layer of Vultur.
The second Vultur APK contains more important functionality, such as AlphaVNC and ngrok setup, displaying of custom HTML code in WebViews, screen recording, and more. Just like the previous versions of Vultur, the latest edition still includes the ability to remotely access the infected device through AlphaVNC and ngrok.
This second Vultur payload also uses the com.google.android.marvin.talkback (Android Accessibility Suite) package name for the malicious Accessibility Service. From here, there are multiple references to methods invoked from another file: the final Vultur payload. This time, the payload is not decrypted from native code. In this sample, an encrypted file named a.int is decrypted using AES/CFB/NoPadding with the decryption key SBhXcwoAiLTNIyLK (stored in SharedPreference key dffa98fe-8bf6-4ed7-8d80-bb1a83c91fbb). We have observed the same decryption key being used in multiple samples for decrypting payload #3.

Figure 13: Decryption of the third Vultur payload.
Furthermore, from payload #2 onwards, Vultur uses encrypted SharedPreferences for further hiding of malicious configuration related key-value pairs.
The final payload is a Dalvik Executable (DEX) file. This decrypted DEX file holds Vultur’s core functionality. It contains the references to all of the C2 methods (used in communication from bot to C2 server, in order to send or retrieve information) and FCM commands (used in communication from C2 server to bot, in order to perform actions on the infected device).
An important observation here, is that code defined in payload #3 can be invoked from payload #2 and vice versa. This means that these final two files effectively work together.

Figure 14: Decompiled code snippet showing some of the FCM commands implemented in Vultur payload #3.
The last Vultur payload does not contain its own Accessibility Service, but it can interact with the Accessibility Service that is implemented in payload #2.
When Vultur infects a device, it initiates a series of communications with its designated C2 server. Communications related to C2 methods such as application.register and vnc.blocked.packages occur using JSON-RPC 2.0 over HTTPS. These requests are sent from the infected device to the C2 server to either provide or receive information.
Actual vultures lack a voice box; their vocalisations include rasping hisses and grunts [4]. While the communication in older variants of Vultur may have sounded somewhat similar to that, you could say that the threat actors have developed a voice box for the latest version of Vultur. The content of the aforementioned requests are now AES encrypted and Base64 encoded, just like the server response.
Next to encrypted communication over HTTPS, the bot can receive commands via Firebase Cloud Messaging (FCM). FCM is a cross-platform messaging solution provided by Google. The FCM related commands are sent from the C2 server to the infected device to perform actions on it.
During our investigation of the latest Vultur variant, we identified the C2 endpoints mentioned below.
| Endpoint | Description |
|---|---|
/ejr/ | Endpoint for C2 communication using JSON-RPC 2.0. Note: in older versions of Vultur the /rpc/ endpoint was used for similar communication. |
/upload/ | Endpoint for uploading files (such as screen recording results). |
/version/app/?filename=ngrok&arch={DEVICE_ARCH} | Endpoint for downloading the relevant version of ngrok. |
/version/app/?filename={FILENAME} | Endpoint for downloading a file specified by the payload (related to the new file manager functionality). |
The commands below are sent from the infected device to the C2 server to either provide or receive information.
| Method | Description |
|---|---|
application.register | Registers the bot by providing the malware package name and information about the device: model, country, installed apps, Android version. It also sends a tag that is used for identifying the dropper campaign name. Note: this method is also used once in Vultur payload #1, but without sending a tag. This method then returns a token to be used in further communication with the C2 server. |
application.state | Sends a token value that was set as a response to the application.register command, together with a status code of “3”. |
The commands below are sent from the infected device to the C2 server to either provide or receive information.
| Method | Description |
|---|---|
vnc.register (UPDATED) | Registers the bot by providing the FCM token, malware package name and information about the device, model, country, Android version. This method has been updated in the latest version of Vultur to also include information on whether the infected device is rooted and if it is detected as an emulator. |
vnc.status (UPDATED) | Sends the following status information about the device: if the Accessibility Service is enabled, if the Device Admin permissions are enabled, if the screen is locked, what the VNC address is. This method has been updated in the latest version of Vultur to also send information related to: active fingerprints on the device, screen resolution, time, battery percentage, network operator, location. |
vnc.apps | Sends the list of apps that are installed on the victim’s device. |
vnc.keylog | Sends the keystrokes that were obtained via keylogging. |
vnc.config (UPDATED) | Obtains the config of the malware, such as the list of targeted applications by the keylogger and VNC. This method has been updated in the latest version of Vultur to also obtain values related to the following new keys: “packages2”, “rurl”, “recording”, “main_content”, “tvmq”. |
vnc.overlay | Obtains the HTML code for overlay injections of a specified package name using the pkg parameter. It is still unclear whether support for overlay injections is fully implemented in Vultur. |
vnc.overlay.logs | Sends the stolen credentials that were obtained via HTML overlay injections. It is still unclear whether support for overlay injections is fully implemented in Vultur. |
vnc.pattern (NEW) | Informs the C2 server whether a PIN pattern was successfully extracted and stored in the application’s Shared Preferences. |
vnc.snapshot (NEW) | Sends JSON data to the C2 server, which can contain: 1. Information about the accessibility event’s class, bounds, child nodes, UUID, event type, package name, text content, screen dimensions, time of the event, and if the screen is locked. 2. Recently copied text, and SharedPreferences values related to “overlay” and “keyboard”. 3. X and Y coordinates related to a click. |
vnc.submit (NEW) | Informs the C2 server whether the bot registration was successfully submitted or if it failed. |
vnc.urls (NEW) | Informs the C2 server about the URL bar related element IDs of either the Google Chrome or Firefox webbrowser (depending on which application triggered the accessibility event). |
vnc.blocked.packages (NEW) | Retrieves a list of “blocked packages” from the C2 server and stores them together with custom HTML code in the application’s Shared Preferences. When one of these package names is detected as running on the victim device, the malware will automatically press the back button and display custom HTML content if available. If unavailable, a default “Temporarily Unavailable” message is displayed. |
vnc.fm (NEW) | Sends file related information to the C2 server. File manager functionality includes downloading, uploading, installing, deleting, and finding of files. |
vnc.syslog | Sends logs. |
crash.logs | Sends logs of all content on the screen. |
installer.config (NEW) | Retrieves the HTML code that is displayed in a WebView of the first Vultur payload. This HTML code contains instructions to enable Accessibility Services permissions. |
The commands below are sent from the C2 server to the infected device via Firebase Cloud Messaging in order to perform actions on the infected device. The new commands use IDs instead of names that describe their functionality. These command IDs are the same in different samples.
| Command | Description |
|---|---|
registered | Received when the bot has been successfully registered. |
start | Starts the VNC connection using ngrok. |
stop | Stops the VNC connection by killing the ngrok process and stopping the VNC service. |
unlock | Unlocks the screen. |
delete | Uninstalls the malware package. |
pattern | Provides a gesture/stroke pattern to interact with the device’s screen. |
109b0e16 (NEW) | Presses the back button. |
18cb31d4 (NEW) | Presses the home button. |
811c5170 (NEW) | Shows the overview of recently opened apps. |
d6f665bf (NEW) | Starts an app specified by the payload. |
1b05d6ee (NEW) | Shows a black view. |
1b05d6da (NEW) | Shows a black view that is obtained from the layout resources in Vultur payload #2. |
7f289af9 (NEW) | Shows a WebView with HTML code loaded from SharedPreference key “946b7e8e”. |
dc55afc8 (NEW) | Removes the active black view / WebView that was added from previous commands (after sleeping for 15 seconds). |
cbd534b9 (NEW) | Removes the active black view / WebView that was added from previous commands (without sleeping). |
4bacb3d6 (NEW) | Deletes an app specified by the payload. |
b9f92adb (NEW) | Navigates to the settings of an app specified by the payload. |
77b58a53 (NEW) | Ensures that the device stays on by acquiring a wake lock, disables keyguard, sleeps for 0,1 second, and then swipes up to unlock the device without requiring a PIN. |
ed346347 (NEW) | Performs a click. |
5c900684 (NEW) | Scrolls forward. |
d98179a8 (NEW) | Scrolls backward. |
7994ceca (NEW) | Sets the text of a specified element ID to the payload text. |
feba1943 (NEW) | Swipes up. |
d403ad43 (NEW) | Swipes down. |
4510a904 (NEW) | Swipes left. |
753c4fa0 (NEW) | Swipes right. |
b183a400 (NEW) | Performs a stroke pattern on an element across a 3×3 grid. |
81d9d725 (NEW) | Performs a stroke pattern based on x+y coordinates and time duration. |
b79c4b56 (NEW) | Press-and-hold 3 times near bottom middle of the screen. |
1a7493e7 (NEW) | Starts capturing (recording) the screen. |
6fa8a395 (NEW) | Sets the “ShowMode” of the keyboard to 0. This allows the system to control when the soft keyboard is displayed. |
9b22cbb1 (NEW) | Sets the “ShowMode” of the keyboard to 1. This means the soft keyboard will never be displayed (until it is turned back on). |
98c97da9 (NEW) | Requests permissions for reading and writing external storage. |
7b230a3b (NEW) | Request permissions to install apps from unknown sources. |
cc8397d4 (NEW) | Opens the long-press power menu. |
3263f7d4 (NEW) | Sets a SharedPreference value for the key “c0ee5ba1-83dd-49c8-8212-4cfd79e479c0” to the specified payload. This value is later checked for in other to determine whether the long-press power menu should be displayed (SharedPref value 1), or whether the back button must be pressed (SharedPref value 2). |
request_accessibility (UPDATED) | Prompts the infected device with either a notification or a custom WebView that instructs the user to enable accessibility services for the malicious app. The related WebView component was not present in older versions of Vultur. |
announcement (NEW) | Updates the value for the C2 domain in the SharedPreferences. |
5283d36d-e3aa-45ed-a6fb-2abacf43d29c (NEW) | Sends a POST with the vnc.config C2 method and stores the malware config in SharedPreferences. |
09defc05-701a-4aa3-bdd2-e74684a61624 (NEW) | Hides / disables the keyboard, obtains a wake lock, disables keyguard (lock screen security), mutes the audio, stops the “TransparentActivity” from payload #2, and displays a black view. |
fc7a0ee7-6604-495d-ba6c-f9c2b55de688 (NEW) | Hides / disables the keyboard, obtains a wake lock, disables keyguard (lock screen security), mutes the audio, stops the “TransparentActivity” from payload #2, and displays a custom WebView with HTML code loaded from SharedPreference key “946b7e8e” (“tvmq” value from malware config). |
8eac269d-2e7e-4f0d-b9ab-6559d401308d (NEW) | Hides / disables the keyboard, obtains a wake lock, disables keyguard (lock screen security), mutes the audio, stops the “TransparentActivity” from payload #2. |
e7289335-7b80-4d83-863a-5b881fd0543d (NEW) | Enables the keyboard and unmutes audio. Then, sends the vnc.snapshot method with empty JSON data. |
544a9f82-c267-44f8-bff5-0726068f349d (NEW) | Retrieves the C2 command, payload and UUID, and executes the command in a thread. |
a7bfcfaf-de77-4f88-8bc8-da634dfb1d5a (NEW) | Creates a custom notification to be shown in the status bar. |
444c0a8a-6041-4264-959b-1a97d6a92b86 (NEW) | Retrieves the list of apps to block and corresponding HTML code through the vnc.blocked.packages C2 method and stores them in the blocked_package_template SharedPreference key. |
a1f2e3c6-9cf8-4a7e-b1e0-2c5a342f92d6 (NEW) | Executes a file manager related command. Commands are: 1. 91b4a535-1a78-4655-90d1-a3dcb0f6388a – Downloads a file2. cf2f3a6e-31fc-4479-bb70-78ceeec0a9f8 – Uploads a file3. 1ce26f13-fba4-48b6-be24-ddc683910da3 – Deletes a file4. 952c83bd-5dfb-44f6-a034-167901990824 – Installs a file5. 787e662d-cb6a-4e64-a76a-ccaf29b9d7ac – Finds files containing a specified pattern |
Writing YARA rules to detect Android malware can be challenging, as APK files are ZIP archives. This means that extracting all of the information about the Android application would involve decompressing the ZIP, parsing the XML, and so on. Thus, most analysts build YARA rules for the DEX file. However, DEX files, such as Vultur payload #3, are less frequently submitted to VirusTotal as they are uncovered at a later stage in the infection chain. To maximise our sample pool, we decided to develop a YARA rule for the Brunhilda dropper. We discovered some unique hex patterns in the dropper APK, which allowed us to create the YARA rule below.
rule brunhilda_dropper
{
meta:
author = "Fox-IT, part of NCC Group"
description = "Detects unique hex patterns observed in Brunhilda dropper samples."
target_entity = "file"
strings:
$zip_head = "PK"
$manifest = "AndroidManifest.xml"
$hex1 = {63 59 5c 28 4b 5f}
$hex2 = {32 4a 66 48 66 76 64 6f 49 36}
$hex3 = {63 59 5c 28 4b 5f}
$hex4 = {30 34 7b 24 24 4b}
$hex5 = {22 69 4f 5a 6f 3a}
condition:
$zip_head at 0 and $manifest and #manifest >= 2 and 2 of ($hex*)
}
Vultur’s recent developments have shown a shift in focus towards maximising remote control over infected devices. With the capability to issue commands for scrolling, swipe gestures, clicks, volume control, blocking apps from running, and even incorporating file manager functionality, it is clear that the primary objective is to gain total control over compromised devices.
Vultur has a strong correlation to Brunhilda, with its C2 communication and payload decryption having the same implementation in the latest variants. This indicates that both the dropper and Vultur are being developed by the same threat actors, as has also been uncovered in the past.
Furthermore, masquerading malicious activity through the modification of legitimate applications, encryption of traffic, and the distribution of functions across multiple payloads decrypted from native code, shows that the actors put more effort into evading detection and complicating analysis.
During our investigation of recently submitted Vultur samples, we observed the addition of new functionality occurring shortly after one another. This suggests ongoing and active development to enhance the malware’s capabilities. In light of these observations, we expect more functionality being added to Vultur in the near future.
| Package name | File hash (SHA-256) | Description |
|---|---|---|
| com.wsandroid.suite | edef007f1ca60fdf75a7d5c5ffe09f1fc3fb560153633ec18c5ddb46cc75ea21 | Brunhilda Dropper |
| com.medical.balance | 89625cf2caed9028b41121c4589d9e35fa7981a2381aa293d4979b36cf5c8ff2 | Vultur payload #1 |
| com.medical.balance | 1fc81b03703d64339d1417a079720bf0480fece3d017c303d88d18c70c7aabc3 | Vultur payload #2 |
| com.medical.balance | 4fed4a42aadea8b3e937856318f9fbd056e2f46c19a6316df0660921dd5ba6c5 | Vultur payload #3 |
| com.wsandroid.suite | 001fd4af41df8883957c515703e9b6b08e36fde3fd1d127b283ee75a32d575fc | Brunhilda Dropper |
| se.accessibility.app | fc8c69bddd40a24d6d28fbf0c0d43a1a57067b19e6c3cc07e2664ef4879c221b | Vultur payload #1 |
| se.accessibility.app | 7337a79d832a57531b20b09c2fc17b4257a6d4e93fcaeb961eb7c6a95b071a06 | Vultur payload #2 |
| se.accessibility.app | 7f1a344d8141e75c69a3c5cf61197f1d4b5038053fd777a68589ecdb29168e0c | Vultur payload #3 |
| com.wsandroid.suite | 26f9e19c2a82d2ed4d940c2ec535ff2aba8583ae3867502899a7790fe3628400 | Brunhilda Dropper |
| com.exvpn.fastvpn | 2a97ed20f1ae2ea5ef2b162d61279b2f9b68eba7cf27920e2a82a115fd68e31f | Vultur payload #1 |
| com.exvpn.fastvpn | c0f3cb3d837d39aa3abccada0b4ecdb840621a8539519c104b27e2a646d7d50d | Vultur payload #2 |
| com.wsandroid.suite | 92af567452ecd02e48a2ebc762a318ce526ab28e192e89407cac9df3c317e78d | Brunhilda Dropper |
| jk.powder.tendence | fa6111216966a98561a2af9e4ac97db036bcd551635be5b230995faad40b7607 | Vultur payload #1 |
| jk.powder.tendence | dc4f24f07d99e4e34d1f50de0535f88ea52cc62bfb520452bdd730b94d6d8c0e | Vultur payload #2 |
| jk.powder.tendence | 627529bb010b98511cfa1ad1aaa08760b158f4733e2bbccfd54050838c7b7fa3 | Vultur payload #3 |
| com.wsandroid.suite | f5ce27a49eaf59292f11af07851383e7d721a4d60019f3aceb8ca914259056af | Brunhilda Dropper |
| se.talkback.app | 5d86c9afd1d33e4affa9ba61225aded26ecaeb01755eeb861bb4db9bbb39191c | Vultur payload #1 |
| se.talkback.app | 5724589c46f3e469dc9f048e1e2601b8d7d1bafcc54e3d9460bc0adeeada022d | Vultur payload #2 |
| se.talkback.app | 7f1a344d8141e75c69a3c5cf61197f1d4b5038053fd777a68589ecdb29168e0c | Vultur payload #3 |
| com.wsandroid.suite | fd3b36455e58ba3531e8cce0326cce782723cc5d1cc0998b775e07e6c2622160 | Brunhilda Dropper |
| com.adajio.storm | 819044d01e8726a47fc5970efc80ceddea0ac9bf7c1c5d08b293f0ae571369a9 | Vultur payload #1 |
| com.adajio.storm | 0f2f8adce0f1e1971cba5851e383846b68e5504679d916d7dad10133cc965851 | Vultur payload #2 |
| com.adajio.storm | fb1e68ee3509993d0fe767b0372752d2fec8f5b0bf03d5c10a30b042a830ae1a | Vultur payload #3 |
| com.protectionguard.app | d3dc4e22611ed20d700b6dd292ffddbc595c42453f18879f2ae4693a4d4d925a | Brunhilda Dropper (old variant) |
| com.appsmastersafey | f4d7e9ec4eda034c29b8d73d479084658858f56e67909c2ffedf9223d7ca9bd2 | Vultur (old variant) |
| com.datasafeaccountsanddata.club | 7ca6989ccfb0ad0571aef7b263125410a5037976f41e17ee7c022097f827bd74 | Vultur (old variant) |
| com.app.freeguarding.twofactor | c646c8e6a632e23a9c2e60590f012c7b5cb40340194cb0a597161676961b4de0 | Vultur (old variant) |
Note: Vultur payloads #1 and #2 related to Brunhilda dropper 26f9e19c2a82d2ed4d940c2ec535ff2aba8583ae3867502899a7790fe3628400 are the same as Vultur payloads #2 and #3 in the latest variants. The dropper in this case only drops two payloads, where the latest versions deploy a total of three payloads.
Authors: Axel Boesenach and Erik Schamper
In this blog post we will go into a user-friendly memory scanning Python library that was created out of the necessity of having more control during memory scanning. We will give an overview of how this library works, share the thought process and the why’s. This blog post will not cover the inner workings of the memory management of the respective platforms.
Memory scanning is the practice of iterating over the different processes running on a computer system and searching through their memory regions for a specific pattern. There can be a myriad of reasons to scan the memory of certain processes. The most common use cases are probably credential access (accessing the memory of the lsass.exe process for example), scanning for possible traces of malware and implants or recovery of interesting data, such as cryptographic material.
If time is as valuable to you as it is to us at Fox-IT, you probably noticed that performing a full memory scan looking for a pattern is a very time-consuming process, to say the least.
Why is scanning memory so time consuming when you know what you are looking for, and more importantly; how can this scanning process be sped up? While looking into different detection techniques to identify running Cobalt Strike beacons, we noticed something we could easily filter on, speeding up our scanning processes: memory attributes.
Memory attributes are comparable to the permission system we all know and love on our regular file and directory structures. The permission system dictates what kind of actions are allowed within a specific memory region and can be changed to different sets of attributes by their respective API calls.
The following memory attributes exist on both the Windows and UNIX platforms:
The Windows platform has some extra permission attributes, plus quite an extensive list of allocation1 and protection2 attributes. These attributes can also be used to filter when looking for specific patterns within memory regions but are not important to go into right now.
So how do we leverage this information about attributes to speed up our scanning processes? It turns out that by filtering the regions to scan based on the memory attributes set for the regions, we can speed up our scanning process tremendously before even starting to look for our specified patterns.
Say for example we are looking for a specific byte pattern of an implant that is present in a certain memory region of a running process on the Windows platform. We already know what pattern we are looking for and we also know that the memory regions used by this specific implant are always set to:
| Type | Protection | Initial |
|---|---|---|
| PRV | ERW | ERW |
Depending on what is running on the system, filtering on the above memory attributes already rules out a large portion of memory regions for most running processes on a Windows system.
If we take a notepad.exe process as an example, we can see that the different sections of the executable have their respective rights. The .text section of an executable contains executable code and is thus marked with the E permission as its protection:

If we were looking for just the sections and regions that are marked as being executable, we would only need to scan the .text section of the notepad.exe process. If we scan all the regions of every running process on the system, disregarding the memory attributes which are set, scanning for a pattern will take quite a bit longer.
We’ve incorporated the techniques described above into an easy to install Python package. The package is designed and tested to work on Linux and Microsoft Windows systems. Some of the notable features include:
The package was designed to be easily extensible by the end users, providing an API that can be leveraged to perform more.
The Python library is available on our GitHub, together with some examples showing scenarios on how to use it.
GitHub: https://github.com/fox-it/skrapa
References
Max Groot & Erik Schamper
mpengine.dll resulted in finding previously undocumented metadata in the Windows Defender quarantine folder that can be used for digital forensics and incident response.dissect.cstruct allows us to use C-like structure definitions in Python, which enables easy continued research in other programming languages or reverse engineering in tools like IDA Pro.
During incident response engagements we often encounter antivirus applications that have rightfully triggered on malicious software that was deployed by threat actors. Most commonly we encounter this for Windows Defender, the antivirus solution that is shipped by default with Microsoft Windows. Windows Defender places malicious files in quarantine upon detection, so that the end user may decide to recover the file or delete it permanently. Threat actors, when faced with the detection capabilities of Defender, either disable the antivirus in its entirety or attempt to evade its detection.
The Windows Defender quarantine folder is valuable from the perspective of digital forensics and incident response (DFIR). First of all, it can reveal information about timestamps, locations and signatures of files that were detected by Windows Defender. Especially in scenarios where the threat actor has deleted the Windows Event logs, but left the quarantine folder intact, the quarantine folder is of great forensic value. Moreover, as the entire file is quarantined (so that the end user may choose to restore it), it is possible to recover files from quarantine for further reverse engineering and analysis.
While scripts already exist to recover files from the Defender quarantine folder, the purpose of much of the contents of this folder were previously unknown. We don’t like big unknowns, so we performed further research into the previously unknown metadata to see if we could uncover additional forensic traces.
Rather than just presenting our results, we’ve structured this blog to also describe the process to how we got there. Skip to the end if you are interested in the results rather than the technical details of reverse engineering Windows Defender.
We started by looking into existing research into the internals of Windows Defender. The most extensive documentation we could find on the structures of Windows Defender quarantine files was Florian Bauchs’ whitepaper analyzing antivirus software quarantine files, but we also looked at several scripts on GitHub.
QuarantineEntry. This QuarantineEntry is RC4-encrypted and saved to disk in the /ProgramData/Microsoft/Windows Defender/Quarantine/Entries folder.QuarantineEntryResourceData file, which is also RC4-encrypted and saved to disk in the /ProgramData/Microsoft/Windows Defender/Quarantine/ResourceData folder./ProgramData/Microsoft/Windows Defender/Quarantine/Resource folder, a Resource file is made. Both from previous research as well as from our own findings during reverse engineering, it appears this file contains no information that cannot be obtained from the QuarantineEntry and the QuarantineEntryResourceData files. Therefore, we ignore the Resource file for the remainder of this blog.While previous scripts are able to recover some properties from the ResourceData and QuarantineEntry files, large segments of data were left unparsed, which gave us a hunch that additional forensic artefacts were yet to be discovered.
Windows Defender encrypts both the QuarantineEntry and the ResourceData files using a hardcoded RC4 key defined in mpengine.dll. This hardcoded key was initially published by Cuckoo and is paramount for the offline recovery of the quarantine folder.
Pivotting off of public scripts and Bauch’s whitepaper, we loaded mpengine.dll into IDA to further review how Windows Defender places a file into quarantine. Using the PDB available from the Microsoft symbol server, we get a head start with some functions and structures already defined.
Let us begin with the QuarantineEntry file. From this file, we would like to recover as much of the QuarantineEntry structure as possible, as this holds all kinds of valuable metadata. The QuarantineEntry file is not encrypted as one RC4 cipherstream, but consists of three chunks that are each individually encrypted using RC4.
These three chunks are what we have come to call QuarantineEntryFileHeader, QuarantineEntrySection1 and QuarantineEntrySection2.
QuarantineEntryFileHeader describes the size of QuarantineEntrySection1 and QuarantineEntrySection2, and contains CRC checksums for both sections.QuarantineEntrySection1 contains valuable metadata that applies to all QuarantineEntryResource instances within this QuarantineEntry file, such as the DetectionName and the ScanId associated with the quarantine action.QuarantineEntrySection2 denotes the length and offset of every QuarantineEntryResource instance within this QuarantineEntry file so that they can be correctly parsed individually.A QuarantineEntry has one or more QuarantineEntryResource instances associated with it. This contains additional information such as the path of the quarantined artefact, and the type of artefact that has been quarantined (e.g. regkey or file).
An overview of the different structures within QuarantineEntry is provided in Figure 1:

Figure 1: An example overview of a QuarantineEntry. In this example, two files were simultaneously quarantined by Windows Defender. Hence, there are two QuarantineEntryResource structures contained within this single QuarantineEntry.
As QuarantineEntryFileHeader is mostly a structure that describes how QuarantineEntrySection1 and QuarantineEntrySection2 should be parsed, we will first look into what those two consist of.
QuarantineEntrySection1When reviewing mpengine.dll within IDA, the contents of both QuarantineEntrySection1 and QuarantineEntrySection2 appear to be determined in theQexQuarantine::CQexQuaEntry::Commit function.
The function receives an instance of the QexQuarantine::CQexQuaEntry class. Unfortunately, the PDB file that Microsoft provides for mpengine.dll does not contain contents for this structure. Most fields could, however, be derived using the function names in the PDB that are associated with the CQexQuaEntry class:

Figure 2: Functions retrieving properties from QuarantineEntry
The Id, ScanId, ThreatId, ThreatName and Time fields are most important, as these will be written to the QuarantineEntry file.
At the start of the QexQuarantine::CQexQuaEntry::Commit function, the size of Section1 is determined.

Figure 3: Reviewing the decompiled output of CqExQuaEntry::Commit shows the size of QuarantineEntrySection1 being set to thre length of ThreatName plus 53.
This sets section1_size to a value of the length of the ThreatName variable plus 53. We can determine what these additional 53 bytes consist of by looking at what values are set in the QexQuarantine::CQexQuaEntry::Commit function for the Section1 buffer.
This took some experimentation and required trying different fields, offsets and sizes for the QuarantineEntrySection1 structure within IDA. After every change, we would review what these changes would do to the decompiled IDA view of the QexQuarantine::CQexQuaEntry::Commit function.
Some trial and error landed us the following structure definition:
| struct QuarantineEntrySection1 { | |
| CHAR Id[16]; | |
| CHAR ScanId[16]; | |
| QWORD Timestamp; | |
| QWORD ThreatId; | |
| DWORD One; | |
| CHAR DetectionName[]; | |
| }; |
While reviewing the final decompiled output (right) for the assembly code (left), we noticed a field always being set to 1:

Figure 4: A field of QuarantineEntrySection1 always being set to the value of 1.
Given that we do not know what this field is used for, we opted to name the field ‘One’ for now. Most likely, it’s a boolean value that is always true within the context of the QexQuarantine::CQexQuaEntry::Commit commit function.
QuarantineEntrySection2Now that we have a structure definition for the first section of a QuarantineEntry, we now move on to the second part. QuarantineEntrySection2 holds the number of QuarantineEntryResource objects confined within a QuarantineEntry, as well as the offsets into the QuarantineEntry structure where they are located.
In most scenarios, one threat gets detected at a time, and one QuarantineEntry will be associated with one QuarantineEntryResource. This is not always the case: for example, if one unpacks a ZIP folder that contains multiple malicious files, Windows Defender might place them all into quarantine. Each individual malicious file of the ZIP would then be one QuarantineEntryResource, but they are all confined within one QuarantineEntry.
QuarantineEntryResourceTo be able to parse QuarantineEntryResource instances, we look into the CQexQuaResource::ToBinary function. This function receives a QuarantineEntryResource object, as well as a pointer to a buffer to which it needs to write the binary output to. If we can reverse the logic within this function, we can convert the binary output back into a parsed instance during forensic recovery.
Looking into the CQexQuaResource::ToBinary function, we see two very similar loops as to what was observed before for serializing the ThreatName of QuarantineEntrySection1. By reviewing various decrypted QuarantineEntry files, it quickly became apparent that these loops are responsible for reserving space in the output buffer for DetectionPath and DetectionType, with DetectionPath being UTF-16 encoded:

Figure 5: Reservation of space for DetectionPath and DetectionType at the beginning of CQexQuaResource::ToBinary
When reviewing the QexQuarantine::CQexQuaEntry::Commit function, we observed an interesting loop that (after investigating function calls and renaming variables) explains the data that is stored between the DetectionType and DetectionPath:

Figure 6: Alignment logic for serializing Fields
It appears QuarantineEntryResource structures have one or more QuarantineResourceField instances associated with them, with the number of fields associated with a QuarantineEntryResource being stored in a single byte in between the DetectionPath and DetectionType. When saving the QuarantineEntry to disk, fields have an alignment of 4 bytes. We could not find mentions of QuarantineEntryResourceField structures in prior Windows Defender research, even though they can hold valuable information.
The CQExQuaResource class has several different implementations of AddField, accepting different kinds of parameters. Reviewing these functions showed that fields have an Identifier, Type, and a buffer Data with a size of Size, resulting in a simple TLV-like format:
| struct QuarantineEntryResourceField { | |
| WORD Size; | |
| WORD Identifier:12; | |
| FIELD_TYPE Type:4; | |
| CHAR Data[Size]; | |
| }; |
To understand what kinds of types and identifiers are possible, we delve further into the different versions of the AddField functions, which all accept a different data type:

Figure 7: Finding different field types based on different implementations of the CqExQuaResource::AddField function
Visiting these functions, we reviewed the Type and Size variables to understand the different possible types of fields that can be set for QuarantineResource instances. This yields the following FIELD_TYPE enum:
| enum FIELD_TYPE : WORD { | |
| STRING = 0x1, | |
| WSTRING = 0x2, | |
| DWORD = 0x3, | |
| RESOURCE_DATA = 0x4, | |
| BYTES = 0x5, | |
| QWORD = 0x6, | |
| }; |
As the AddField functions are part of a virtual function table (vtable) of the CQexQuaResource class, we cannot trivially find all places where the AddField function is called, as they are not directly called (which would yield an xref in IDA). Therefore, we have not exhausted all code paths leading to a call of AddField to identify all possible Identifier values and how they are used. Our research yielded the following field identifiers as the most commonly observed, and of the most forensic value:
| enum FIELD_IDENTIFIER : WORD { | |
| CQuaResDataID_File = 0x02, | |
| CQuaResDataID_Registry = 0x03, | |
| Flags = 0x0A, | |
| PhysicalPath = 0x0C, | |
| DetectionContext = 0x0D, | |
| Unknown = 0x0E, | |
| CreationTime = 0x0F, | |
| LastAccessTime = 0x10, | |
| LastWriteTime = 0x11, | |
| }; |
Especially CreationTime, LastAccessTime and LastWriteTime can provide crucial data points during an investigation.
QuarantineEntrySection2 and QuarantineEntryResource structuresNow that we have an understanding of how fields work and how they are stored within the QuarantineEntryResource, we can derive the following structure for it:
| struct QuarantineEntryResource { | |
| WCHAR DetectionPath[]; | |
| WORD FieldCount; | |
| CHAR DetectionType[]; | |
| }; |
Revisiting the QexQuarantine::CQexQuaEntry::Commit function, we can now understand how this function determines at which offset every QuarantineEntryResource is located within QuarantineEntry. Using these offsets, we will later be able to parse individual QuarantineEntryResource instances. Thus, the QuarantineEntrySection2 structure is fairly straightforward:
| struct QuarantineEntrySection2 { | |
| DWORD EntryCount; | |
| DWORD EntryOffsets[EntryCount]; | |
| }; |
QuarantineEntry: the QuarantineEntryFileHeaderNow that we have a proper understanding of the QuarantineEntry, we want to know how it ends up written to disk in encrypted form, so that we can properly parse the file upon forensic recovery. By inspecting the QexQuarantine::CQexQuaEntry::Commit function further, we can find how this ends up passing QuarantineSection1 and QuarantineSection2 to a function named CUserDatabase::Add.
We noted earlier that the QuarantineEntry contains three RC4-encrypted chunks. The first chunk of the file is created in the CUserDatabase::Add function, and is the QuarantineEntryHeader. The second chunk is QuarantineEntrySection1. The third chunk starts with QuarantineEntrySection2, followed by all QuarantineEntryResource structures and their 4-byte aligned QuarantineEntryResourceField structures.
We knew from Bauch’s work that the QuarantineEntryFileHeader has a static size of 60 bytes, and contains the size of QuarantineEntrySection1 and QuarantineEntrySection2. Thus, we need to decrypt the QuarantineEntryFileHeader first.
Based on Bauch’s work, we started with the following structure for QuarantineEntryFileHeader:
| struct QuarantineEntryHeader { | |
| char magic[16]; | |
| char unknown1[24]; | |
| uint32_t section1_size; | |
| uint32_t section2_size; | |
| char unknown[12]; | |
| }; |
That leaves quite some bytes unknown though, so we went back to trusty IDA. Inspecting the CUserDatabase:Add function helps us further understand the QuarantineEntryHeader structure. For example, we can see the hardcoded magic header and footer:

Figure 8: Magic header and footer being set for the QuarantineEntryHeader
A CRC checksum calculation can be seen for both the buffer of QuarantineEntrySection1 and QuarantineSection2:

Figure 9: CRC Checksum logic within CUserDatabase::Add
These checksums can be used upon recovery to verify the validity of the file. The CUserDatabase:Add function then writes the three chunks in RC4-encrypted form to the QuarantineEntry file buffer.
Based on these findings of the Magic header and footer and the CRC checksums, we can revise the structure definition for the QuarantineEntryFileHeader:
| struct QuarantineEntryFileHeader { | |
| CHAR MagicHeader[4]; | |
| CHAR Unknown[4]; | |
| CHAR _Padding[32]; | |
| DWORD Section1Size; | |
| DWORD Section2Size; | |
| DWORD Section1CRC; | |
| DWORD Section2CRC; | |
| CHAR MagicFooter[4]; | |
| }; |
This was the last piece to be able to parse QuarantineEntry structures from their on-disk form. However, we do not want just the metadata: we want to recover the quarantined files as well.
QuarantineEntryResourceDataWe can now correctly parse QuarantineEntry files, so it is time to turn our attention to the QuarantineEntryResourceData file. This file contains the RC4-encrypted contents of the file that has been placed into quarantine.
Let’s start by letting Windows Defender quarantine a Mimikatz executable and reviewing its output files in the quarantine folder. One would think that merely RC4 decrypting the QuarantineEntryResourceData file would result in the contents of the original file. However, a quick hexdump of a decrypted QuarantineEntryResourceData file shows us that there is more information contained within:
| max@dissect $ hexdump -C mimikatz_resourcedata_rc4_decrypted.bin | head -n 20 | |
| 00000000 03 00 00 00 02 00 00 00 a4 00 00 00 00 00 00 00 |…………….| | |
| 00000010 00 00 00 00 01 00 04 80 14 00 00 00 30 00 00 00 |…………0…| | |
| 00000020 00 00 00 00 4c 00 00 00 01 05 00 00 00 00 00 05 |….L………..| | |
| 00000030 15 00 00 00 a4 14 d2 9b 1a 02 a7 4f 07 f6 37 b4 |………..O..7.| | |
| 00000040 e8 03 00 00 01 05 00 00 00 00 00 05 15 00 00 00 |…………….| | |
| 00000050 a4 14 d2 9b 1a 02 a7 4f 07 f6 37 b4 01 02 00 00 |…….O..7…..| | |
| 00000060 02 00 58 00 03 00 00 00 00 00 14 00 ff 01 1f 00 |..X………….| | |
| 00000070 01 01 00 00 00 00 00 05 12 00 00 00 00 00 18 00 |…………….| | |
| 00000080 ff 01 1f 00 01 02 00 00 00 00 00 05 20 00 00 00 |………… …| | |
| 00000090 20 02 00 00 00 00 24 00 ff 01 1f 00 01 05 00 00 | …..$………| | |
| 000000a0 00 00 00 05 15 00 00 00 a4 14 d2 9b 1a 02 a7 4f |……………O| | |
| 000000b0 07 f6 37 b4 e8 03 00 00 01 00 00 00 00 00 00 00 |..7………….| | |
| 000000c0 00 ae 14 00 00 00 00 00 00 00 00 00 4d 5a 90 00 |…………MZ..| | |
| 000000d0 03 00 00 00 04 00 00 00 ff ff 00 00 b8 00 00 00 |…………….| | |
| 000000e0 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 |….@………..| | |
| 000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….| | |
| 00000100 00 00 00 00 00 00 00 00 20 01 00 00 0e 1f ba 0e |…….. …….| | |
| 00000110 00 b4 09 cd 21 b8 01 4c cd 21 54 68 69 73 20 70 |….!..L.!This p| | |
| 00000120 72 6f 67 72 61 6d 20 63 61 6e 6e 6f 74 20 62 65 |rogram cannot be| | |
| 00000130 20 72 75 6e 20 69 6e 20 44 4f 53 20 6d 6f 64 65 | run in DOS mode| |
As visible in the hexdump, the MZ value (which is located at the beginning of the buffer of the Mimikatz executable) only starts at offset 0xCC. This gives reason to believe there is potentially valuable information preceding it.
There is also additional information at the end of the ResourceData file:
| max@dissect $ hexdump -C mimikatz_resourcedata_rc4_decrypted.bin | tail -n 10 | |
| 0014aed0 00 00 00 00 52 00 00 00 00 00 00 00 2c 00 00 00 |….R…….,…| | |
| 0014aee0 3a 00 5a 00 6f 00 6e 00 65 00 2e 00 49 00 64 00 |:.Z.o.n.e…I.d.| | |
| 0014aef0 65 00 6e 00 74 00 69 00 66 00 69 00 65 00 72 00 |e.n.t.i.f.i.e.r.| | |
| 0014af00 3a 00 24 00 44 00 41 00 54 00 41 00 5b 5a 6f 6e |:.$.D.A.T.A.[Zon| | |
| 0014af10 65 54 72 61 6e 73 66 65 72 5d 0d 0a 5a 6f 6e 65 |eTransfer]..Zone| | |
| 0014af20 49 64 3d 33 0d 0a 52 65 66 65 72 72 65 72 55 72 |Id=3..ReferrerUr| | |
| 0014af30 6c 3d 43 3a 5c 55 73 65 72 73 5c 75 73 65 72 5c |l=C:\Users\user\| | |
| 0014af40 44 6f 77 6e 6c 6f 61 64 73 5c 6d 69 6d 69 6b 61 |Downloads\mimika| | |
| 0014af50 74 7a 5f 74 72 75 6e 6b 2e 7a 69 70 0d 0a |tz_trunk.zip..| |
At the end of the hexdump, we see an additional buffer, which some may recognize as the “Zone Identifier”, or the “Mark of the Web”. As this Zone Identifier may tell you something about where a file originally came from, it is valuable for forensic investigations.
To understand where these additional buffers come from and how we can parse them, we again dive into the bowels of mpengine.dll. If we review the QuarantineFile function, we see that it receives a QuarantineEntryResource and QuarantineEntry as parameters. When following the code path, we see that the BackupRead function is called to write to a buffer of which we know that it will later be RC4-encrypted by Defender and written to the quarantine folder:

Figure 10: BackupRead being called withi nthe QuarantineFile function.
A glance at the documentation of BackupRead reveals that this function returns a buffer seperated by Win32 stream IDs. The streams stored by BackupRead contain all data streams as well as security data about the owner and permissions of a file. On NTFS file systems, a file can have multiple data attributes or streams: the “main” unnamed data stream and optionally other named data streams, often referred to as “alternate data streams”. For example, the Zone Identifier is stored in a seperate Zone.Identifier data stream of a file. It makes sense that a function intended for backing up data preserves these alternate data streams as well.
The fact that BackupRead preserves these streams is also good news for forensic analysis. First of all, malicious payloads can be hidden in alternate data streams. Moreover, alternate datastreams such as the Zone Identifier and the security data can help to understand where a file has come from and what it contains. We just need to recover the streams as they have been saved by BackupRead!
Diving into IDA is not necessary, as the documentation tells us all that we need. For each data stream, the BackupRead function writes a WIN32_STREAM_ID to disk, which denotes (among other things) the size of the stream. Afterwards, it writes the data of the stream to the destination file and continues to the next stream. The WIN32_STREAM_ID structure definition is documented on the Microsoft Learn website:
| typedef struct _WIN32_STREAM_ID { | |
| STREAM_ID StreamId; | |
| STREAM_ATTRIBUTES StreamAttributes; | |
| QWORD Size; | |
| DWORD StreamNameSize; | |
| WCHAR StreamName[StreamNameSize / 2]; | |
| } WIN32_STREAM_ID; |
While reversing parts of mpengine.dll, we came across an interesting looking call in the HandleThreatDetection function. We appreciate that threats must be dealt with swiftly and with utmost discipline, but could not help but laugh at the curious choice of words when it came to naming this particular function.
Figure 11: A function call to SendThreatToCamp, a ‘call’ to action that seems pretty harsh.
We now have all structure definitions that we need to recover all metadata and quarantined files from the quarantine folder. There is only one step left: writing an implementation.
During incident response, we do not want to rely on scripts scattered across home directories and git repositories. This is why we integrate our research into Dissect.
We can leave all the boring stuff of parsing disks, volumes and evidence containers to Dissect, and write our implementation as a plugin to the framework. Thus, the only thing we need to do is parse the artefacts and feed the results back into the framework.
The dive into Windows Defender of the previous sections resulted in a number of structure definitions that we need to recover data from the Windows Defender quarantine folder. When making an implementation, we want our code to reflect these structure definitions as closely as possible, to make our code both readable and verifiable. This is where dissect.cstruct comes in. It can parse structure definitions and make them available in your Python code. This removes a lot of boilerplate code for parsing structures and greatly enhances the readability of your parser. Let’s review how easily we can parse a QuarantineEntry file using dissect.cstruct :
| from dissect.cstruct import cstruct | |
| defender_def= """ | |
| struct QuarantineEntryFileHeader { | |
| CHAR MagicHeader[4]; | |
| CHAR Unknown[4]; | |
| CHAR _Padding[32]; | |
| DWORD Section1Size; | |
| DWORD Section2Size; | |
| DWORD Section1CRC; | |
| DWORD Section2CRC; | |
| CHAR MagicFooter[4]; | |
| }; | |
| struct QuarantineEntrySection1 { | |
| CHAR Id[16]; | |
| CHAR ScanId[16]; | |
| QWORD Timestamp; | |
| QWORD ThreatId; | |
| DWORD One; | |
| CHAR DetectionName[]; | |
| }; | |
| struct QuarantineEntrySection2 { | |
| DWORD EntryCount; | |
| DWORD EntryOffsets[EntryCount]; | |
| }; | |
| struct QuarantineEntryResource { | |
| WCHAR DetectionPath[]; | |
| WORD FieldCount; | |
| CHAR DetectionType[]; | |
| }; | |
| struct QuarantineEntryResourceField { | |
| WORD Size; | |
| WORD Identifier:12; | |
| FIELD_TYPE Type:4; | |
| CHAR Data[Size]; | |
| }; | |
| """ | |
| c_defender = cstruct() | |
| c_defender.load(defender_def) | |
| class QuarantineEntry: | |
| def __init__(self, fh: BinaryIO): | |
| # Decrypt & parse the header so that we know the section sizes | |
| self.header = c_defender.QuarantineEntryFileHeader(rc4_crypt(fh.read(60))) | |
| # Decrypt & parse Section 1. This will tell us some information about this quarantine entry. | |
| # These properties are shared for all quarantine entry resources associated with this quarantine entry. | |
| self.metadata = c_defender.QuarantineEntrySection1(rc4_crypt(fh.read(self.header.Section1Size))) | |
| # […] | |
| # The second section contains the number of quarantine entry resources contained in this quarantine entry, | |
| # as well as their offsets. After that, the individal quarantine entry resources start. | |
| resource_buf = BytesIO(rc4_crypt(fh.read(self.header.Section2Size))) |
As you can see, when the structure format is known, parsing it is trivial using dissect.cstruct. The only caveat is that the QuarantineEntryFileHeader, QuarantineEntrySection1 and QuarantineEntrySection2 structures are individually encrypted using the hardcoded RC4 key. Because only the size of QuarantineEntryFileHeader is static (60 bytes), we parse that first and use the information contained in it to decrypt the other sections.
To parse the individual fields contained within the QuarantineEntryResource, we have to do a bit more work. We cannot add the QuarantineEntryResourceField directly to the QuarantineEntryResource structure definition within dissect.cstruct, as it currently does not support the type of alignment used by Windows Defender. However, it does support the QuarantineEntryResourceField structure definition, so all we have to do is follow the alignment logic that we saw in IDA:
| # As the fields are aligned, we need to parse them individually | |
| offset = fh.tell() | |
| for _ in range(field_count): | |
| # Align | |
| offset = (offset + 3) & 0xFFFFFFFC | |
| fh.seek(offset) | |
| # Parse | |
| field = c_defender.QuarantineEntryResourceField(fh) | |
| self._add_field(field) | |
| # Move pointer | |
| offset += 4 + field.Size |
We can use dissect.cstruct‘s dumpstruct function to visualize our parsing to verify if we are correctly loading in all data:

And just like that, our parsing is done. Utilizing dissect.cstruct makes parsing structures much easier to understand and implement. This also facilitates rapid iteration: we have altered our structure definitions dozens of times during our research, which would have been pure pain without having the ability to blindly copy-paste structure definitions into our Python editor of choice.
Implementing the parser within the Dissect framework brings great advantages. We do not have to worry at all about the format in which the forensic evidence is provided. Implementing the Defender recovery as a Dissect plugin means it just works on standard forensic evidence formats such as E01 or ASDF, or against forensic packages the like of KAPE and Acquire, and even on a live virtual machine:
| max@dissect $ target-query ~/Windows10.vmx -q -f defender.quarantine | |
| <filesystem/windows/defender/quarantine/file hostname='DESKTOP-AR98HFK' domain=None ts=2022-11-22 09:37:16.536575+00:00 quarantine_id=b'\xe3\xc1\x03\x80\x00\x00\x00\x003\x12]]\x07\x9a\xd2\xc9' scan_id=b'\x88\x82\x89\xf5?\x9e J\xa5\xa8\x90\xd0\x80\x96\x80\x9b' threat_id=2147729891 detection_type='file' detection_name='HackTool:Win32/Mimikatz.D' detection_path='C:\\Users\\user\\Documents\\mimikatz.exe' creation_time=2022-11-22 09:37:00.115273+00:00 last_write_time=2022-11-22 09:37:00.240202+00:00 last_accessed_time=2022-11-22 09:37:08.081676+00:00 resource_id='9EC21BB792E253DBDC2E88B6B180C4E048847EF6'> | |
| max@dissect $ target-query ~/Windows10.vmx -f defender.recover -o /tmp/ -v | |
| 2023-02-14T07:10:20.335202Z [info] <Target /home/max/Windows10.vmx>: Saving /tmp/9EC21BB792E253DBDC2E88B6B180C4E048847EF6.security_descriptor [dissect.target.target] | |
| 2023-02-14T07:10:20.335898Z [info <Target /home/max/Windows10.vmx>: Saving /tmp/9EC21BB792E253DBDC2E88B6B180C4E048847EF6 [dissect.target.target] | |
| 2023-02-14T07:10:20.337956Z [info] <Target /home/max/Windows10.vmx>: Saving /tmp/9EC21BB792E253DBDC2E88B6B180C4E048847EF6.ZoneIdentifierDATA [dissect.target.target] |
The full implementation of Windows Defender quarantine recovery can be observed on Github.
We hope to have shown that there can be great benefits to reverse engineering the internals of Microsoft Windows to discover forensic artifacts. By reverse engineering mpengine.dll, we were able to further understand how Windows Defender places detected files into quarantine. We could then use this knowledge to discover (meta)data that was previously not fully documented or understood. The main results of this are the recovery of more information about the original quarantined file, such as various timestamps and additional NTFS data streams, like the Zone.Identifier, which is information that can be useful in digital forensics or incident response investigations.
The documentation of QuarantineEntryResourceField was not available prior to this research and we hope others can use this to further investigate which fields are yet to be discovered. We have also documented how the BackupRead functionality is used by Defender to preserve the different data streams present in the NTFS file, including the Zone Identifier and Security Descriptor.
When writing our parser, using dissect.cstruct allowed us to tightly integrate our findings of reverse engineering in our parsing, enhancing the readability and verifiability of the code. This can in turn help others to pivot off of our research, just like we did when pivotting off of the research of others into the Windows Defender quarantine folder.
This research has been implemented as a plugin for the Dissect framework. This means that our parser can operate independently of the type of evidence it is being run against. This functionality has been added to dissect.target as of January 2nd 2023 and is installed with Dissect as of version 3.4.
Authored by Margit Hazenbroek
At Fox-IT (part of NCC Group) identifying servers that host nefarious activities is a critical aspect of our threat intelligence. One approach involves looking for anomalies in responses of HTTP servers. Sometimes cybercriminals that host malicious servers employ tactics that involve mimicking the responses of legitimate software to evade detection. However, a common pitfall of these malicious actors are typos, which we use as unique fingerprints to identify such servers. For example, we have used a simple extraneous whitespace in HTTP responses as a fingerprint to identify servers that were hosting Cobalt Strike with high confidence1. In fact, we have created numerous fingerprints based on textual slipups in HTTP responses of malicious servers, highlighting how fingerprinting these servers can be a matter of a simple mistake.
HTTP servers are expected to follow the established RFC guidelines of HTTP, producing consistent HTTP responses in accordance with standardized protocols. HTTP responses that are not set up properly can have an impact on the safety and security of websites and web services. With these considerations in mind, we decided to research the possibility of identifying unknown malicious servers by proactively searching for textual errors in HTTP responses.
In this blog post, we delve into this research, titled “The Spelling Police,” which aims to identify malevolent servers through the detection of typos in HTTP responses. Before we go into the methodology, we provide a brief overview of HTTP response headers and semantics. Then we explain how we spotted the spelling errors, focusing on the Levenshtein distance, a way to measure the differences between the expected and actual responses. Our preliminary research suggests that mistakes in HTTP responses are surprisingly common, even among legitimate servers. This finding suggests that typos alone are not enough to confirm malicious intent. However, we maintain that typos in HTTP response headers can be indicative of malicious servers, particularly when combined with other suspicious indicators.
HTTP response headers and semantics
HTTP is a protocol that governs communication between web servers and clients2. Typically, a client, such as a web browser, sends a request to a server to achieve specific goals, such as requesting to view a webpage. The server receives and processes these requests, then sends back corresponding responses. The client subsequently interprets the message semantics of these responses, for example by rendering the HTML in an HTTP response (see example 1).
An HTTP response includes the status code and status line that provide information on how the server is responding, such as a ‘404 Page Not Found’ message. This status code is followed by response headers. Response headers are key:value pairs as described in the RFC that allow the server to give more information for context about the response and it can give information to the client on how to process the received data. Ensuring appropriate implementation of HTTP response headers plays a crucial role in preventing security vulnerabilities like Cross-Site Scripting, Clickjacking, Information disclosure, and many others34
Methodology
The purpose of this research is to identify textual deviations in HTTP response headers and verify the servers behind them to detect new or unknown malicious servers. To accomplish this, we collected a large sample of HTTP responses and applied a spelling-checking model to flag any anomalous responses that contained deviations (see example 3 for an overview of the pipeline). These anomalous HTTP responses were further investigated to determine if they were originating from potentially malicious servers.
Data: Batch of HTTP responses
We sampled approximately 800,000 HTTP responses from public Censys scan data5. We also created a list of common HTTP response header fields, such as ‘Cache-Control’, ‘Expires’, ‘Content-Type’, and a list of typical server values, such as ‘Apache’, ‘Microsoft-IIS’, and ‘Nginx.’ We included a few common status codes like ‘200 OK,’ ensuring that the list contained commonly occurring words in HTTP responses to serve as our reference.
Metric: The Levenshtein distance
To measure typos, we used the Levenshtein distance, an intuitive spelling-checking model that measures the difference between two strings. The distance is calculated by counting the number of operations required to transform one string into the other. These operations can include insertions, deletions, and substitutions of characters. For example, when comparing the words ‘Cat’ and ‘Chat’ using the Levenshtein distance, we would observe that only one operation is needed to transform the word ‘Cat’ into ‘Chat’ (i.e., adding an ‘h’). Therefore, ‘Chat’ has a Levenshtein distance of one compared to ‘Cat’. However, comparing the words ‘Hats’ and ‘Cat’ would require two operations (i.e., changing ‘H’ to ‘C’ and adding an ‘s’ in the end), and therefore, ‘Hats’ would have a Levenshtein distance of two compared to ‘Cat.’
The Levenshtein distance can be made sensitive to capitalization and any character, allowing for the detection of unusual additional spaces or lowercase characters, for example. This measure can be useful for identifying small differences in text, such as those that may be introduced by typos or other anomalies in HTTP response headers. While HTTP header keys are case-insensitive by specification, our model has been adjusted to consider any character variation. Specifically, we have made the ‘Server’ header case-sensitive to catch all nuances of the server’s identity and possible anomalies.
Our model performs a comparative analysis between our predefined list (of commonly occurring HTTP response headers and server values) and the words in the HTTP responses. It is designed to return words that are nearly identical to those of the list but includes small deviations. For instance, it can detect slight deviations such as ‘Content-Tyle’ instead of the correct ‘Content-Type’.
Output: A list with anomalous HTTP responses
The model returned a list of two hundred anomalous HTTP responses from our batch of HTTP responses. We decided to check the frequency of these anomalies over the entire scan dataset, rather than the initial sample of 800.000 HTTP Responses. Our aim was to get more context regarding the prevalence of these spelling errors.
We found that some of these anomalies were relatively common among HTTP response headers. For example, we discovered more than eight thousand instances of the HTTP response header ‘Expired’ instead of ‘Expires.’ Additionally, we saw almost three thousand instances of server names that deviated from the typical naming convention of ‘Apache’ as can be seen in table 1.
| Deviation | Common Name | Amount |
|---|---|---|
| Server: Apache Coyote | Server: Apache-Coyote | 2941 |
| Server: Apache \r\n | Server: Apache | 2952 |
| Server: Apache. | Server: Apache | 3047 |
| Server: CloudFlare | Server: Cloudflare | 6615 |
| Expired: | Expires: | 8260 |
Refining our research: Delving into the rarest anomalies
However, the rarest anomalies piqued our interest, as they could potentially indicate new or unknown malicious servers. We narrowed our investigation by only analyzing HTTP responses that appeared less than two hundred times in the wild and cross-referenced them with our own telemetry. By doing this, we could obtain more context from surrounding traffic to investigate potential nefarious activities. In the following section, we will focus on the most interesting typos that stood out and investigate them based on our telemetry.
Findings
Anomalous server values
During our investigation, we came across several HTTP responses that displayed deviations from the typical naming conventions of the values of the ‘Server’ header.
For instance, we encountered an HTTP response header where the ‘Server’ value was written differently than the typical ‘Microsoft-IIS’ servers. In this case, the header read ‘Microsoft -IIS’ instead of ‘Microsoft-IIS’ (again, note the space) as shown in example 3. We suspected that this deviation was an attempt to make it appear like a ‘Microsoft-IIS’ server response. However, our investigation revealed that a legitimate company was behind the server which did not immediately indicate any nefarious activity. Therefore, even though the typo in the server’s name was suspicious, it did not turn out to come from a malicious server.
The ‘ngengx’ server value appeared to intentionally mimic the common server name ‘nginx’ (see example 4). We found that it was linked to a cable setup account from an individual that subscribed to a big telecom and hosting provider in The Netherlands. This deviation from typical naming conventions was strange, but we could not find anything suspicious in this case.
Similarly, the ‘Apache64’ server value deviates from the standard ‘Apache’ server value (see example 5). We found that this HTTP response was associated with webservers of a game developer, and no apparent malevolent activities were detected.
While these deviations from standard naming conventions could potentially indicate an attempt to disguise a malicious server, it does not always indicate nefarious activity.
Anomalous response headers
Moreover, we encountered HTTP response headers that deviated from the standard naming conventions. The ‘Content-Tyle’ header deviated from the standard ‘Content-Type’ header, and we found both the correct and incorrect spellings within the HTTP response (see example 6). We discovered that these responses originated from ‘imgproxy,’ a service designed for image resizing. This service appears to be legitimate. Moreover, a review of the source code confirms that the ‘Content-Tyle’ header is indeed hardcoded in the landing page source code (see Example 7).
Similarly, the ‘CONTENT_LENGTH’ header deviated from the standard spelling of ‘Content-Length’ (see example 7). However, upon further investigation, we found that the server behind this response also belongs to a server associated with webservers of a game developer. Again, we did not detect any malicious activities associated with this deviation from typical naming conventions.
The findings of our research seem to reveal that even HTTP responses set up by legitimate companies include messy and incorrect response headers.
Concluding Insights
Our study was designed to uncover potentially malicious servers by proactively searching for spelling mistakes in HTTP response headers. HTTP servers are generally expected to adhere to the established RFC guidelines, producing consistent HTTP responses as dictated by the standard protocols. Sometimes cybercriminals hosting malicious servers attempt to evade detection by imitating standard responses of legitimate software. However, sometimes they slip up, leaving inadvertent typos, which can be used for fingerprinting purposes.
Our study reveals that typos in HTTP responses are not as rare as one might assume. Despite the crucial role that appropriate implementation of HTTP response headers plays in the security and safety of websites and web services, our research suggests that textual errors in HTTP responses are surprisingly widespread, even in the outputs of servers from legitimate organizations. Although these deviations from standard naming conventions could potentially indicate an attempt to disguise a malicious server, they do not always signify nefarious activity. The internet is simply too messy.
Our research concludes that typos alone are insufficient to identify malicious servers. Nevertheless, they retain potential as part of a broader detection framework. We propose advancing this research by combining the presence of typos with additional metrics. One approach involves establishing a baseline of common anomalous HTTP responses, and then flagging HTTP responses with new typos as they emerge.
Furthermore, more research could be conducted regarding the order of HTTP headers. If the header order in the output differs from what is expected from a particular software, in combination with (new) typos, it may signal an attempt to mimic that software.
Lastly, this strategy could be integrated with other modelling approaches, such as data science models in Security Operations Centers. For instance, monitoring servers that are not only new to the network but also exhibit spelling errors. By integrating these efforts, we strive to enhance our ability to detect emerging malicious servers.
References
Authored by Mick Koomen
Blister is a piece of malware that loads a payload embedded inside it. We provide an overview of payloads dropped by the Blister loader based on 137 unpacked samples from the past one and a half years and take a look at recent activity of Blister. The overview shows that since its support for environmental keying, most samples have this feature enabled, indicating that attackers mostly use Blister in a targeted manner. Furthermore, there has been a shift in payload type from Cobalt Strike to Mythic agents, matching with previous reporting. Blister drops the same type of Mythic agent which we thus far cannot link to any public Mythic agents. Another development is that its developers started obfuscating the first stage of Blister, making it more evasive. We provide YARA rules and scripts1 to help analyze the Mythic agent and the packer we observed with it.
Blister is a loader that loads a payload embedded inside it and in the past was observed with activity linked to Evil Corp2,3. Matching with public reporting, we have also seen it as a follow-up in SocGholish infections. In the past, we observed Blister mostly dropping Cobalt Strike beacons, yet current developments show a shift to Mythic agents, another red teaming framework.
Elastic Security first documented Blister in December 2021 in a campaign that used malicious installers4. It used valid code signatures referencing the company Blist LLC to pose as a legitimate executable, likely leading to the name Blister. That campaign reportedly dropped Cobalt Strike and BitRat.
In 2022, Blister started solely using the x86-64 instruction set, versus including 32-bit as well. Furthermore, RedCanary wrote observing SocGholish dropping Blister5, which was later confirmed by other vendors as well6.
In August the same year, we observed a new version of Blister. This update included more configuration options, along with an optional domain hash for environmental keying, allowing attackers to deploy Blister in a targeted manner. Elastic Security recently wrote about this version7.
2023 initially did not bring new developments for Blister. However, similar to its previous update, we observed development activity in August. Notably, we saw samples with added obfuscation to the first stage of Blister, i.e. the loader component that is injected into a legitimate executable. Additionally, in July, Unit 428 observed SocGholish dropping Blister with a Mythic agent.
In summary, 2023 brought new developments for Blister, with added obfuscations to the first stage and a new type of payload. The next part of this blog is divided into two parts: firstly, we look back at previous Blister payloads and configurations, and in the second part, we discuss the recent developments.
In early 2023, we observed a SocGholish infection at our security operations center (SOC). We notified the customer and were given a binary that was related to the infection. This turned out to be a Blister sample, with Cobalt Strike as its payload.
We wrote an extractor that worked on the sample encountered at the SOC, but for certain other Blister samples it did not. It turned out that the sample from the SOC investigation belonged to a version of Blister that was introduced in August, 2022, while older samples had a different configuration. After writing an extractor for these older versions, we made an overview of what Blister had been dropping in roughly the past two years.
The samples we analyzed are all available on VirusTotal, the platform we used to find samples. We focus on 64-bit Blister samples, newer samples are not using 32-bit anymore, as far as we know. In total, we found 137 samples we could unpack, 33 samples with the older version and 104 samples with the newer version from 2022.
In the Appendix, we list these samples, where version 1 and 2 refer to the old and new version respectively. The table is sorted on the first seen date of a sample in VirusTotal, where you clearly see the introduction of the update.
Because we want to keep the tables comprehensible, we have split up the data into four tables. For now, it is important to note that Table 2 provides information per Blister sample we unpacked, including the date it was first uploaded to VirusTotal, the version, the label of the payload it drops, the type of payload, and two configuration flags. Furthermore, to have a list of Blister and payload hashes in clear text in the blog, we included these in Table 6. We also included a more complete data set at https://github.com/fox-it/blister-research.
Looking at the dropped payloads, we see that it mostly conforms with what has already been reported. In Figure 1, we provide a timeline based on the first seen date of a sample in VirusTotal and the family of the payload. The observed payloads consist of Cobalt Strike, Mythic, Putty, and a test application. Initially, Blister dropped various flavors of Cobalt Strike and later dropped a Mythic agent, which we refer to as BlisterMythic. Recently, we also observed a packer that unpacks BlisterMythic, which we refer to as MythicPacker. Interestingly, we did not observe any samples drop BitRat.

Figure 1, Overview of Blister samples we were able to unpack, based on the first seen date reported in VirusTotal.
From the 137 samples, we were able to retrieve 74 unique payloads. This discrepancy in amount of unique Blister samples versus unique payloads is mainly caused by various Blister samples that drop the same Putty or test application, namely 18 and 22 samples, respectively. This summer has shown a particular increase in test payloads.
Cobalt Strike was dropped through three different types of payloads, generic shellcode, DLL stagers, or obfuscated shellcode. In total, we retrieved 61 beacons, in Table 1 we list the Cobalt Strike watermarks we observed. Watermarks are a unique value linked to a license key. It should be noted that Cobalt Strike watermarks can be changed and hence are not a sound way to identify clusters of activity.
| Watermark (decimal) | Watermark (hexadecimal) | Nr. of beacons |
|---|---|---|
| 206546002 | 0xc4fa452 | 2 |
| 1580103824 | 0x5e2e7890 | 21 |
| 1101991775 | 0x41af0f5f | 38 |
The watermark 206546002, though only used twice, shows up in other reports as well, e.g. a report on an Emotet intrusion9 and a report linking it to Royal, Quantum, and Play ransomware activity10,11. The watermark 1580103824 is mentioned in reports on Gootloader12, but also Cl0p13 and also is the 9th most common beacon watermark, based on our dataset of Cobalt Strike beacons14. Interestingly, 1101991775, the watermark that is most common, is not mentioned in public reporting as far as we can tell.
In Table 3, we list information on the extracted beacons. In there, we also list the submission path. Most of the submission paths contain /safebrowsing/ and /rest/2/meetings, matching with paths found in SourcePoint15, a Cobalt Strike command-and-control (C2) profile generator. This is only, however, for the regular shellcode beacons, when we look at the obfuscated shellcode and the DLL stager beacons, it seems to use a different C2 profile. The C2 profiles for these payloads match with another public C2 profile generator16.
Some of the beacons are configured to use “domain fronting”, which is a technique that allows malicious actors to hide the true destination of their network traffic and evade detection by security systems. It involves routing malicious traffic through a content delivery network (CDN) or other intermediary server, making it appear as if the traffic is going to a legitimate or benign domain, while in reality, it’s communicating with a malicious C2 server.
Certain beacons have subdomains of fastly[.]net as their C2 server, e.g. backend.int.global.prod.fastly[.]net or python.docs.global.prod.fastly[.]net. However, the domains they connect to are admin.reddit[.]com or admin.wikihow[.]com, which are legitimate domains hosted on a CDN.
In five cases, we observed Blister drop Cobalt Strike by first loading obfuscated shellcode. We included a YARA rule for this particular shellcode in the Appendix.
Performing a retrohunt on VirusTotal yielded only 12 samples, with names indicating potential test files and at least one sample dropping Cobalt Strike. We are unsure whether this is an obfuscator solely used by Evil Corp or whether it is used by other threat actors as well.

Figure 2, Layout of particular shellcode, with denoted steps.
The shellcode is fairly simple, we provide an overview of it in Figure 2. The entrypoint is at the start of the buffer, which calls into the decoding stub. This call instruction automatically pushes the next instruction’s address on the stack, which the decoding stub uses as a starting point to start mutating memory. Figure 3 shows some of these instructions, which are quite distinctive.

Figure 3, Decoding instructions observed in particular shellcode.
At the end of the decoding stub, it either jumps or calls back and then invokes the decryption function. This decryption function uses RC4, but the S-Box is already initialized, thus no key-scheduling algorithm is implemented. Lastly, it jumps to the final payload.
Matching with what was already reported by Unit 428, Blister recently started using Mythic agents as its payload. Mythic is one of the many red teaming frameworks on GitHub18. You can use various agents, which are listed on GitHub as well19 and can roughly be compared to a Cobalt Strike beacon. It is possible to write your own Mythic agent, as long as you comply with a set of constraints. Thus far, we keep seeing the same Mythic agent, which we discuss in more detail later on. The first sample dropping Mythic agents was uploaded to VirusTotal on July 24th 2023, just days before initial reportings of SocGholish infections leading to Mythic. In Table 4, we provide the C2 information from the observed Mythic agents.
We observed Mythic either as a Portable Executable (PE) or as shellcode. The shellcode seems to be rare and unpacks a PE file which thus far always resulted in a Mythic agent, in our experience. We discuss this packer later on as well and provide scripts that help with retrieving the PE file it packs. We refer to this specific Mythic agent as BlisterMythic and to the packer as MythicPacker.
In Table 5, we list the BlisterMythic C2 servers we were able to find. Interestingly, the domains were all registered at DNSPod. We also observed this in the past with Cobalt Strike domains we linked to Evil Corp. Apart from this, we also see similarities in the domain names used, e.g. domains consisting of two or three words concatenated to each other and using com as top-level domain (TLD).
Besides red team tooling like Mythic and Cobalt Strike, we also observed Putty and a test application as payloads. Running Putty through Blister does not seem logical and is likely linked to testing. It would only result in Putty not touching the disk and running in memory, which in itself is not useful. Additionally, when we look at the domain hashes in the Blister samples, only the Putty and test application samples in some cases share their domain hash.
We also looked at the configurations of Blister, from this we can to some extent derive how it is used by attackers. Note that the collection also contains “test samples” from the attacker. Except for the more obvious Putty and test application, some samples that dropped Mythic, for instance, could also be linked to testing. We chose to leave out samples that drop Putty or the test application, leaving 97 samples in total. This means that the samples paint a partly biased picture, though we think it is still valuable and provides a view into how Blister is used.
Since its update in 2022, Blister includes an optional domain hash, that it computes over the DNS search domain of the machine (ComputerNameDnsDomain). It only continues executing if the hash matches with its configuration, enabling environmental keying.
By looking at the amount of samples that have domain hash verification enabled, we can say something about how Blister is deployed. From the 66 Blister samples, only 6 samples did not have domain hash verification enabled. This indicates it is mostly used in a targeted manner, corresponding with using SocGholish for initial access and reconnaissance and then deploying Blister, for example.
Of the 97 samples, 70 have persistence enabled. For persistence, Blister still uses the same method as described by Elastic Security20. It mostly uses IFileOperation COM interface to copy rundll32.exe and itself to the Startup folder, this is significant for detection, as it means that these operations are done by the process DllHost.exe, not the rundll32.exe process that hosts Blister.
Blister’s previous update altered the core payload, however, the loader that is injected into the legitimate executable remained unchanged. In August this year, we observed experimental samples on VirusTotal with an obfuscated loader component, hinting at developer activity. Interestingly, we could link these samples to another sample on VirusTotal which solely contained the function body of the loader and another sample that contained a loader with a large set of INT 3 instructions added to it. Perhaps the developer was experimenting with different mutations to see how it influences the detection rate.
Recent samples from September 2023 have the loader obfuscated in the same manner, with bogus instructions and excessive jump instructions. These changes make it harder to detect Blister using YARA, as the loader instructions are now intertwined with junk instructions and sometimes are followed by junk data due to the added jump instructions.

Figure 4, Comparison of two loader components from recent Blister samples, left is without obfuscation and right is with obfuscation.
In Figure 4, we compare the two function bodies of the loader, one body which is normally seen in Blister samples and one obfuscated function body, observed in the recent samples. The comparison shows that naive YARA rules are less likely to trigger on the obfuscated function body. In the Appendix, we provide a Blister rule that tries to detect these obfuscated samples. The added bogus instructions include instructions, such as btc, bts, lahf and cqo, bogus instructions we also observed in the Blister core before, see the core component of SHA256 4faf362b3fe403975938e27195959871523689d0bf7fba757ddfa7d00d437fd4, for example.
Apart from an obfuscated loader, Mythic agents currently are the payload of choice. In September and October, we found obfuscated Blister samples only dropping Mythic. Certain samples have low or zero detections on VirusTotal21 at the time of writing, showing that obfuscation does pay off.
We now discuss one sample22 that drops a shellcode eventually executing a Mythic agent. The shellcode unpacks a PE file and executes it. We provide a YARA rule for this packer in the Appendix, which we refer to as MythicPacker. Based on this rule, we did not find other samples, suggesting it is a custom packer. Until now, we have only seen this packer unpacking Mythic agents.
The dropped Mythic agents are all similar and we cannot link them to any public agents thus far. This could mean that Blister developers created their own Mythic agent, though this is uncertain. We provided a YARA rule that matches on all agents we encountered, a VirusTotal retrohunt over the past year resulted in only four samples, all linked to Blister. We think this Mythic agent is likely custom-made.

Figure 5, BlisterMythic configuration decryption.
The agents all share a similar structure, namely an encrypted configuration in the .bss section of the executable. The agent has an encrypted configuration which is decrypted by XORing the size of the configuration with a constant that differs per sample, it seems. For PE files, we have a Python script that can decrypt a configuration. Figure 5 denotes this decryption loop, where the XOR constant is 0x48E12000.

Figure 6, Decrypted BlisterMythic configuration
Dumping the configuration results in a binary blob that contains various information, including the C2 server. Figure 6 shows a hexdump of a snippet from the decrypted configuration. We created a script to dump the decrypted configuration of the BlisterMythic agent in PE format and also a script that unpacks MythicPacker shellcode and outputs a reconstructed PE file, see https://github.com/fox-it/blister-research.
In this post, we provided an overview of observed Blister payloads from the past one and a half years on VirusTotal and also gave insight into recent developments. Furthermore, we provided scripts and YARA rules to help analyze Blister and the Mythic agent it drops.
From the analyzed payloads, we see that Cobalt Strike was the favored choice, but that lately this has been replaced by Mythic. Cobalt Strike was mostly dropped as shellcode and briefly run through obfuscated shellcode or a DLL stager. Apart from Cobalt Strike and Mythic, we saw that Blister test samples are uploaded to VirusTotal as well.
The custom Mythic agent together with the obfuscated loader, are new Blister developments that happened in the past months. It is likely that its developers were aware that the loader component was still a weak spot in terms of static detection. Additionally, throughout the years, Cobalt Strike has received a lot of attention from the security community, with available dumpers and C2 feeds readily available. Mythic is not as popular and allows you to write your own agent, making it an appropriate replacement for now.
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎
︎rule shellcode_obfuscator
{
meta:
os = "Windows"
arch = "x86-64"
description = "Detects shellcode packed with unknown obfuscator observed in Blister samples."
reference_sample = "178ffbdd0876b99ad1c2d2097d9cf776eca56b540a36c8826b400cd9d5514566"
strings:
$rol_ror = { 48 C1 ?? ?? ?? 48 C1 ?? ?? ?? 48 C1 ?? ?? ?? }
$mov_rol_mov = { 4d ?? ?? ?? 49 c1 ?? ?? ?? 4d ?? ?? ?? }
$jmp = { 49 81 ?? ?? ?? ?? ?? 41 ?? }
condition:
#rol_ror > 60 and $jmp and filesize < 2MB and #mov_rol_mov > 60
}
import "pe"
import "math"
rule blister_x64_windows_loader {
meta:
os = "Windows"
arch = "x86-64"
family = "Blister"
description = "Detects Blister loader component injected into legitimate executables."
reference_sample = "343728792ed1e40173f1e9c5f3af894feacd470a9cdc72e4f62c0dc9cbf63fc1, 8d53dc0857fa634414f84ad06d18092dedeb110689a08426f08cb1894c2212d4, a5fc8d9f9f4098e2cecb3afc66d8158b032ce81e0be614d216c9deaf20e888ac"
strings:
// 65 48 8B 04 25 60 00 00 00 mov rax, gs:60h
$inst_1 = {65 48 8B 04 25 60 00 00 00}
// 48 8D 87 44 6D 00 00 lea rax, [rdi+6D44h]
$inst_2 = {48 8D 87 44 6D 00 00}
// 44 69 C8 95 E9 D1 5B imul r9d, eax, 5BD1E995h
$inst_3 = {44 ?? ?? 95 E9 D1 5B}
// 41 81 F9 94 85 09 64 cmp r9d, 64098594h
$inst_4 = {41 ?? ?? 94 85 09 64}
// B8 FF FF FF 7F mov eax, 7FFFFFFFh
$inst_5 = {B8 FF FF FF 7F}
// 48 8D 4D 48 lea rcx, [rbp+48h]
$inst_6 = {48 8D 4D 48}
condition:
uint16(0) == 0x5A4D and
all of ($inst_*) and
pe.number_of_resources > 0 and
for any i in (0..pe.number_of_resources - 1):
( (math.entropy(pe.resources[i].offset, pe.resources[i].length) > 6) and
pe.resources[i].length > 200000
)
}
rule blister_mythic_payload {
meta:
os = "Windows"
arch = "x86-64"
family = "BlisterMythic"
description = "Detects specific Mythic agent dropped by Blister."
reference_samples = "2fd38f6329b9b2c5e0379a445e81ece43fe0372dec260c1a17eefba6df9ffd55, 3d2499e5c9b46f1f144cfbbd4a2c8ca50a3c109496a936550cbb463edf08cd79, ab7cab5192f0bef148670338136b0d3affe8ae0845e0590228929aef70cb9b8b, f89cfbc1d984d01c57dd1c3e8c92c7debc2beb5a2a43c1df028269a843525a38"
strings:
$start_inst = { 48 83 EC 28 B? [4-8] E8 ?? ?? 00 00 }
$for_inst = { 48 2B C8 0F 1F 00 C6 04 01 00 48 2D 00 10 00 00 }
condition:
all of them
}
rule mythic_packer
{
meta:
os = "Windows"
arch = "x86-64"
family = "MythicPacker"
description = "Detects specific PE packer dropped by Blister."
reference_samples = "9a08d2db7d0bd7d4251533551d4def0f5ee52e67dff13a2924191c8258573024, 759ac6e54801e7171de39e637b9bb525198057c51c1634b09450b64e8ef47255"
strings:
// 41 81 38 72 47 65 74 cmp dword ptr [r8], 74654772h
$a = { 41 ?? ?? 72 47 65 74 }
// 41 81 38 72 4C 6F 61 cmp dword ptr [r8], 616F4C72h
$b = { 41 ?? ?? 72 4C 6F 61 }
// B8 01 00 00 00 mov eax, 1
// C3 retn
$c = { B8 01 00 00 00 C3 }
condition:
all of them and uint8(0) == 0x48
}
| First seen | Version | Payload family | Payload type | Environmental keying | Persistence |
|---|---|---|---|---|---|
| 2021-12-03 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2021-12-05 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2021-12-14 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-01-10 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-01-11 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-01-19 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-01-19 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-01-31 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-02-14 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-02-17 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-02-22 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-02-26 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-03-10 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-03-14 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-03-15 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-03-15 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-03-18 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-03-18 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-03-24 | 1 | Putty | exe | N/a | 0 |
| 2022-03-24 | 1 | Putty | exe | N/a | 0 |
| 2022-03-30 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-04-01 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-04-11 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-04-22 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-04-25 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-06-01 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-06-02 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-06-14 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-07-04 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-07-19 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-07-21 | 1 | Cobalt Strike | shellcode | N/a | 0 |
| 2022-08-05 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2022-08-29 | 2 | Cobalt Strike | shellcode | 0 | 1 |
| 2022-09-02 | 2 | Cobalt Strike | shellcode | 0 | 0 |
| 2022-09-29 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-10-18 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-18 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-18 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-10-18 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-21 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-21 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-10-24 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-26 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-26 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-10-28 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-10-31 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-02 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-03 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-07 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-08 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-17 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-22 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-11-30 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-01 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-01 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-12-01 | 2 | Cobalt Strike | shellcode | 1 | 0 |
| 2022-12-02 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-05 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-12 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-13 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2022-12-23 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-01-06 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-01-16 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-16 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-16 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-17 | 2 | Cobalt Strike | shellcode | 0 | 1 |
| 2023-01-17 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-20 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-20 | 2 | Cobalt Strike obfuscated shellcode | shellcode | 1 | 1 |
| 2023-01-24 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-01-26 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-01-26 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-02-02 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-02-02 | 2 | Test application | shellcode | 1 | 0 |
| 2023-02-02 | 2 | Test application | shellcode | 1 | 0 |
| 2023-02-02 | 2 | Putty | exe | 1 | 0 |
| 2023-02-02 | 2 | Test application | shellcode | 1 | 0 |
| 2023-02-15 | 2 | Putty | exe | 1 | 0 |
| 2023-02-15 | 2 | Test application | shellcode | 1 | 0 |
| 2023-02-15 | 2 | Putty | exe | 1 | 0 |
| 2023-02-15 | 2 | Test application | shellcode | 1 | 0 |
| 2023-02-17 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-02-27 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-02-28 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-06 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-06 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-06 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-15 | 2 | Cobalt Strike stager | exe | 1 | 0 |
| 2023-03-19 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-23 | 1 | Cobalt Strike | shellcode | N/a | 1 |
| 2023-03-28 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-03-28 | 2 | Cobalt Strike stager | exe | 1 | 0 |
| 2023-04-03 | 2 | Cobalt Strike stager | exe | 1 | 1 |
| 2023-05-25 | 2 | Cobalt Strike stager | exe | 0 | 1 |
| 2023-05-26 | 2 | Cobalt Strike | shellcode | 1 | 1 |
| 2023-06-11 | 2 | Test application | shellcode | 1 | 0 |
| 2023-06-11 | 2 | Putty | exe | 1 | 0 |
| 2023-06-11 | 2 | Putty | exe | 1 | 0 |
| 2023-07-24 | 2 | BlisterMythic | exe | 1 | 1 |
| 2023-07-27 | 2 | BlisterMythic | exe | 1 | 1 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-09 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-10 | 2 | Putty | shellcode | 1 | 0 |
| 2023-08-11 | 2 | BlisterMythic | exe | 1 | 0 |
| 2023-08-15 | 2 | Test application | shellcode | 1 | 0 |
| 2023-08-17 | 2 | BlisterMythic | exe | 1 | 1 |
| 2023-08-18 | 2 | MythicPacker | shellcode | 1 | 0 |
| 2023-09-05 | 2 | MythicPacker | shellcode | 0 | 0 |
| 2023-09-05 | 2 | MythicPacker | shellcode | 0 | 1 |
| 2023-09-08 | 2 | Test application | shellcode | 1 | 0 |
| 2023-09-08 | 2 | Test application | shellcode | 1 | 0 |
| 2023-09-08 | 2 | Test application | shellcode | 1 | 0 |
| 2023-09-08 | 2 | Putty | shellcode | 1 | 0 |
| 2023-09-08 | 2 | Putty | shellcode | 1 | 0 |
| 2023-09-08 | 2 | Test application | shellcode | 1 | 0 |
| 2023-09-19 | 2 | BlisterMythic | exe | 1 | 1 |
| 2023-09-21 | 2 | MythicPacker | shellcode | 1 | 0 |
| 2023-09-21 | 2 | MythicPacker | shellcode | 1 | 0 |
| 2023-10-03 | 2 | MythicPacker | shellcode | 1 | 0 |
| 2023-10-10 | 2 | MythicPacker | shellcode | 1 | 0 |
| Watermark | Domain | URI |
|---|---|---|
| 1101991775 | albertonne[.]com | /safebrowsing/d4alBmGBO/HafYg4QZaRhMBwuLAjVmSPc |
| 1101991775 | astradamus[.]com | /Collect/union/QXMY8BHNIPH7 |
| 1101991775 | backend.int.global.prod.fastly[.]net | /Detect/devs/NJYO2MUY4V |
| 1101991775 | cclastnews[.]com | /safebrowsing/d4alBmGBO/UaIzXMVGvV3tS2OJiKxSzyzbh4u1 |
| 1101991775 | cdp-chebe6efcxhvd0an.z01.azurefd[.]net | /Detect/devs/NJYO2MUY4V |
| 1101991775 | deep-linking[.]com | /safebrowsing/fDeBjO/2hmXORzLK7PkevU1TehrmzD5z9 |
| 1101991775 | deep-linking[.]com | /safebrowsing/fDeBjO/dMfdNUdgjjii3Ccalh10Mh4qyAFw5mS |
| 1101991775 | deep-linking[.]com | /safebrowsing/fDeBjO/vnZNyQrwUjndCPsCUXSaI |
| 1101991775 | diggin-fzbvcfcyagemchbq.z01.azurefd[.]net | /restore/how/3RG4G5T87 |
| 1101991775 | edubosi[.]com | /safebrowsing/bsaGbO6l/ybGoI3wmK2uF9w9aL5qKmnS8IZIWsJqhp |
| 1101991775 | e-sistem[.]com | /Detect/devs/NJYO2MUY4V |
| 1101991775 | ewebsofts[.]com | /safebrowsing/3Tqo/UMskN3Lh0LyLy8BfpG1Bsvp |
| 1101991775 | expreshon[.]com | /safebrowsing/fDeBjO/2hmXORzLK7PkevU1TehrmzD5z9 |
| 1101991775 | eymenelektronik[.]com | /safebrowsing/dfKa/B58qAhJ0AEF7aNwauoqpAL8 |
| 1101991775 | gotoknysna.com.global.prod.fastly[.]net | /safebrowsing/fDeBjO/2hmXORzLK7PkevU1TehrmzD5z9 |
| 1101991775 | henzy-h6hxfpfhcaguhyf5.z01.azurefd[.]net | /Detect/devs/NJYO2MUY4V |
| 1101991775 | lepont-edu[.]com | /safebrowsing/dfKa/9T1BuXpqEDg9tx53mQRU6 |
| 1101991775 | lindecolas[.]com | /safebrowsing/d4alBmGBO/UaIzXMVGvV3tS2OJiKxSzyzbh4u1 |
| 1101991775 | lodhaamarathane[.]com | /safebrowsing/dfKa/9T1BuXpqEDg9tx53mQRU6 |
| 1101991775 | mail-adv[.]com | /safebrowsing/bsaGbO6l/dl1sskHxt1uGDGUnLDB5gxn4vYZQK1kaG6 |
| 1101991775 | mainecottagebythesea[.]com | /functionalStatus/cjdl-CLe4j-XHyiEaDqQx |
| 1101991775 | onscenephotos[.]com | /restore/how/3RG4G5T87 |
| 1101991775 | promedia-usa[.]com | /safebrowsing/d4alBmGBO/HafYg4QZaRhMBwuLAjVmSPc |
| 1101991775 | python.docs.global.prod.fastly[.]net | /Collect/union/QXMY8BHNIPH7 |
| 1101991775 | realitygangnetwork[.]com | /functionalStatus/qPprp9dtVhrGV3R3re5Xy4M2cfQo4wB |
| 1101991775 | realitygangnetwork[.]com | /functionalStatus/vFi8EPnc9zJTD0GgRPxggCQAaNb |
| 1101991775 | sanfranciscowoodshop[.]com | /safebrowsing/dfKa/GgVYon5zhYu5L7inFbl1MZEv7RGOnsS00b |
| 1101991775 | sohopf[.]com | /apply/admin_/99ZSSAHDH |
| 1101991775 | spanish-home-sales[.]com | /safebrowsing/d4alBmGBO/EB-9sfMPmsHmH-A7pmll9HbV0g |
| 1101991775 | steveandzina[.]com | /safebrowsing/d4alBmGBO/mr3lHbohEvZa0mKDWWdwTV5Flsxh |
| 1101991775 | steveandzina[.]com | /safebrowsing/d4alBmGBO/YwTM1CK0mBV1Y7UDagpjP |
| 1101991775 | websterbarn[.]com | /safebrowsing/fDeBjO/CGZcHKnX3arVCfFp98k8 |
| 1580103824 | 10.158.128[.]50 | |
| 1580103824 | bimelectrical[.]com | /safebrowsing/7IAMO/hxNTeZ8lBNYqjAsQ2tBRS |
| 1580103824 | bimelectrical[.]com | /safebrowsing/7IAMO/Jwee0NMJNKn9sDD8sUEem4g8jcB2v44UINpCIj |
| 1580103824 | bookmark-tag[.]com | /safebrowsing/eMUgI4Z/3RzgDBAvgg3DQUn8XtN8l |
| 1580103824 | braprest[.]com | /safebrowsing/d5pERENa/3tPCoNwoGwXAvV1w1JAS-OOPyVYxL1K2styHFtbXar7ME |
| 1580103824 | change-land[.]com | /safebrowsing/TKc3hA/DzwHHcc8y8O9kAS7cl4SDK0e6z0KHKIX9w7 |
| 1580103824 | change-land[.]com | /safebrowsing/TKc3hA/nLTHCIhzOKpdFp0GFHYBK-0bRwdNDlZz6Qc |
| 1580103824 | clippershipintl[.]com | /safebrowsing/sj0IWAb/YhcZADXFB3NHbxFtKgpqBtK9BllJiGEL |
| 1580103824 | couponbrothers[.]com | /safebrowsing/Jwjy4/mzAoZyZk7qHIyw3QrEpXij5WFhIo1z8JDUVA0N0 |
| 1580103824 | electronic-infinity[.]com | /safebrowsing/TKc3hA/t-nAkENGu9rpZ9ebRRXr79b |
| 1580103824 | final-work[.]com | /safebrowsing/AvuvAkxsR/8I6ikMUvdNd8HOgMeD0sPfGpwSZEMr |
| 1580103824 | geotypico[.]com | /safebrowsing/d5pERENa/f5oBhEk7xS3cXxstp6Kx1G7u3N546UStcg9nEnzJn2k |
| 1580103824 | imsensors[.]com | /safebrowsing/eMUgI4Z/BOhKRIMsJsuPnn3IQvgrEc3XLQUB3W |
| 1580103824 | intradayinvestment[.]com | /safebrowsing/dpNqi/nXeFgGufr9VqHjDdsIZbw-ZH0 |
| 1580103824 | medicare-cost[.]com | /safebrowsing/dpNqi/F3QExtY65SvTVK1ewA26 |
| 1580103824 | optiontradingsignal[.]com | /safebrowsing/dpNqi/7CtHhF-isMMQ6m7NmHYNb0N7E7Fe |
| 1580103824 | setechnowork[.]com | /safebrowsing/fBm1b/JbcKDYjMWcQNjn69LnGggFe6mpjn5xOQ |
| 1580103824 | sikescomposites[.]com | /safebrowsing/Jwjy4/cmr4tZ7IyFGbgCiof2tHMO |
| 1580103824 | technicollit[.]com | /safebrowsing/b0kKKIjr/AzX9ZHB37oJfPsUBUaxBJjzzi132cYRZhUZc81g |
| 1580103824 | wasfatsahla[.]com | /safebrowsing/IsXNCJJfH/5x0rUIrn–r85sLJIuEY7C9q |
| 206546002 | smutlr[.]com | /functionalStatus/qPprp9dtVhrGV3R3re5Xy4M2cfQo4wB |
| 206546002 | spanish-home-sales[.]com | /functionalStatus/fb8ClEdmm-WwYudk-zODoQYB7DX3wQYR |
| Domain | URI |
|---|---|
| 139-177-202-78.ip.linodeusercontent[.]com | /etc.clientlibs/sapdx/front-layer/dist/resources/sapcom/919.9853a7ee629d48b1ddbe.js |
| 23-92-30-58.ip.linodeusercontent[.]com | /etc.clientlibs/sapdx/front-layer/dist/resources/sapcom/919.9853a7ee629d48b1ddbe.js |
| aviditycellars[.]com | /etc.clientlibs/sapdx/front-layer/dist/resources/sapcom/919.9853a7ee629d48b1ddbe.js |
| boxofficeseer[.]com | /s/0.7.8/clarity.js |
| d1hp6ufzqrj3xv.cloudfront[.]net | /organizations/oauth2/v2.0/authorize |
| makethumbmoney[.]com | /s/0.7.8/clarity.js |
| rosevalleylimousine[.]com | /login.sophos.com/B2C_1A_signup_signin/api/SelfAsserted/confirmed |
| IP | Domain |
|---|---|
| 37.1.215[.]57 | angelbusinessteam[.]com |
| 92.118.112[.]100 | danagroupegypt[.]com |
| 104.238.60[.]11 | shchiswear[.]com |
| 172.233.238[.]215 | N/a |
| 96.126.111[.]127 | N/a |
| 23.239.11[.]145 | N/a |
| 45.33.98[.]254 | N/a |
| 45.79.199[.]4 | N/a |
| 45.56.105[.]98 | N/a |
| 149.154.158[.]243 | futuretechfarm[.]com |
| 104.243.33[.]161 | sms-atc[.]com |
| 104.243.33[.]129 | makethumbmoney[.]com |
| 138.124.180[.]241 | vectorsandarrows[.]com |
| 94.131.101[.]58 | pacatman[.]com |
| 198.58.119[.]214 | N/a |
| 185.174.101[.]53 | personmetal[.]com |
| 185.45.195[.]30 | aviditycellars[.]com |
| 185.250.151[.]145 | bureaudecreationalienor[.]com |
| 23.227.194[.]115 | bitscoinc[.]com |
| 88.119.175[.]140 | boxofficeseer[.]com |
| 88.119.175[.]137 | thesheenterprise[.]com |
| 37.1.214[.]162 | remontisto[.]com |
| 45.66.248[.]99 | N/a |
| 88.119.175[.]104 | visioquote[.]com |
| 45.66.248[.]13 | cannabishang[.]com |
| 92.118.112[.]8 | turanmetal[.]com |
| 37.1.211[.]150 | lucasdoors[.]com |
| 185.72.8[.]219 | displaymercials[.]com |
| 172.232.172[.]128 | N/a |
| 82.117.253[.]168 | digtupu[.]com |
| 104.238.60[.]112 | avblokhutten[.]com |
| 173.44.141[.]34 | hom4u[.]com |
| 170.130.165[.]140 | rosevalleylimousine[.]com |
| 172.232.172[.]110 | N/a |
| 5.8.63[.]79 | boezgrt[.]com |
| 172.232.172[.]125 | N/a |
| 162.248.224[.]56 | hatchdesignsnh[.]com |
| 185.174.101[.]13 | formulaautoparts[.]com |
| 23.152.0[.]193 | ivermectinorder[.]com |
| 192.169.6[.]200 | szdeas[.]com |
| 194.87.32[.]85 | licencesolutions[.]com |
| 185.45.195[.]205 | motorrungoli[.]com |
| SHA256 | Payload family | Payload SHA256 |
|---|---|---|
| 0a73a9ee3650821352d9c4b46814de8f73fde659cae6b82a11168468becb68d1 | Cobalt Strike | 397c08f5cdc59085a48541c89d23a8880d41552031955c4ba38ff62e57cfd803 |
| 0bbf1a3a8dd436fda213bc126b1ad0b8704d47fd8f14c75754694fd47a99526c | BlisterMythic | ab7cab5192f0bef148670338136b0d3affe8ae0845e0590228929aef70cb9b8b |
| 0e8458223b28f24655caf37e5c9a1c01150ac7929e6cb1b11d078670da892a5b | Cobalt Strike | 4420bd041ae77fce2116e6bd98f4ed6945514fad8edfbeeeab0874c84054c80a |
| 0f07c23f7fe5ff918ee596a7f1df320ed6e7783ff91b68c636531aba949a6f33 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| a3cb53ddd4a5316cb02b7dc4ccd1f615755b46e86a88152a1f8fc59efe170497 | Cobalt Strike | e85a2e8995ef37acf15ea79038fae70d4566bd912baac529bad74fbec5bb9c21 |
| a403b82a14b392f8485a22f105c00455b82e7b8a3e7f90f460157811445a8776 | Cobalt Strike | e0c0491e45dda838f4ac01b731dd39cc7064675a6e1b79b184fff99cdce52f54 |
| a5fc8d9f9f4098e2cecb3afc66d8158b032ce81e0be614d216c9deaf20e888ac | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| a9ea85481e178cd35ae323410d619e97f49139dcdb2e7da72126775a89a8464f | Cobalt Strike | c7accad7d8da9797788562a3de228186290b0f52b299944bec04a95863632dc0 |
| ac232e7594ce8fbbe19fc74e34898c562fe9e8f46d4bfddc37aefeb26b85c02b | Cobalt Strike obfuscated shellcode | cef1a88dfc436dab9ae104f0770a434891bbd609e64df43179b42b03a7e8f908 |
| acdaac680e2194dd8fd06f937847440e7ab83ce1760eab028507ee8eba557291 | Cobalt Strike | b96d4400e9335d80dedee6f74ffaa4eca9ffce24c370790482c639df52cb3127 |
| ae148315cec7140be397658210173da372790aa38e67e7aa51597e3e746f2cb2 | Cobalt Strike | f245b2bc118c3c20ed96c8a9fd0a7b659364f9e8e2ee681f5683681e93c4d78b |
| aeecc65ac8f0f6e10e95a898b60b43bf6ba9e2c0f92161956b1725d68482721d | Cobalt Strike | 797abd3de3cb4c7a1ceb5de5a95717d84333bedcbc0d9e9776d34047203181bc |
| b062dd516cfa972993b6109e68a4a023ccc501c9613634468b2a5a508760873e | Cobalt Strike | 122b77fd4d020f99de66bba8346961b565e804a3c29d0757db807321e9910833 |
| b10db109b64b798f36c717b7a050c017cf4380c3cb9cfeb9acd3822a68201b5b | Cobalt Strike | 902d29871d3716113ca2af5caa6745cb4ab9d0614595325c1107fb83c1494483 |
| b1d1a972078d40777d88fb4cd6aef1a04f29c5dd916f30a6949b29f53a2d121c | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| b1f3f1c06b1cc9a249403c2863afc132b2d6a07f137166bdd1e4863a0cece5b1 | Cobalt Strike | e63807daa9be0228d90135ee707ddf03b0035313a88a78e50342807c27658ff2 |
| b4c746e9a49c058ae3843799cdd6a3bb5fe14b413b9769e2b5a1f0f846cb9d37 | Cobalt Strike stager | 063191c49d49e6a8bdcd9d0ee2371fb1b90f1781623827b1e007e520ec925445 |
| b4f37f13a7e9c56ea95fa3792e11404eb3bdb878734f1ca394ceed344d22858f | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| b956c5e8ec6798582a68f24894c1e78b9b767aae4d5fb76b2cc71fc9c8befed8 | Cobalt Strike | 6fc283acfb7dda7bab02f5d23dc90b318f4c73a8e576f90e1cac235bf8d02470 |
| b99ba2449a93ab298d2ec5cacd5099871bacf6a8376e0b080c7240c8055b1395 | Cobalt Strike | 96fab57ef06b433f14743da96a5b874e96d8c977b758abeeb0596f2e1222b182 |
| b9e313e08b49d8d2ffe44cb6ec2192ee3a1c97b57c56f024c17d44db042fb9eb | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| bc238b3b798552958009f3a4ce08e5ce96edff06795281f8b8de6f5df9e4f0fe | Cobalt Strike stager | 191566d8cc119cd6631d353eab0b8c1b8ba267270aa88b5944841905fa740335 |
| bcd64a8468762067d8a890b0aa7916289e68c9d8d8f419b94b78a19f5a74f378 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| c113e8a1c433b4c67ce9bce5dea4b470da95e914de4dc3c3d5a4f98bce2b7d6c | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| c1261f57a0481eb5d37176702903025c5b01a166ea6a6d42e1c1bdc0e5a0b04b | Cobalt Strike obfuscated shellcode | 189b7afdd280d75130e633ebe2fcf8f54f28116a929f5bb5c9320f11afb182d4 |
| c149792a5e5ce4c15f8506041e2f234a9a9254dbda214ec79ceef7d0911a3095 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| c2046d64bcfbab5afcb87a75bf3110e0fa89b3e0f7029ff81a335911cf52f00a | Cobalt Strike | d048001f09ad9eedde44f471702a2a0f453c573db9c8811735ec45d65801f1d0 |
| c3509ba690a1fcb549b95ad4625f094963effc037df37bd96f9d8ed5c7136d94 | Cobalt Strike | e0c0491e45dda838f4ac01b731dd39cc7064675a6e1b79b184fff99cdce52f54 |
| c3cfbede0b561155062c2f44a9d44c79cdb78c05461ca50948892ff9a0678f3f | Cobalt Strike | bcb32a0f782442467ea8c0bf919a28b58690c68209ae3d091be87ef45d4ef049 |
| c79ab271d2abd3ee8c21a8f6ad90226e398df1108b4d42dc551af435a124043c | Cobalt Strike | 749d061acb0e584df337aaef26f3b555d5596a96bfffc9d6cd7421e22c0bacea |
| cab95dc6d08089dcd24c259f35b52bca682635713c058a74533501afb94ab91f | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| cea5c060dd8abd109b478e0de481f0df5ba3f09840746a6a505374d526bd28dc | MythicPacker | 759ac6e54801e7171de39e637b9bb525198057c51c1634b09450b64e8ef47255 |
| cfa604765b9d7a93765d46af78383978251486d9399e21b8e3da4590649c53e4 | Cobalt Strike stager | 57acdb7a22f5f0c6d374be2341dbef97efbcc61f633f324beb0e1214614fef82 |
| d1afca36f67b24eae7f2884c27c812cddc7e02f00f64bb2f62b40b21ef431084 | Cobalt Strike | f570bd331a3d75e065d1825d97b922503c83a52fc54604d601d2e28f4a70902b |
| d1b6671fc0875678ecf39d737866d24aca03747a48f0c7e8855a5b09fc08712d | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| d3d48aa32b062b6e767966a8bab354eded60e0a11be5bc5b7ad8329aa5718c76 | Cobalt Strike | 60905c92501ec55883afc3f6402a05bddfd335323fdc0144515f01e8da0acbda |
| d3eab2a134e7bd3f2e8767a6285b38d19cd3df421e8af336a7852b74f194802c | BlisterMythic | 2fd38f6329b9b2c5e0379a445e81ece43fe0372dec260c1a17eefba6df9ffd55 |
| d439f941b293e3ded35bf52fac7f20f6a2b7f2e4b189ad2ac7f50b8358110491 | Cobalt Strike | 18a9eafb936bf1d527bd4f0bfae623400d63671bafd0aad0f72bfb59beb44d5f |
| dac00ec780aabaffed1e89b3988905a7f6c5c330218b878679546a67d7e0eef2 | Cobalt Strike | adc73af758c136e5799e25b4d3d69e462e090c8204ec8b8f548e36aac0f64a66 |
| db62152fe9185cbd095508a15d9008b349634901d37258bc3939fe3a563b4b3c | MythicPacker | 7f71d316c197e4e0aa1fce9d40c6068ada4249009e5da51479318de039973ad8 |
| db81e91fc05991f71bfd5654cd60b9093c81d247ccd8b3478ab0ebef61efd2ad | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| dd42c1521dbee54173be66a5f98a811e5b6ee54ad1878183c915b03b68b7c9bb | Cobalt Strike | d988a867a53c327099a4c9732a1e4ced6fe6eca5dd68f67e5f562ab822b8374b |
| e0888b80220f200e522e42ec2f15629caa5a11111b8d1babff509d0da2b948f4 | Cobalt Strike | 915503b4e985ab31bc1d284f60003240430b3bdabb398ae112c4bd1fe45f3cdd |
| e30503082d3257737bba788396d7798e27977edf68b9dba7712a605577649ffb | Cobalt Strike | df01b0a8112ca80daf6922405c3f4d1ff7a8ff05233fc0786e9d06e63c9804d6 |
| e521cad48d47d4c67705841b9c8fa265b3b0dba7de1ba674db3a63708ab63201 | Cobalt Strike stager | 40cac28490cddfa613fd58d1ecc8e676d9263a46a0ac6ae43bcbdfedc525b8ee |
| e62f5fc4528e323cb17de1fa161ad55eb451996dec3b31914b00e102a9761a52 | Cobalt Strike | 19e7bb5fa5262987d9903f388c4875ff2a376581e4c28dbf5ae7d128676b7065 |
| ebafb35fd9c7720718446a61a0a1a10d09bf148d26cdcd229c1d3d672835335c | Cobalt Strike | 5cb2683953b20f34ff26ddc0d3442d07b4cd863f29ec3a208cbed0dc760abd04 |
| ebf40e12590fcc955b4df4ec3129cd379a6834013dae9bb18e0ec6f23f935bba | Cobalt Strike | d99bac48e6e347fcfd56bbf723a73b0b6fb5272f92a6931d5f30da76976d1705 |
| ef7ff2d2decd8e16977d819f122635fcd8066fc8f49b27a809b58039583768d2 | Cobalt Strike | adc73af758c136e5799e25b4d3d69e462e090c8204ec8b8f548e36aac0f64a66 |
| efbffc6d81425ffb0d81e6771215c0a0e77d55d7f271ec685b38a1de7cc606a8 | Cobalt Strike | 47bd5fd96c350f5e48f5074ebee98e8b0f4efb8a0cd06db5af2bdc0f3ee6f44f |
| f08fdb0633d018c0245d071fa79cdc3915da75d3c6fc887a5ca6635c425f163a | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| f3bfd8ab9e79645babf0cb0138d51368fd452db584989c4709f613c93caf2bdc | Cobalt Strike | cd7135c94929f55e19e5d66359eab46422c3c59d794dde00c8b4726498e4e01a |
| f58de1733e819ea38bce21b60bb7c867e06edb8d4fd987ab09ecdbf7f6a319b9 | MythicPacker | 19eae7c0b7a1096a71b595befa655803c735006d75d5041c0e18307bd967dee6 |
| f7fa532ad074db4a39fd0a545278ea85319d08d8a69c820b081457c317c0459e | Cobalt Strike | 902d29871d3716113ca2af5caa6745cb4ab9d0614595325c1107fb83c1494483 |
| fce9de0a0acf2ba65e9e252a383d37b2984488b6a97d889ec43ab742160acce1 | Cobalt Strike stager | 40cac28490cddfa613fd58d1ecc8e676d9263a46a0ac6ae43bcbdfedc525b8ee |
| ffb255e7a2aa48b96dd3430a5177d6f7f24121cc0097301f2e91f7e02c37e6bf | Cobalt Strike | 5af6626a6bc7265c21adaffb23cc58bc52c4ebfe5bf816f77711d3bc7661c3d6 |
| 1a50c358fa4b725c6e0e26eee3646de26ba38e951f3fe414f4bf73532af62455 | Cobalt Strike | 8f1cc6ab8e95b9bfdf22a2bde77392e706b6fb7d3c1a3711dbc7ccd420400953 |
| 1be3397c2a85b4b9a5a111b9a4e53d382df47a0a09065639d9e66e0b55fe36fc | Cobalt Strike stager | 3f28a055d56f46559a21a2b0db918194324a135d7e9c44b90af5209a2d2fd549 |
| 1d058302d1e747714cac899d0150dcc35bea54cc6e995915284c3a64a76aacb1 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 02b1bd89e9190ff5edfa998944fd6048d32a3bde3a72d413e8af538d9ad770b4 | Cobalt Strike obfuscated shellcode | 3760db55a6943f4216f14310ab10d404e5c0a53b966dd634b76dd669f59d2507 |
| 2cf125d6f21c657f8c3732be435af56ccbe24d3f6a773b15eccd3632ea509b1a | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 2f2e62c9481ba738a5da7baadfc6d029ef57bf7a627c2ac0b3e615cab5b0cfa2 | Cobalt Strike | 39ed516d8f9d9253e590bad7c5daecce9df21f1341fb7df95d7caa31779ea40f |
| 3bc8ce92409876526ad6f48df44de3bd1e24a756177a07d72368e2d8b223bb39 | Cobalt Strike | 20e43f60a29bab142f050fab8c5671a0709ee4ed90a6279a80dd850e6f071464 |
| 3dffb7f05788d981efb12013d7fadf74fdf8f39fa74f04f72be482847c470a53 | Cobalt Strike | 8e78ad0ef549f38147c6444910395b053c533ac8fac8cdaa00056ad60b2a0848 |
| 3f6e3e7747e0b1815eb2a46d79ebd8e3cb9ccdc7032d52274bc0e60642e9b31e | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 3fff407bc45b879a1770643e09bb99f67cdcfe0e4f7f158a4e6df02299bac27e | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 4b3cd3aa5b961791a443b89e281de1b05bc3a9346036ec0da99b856ae7dc53a8 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 4faf362b3fe403975938e27195959871523689d0bf7fba757ddfa7d00d437fd4 | Cobalt Strike | 60905c92501ec55883afc3f6402a05bddfd335323fdc0144515f01e8da0acbda |
| 5d72cc2e47d3fd781b3fc4e817b2d28911cd6f399d4780a5ff9c06c23069eae1 | MythicPacker | 9a08d2db7d0bd7d4251533551d4def0f5ee52e67dff13a2924191c8258573024 |
| 5ea74bca527f7f6ea8394d9d78e085bed065516eca0151a54474fffe91664198 | Cobalt Strike | be314279f817f9f000a191efb8bcc2962fcc614b1f93c73dda46755269de404f |
| 5fc79a4499bafa3a881778ef51ce29ef015ee58a587e3614702e69da304395db | BlisterMythic | 3d2499e5c9b46f1f144cfbbd4a2c8ca50a3c109496a936550cbb463edf08cd79 |
| 06cd6391b5fcf529168dc851f27bf3626f20e038a9c0193a60b406ad1ece6958 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 6a7ae217394047c17d56ec77b2243d9b55617a1ff591d2c2dfc01f2da335cbbf | MythicPacker | 1e3b373f2438f1cc37e15fdede581bdf2f7fc22068534c89cb4e0c128d0e45dd |
| 6e75a9266e6bbfd194693daf468dd86d106817706c57b1aad95d7720ac1e19e3 | Cobalt Strike | 4adf3875a3d8dd3ac4f8be9c83aaa7e3e35a8d664def68bc41fc539bfedfd33f |
| 7e61498ec5f0780e0e37289c628001e76be88f647cad7a399759b6135be8210a | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 7f7b9f40eea29cfefc7f02aa825a93c3c6f973442da68caf21a3caae92464127 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 8b6eb2853ae9e5faff4afb08377525c9348571e01a0e50261c7557d662b158e1 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 8d53dc0857fa634414f84ad06d18092dedeb110689a08426f08cb1894c2212d4 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 8e6c0d338f201630b5c5ba4f1757e931bc065c49559c514658b4c2090a23e57b | Cobalt Strike | f2329ae2eb28bba301f132e5923282b74aa7a98693f44425789b18a447a33bff |
| 8f9289915b3c6f8bf9a71d0a2d5aeb79ff024c108c2a8152e3e375076f3599d5 | BlisterMythic | f89cfbc1d984d01c57dd1c3e8c92c7debc2beb5a2a43c1df028269a843525a38 |
| 9c5c9d35b7c2c448a610a739ff7b85139ea1ef39ecd9f51412892cd06fde4b1b | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 13c7f28044fdb1db2289036129b58326f294e76e011607ca8d4c5adc2ddddb16 | Cobalt Strike | 19e7bb5fa5262987d9903f388c4875ff2a376581e4c28dbf5ae7d128676b7065 |
| 19b0db9a9a08ee113d667d924992a29cd31c05f89582953eff5a52ad8f533f4b | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 19d4a7d08176119721b9a302c6942718118acb38dc1b52a132d9cead63b11210 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 22e65a613e4520a6f824a69b795c9f36af02247f644e50014320857e32383209 | Cobalt Strike | 18a9eafb936bf1d527bd4f0bfae623400d63671bafd0aad0f72bfb59beb44d5f |
| 028da30664cb9f1baba47fdaf2d12d991dcf80514f5549fa51c38e62016c1710 | Cobalt Strike | 8e78ad0ef549f38147c6444910395b053c533ac8fac8cdaa00056ad60b2a0848 |
| 37b6fce45f6bb52041832eaf9c6d02cbc33a3ef2ca504adb88e19107d2a7aeaa | Cobalt Strike | 902d29871d3716113ca2af5caa6745cb4ab9d0614595325c1107fb83c1494483 |
| 42beac1265e0efc220ed63526f5b475c70621573920968a457e87625d66973af | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 43c1ee0925ecd533e0b108c82b08a3819b371182e93910a0322617a8acf26646 | Cobalt Strike | 5cb2683953b20f34ff26ddc0d3442d07b4cd863f29ec3a208cbed0dc760abd04 |
| 44ce7403ca0c1299d67258161b1b700d3fa13dd68fbb6db7565104bba21e97ae | MythicPacker | f3b0357562e51311648684d381a23fa2c1d0900c32f5c4b03f4ad68f06e2adc1 |
| 49ba10b4264a68605d0b9ea7891b7078aeef4fa0a7b7831f2df6b600aae77776 | Cobalt Strike | 0603cf8f5343723892f08e990ae2de8649fcb4f2fd4ef3a456ef9519b545ed9e |
| 54c7c153423250c8650efc0d610a12df683b2504e1a7a339dfd189eda25c98d4 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 58fdee05cb962a13c5105476e8000c873061874aadbc5998887f0633c880296a | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 73baa040cd6879d1d83c5afab29f61c3734136bffe03c72f520e025385f4e9a2 | Cobalt Strike | 17392d830935cfad96009107e8b034f952fb528f226a9428718669397bafd987 |
| 78d93b13efd0caa66f5d91455028928c3b1f44d0f2222d9701685080e30e317d | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 83c121db96d99f0d99b9e7a2384386f3f6debcb01d977c4ddca5bcdf2c6a2daa | Cobalt Strike stager | 39323f9c0031250414cb4683662e1c533960dea8a54d7a700f77c6133a59c783 |
| 84b245fce9e936f1d0e15d9fca8a1e4df47c983111de66fcc0ad012a63478c8d | Cobalt Strike stager | d961e9db4a96c87226dbc973658a14082324e95a4b30d4aae456a8abe38f5233 |
| 84b2d16124b690d77c5c43c3a0d4ad78aaf10d38f88d9851de45d6073d8fcb65 | Cobalt Strike | 0091186459998ad5b699fdd54d57b1741af73838841c849c47f86601776b0b33 |
| 85d3f81a362a3df9ba2f0a00dd12cd654e55692feffc58782be44f4c531d9bb9 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 96e8b44ec061c49661bd192f279f7b7ba394d03495a2b46d3b37dcae0f4892f1 | Cobalt Strike stager | 6f7d7da247cac20d5978f1257fdd420679d0ce18fd8738bde02246129f93841b |
| 96ebacf48656b804aed9979c2c4b651bbb1bc19878b56bdf76954d6eff8ad7ca | Cobalt Strike | d988a867a53c327099a4c9732a1e4ced6fe6eca5dd68f67e5f562ab822b8374b |
| 113c9e7760da82261d77426d9c41bc108866c45947111dbae5cd3093d69e0f1d | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 149c3d044abc3c3a15ba1bb55db7e05cbf87008bd3d23d7dd4a3e31fcfd7af10 | Cobalt Strike | e63807daa9be0228d90135ee707ddf03b0035313a88a78e50342807c27658ff2 |
| 307fc7ebde82f660950101ea7b57782209545af593d2c1115c89f328de917dbb | Cobalt Strike stager | 40cac28490cddfa613fd58d1ecc8e676d9263a46a0ac6ae43bcbdfedc525b8ee |
| 356efe6b10911d7daaffed64278ba713ab51f7130d1c15f3ca86d17d65849fa5 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 394ce0385276acc6f6c173a3dde6694881130278bfb646be94234cc7798fd9a9 | Cobalt Strike | 60e2fe4eb433d3f6d590e75b2a767755146aca7a9ba6fd387f336ccb3c5391f8 |
| 396dce335b16111089a07ecb2d69827f258420685c2d9f3ea9e1deee4bff9561 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 541eab9e348c40d510db914387068c6bfdf46a6ff84364fe63f6e114af8d79cf | Cobalt Strike stager | 4e2a011922e0060f995bfde375d75060bed00175dc291653445357b29d1afc38 |
| 745a3dcdda16b93fedac8d7eefd1df32a7255665b8e3ee71e1869dd5cd14d61c | Cobalt Strike obfuscated shellcode | cef1a88dfc436dab9ae104f0770a434891bbd609e64df43179b42b03a7e8f908 |
| 753f77134578d4b941b8d832e93314a71594551931270570140805675c6e9ad3 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 863de84a39c9f741d8103db83b076695d0d10a7384e4e3ba319c05a6018d9737 | Cobalt Strike | 3a1e65d7e9c3c23c41cb1b7d1117be4355bebf0531c7473a77f957d99e6ad1d4 |
| 902fa7049e255d5c40081f2aa168ac7b36b56041612150c3a5d2b6df707a3cff | Cobalt Strike | 397c08f5cdc59085a48541c89d23a8880d41552031955c4ba38ff62e57cfd803 |
| 927e04371fa8b8d8a1de58533053c305bb73a8df8765132a932efd579011c375 | Cobalt Strike | 2e0767958435dd4d218ba0bc99041cc9f12c9430a09bb1222ac9d1b7922c2632 |
| 2043d7f2e000502f69977b334e81f307e2fda742bbc5b38745f6c1841757fddc | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 02239cac2ff37e7f822fd4ee57ac909c9f541a93c27709e9728fef2000453afe | Cobalt Strike | 18a9eafb936bf1d527bd4f0bfae623400d63671bafd0aad0f72bfb59beb44d5f |
| 4257bf17d15358c2f22e664b6112437b0c2304332ff0808095f1f47cf29fc1a2 | Cobalt Strike | 3a1e65d7e9c3c23c41cb1b7d1117be4355bebf0531c7473a77f957d99e6ad1d4 |
| 6558ac814046ecf3da8c69affea28ce93524f93488518d847e4f03b9327acb44 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 8450ed10b4bef6f906ff45c66d1a4a74358d3ae857d3647e139fdaf0e3648c10 | BlisterMythic | ab7cab5192f0bef148670338136b0d3affe8ae0845e0590228929aef70cb9b8b |
| 9120f929938cd629471c7714c75d75d30daae1f2e9135239ea5619d77574c1fe | Cobalt Strike | 647e992e24e18c14099b68083e9b04575164ed2b4f5069f33ff55f84ee97fff0 |
| 28561f309d208e885a325c974a90b86741484ba5e466d59f01f660bed1693689 | Cobalt Strike | 397c08f5cdc59085a48541c89d23a8880d41552031955c4ba38ff62e57cfd803 |
| 30628bcb1db7252bf710c1d37f9718ac37a8e2081a2980bead4f21336d2444bc | Cobalt Strike obfuscated shellcode | 13f23b5db4a3d0331c438ca7d516d565a08cac83ae515a51a7ab4e6e76b051b1 |
| 53121c9c5164d8680ae1b88d95018a553dff871d7b4d6e06bd69cbac047fe00f | Cobalt Strike | 902d29871d3716113ca2af5caa6745cb4ab9d0614595325c1107fb83c1494483 |
| 67136ab70c5e604c6817105b62b2ee8f8c5199a647242c0ddbf261064bb3ced3 | Cobalt Strike obfuscated shellcode | 0aecd621b386126459b39518f157ee240866c6db1885780470d30a0ebf298e16 |
| 79982f39ea0c13eeb93734b12f395090db2b65851968652cab5f6b0827b49005 | MythicPacker | 152455f9d970f900eb237e1fc2c29ac4c72616485b04e07c7e733b95b6afc4d8 |
| 87269a95b1c0e724a1bfe87ddcb181eac402591581ee2d9b0f56dedbaac04ff8 | Cobalt Strike | f3d42e4c1a47f0e1d3812d5f912487d04662152c17c7aa63e836bef01a1a4866 |
| 89196b39a0edebdf2026053cb4e87d703b9942487196ff9054ef775fdcad1899 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 91446c6d3c11074e6ff0ff42df825f9ffd5f852c2e6532d4b9d8de340fa32fb8 | Test application | 43308bde79e71b2ed14f318374a80fadf201cc3e34a887716708635294031b1b |
| 96823bb6befe5899739bd69ab00a6b4ae1256fd586159968301a4a69d675a5ec | Cobalt Strike | 3b3bdd819f4ee8daa61f07fc9197b2b39d0434206be757679c993b11acc8d05f |
| 315217b860ab46c6205b36e49dfaa927545b90037373279723c3dec165dfaf11 | Cobalt Strike | 96fab57ef06b433f14743da96a5b874e96d8c977b758abeeb0596f2e1222b182 |
| 427481ab85a0c4e03d1431a417ceab66919c3e704d7e017b355d8d64be2ccf41 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 595153eb56030c0e466cda0becb1dc9560e38601c1e0803c46e7dfc53d1d2892 | Cobalt Strike | f245b2bc118c3c20ed96c8a9fd0a7b659364f9e8e2ee681f5683681e93c4d78b |
| 812263ea9c6c44ef6b4d3950c5a316f765b62404391ddb6482bdc9a23d6cc4a6 | Cobalt Strike | 18a9eafb936bf1d527bd4f0bfae623400d63671bafd0aad0f72bfb59beb44d5f |
| 1358156c01b035f474ed12408a9e6a77fe01af8df70c08995393cbb7d1e1f8a6 | Cobalt Strike | b916749963bb08b15de7c302521fd0ffec1c6660ba616628997475ae944e86a3 |
| 73162738fb3b9cdd3414609d3fe930184cdd3223d9c0d7cb56e4635eb4b2ab67 | Cobalt Strike | 19e7bb5fa5262987d9903f388c4875ff2a376581e4c28dbf5ae7d128676b7065 |
| 343728792ed1e40173f1e9c5f3af894feacd470a9cdc72e4f62c0dc9cbf63fc1 | Putty | 0581160998be30f79bd9a0925a01b0ebc4cb94265dfa7f8da1e2839bf0f1e426 |
| 384408659efa1f87801aa494d912047c26259cd29b08de990058e6b45619d91a | Cobalt Strike stager | 824914bb34ca55a10f902d4ad2ec931980f5607efcb3ea1e86847689e2957210 |
| 49925637250438b05d3aebaac70bb180a0825ec4272fbe74c6fecb5e085bcf10 | Cobalt Strike | e0c0491e45dda838f4ac01b731dd39cc7064675a6e1b79b184fff99cdce52f54 |
Authored by Joshua Kamp (main author) and Alberto Segura.
Hook and ERMAC are Android based malware families that are both advertised by the actor named “DukeEugene”. Hook is the latest variant to be released by this actor and was first announced at the start of 2023. In this announcement, the actor claims that Hook was written from scratch [1]. In our research, we have analysed two samples of Hook and two samples of ERMAC to further examine the technical differences between these malware families.
After our investigation, we concluded that the ERMAC source code was used as a base for Hook. All commands (30 in total) that the malware operator can send to a device infected with ERMAC malware, also exist in Hook. The code implementation for these commands is nearly identical. The main features in ERMAC are related to sending SMS messages, displaying a phishing window on top of a legitimate app, extracting a list of installed applications, SMS messages and accounts, and automated stealing of recovery seed phrases for multiple cryptocurrency wallets.
Hook has introduced a lot of new features, with a total of 38 additional commands when comparing the latest version of Hook to ERMAC. The most interesting new features in Hook are: streaming the victim’s screen and interacting with the interface to gain complete control over an infected device, the ability to take a photo of the victim using their front facing camera, stealing of cookies related to Google login sessions, and the added support for stealing recovery seeds from additional cryptocurrency wallets.
Hook had a relatively short run. It was first announced on the 12th of January 2023, and the closing of the project was announced on April 19th, 2023, due to “leaving for special military operation”. On May 11th, 2023, the actors claimed that the source code of Hook was sold at a price of $70.000. If these announcements are true, it could mean that we will see interesting new versions of Hook in the future.
On the 12th of January 2023, DukeEugene started advertising a new Android botnet to be available for rent: Hook.
Hook malware is designed to steal personal information from its infected users. It contains features such as keylogging, injections/overlay attacks to display phishing windows over (banking) apps (more on this in the “Overlay attacks” section of this blog), and automated stealing of cryptocurrency recovery seeds.
Financial gain seems to be the main motivator for operators that rent Hook, but the malware can be used to spy on its victims as well. Hook is rented out at a cost of $7.000 per month.
The malware was advertised with a wide range of functionality in both the control panel and build itself, and a snippet of this can be seen in the screenshot below.
Analyst’s note: The package names and file hashes that were analysed for this research can be found in the “Analysed samples” section at the end of this blog post.
While checking out the differences in these malware families, we compared the C2 commands (instructions that are sent by the malware operator to the infected device) in each sample. This analysis did lead us to find several new commands and features on Hook, as can be seen just looking at the number of commands implemented in each variant.
| Sample | Number of commands |
| Hook sample #1 | 58 |
| Hook sample #2 | 68 |
| Ermac sample #1 & #2 | 30 |
All 30 commands that exist in ERMAC also exist in Hook. Most of these commands are related to sending SMS messages, updating and starting injections, extracting a list of installed applications, SMS messages and accounts, and starting another app on the victim’s device (where cryptocurrency wallet apps are the main target). While simply launching another app may not seem that malicious at first, you will think differently after learning about the automated features in these malware families.
Both Hook and ERMAC contain automated functionality for stealing recovery seeds from cryptocurrency wallets. These can be used to gain access to the victim’s cryptocurrency. We will dive deeper into this feature later in the blog.
When comparing Hook to ERMAC, 29 new commands have been added to the first sample of Hook that we analysed, and the latest version of Hook contains 9 additional commands on top of that. Most of the commands that were added in Hook are related to interacting with the user interface (UI).
The UI interaction related commands (such as “clickat” to click on a specific UI element and “longpress” to dispatch a long press gesture) in Hook go hand in hand with the new “start_vnc” command, which starts streaming the victim’s screen.
In the code snippet above we can see that the createScreenCaptureIntent() method is called on the MediaProjectionManager, which is necessary to start screen capture on the device. Along with the many commands to interact with the UI, this allows the malware operator to gain complete control over an infected device and perform actions on the victim’s behalf.
For the commands that are available in both ERMAC and Hook, the code implementation is nearly identical. Take the “logaccounts” command for example:
This command is used to obtain a list of available accounts by their name and type on the victim’s device. When comparing the code, it’s clear that the logging messages are the main difference. This is the case for all commands that are present in both ERMAC and Hook.
Both ERMAC and the Hook v1 sample that we analysed contain some rather edgy commands in Russian, that do not provide any useful functionality.
The command above translates to “Die_he_who_reversed_this“.
All the Russian commands create a file named “system.apk” in the “apk” directory and immediately deletes it. It appears that the authors have recently adapted their approach to managing a reputable business, as these commands were removed in the latest Hook sample that we analysed.
In the latest versions of Hook, the authors have added 9 additional commands compared to the first Hook sample that we analysed. These commands are:
| Command | Description |
| send_sms_many | Sends an SMS message to multiple phone numbers |
| addwaitview | Displays a “wait / loading” view with a progress bar, custom background colour, text colour, and text to be displayed |
| removewaitview | Removes the “wait / loading” view that is displayed on the victim’s device because of the “addwaitview” command |
| addview | Adds a new view with a black background that covers the entire screen |
| removeview | Removes the view with the black background that was added by the “addview” command |
| cookie | Steals session cookies (targets victim’s Google account) |
| safepal | Starts the Safepal Wallet application (and steals seed phrases as a result of starting this application, as observed during analysis of the accessibility service) |
| exodus | Starts the Exodus Wallet application (and steals seed phrases as a result of starting this application, as observed during analysis of the accessibility service) |
| takephoto | Takes a photo of the victim using the front facing camera |
One of the already existing commands, “onkeyevent”, also received a new payload option: “double_tap”. As the name suggests, this performs a double tap gesture on the victim’s screen, providing the malware operator with extra functionality to interact with the victim’s device user interface.
More interesting additions are: the support for stealing recovery seed phrases from other crypto wallets (Safepal and Exodus), taking a photo of the victim, and stealing session cookies. Session cookie stealing appears to be a popular trend in Android malware, as we have observed this feature being added to multiple malware families. This is an attractive feature, as it allows the actor to gain access to user accounts without needing the actual login credentials.
Besides adding new commands, the authors have added more functionality related to the “Device Administration API” in the latest version of Hook. This API was developed to support enterprise apps in Android. When an app has device admin privileges, it gains additional capabilities meant for managing the device. This includes the ability to enforce password policies, locking the screen and even wiping the device remotely. As you may expect: abuse of these privileges is often seen in Android malware.
To implement custom device admin functionality in a new class, it should extend the “DeviceAdminReceiver”. This class can be found by examining the app’s Manifest file and searching for the receiver with the “BIND_DEVICE_ADMIN” permission or the “DEVICE_ADMIN_ENABLED” action.
In the screenshot above, you can see an XML file declared as follows: android:resource=”@xml/buyanigetili. This file will contain the device admin policies that can be used by the app. Here’s a comparison of the device admin policies in ERMAC, Hook 1, and Hook 2:
Comparing Hook to ERMAC, the authors have removed the “WIPE_DATA” policy and added the “RESET_PASSWORD” policy in the first version of Hook. In the latest version of Hook, the “DISABLE_KEYGUARD_FEATURES” and “WATCH_LOGIN” policies were added. Below you’ll find a description of each policy that is seen in the screenshot.
| Device Admin Policy | Description |
| USES_POLICY_FORCE_LOCK | The app can lock the device |
| USES_POLICY_WIPE_DATA | The app can factory reset the device |
| USES_POLICY_RESET_PASSWORD | The app can reset the device’s password/pin code |
| USES_POLICY_DISABLE_KEYGUARD_FEATURES | The app can disable use of keyguard (lock screen) features, such as the fingerprint scanner |
| USES_POLICY_WATCH_LOGIN | The app can watch login attempts from the user |
The “DeviceAdminReceiver” class in Android contains methods that can be overridden. This is done to customise the behaviour of a device admin receiver. For example: the “onPasswordFailed” method in the DeviceAdminReceiver is called when an incorrect password is entered on the device. This method can be overridden to perform specific actions when a failed login attempt occurs. In ERMAC and Hook 1, the class that extends the DeviceAdminReceiver only overrides the onReceive() method and the implementation is minimal:

The onReceive() method is the entry point for broadcasts that are intercepted by the device admin receiver. In ERMAC and Hook 1 this only performs a check to see whether the received parameters are null and will throw an exception if they are.
In the latest edition of Hook, the class to extend the DeviceAdminReceiver does not just override the “onReceive” method. It also overrides the following methods:
| Device Admin Method | Description |
| onDisableRequested() | Called when the user attempts to disable device admin. Gives the developer a chance to present a warning message to the user |
| onDisabled() | Called prior to device admin being disabled. Upon return, the app can no longer use the protected parts of the DevicePolicyManager API |
| onEnabled() | Called after device admin is first enabled. At this point, the app can use “DevicePolicyManager” to set the desired policies |
| onPasswordFailed() | Called when the user has entered an incorrect password for the device |
| onPasswordSucceeded() | Called after the user has entered a correct password for the device |
When the victim attempts to disable device admin, a warning message is displayed that contains the text “Your mobile is die”.

The fingerprint scanner will be disabled when an incorrect password was entered on the victim’s device. Possibly to make it easier to break into the device later, by forcing the victim to enter their PIN and capturing it.

All keyguard (lock screen) features are enabled again when a correct password was entered on the victim’s device.

Overlay attacks, also known as injections, are a popular tactic to steal credentials on Android devices. When an app has permission to draw overlays, it can display content on top of other apps that are running on the device. This is interesting for threat actors, because it allows them to display a phishing window over a legitimate app. When the victim enters their credentials in this window, the malware will capture them.
Both ERMAC and Hook use web injections to display a phishing window as soon as it detects a targeted app being launched on the victim’s device.
In the screenshot above, you can see how ERMAC and Hook set up a WebView component and load the HTML code to be displayed over the target app by calling webView5.loadDataWithBaseURL(null, s6, “text/html”, “UTF-8”, null) and this.setContentView() on the WebView object. The “s6” variable will contain the data to be loaded. The main functionality is the same for both variants, with Hook having some additional logging messages.
Accessibility Service abuse plays an important role when it comes to web injections and other automated feature in ERMAC and Hook. Accessibility services are used to assist users with disabilities, or users who may temporarily be unable to fully interact with their Android device. For example: users that are driving might need additional or alternative interface feedback. Accessibility services run in the background and receive callbacks from the system when AccessibilityEvent is fired. Apps with accessibility service can have full visibility over UI events, both from the system and from 3rd party apps. They can receive notifications, they can get the package name, list UI elements, extract text, and more. While these services are meant to assist users, they can also be abused by malicious apps for activities such as: keylogging, automatically granting itself additional permissions, and monitoring foreground apps and overlaying them with phishing windows.
When ERMAC or Hook malware is first launched, it prompts the victim with a window that instructs them to enable accessibility services for the malicious app.

A warning message is displayed before enabling the accessibility service, which shows what actions the app will be able to perform when this is enabled.
With accessibility services enabled, ERMAC and Hook malware automatically grants itself additional permissions such as permission to draw overlays. The onAccessibilityEvent() method monitors the package names from received accessibility events, and the web injection related code will be executed when a target app is launched.
When the infected device is ready to communicate with the C2 server, it sends a list of applications that are currently installed on the device. The C2 server then responds with the target apps that it has injections for. While dynamically analysing the latest version of Hook, we sent a custom HTTP request to the C2 server to make it believe that we have a large amount of apps (700+) installed. For this, we used the list of package names that CSIRT KNF had shared in an analysis report of Hook [2].

The server responded with the list of target apps that the malware can display phishing windows for. Most of the targeted apps in both Hook and ERMAC are related to banking.
Keylogging functionality can be found in the onAccessibilityEvent() method of both ERMAC and Hook. For every accessibility event type that is triggered on the infected device, a method is called that contains keylogger functionality. This method then checks what the accessibility event type was to label the log and extracts the text from it. Comparing the code implementation of keylogging in ERMAC to Hook, there are some slight differences in the accessibility event types that it checks for. But the main functionality of extracting text and sending it to the C2 with a certain label is the same.
The ERMAC keylogger contains an extra check for accessibility event “TYPE_VIEW_SELECTED” (triggered when a user selects a view, such as tapping on a button). Accessibility services can extract information about a selected view, such as the text, and that is exactly what is happening here.
Hook specifically checks for two other accessibility events: the “TYPE_WINDOW_STATE_CHANGED” event (triggered when the state of an active window changes, for example when a new window is opened) or the “TYPE_WINDOW_CONTENT_CHANGED” event (triggered when the content within a window changes, like when the text within a window is updated).
It checks for these events in combination with the content change type
“CONTENT_CHANGE_TYPE_TEXT” (indicating that the text of an UI element has changed). This tells us that the accessibility service is interested in changes of the textual content within a window, which is not surprising for a keylogger.
Automatic stealing of recovery seeds from crypto wallets is one of the main features in ERMAC and Hook. This feature is actively developed, with support added for extra crypto wallets in the latest version of Hook.
For this feature, the accessibility service first checks if a crypto wallet app has been opened. Then, it will find UI elements by their ID (such as “com.wallet.crypto.trustapp:id/wallets_preference” and “com.wallet.crypto.trustapp:id/item_wallet_info_action”) and automatically clicks on these elements until it navigated to the view that contains the recovery seed phrase. For the crypto wallet app, it will look like the user is browsing to this phrase by themselves.

Once the window with the recovery seed phrase is reached, it will extract the words from the recovery seed phrase and send them to the C2 server.
The main implementation is the same in ERMAC and Hook for this feature, with Hook containing some extra logging messages and support for stealing seed phrases from additional cryptocurrency wallets.
Besides being able to automatically steal recovery seeds from opened crypto wallet apps, ERMAC and Hook can also detect whether a wallet address has been copied and replaces the clipboard with their own wallet address. It does this by monitoring for the “TYPE_VIEW_TEXT_CHANGED” event, and checking whether the text matches a regular expression for Bitcoin and Ethereum wallet addresses. If it matches, it will replace the clipboard text with the wallet address of the threat actor.
The wallet addresses that the actors use in both ERMAC and Hook are bc1ql34xd8ynty3myfkwaf8jqeth0p4fxkxg673vlf for Bitcoin and 0x3Cf7d4A8D30035Af83058371f0C6D4369B5024Ca for Ethereum. It’s worth mentioning that these wallet addresses are the same in all samples that we analysed. It appears that this feature has not been very successful for the actors, as they have received only two transactions at the time of writing.
Since the feature has been so unsuccessful, we assume that both received transactions were initiated by the actors themselves. The latest transaction was received from a verified Binance exchange wallet, and it’s unlikely that this comes from an infected device. The other transaction comes from a wallet that could be owned by the Hook actors.
The “cookie” command is exclusive to Hook and was only added in the latest version of this malware. This feature allows the malware operator to steal session cookies in order to take over the victim’s login session. To do so, a new WebViewClient is set up. When the victim has logged onto their account, the onPageFinished() method of the WebView will be called and it sends the stolen cookies to the C2 server.
All cookie stealing code is related to Google accounts. This is in line with DukeEugene’s announcement of new features that were posted about on April 1st, 2023. See #12 in the screenshot below.
ERMAC is known to use the HTTP protocol for communicating with the C2 server, where data is encrypted using AES-256-CBC and then Base64 encoded. The bot sends HTTP POST requests to a randomly generated URL that ends with “.php/” (note that the IP of the C2 server remains the same).
The first editions of Hook introduced WebSocket communication using Socket.IO, and data is encrypted using the same mechanism as in ERMAC. The Socket.IO library is built on top of the WebSocket protocol and offers low-latency, bidirectional and event-based communication between a client and a server. Socket.IO provides additional guarantees such as fallback to the HTTP protocol and automatic reconnection [3].
The screenshot above shows that the login command was issued to the server, with the user ID of the infected device being sent as encrypted data. The “42” at the beginning of the message is standard in Socket.IO, where the “4” stands for the Engine.IO “message” packet type and the “2” for Socket.IO’s “message” packet type [3].
The latest Hook version that we’ve analysed contains the ERMAC HTTP protocol implementation, as well as the WebSocket implementation which already existed in previous editions of Hook. The Hook code snippet below shows that it uses the exact same code implementation as observed in ERMAC to build the URLs for HTTP requests.

Both Hook and ERMAC use the “checkAP” command to check for commands sent by the C2 server. In the screenshot below, you can see that the malware operator sent the “killme” command to the infected device to uninstall Hook. This shows that the ERMAC HTTP protocol is actively used in the latest versions of Hook, together with the already existing WebSocket implementation.
During our investigation into the technical differences between Hook and ERMAC, we have also collected C2 servers related to both families. From these servers, Russia is clearly the preferred country for hosting Hook and ERMAC C2s. We have identified a total of 23 Hook C2 servers that are hosted in Russia.
Other countries that we have found ERMAC and Hook are hosted in are:
On the 19th of April 2023, DukeEugene announced that they are closing the Hook project due to leaving for “special military operation”. The actor mentions that the coder of the Hook project, who goes by the nickname “RedDragon”, will continue to support their clients until their lease runs out.

Two days prior to this announcement, the coder of Hook created a post stating that the source code of Hook is for sale at a price of $70.000. Nearly a month later, on May 11th, the coder asked if the thread could be closed as the source code was sold.
In the “Replacing copied crypto wallet addresses” section of this blog, we mentioned that the first received transaction comes from an Ethereum wallet address that could possibly be owned by the Hook actors. We noticed that this wallet received a transaction of roughly $25.000 the day after Hook was announced sold. This could be a coincidence, but the fact that this wallet was also the first to send (a small amount of) money to the Ethereum address that is hardcoded in Hook and ERMAC makes us suspect this.
We can’t verify whether the messages from DukeEugene and RedDragon are true. But if they are, we expect to see interesting new forks of Hook in the future.
In this blog we’ve debunked DukeEugene’s statement of Hook being fully developed from scratch. Additionally, in DukeEugene’s advertisement of HookBot we see a screenshot of the Hook panel that seemed to show similarities with ERMAC’s panel.
While the actors of Hook had announced that the malware was written from scratch, it is clear that the ERMAC source code was used as a base. All commands that are present in ERMAC also exist in Hook, and the code implementation of these commands is nearly identical in both malware families. Both Hook and ERMAC contain typical features to steal credentials which are common in Android malware, such as overlay attacks/injections and keylogging. Perhaps a more interesting feature that exists in both malware families is the automated stealing of recovery seeds from cryptocurrency wallets.
While Hook was not written completely from scratch, the authors have added interesting new features compared to ERMAC. With the added capability of being able to stream the victim’s screen and interacting with the UI, operators of Hook can gain complete control over infected devices and perform actions on the user’s behalf. Other interesting new features include the ability to take a photo of the victim using their front facing camera, stealing of cookies related to Google login sessions, and the added support for stealing recovery seeds from additional cryptocurrency wallets.
Besides these new features, significant changes were made in the protocol for communicating with the C2 server. The first versions of Hook introduced WebSocket communication using the Socket.IO library. The latest version of Hook added the HTTP protocol implementation that was already present in ERMAC and can use this next to WebSocket communication.
Hook had a relatively short run. It was first announced on the 12th of January 2023, and the closing of the project was announced on April 19th, 2023, with the actor claiming that he is leaving for “special military operation”. The coder of Hook has allegedly put the source code up for sale at a price of $70,000 and stated that it was sold on May 11th, 2023. If these announcements are true, it could mean that we will see interesting new forks of Hook in the future.
Analysed samples
| Family | Package name | File hash (SHA-256) |
| Hook | com.lojibiwawajinu.guna | c5996e7a701f1154b48f962d01d457f9b7e95d9c3dd9bbd6a8e083865d563622 |
| Hook | com.wawocizurovi.gadomi | d651219c28eec876f8961dcd0a0e365df110f09b7ae72eccb9de8c84129e23cb |
| ERMAC | com.cazojowiruje.tutado | e0bd84272ea93ea857cc74a745727085cf214eef0b5dcaf3a220d982c89cea84 |
| ERMAC | com.jakedegivuwuwe.yewo | 6d8707da5cb71e23982bd29ac6a9f6069d6620f3bc7d1fd50b06e9897bc0ac50 |
C2 servers
| Family | IP address |
| Hook | 5.42.199[.]22 |
| Hook | 45.81.39[.]149 |
| Hook | 45.93.201[.]92 |
| Hook | 176.100.42[.]11 |
| Hook | 91.215.85[.]223 |
| Hook | 91.215.85[.]37 |
| Hook | 91.215.85[.]23 |
| Hook | 185.186.246[.]69 |
| ERMAC | 5.42.199[.]91 |
| ERMAC | 31.41.244[.]187 |
| ERMAC | 45.93.201[.]92 |
| ERMAC | 92.243.88[.]25 |
| ERMAC | 176.113.115[.]66 |
| ERMAC | 165.232.78[.]246 |
| ERMAC | 51.15.150[.]5 |
| ERMAC | 176.100.42[.]11 |
| ERMAC | 91.215.85[.]22 |
| ERMAC | 35.91.53[.]224 |
| ERMAC | 193.106.191[.]148 |
| ERMAC | 20.249.63[.]72 |
| ERMAC | 62.204.41[.]98 |
| ERMAC | 193.106.191[.]121 |
| ERMAC | 193.106.191[.]116 |
| ERMAC | 176.113.115[.]150 |
| ERMAC | 91.213.50[.]62 |
| ERMAC | 193.106.191[.]118 |
| ERMAC | 5.42.199[.]3 |
| ERMAC | 193.56.146[.]176 |
| ERMAC | 62.204.41[.]94 |
| ERMAC | 176.113.115[.]67 |
| ERMAC | 108.61.166[.]245 |
| ERMAC | 45.159.248[.]25 |
| ERMAC | 20.108.0[.]165 |
| ERMAC | 20.210.252[.]118 |
| ERMAC | 68.178.206[.]43 |
| ERMAC | 35.90.154[.]240 |
The following Suricata rules were tested successfully against Hook network traffic:
| # Detection for Hook/ERMAC mobile malware | |
| alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"FOX-SRT – Mobile Malware – Possible Hook/ERMAC HTTP POST"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/php/"; depth:5; content:".php/"; isdataat:!1,relative; fast_pattern; pcre:"/^\/php\/[a-z0-9]{1,21}\.php\/$/U"; classtype:trojan-activity; priority:1; threshold:type limit,track by_src,count 1,seconds 3600; metadata:ids suricata; metadata:created_at 2023-06-02; metadata:updated_at 2023-06-07; sid:21004440; rev:2;) | |
| alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"FOX-SRT – Mobile Malware – Possible Hook Websocket Packet Observed (login)"; content:"|81|"; depth:1; byte_test:1,&,0x80,1; luajit:hook.lua; classtype:trojan-activity; priority:1; threshold:type limit,track by_src,count 1,seconds 3600; metadata:ids suricata; metadata:created_at 2023-06-02; metadata:updated_at 2023-06-07; sid:21004441; rev:2;) |
The second Suricata rule uses an additional Lua script, which can be found here
| Family | Command | Description |
| ERMAC, Hook 1 & 2 | sendsms | Sends a specified SMS message to a specified number. If the SMS message is too large, it will send the message in multiple parts |
| ERMAC, Hook 1 & 2 | startussd | Executes a given USSD code on the victim’s device |
| ERMAC, Hook 1 & 2 | forwardcall | Sets up a call forwarder to forward all calls to the specified number in the payload |
| ERMAC, Hook 1 & 2 | push | Displays a push notification on the victim’s device, with a custom app name, title, and text to be edited by the malware operator |
| ERMAC, Hook 1 & 2 | getcontacts | Gets list of all contacts on the victim’s device |
| ERMAC, Hook 1 & 2 | getaccounts | Gets a list of the accounts on the victim’s device by their name and account type |
| ERMAC, Hook 1 & 2 | logaccounts | Gets a list of the accounts on the victim’s device by their name and account type |
| ERMAC, Hook 1 & 2 | getinstallapps | Gets a list of the installed apps on the victim’s device |
| ERMAC, Hook 1 & 2 | getsms | Steals all SMS messages from the victim’s device |
| ERMAC, Hook 1 & 2 | startinject | Performs a phishing overlay attack against the given application |
| ERMAC, Hook 1 & 2 | openurl | Opens the specified URL |
| ERMAC, Hook 1 & 2 | startauthenticator2 | Starts the Google Authenticator app |
| ERMAC, Hook 1 & 2 | trust | Launches the Trust Wallet app |
| ERMAC, Hook 1 & 2 | mycelium | Launches the Mycelium Wallet app |
| ERMAC, Hook 1 & 2 | piuk | Launches the Blockchain Wallet app |
| ERMAC, Hook 1 & 2 | samourai | Launches the Samourai Wallet app |
| ERMAC, Hook 1 & 2 | bitcoincom | Launches the Bitcoin Wallet app |
| ERMAC, Hook 1 & 2 | toshi | Launches the Coinbase Wallet app |
| ERMAC, Hook 1 & 2 | metamask | Launches the Metamask Wallet app |
| ERMAC, Hook 1 & 2 | sendsmsall | Sends a specified SMS message to all contacts on the victim’s device. If the SMS message is too large, it will send the message in multiple parts |
| ERMAC, Hook 1 & 2 | startapp | Starts the app specified in the payload |
| ERMAC, Hook 1 & 2 | clearcash | Sets the “autoClickCache” shared preference key to value 1, and launches the “Application Details” setting for the specified app (probably to clear the cache) |
| ERMAC, Hook 1 & 2 | clearcache | Sets the “autoClickCache” shared preference key to value 1, and launches the “Application Details” setting for the specified app (probably to clear the cache) |
| ERMAC, Hook 1 & 2 | calling | Calls the number specified in the “number” payload, tries to lock the device and attempts to hide and mute the application |
| ERMAC, Hook 1 & 2 | deleteapplication | Uninstalls a specified application |
| ERMAC, Hook 1 & 2 | startadmin | Sets the “start_admin” shared preference key to value 1, which is probably used as a check before attempting to gain Device Admin privileges (as seen in Hook samples) |
| ERMAC, Hook 1 & 2 | killme | Stores the package name of the malicious app in the “killApplication” shared preference key, in order to uninstall it. This is the kill switch for the malware |
| ERMAC, Hook 1 & 2 | updateinjectandlistapps | Gets a list of the currently installed apps on the victim’s device, and downloads the injection target lists |
| ERMAC, Hook 1 & 2 | gmailtitles | Sets the “gm_list” shared preference key to the value “start” and starts the Gmail app |
| ERMAC, Hook 1 & 2 | getgmailmessage | Sets the “gm_mes_command” shared preference key to the value “start” and starts the Gmail app |
| Hook 1 & 2 | start_vnc | Starts capturing the victim’s screen constantly (streaming) |
| Hook 1 & 2 | stop_vnc | Stops capturing the victim’s screen constantly (streaming) |
| Hook 1 & 2 | takescreenshot | Takes a screenshot of the victim’s device (note that it starts the same activity as for the “start_vnc” command, but it does so without the extra “streamScreen” set to true to only take one screenshot) |
| Hook 1 & 2 | swipe | Performs a swipe gesture with the specified 4 coordinates |
| Hook 1 & 2 | swipeup | Perform a swipe up gesture |
| Hook 1 & 2 | swipedown | Performs a swipe down gesture |
| Hook 1 & 2 | swipeleft | Performs a swipe left gesture |
| Hook 1 & 2 | swiperight | Performs a swipe right gesture |
| Hook 1 & 2 | scrollup | Performs a scroll up gesture |
| Hook 1 & 2 | scrolldown | Performs a scroll down gesture |
| Hook 1 & 2 | onkeyevent | Performs a certain action depending on the specified key payload (POWER DIALOG, BACK, HOME, LOCK SCREEN, or RECENTS |
| Hook 1 & 2 | onpointerevent | Sets X and Y coordinates and performs an action based on the payload text provided. Three options: “down”, “continue”, and “up”. It looks like these payload texts work together, as in: it first sets the starting coordinates where it should press down, then it sets the coordinates where it should draw a line to from the previous starting coordinates, then it performs a stroke gesture using this information |
| Hook 1 & 2 | longpress | Dispatches a long press gesture at the specified coordinates |
| Hook 1 & 2 | tap | Dispatches a tap gesture at the specified coordinates |
| Hook 1 & 2 | clickat | Clicks at a specific UI element |
| Hook 1 & 2 | clickattext | Clicks on the UI element with a specific text value |
| Hook 1 & 2 | clickatcontaintext | Clicks on the UI element that contains the payload text |
| Hook 1 & 2 | cuttext | Replaces the clipboard on the victim’s device with the payload text |
| Hook 1 & 2 | settext | Sets a specified UI element to the specified text |
| Hook 1 & 2 | openapp | Opens the specified app |
| Hook 1 & 2 | openwhatsapp | Sends a message through Whatsapp to the specified number |
| Hook 1 & 2 | addcontact | Adds a new contact to the victim’s device |
| Hook 1 & 2 | getcallhistory | Gets a log of the calls that the victim made |
| Hook 1 & 2 | makecall | Calls the number specified in the payload |
| Hook 1 & 2 | forwardsms | Sets up an SMS forwarder to forward the received and sent SMS messages from the victim device to the specified number in the payload |
| Hook 1 & 2 | getlocation | Gets the geographic coordinates (latitude and longitude) of the victim |
| Hook 1 & 2 | getimages | Gets list of all images on the victim’s device |
| Hook 1 & 2 | downloadimage | Downloads an image from the victim’s device |
| Hook 1 & 2 | fmmanager | Either lists the files at a specified path (additional parameter “ls”), or downloads a file from the specified path (additional parameter “dl”) |
| Hook 2 | send_sms_many | Sends an SMS message to multiple phone numbers |
| Hook 2 | addwaitview | Displays a “wait / loading” view with a progress bar, custom background colour, text colour, and text to be displayed |
| Hook 2 | removewaitview | Removes a “RelativeLayout” view group, which displays child views together in relative positions. More specifically: this command removes the “wait / loading” view that is displayed on the victim’s device as a result of the “addwaitview” command |
| Hook 2 | addview | Adds a new view with a black background that covers the entire screen |
| Hook 2 | removeview | Removes a “LinearLayout” view group, which arranges other views either horizontally in a single column or vertically in a single row. More specifically: this command removes the view with the black background that was added by the “addview” command |
| Hook 2 | cookie | Steals session cookies (targets victim’s Google account) |
| Hook 2 | safepal | Starts the Safepal Wallet application (and steals seed phrases as a result of starting this application, as observed during analysis of the accessibility service) |
| Hook 2 | exodus | Starts the Exodus Wallet application (and steals seed phrases as a result of starting this application, as observed during analysis of the accessibility service) |
| Hook 2 | takephoto | Takes a photo of the victim using the front facing camera |
[1] – https://www.threatfabric.com/blogs/hook-a-new-ermac-fork-with-rat-capabilities
[2] – https://cebrf.knf.gov.pl/komunikaty/artykuly-csirt-knf/362-ostrzezenia/858-hookbot-a-new-mobile-malware
[3] – https://socket.io/docs/v4/
ClearSky Cyber Security has detected a watering hole attack on at least eight Israeli websites. The attack is highly likely to be orchestrated by a nation-state actor from Iran, with a low confidence specific attribution to Tortoiseshell (also called TA456 or Imperial Kitten).
The Infected sites collect preliminary user information through a script. We have discovered several details that suggest this script is used for malicious purposes.
Read the Full report: Fata Morgana Watering hole report