BinaryAlert

BinaryAlert Logo

BinaryAlert is a serverless, real-time framework for detecting malicious files. BinaryAlert can efficiently analyze millions of files a day with a configurable set of YARA rules and will trigger an alert as soon as anything malicious is discovered! Organizations can deploy BinaryAlert to their AWS account in a matter of minutes, allowing them to analyze internal files and documents within the confines of their own environment.

Features

  • Built with Amazon Web Services (AWS): An AWS account is all you need to deploy BinaryAlert.
  • Broad YARA support: BinaryAlert includes dozens of YARA rules out-of-the-box and makes it easy to add your own rules or clone them from other repositories.
  • Real-Time: Files uploaded to BinaryAlert (S3 bucket) are immediately queued for analysis.
  • Serverless: All computation is handled by Lambda functions. No servers to manage means stronger security and automatic scaling!
  • Infrastructure-As-Code: The entire infrastructure is described with Terraform configuration files, enabling anyone to deploy BinaryAlert in a matter of minutes with a single command.
  • Retroactive Analysis: After updating the YARA ruleset, BinaryAlert can retroactively scan the entire file corpus to find any new matches.
  • Production-Ready: BinaryAlert ships with a custom metric dashboard and alarms which automatically trigger on error conditions.
  • Low Cost: The AWS bill is based only on how many files you upload and how often they are re-analyzed.

Resources

Table of Contents

Getting Started

All you need is an AWS account to get BinaryAlert up and running in just a few minutes!

Install Dependencies

BinaryAlert can be deployed from any MacOS/Linux environment (and likely Windows as well, though we haven’t tried).

  1. Install Python 3.6:
# MacOS Homebrew
brew install python3
python3 --version

# Ubuntu16 - Python 3.6 is only available in third-party repositories
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6 python3.6-dev python3-pip
sudo -H pip3 install --upgrade pip
python3.6 --version

Warning

Python 3.5 or 3.7 is installed by default on some systems, but AWS Lambda requires Python 3.6.

  1. Install Terraform v0.11.X:
$ brew install terraform  # MacOS Homebrew
$ terraform --version  # Must be v0.11.X

3. Install the OpenSSL development library if it isn’t already (OS X should have it). This is required for YARA’s hash module and must be installed before installing the BinaryAlert requirements.

$ sudo apt-get install libssl-dev  # Ubuntu
$ sudo yum install openssl-devel   # Amazon Linux

Download BinaryAlert

  1. Clone the latest official release of BinaryAlert:
$ git clone --branch v1.2.0 https://github.com/airbnb/binaryalert
  1. Create and activate a virtual environment:
$ cd binaryalert
$ python3.6 -m venv venv
$ source venv/bin/activate
  1. Install the BinaryAlert requirements:
$ pip3 install -r requirements.txt

Note

If there is an error finding openssl.h, try export CFLAGS='-I/usr/local/opt/openssl/include' before the install.

  1. Run unit tests to make sure everything is installed correctly:
$ ./manage.py unit_test

Set AWS Credentials

  1. Create an AWS account and an IAM user with permissions for at least the following services:
  • CloudWatch
  • DynamoDB
  • IAM
  • KMS
  • Lambda
  • S3
  • SNS
  • SQS

Note

See Creating an IAM group for a least-privilege policy that allows users to deploy BinaryAlert.

2. Set your AWS credentials using any method supported by Terraform. For example, using the AWS CLI:

$ pip3 install awscli
$ aws configure

Deploy!

  1. Configure BinaryAlert settings:
$ ./manage.py configure
AWS Region (us-east-1):
Unique name prefix, e.g. "company_team": your_unique_prefix
Enable the CarbonBlack downloader? (no):
  1. Deploy!
$ ./manage.py deploy
# Terraform will generate a plan and request approval before applying
  1. BinaryAlert is live! Test it by uploading a harmless EICAR test string:
$ ./manage.py live_test

Note

You must add an SNS subscription in order to receive YARA match alerts.

Creating an IAM Group

When thinking about who on your team will be deploying BinaryAlert, we recommend creating an IAM group with least-privilege permissions and adding users to that group.

The following is an example Terraform file that can be applied by an account admin outside of the BinaryAlert repo to create a least-privilege group. This group will have permission to create, modify, and destroy all of the BinaryAlert infrastructure:

# ========== Variables ==========

variable "account" {
  default = "123412341234"  # Replace with your account ID
}

variable "region" {
  default = "us-east-1"  # Region in which BinaryAlert will be deployed
}

variable "prefix" {
  default = "binaryalert-prefix"  # The name prefix you will use when deploying BinaryAlert
}

# ========== IAM policy ==========

data "aws_iam_policy_document" "binaryalert_admin" {
  statement {
    effect = "Allow"

    actions = [
      "cloudwatch:DeleteAlarms",
      "cloudwatch:DeleteDashboards",
      "cloudwatch:DescribeAlarms",
      "cloudwatch:PutMetricAlarm",
    ]

    resources = ["*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["cloudwatch:*"]
    resources = ["arn:aws:cloudwatch::${var.account}:dashboard/BinaryAlert"]
  }

  statement {
    effect    = "Allow"
    actions   = ["dynamodb:*"]
    resources = ["arn:aws:dynamodb:${var.region}:${var.account}:table/${var.prefix}_binaryalert*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["events:*"]
    resources = ["arn:aws:events:${var.region}:${var.account}:rule/${var.prefix}_binaryalert*"]
  }

  statement {
    effect  = "Allow"
    actions = ["iam:*"]

    resources = [
      "arn:aws:iam::${var.account}:policy/${var.prefix}_binaryalert*",
      "arn:aws:iam::${var.account}:role/${var.prefix}_binaryalert*",
    ]
  }

  statement {
    effect = "Allow"

    actions = [
      "iam:Get*",
      "iam:List*",
    ]

    resources = ["*"]
  }

  statement {
    effect = "Allow"

    actions = [
      "kms:CreateKey",
      "kms:Describe*",
      "kms:Get*",
      "kms:List*",
    ]

    resources = ["*"]
  }

  statement {
    effect  = "Allow"
    actions = ["kms:*"]

    resources = [
      "arn:aws:kms:${var.region}:${var.account}:alias/${var.prefix}_binaryalert*",

      # NOTE: For each new key that is generated, add permissions to use that key here:
      # "arn:aws:kms:${var.region}:${var.account}:key/KEY-UUID",
    ]
  }

  statement {
    effect    = "Allow"
    actions   = ["lambda:*"]
    resources = ["arn:aws:lambda:${var.region}:${var.account}:function:${var.prefix}_binaryalert*"]
  }

  statement {
    effect = "Allow"

    actions = [
      "logs:Describe*",
      "logs:Get*",
      "logs:List*",
    ]

    resources = ["*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["logs:*"]
    resources = ["arn:aws:logs:${var.region}:${var.account}:log-group:/aws/lambda/${var.prefix}_binaryalert*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["s3:*"]
    resources = ["arn:aws:s3:::${replace(var.prefix, "_", ".")}.binaryalert*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["sns:*"]
    resources = ["arn:aws:sns:${var.region}:${var.account}:${var.prefix}_binaryalert*"]
  }

  statement {
    effect    = "Allow"
    actions   = ["sqs:*"]
    resources = ["arn:aws:sqs:${var.region}:${var.account}:${var.prefix}_binaryalert*"]
  }
}

resource "aws_iam_policy" "binaryalert_admin" {
  name        = "binaryalert_admin_policy"
  description = "Policy for managing BinaryAlert"
  policy      = "${data.aws_iam_policy_document.binaryalert_admin.json}"
}


# ========== IAM Group ==========

resource "aws_iam_group" "binaryalert_admin" {
  name = "BinaryAlertAdmin"
}

resource "aws_iam_group_policy_attachment" "custom_policy" {
  group      = "${aws_iam_group.binaryalert_admin.name}"
  policy_arn = "${aws_iam_policy.binaryalert_admin.arn}"
}

Once you terraform apply to create the IAM group, you can add new or existing users to the group (manually or with Terraform).

Architecture

BinaryAlert utilizes a serverless architecture which is low-cost and easy to scale and maintain. While it’s helpful to understand how BinaryAlert works, keep in mind that Terraform manages all of these components so you don’t have to!

BinaryAlert Architecture

Analysis Lifecycle

  1. The organization collects files and delivers them to their BinaryAlert S3 bucket. Files of interest could include executable binaries, email attachments, documents, etc.
  2. Every file uploaded to the S3 bucket is immediately queued for analysis (using S3 event notifications).
  3. The SQS queue automatically batches files and invokes many analyzers in parallel.
  4. Each analyzer scans its files using a list of pre-compiled YARA rules.
  5. YARA matches are saved to DynamoDB and an alert is sent to an SNS topic. You can subscribe to these alerts via StreamAlert, email, or any other supported SNS subscription.
  6. For retroactive analysis, the CLI will enqueue the entire S3 bucket to be re-analyzed.
  7. Configurable CloudWatch alarms will trigger if any BinaryAlert component is behaving abnormally. This will notify a different SNS topic than the one used for YARA match alerts.

Adding YARA Rules

YARA is a powerful pattern-matching tool designed for identifying and classifying malware. BinaryAlert includes a number of custom YARA rules and makes it easy to add more of your own. Rules are automatically compiled and bundled with every deploy.

Included Rules

BinaryAlert includes a number of custom YARA rules written by Airbnb’s analysts which detect a variety of hacktools, malware, and ransomware. All included rules have been tested against a corpus of more than 2 million binaries to ensure the highest fidelity.

Clone Rules From Other Projects

BinaryAlert makes it easy to clone YARA rules from other projects:

$ ./manage.py clone_rules

This will copy a subset of YARA rules from several default open-source collections into the rules/ folder. The cloned folder structure will mirror that of the remote repository.

Note

To ensure all upstream changes are copied (including deletions), the cloned folder structure for each repo will be deleted before cloning. For example, rules/github.com/Yara-Rules/rules.git will be deleted from your local filesystem before cloning from Yara-Rules.

Configuring Rule Sources

You can configure the remote rule sources in rules/rule_sources.json. Each rule source is defined by a git-cloneable url, an optional list of file paths to include, and an optional list of file paths to exclude.

Some examples using the Yara-Rules repository:

1. URL only

{
  "repos": [
    {
      "url": "https://github.com/Yara-Rules/rules.git"
    }
  ]
}

If you specify just the git URL, BinaryAlert will traverse the entire repo and copy every .yar and .yara file (case insensitive). SSH URLs (e.g. git@github.com:Yara-Rules/rules.git) are also supported, since BinaryAlert just runs a git clone on the specified URL.

2. Filter with Include and Exclude

The Yara-Rules repo is very large, and you may only be interested in a specific subset of rules:

{
  "repos": [
    {
      "url": "https://github.com/Yara-Rules/rules.git",
      "include": [
        "CVE_Rules/*",
        "Malware/*"
      ],
      "exclude": [
        "Malware/POS*",
        "*_index.yar"
      ]
    }
  ]
}

Note

This example is for demonstrative purposes only and is not necessarily recommended.

This will copy rules from the CVE_Rules and Malware folders, excluding POS and index files. BinaryAlert runs Unix filename pattern matching via fnmatch.

In summary, BinaryAlert will copy a file from a remote repository if and only if the following conditions apply:

  1. The file name ends in .yar or .yara (case insensitive), AND
  2. The file path matches a pattern in the include list (OR the include list is empty), AND
  3. The file path does not match a pattern in the exclude list.

Write Your Own Rules

You can add your own .yar or .yara files anywhere in the rules/ directory tree. Refer to the writing YARA rules documentation for guidance and examples. Note that when BinaryAlert finds a file which matches a YARA rule, the rule name, metadata, tags, and matched string names and string data will be included in the alert for your convenience.

Note

Because the folders for each remote source will be overwritten during rule cloning, we recommend keeping your own YARA rules in rules/private or similar.

External Variables

In order to support the rule repositories listed above, BinaryAlert provides the following external variables to YARA:

  • extension - File extension (“.docx”, “.exe”, “.pdf”, etc)
  • filename - File basename (“file.exe”)
  • filepath - Full file path (“/path/to/file.exe”)
  • filetype - Uppercase extension without leading period (“DOCX”, “EXE”, “PDF”), etc

You can use these variables in your own rules to match or exclude certain file paths. (Note that the variables will default to empty strings if they are not available.) For example, this is a YARA rule which matches only files containing the string “evil” in the /home/ directory:

rule evil_at_home
{
    strings:
        $evil = "evil" nocase wide ascii

    condition:
        $evil and filepath matches /\/home\/*/
}

Warning

YARA analysis of archives does not yet support external variables.

Supported Modules

BinaryAlert supports all of the default YARA modules, including ELF, Math, Hash, and PE. Support for other modules is not planned at this time, but please let us know if you need a special module.

Disabling Rules

There may be times you want to disable certain YARA rules, but not delete them (e.g. rules with high false-positive rates). Since only .yar and .yara files in the rules/ directory tree are bundled in a BinaryAlert deploy, you can simply rename rules.yar to any other extension, e.g. rules.yar.DISABLED, to skip it during rules compilation.

If you want to disable an individual rule (not the entire file), you can either comment it out or prefix the rule with the private modifier to elide it from reported YARA match results.

Testing Your Rules

The easiest way to test individual YARA rules is to install YARA locally. Note that you will need the -d flag to define external variables. For example, to test the evil_at_home rule above:

$ brew install yara  # MacOS
$ yara evil_at_home.yar file_to_test.exe -d filepath="/home/user/file_to_test.exe"
# evil_at_home file_to_text.exe

To test all of your YARA rules, you first need to compile them into a single binary file:

$ ./manage.py compile_rules  # Saves "compiled_yara_rules.bin"

This compiled rules file is what gets bundled with the BinaryAlert analyzers, and you can use it with YARA just like any other rules file:

$ yara compiled_yara_rules.bin file_to_test

Deploying

After you’ve setup your environment, deploying BinaryAlert is as easy as:

$ ./manage.py deploy

A deploy is equivalent to the following 3 operations executed in sequence:

$ ./manage.py unit_test  # Unit tests ensure YARA rules compile correctly
$ ./manage.py build      # Build the Lambda ".zip" deployment package(s)
$ ./manage.py apply      # Update the infrastructure and deploy Lambda functions

Lambda Versions and Aliases

Each BinaryAlert Lambda function has a Production alias which points to the most recent version of that function. Every time a deploy changes one of the Lambda deployment packages, a new version is published and the Production alias is updated accordingly. For more information, see AWS Lambda Function Versioning and Aliases.

Add SNS Subscriptions

BinaryAlert sends YARA match alerts to an SNS topic. In order to receive these alerts, you must manually add a subscription to the generated NAME_PREFIX_binaryalert_yara_match_alerts topic. SNS supports a variety of subscription endpoints, including email, SMS, and other Lambda functions. Email/SMS subscriptions must be confirmed by the destination, which is why this step can’t be automated with Terraform.

For example, since StreamAlert supports SNS datasources, you could use StreamAlert to forward the YARA match alert to PagerDuty, Slack, etc.

Terraform State

By default, Terraform will save the state of the infrastructure locally in terraform/terraform.tfstate. If you are deploying BinaryAlert in an enterprise environment, we recommend configuring Terraform remote state. For example, you can store the Terraform state in a versioned S3 bucket.

Terraform Commands

We recommend using the manage.py wrapper script for most BinaryAlert management, but you can also run terraform commands directly from the terraform/ directory:

$ cd terraform/
$ terraform plan  # Show pending changes
$ terraform show  # Print the current state of the infrastructure

Teardown

To teardown all of the BinaryAlert infrastructure:

$ ./manage.py destroy

Terraform will build a destroy plan which you must approve before the delete will proceed.

By default, the BinaryAlert S3 buckets can’t be deleted until they are empty. You will be asked if you want to override this setting and delete all objects as well. If so, the new setting will be applied before building the destroy plan.

Note

You can set force_destroy = true in the terraform/terraform.tfvars config file and apply the change if you want to manually disable S3 delete protections.

Analyzing Files

Files uploaded to the BinaryAlert S3 bucket will be automatically queued for analysis. You can also invoke the analyzer directly, scan files in other buckets, or download files from CarbonBlack.

Uploading Files

All files uploaded to the BinaryAlert S3 bucket will be immediately queued for analysis. The S3 bucket name is of the form

YOUR.NAME.PREFIX.binaryalert-binaries.REGION

When uploading to S3, any object metadata you set will be included in all match alerts. In addition, if there is a filepath metadata key, BinaryAlert will make the filepath external variables available to the YARA rules.

Uploaded files are persisted indefinitely so that BinaryAlert can retroactively analyze all files. The S3 bucket has access logging, object versioning, inventory, and server-side encryption enabled.

Analyzing Existing Buckets

To scan files in other S3 buckets, you first need to grant BinaryAlert permission to access them. Modify the S3 section of your terraform.tfvars file and deploy the changes:

# ##### S3 #####

# If using BinaryAlert to scan existing S3 buckets, add the S3 and KMS resource ARNs here
# (KMS if the objects are server-side encrypted)
external_s3_bucket_resources = ["arn:aws:s3:::bucket-name/*"]
external_kms_key_resources = ["arn:aws:kms:REGION:ACCOUNT:key/KEY-UUID"]

Direct Invocation

You can directly invoke the BinaryAlert analyzer to scan any S3 object it has access to. The match results will always be saved to Dynamo, but you can configure whether each request should also trigger the normal SNS alerts:

import boto3, json

response = boto3.client('lambda').invoke(
    FunctionName='your_prefix_binaryalert_analyzer',
    InvocationType='RequestResponse',
    Payload=json.dumps({
        'BucketName': 'your-bucket-name',  # S3 bucket name
        'EnableSNSAlerts': False,          # Toggle SNS alerts
        'ObjectKeys': ['key1', 'key2']     # List of S3 object keys
    }),
    Qualifier='Production'
)

results = json.loads(response['Payload'].read().decode('utf-8'))
print(json.dumps(results, sort_keys=True, indent=4))

{
    'S3:BUCKET-NAME:KEY1': {
        'FileInfo': {
            'MD5': '...',
            'S3LastModified': '...',
            'S3Metadata': {},
            'SHA256': '...'
        },
        'MatchedRules': {
            'Rule1':
                'MatchedData': ['abc'],
                'MatchedStrings': ['$a'],
                'Meta': {
                    'description': 'Test YARA rule'
                },
                'RuleFile': 'rules.yara',
                'RuleName': 'test_dummy_true'
         },
         'NumMatchedRules': 1
    }
    'S3:BUCKET-NAME:KEY2': {
        'FileInfo': {
            'MD5': '...',
            'S3LastModified': '...',
            'S3Metadata': {},
            'SHA256': '...'
        },
        'MatchedRules': {},
        'NumMatchedRules': 0
    }
}

Configuring Event Notifications

You can configure other buckets to send S3 event notifications to the BinaryAlert SQS queue. To do so, create an event notification on your existing bucket and then modify the BinaryAlert SQS permissions accordingly. Once configured, BinaryAlert will be automatically analyzing new objects in your existing buckets in addition to its own.

Retroactive Analysis

When adding new YARA rules to your collection, you can easily re-scan all of your files in the BinaryAlert bucket to see if any of them match the new rules:

$ ./manage.py retro_fast

This will enumerate the most recent S3 inventory manifest, adding all object keys to the analysis SQS queue. However, if your bucket is less than 48 hours old, it may not yet have an inventory manifest. In that case, you can list the objects yourself:

$ ./manage.py retro_slow

As its name suggests, enumerating the bucket directly will generally be much slower than reading the inventory, particularly for buckets with thousands of objects or more.

Note

Because the inventory may be up to 24 hours old, a retro_fast scan may miss the newest objects in the bucket. If you need to scan all files immediately, use retro_slow.

In either case, once all of the objects are in the analyzer SQS queue, it will take some time for BinaryAlert to finish scanning all of them (depending on how many objects you have). YARA matches found during a retroactive scan are treated like any other - the matches are saved to Dynamo and reported via SNS.

Stopping a Retro Scan

Sometimes, a new YARA rule you thought would be great turns out to be super noisy, flooding you with false positive alerts. Unfortunately, if you have millions of objects in your BinaryAlert bucket, a retro scan can take hours to finish. To stop a retro scan dead in its tracks, you can drop all messages from the analysis queue:

$ ./manage.py purge_queue

Warning

This will also drop any event notifications from newly added objects that arrived after the retro scan started. These objects won’t be scanned again until either (a) the next retro_slow scan or (b) the next retro_fast after 24 hours when the new object is in the inventory.

CarbonBlack Downloader

If you use CarbonBlack Enterprise Response, you can enable BinaryAlert’s optional downloader SQS queue and Lambda function. The downloader copies files (and some metadata) from CarbonBlack into BinaryAlert’s S3 bucket. To enable it:

$ ./manage.py configure
AWS Region (us-east-1):
Unique name prefix, e.g. "company_team": your_unique_prefix
Enable the CarbonBlack downloader? (no): yes
CarbonBlack URL: https://your.carbonblack.url
CarbonBlack API token (only needs binary read access):

$ ./manage.py deploy

Warning

The API token only needs access to read binaries. Do not use a token with admin privileges, do not allow other users to share the same token, and be sure to regularly rotate the token.

Note

The API token will not be shown on screen and BinaryAlert will create a new KMS key to encrypt the credentials before saving them to the terraform.tfvars configuration file. The downloader (and no other component) is authorized to decrypt the credentials with the generated key.

Binaries downloaded from CarbonBlack are saved to the BinaryAlert S3 bucket with the key carbonblack/MD5 and with the following metadata:

[
    'carbon_black_group',
    'carbon_black_host_count',
    'carbon_black_last_seen',
    'carbon_black_md5',
    'carbon_black_os_type',
    'carbon_black_virustotal_score',
    'carbon_black_webui_link',
    'filepath'  # from the "observed_filenames" CarbonBlack metadata
]

Copy All Files

If you want to run a one-time job to copy every file from CarbonBlack into BinaryAlert:

$ ./manage.py cb_copy_all

This runs locally, using multiple threads to enumerate the files in CarbonBlack into the BinaryAlert downloader SQS queue.

Real-Time Invocations

For real-time file analysis, we recommend publishing to the downloader SQS queue every time CarbonBlack logs a binarystore.file.added event. If you use StreamAlert to process CarbonBlack logs, the following rule will publish a message for every new binary (assuming the SQS queue is a properly configured StreamAlert output):

@rule(logs=['carbonblack:binarystore.file.added'], outputs=['aws-sqs:binaryalert'])
def cb_binarystore_file_added(rec):
    """
    description: CarbonBlack found a new binary: forward to BinaryAlert for YARA analysis.
    """
    return True

You can also directly publish messages to the downloader SQS queue. Messages are expected to be in the very simple format {'md5': 'ABCDE....'}

YARA Matches

When BinaryAlert finds a file that matches at least one YARA rule, it will save the match information to a DynamoDB table and send an alert to the NAME_PREFIX_binaryalert_yara_matches SNS topic (if it hasn’t already).

You can also opt to notify a different SNS topic for files which did not match any YARA rules.

DynamoDB Records

All YARA matches are saved to a DynamoDB table. The table has two primary keys, AnalyzerVersion and SHA256. This makes it easy to find every match associated with a given file or, conversely, to find all matches from a specific version of your BinaryAlert deployment.

A manage.py live_test will show you an example of the match record stored in the DynamoDB table:

{
    'AnalyzerVersion': Decimal('1'),
    'MD5': 'FILE_MD5',
    'MatchedRules': {'public/eicar.yara:eicar_av_test'},
    'S3LastModified': '2017-09-16 00:25:37+00:00',
    'S3Metadata': {'filepath': 'eicar_test_UUID.txt'},
    'S3Objects': {'S3:NAME.PREFIX.binaryalert-binaries.REGION:eicar_test_UUID.txt'},
    'SHA256': 'FILE_SHA256'
}

SNS Match Alerts

In addition to saving the DynamoDB record, an alert is sent to the NAME_PREFIX_binaryalert_yara_matches SNS topic when one of the following conditions apply:

  1. The file matches a YARA rule that was not matched in the previous version of the BinaryAlert analyzers, OR
  2. A new S3 object appears which is identical to an already matched binary.

Without these conditions, an alert would trigger for every match in every retroactive analysis. Instead, an alert triggers only when there is a new match.

Note

You must add an SNS subscription in order to receive YARA match alerts.

SNS Non-Match Alerts

If you’d like to be notified in real time when a scanned file did not match any YARA rules, enable the corresponding config option in terrform.tfvars and redeploy:

##### SNS #####
# Create a separate SNS topic which reports files that do NOT match any YARA rules.
enable_negative_match_alerts = true

Metrics and Monitoring

BinaryAlert automatically generates logs, custom metrics, alarms, and a dashboard to help you visualize its performance. These are all part of the AWS CloudWatch service.

Logging

Each BinaryAlert Lambda function logs information about its execution; logs are saved for 14 days (by default) and are accessible from AWS CloudWatch.

Custom Metrics

In addition to the wide array of metrics provided automatically AWS, BinaryAlert publishes the following custom metrics in the BinaryAlert namespace:

Metric Name Unit Description
AnalyzedBinaries Count Number of binaries analyzed
MatchedBinaries Count Number of binaries which matched a YARA rule
S3DownloadLatency Milliseconds Time to download binaries from S3
YaraRules Count Number of compiled YARA rules

Metric Alarms

BinaryAlert creates metric alarms which trigger if BinaryAlert behavior is abnormal. Similar to adding SNS subscriptions for YARA match alerts, you will need to configure subscriptions for the NAME_PREFIX_binaryalert_metric_alarms SNS topic if you want to be notified about metric alarms.

Alarms can be configured from the terraform/terraform.tfvars configuration file, or else by directly modifying terraform/cloudwatch_metric_alarm.tf. The alarm defaults are as follows:

Namespace Metric Name Alarm Condition
AWS/DynamoDB ThrottledRequests > 0
AWS/Lambda Errors > 0 (for each Lambda function)
AWS/SQS ApproximateAgeOfOldestMessage >= 75% of max age (for each SQS queue)
BinaryAlert AnalyzedBinaries == 0 for an hour
BinaryAlert YaraRules < 5

The description for each alarm includes context and troubleshooting information.

Dashboard

The aforementioned metrics (and many others) are aggregated into a single BinaryAlert dashboard at the following URL (substitute your region for us-east-1): https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#dashboards:name=BinaryAlert.

Troubleshooting / FAQ

How long does it take a file to be analyzed?

Under normal operation, the analysis is usually finished within 1-2 minutes after being uploaded to the S3 bucket.

What’s the filesize limit?

The limiting factor is the space Lambda allocates for “/tmp”, i.e. 512 MB. If you use the downloader, note that CarbonBlack automatically truncates files to 25 MB.

YARA rules with “hash” or “imphash” fail to compile

If the openssl development libraries aren’t on your system when installing YARA, the hash module won’t work (example). Be sure to follow instructions for Installing Dependencies.

How much does BinaryAlert cost?

The two biggest costs are the S3 storage and Lambda invocations, so it will depend on how many files you have and how often you re-analyze all of them, but generally no more than a few hundred dollars per month for several TB worth of files.

Does BinaryAlert automatically test YARA rules?

BinaryAlert ensures that the YARA rules compile correctly before every deploy, but it does not verify that YARA rules match any particular files. However, you can test your rules locally.

Why did my live test fail?

Check the Lambda execution logs and the BinaryAlert dashboard for abnormalities. A common problem is that the BinaryAlert analyzers don’t understand the compiled YARA rules file. Make sure your virtual environment is set up correctly with the same YARA version and that your YARA rules only use the supported modules.

It may take 1-3 minutes after a deploy before the Lambda functions are ready to go. If a live test fails immediately after a deploy, wait a few minutes and try again.

Finally, if BinaryAlert is in the middle of a retroactive scan, the analysis queue may be backlogged.

How do I setup YARA match / metric alarm alerts?

You have to add a subscription to the generated SNS topic.

Analyzer timeouts

Analyzers can sometimes time out while downloading files from S3. If the analyzers are timing out during a retroactive scan, you can lower the objects_per_retro_message configuration option in terraform/terraform.tfvars.

Terraform destroy fails because “bucket is not empty”

By default, BinaryAlert S3 buckets can’t be deleted until they are empty. ./manage.py destroy will ask if you want to override this setting. See the teardown documentation for more information.

Contact Us

If your question wasn’t answered here, feel free to open an issue or ping us on Slack!

Credits

People

BinaryAlert is brought to you by Airbnb:

YARA Rules

When cloning YARA rules from other projects, subsets of the following collections are included by default:

Open-Source Tools

We are proud to contribute to the open-source community, without which BinaryAlert would not be possible. BinaryAlert relies on several open-source tools and libraries:

  • backoff: Function decoration for backoff and retry
  • boto3: AWS SDK for Python
  • cbapi: Carbon Black API for Python
  • pyhcl: Python parser for HCL (e.g. Terraform configuration)
  • terraform: Infrastructure-as-Code
  • yara: Pattern matching for malware analysis
  • yara-python: The Python interface for YARA
  • yextend: YARA analysis of archive data

Bundled Software

The following tools are pre-compiled for use in Lambda and included in the BinaryAlert repo: