This module allows you to interact with the Valhalla API, retrieve YARA rules in different formats, filter them and write them to disk. You can find more information about Valhalla on our website. The web interface, which doesn't have the filtering features of the Python module and the client, can be accessed here.
It contains a Python module valhallaAPI and a Python command line API client valhalla-cli.
The web API allows you to retrieve the subscribed rules.
The 2 main functions of the Python module are:
get_rules_text() retrieves rules as textget_rules_json() retrieves rules as JSONThe module provides functions to filter the retrieved YARA rules based on - tags - score - keywords - supported YARA version and required YARA modules
It also allows you to retrieve a filtered rule set that fits the product that you use to apply the rules. For example, you can get a filtered rule set with rules that will run on your FireEyeEX appliance by filtering all rules that use feature only available in YARA versions higher than the supported 1.7.0.
There are 2 extra functions for special lookups in the Valhalla database (for customers only):
get_rule_info retrieves rule information and all matching sample hashesget_hash_info retrieves all rules matching on a certain sha256 hashThere is a demo API key that can be used for testing purposes.
1111111111111111111111111111111111111111111111111111111111111111
It will allow you to retrieve the processed public signature-base rule set.
The key will also allow you to query the rule info for a single rule, which is:
Casing_Anomaly_ByPass
Please note that Valhalla has protection mechanisms in place that will block your end of the Bifrost for a significant amount of time if you try foolish things.
pip install valhallaAPI
Notes:
- make sure to use Python 3.6 or higher
- you may need to use pip3 install valhallaAPI on Debian systems
Get a service status (does not require a valid API key)
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI()
status = v.get_status()
Response
{
"error": "none",
"num_rules": 10463,
"status": "green",
"version": 2020051212
}
Get all subscribed rules as text and save them to a file
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_rules_text()
with open('valhalla-rules.yar', 'w') as fh:
fh.write(response)
Or use the DEMO API key, which allows you to retrieve all public rules
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="1111111111111111111111111111111111111111111111111111111111111111")
response = v.get_rules_text()
with open('valhalla-rules.yar', 'w') as fh:
fh.write(response)
Get all subscribed rules with a minimum score of 75 and save it to a file
response = v.get_rules_text(score=75)
Get all subscribed rules that contain the keyword Mimikatz and save them to a file
response = v.get_rules_text(search="Mimikatz")
Get all subscribed rules for your scan engine, which suppports YARA up to version 3.2.0 and the pe module, and save them to a file
response = v.get_rules_text(max_version="3.2.0", modules=['pe'])
Get all subscribed rules for your FireEyeEX
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_rules_text(product="FireEyeEX")
Get all subscribed rules for your Tanium
response = v.get_rules_text(product=v.TANIUM)
The following products have predefined presets
FIREEYEAX = "FireEyeAX"
FIREEYENX = "FireEyeNX"
FIREEYEEX = "FireEyeEX"
CARBONBLACK = "CarbonBlack"
TANIUM = "Tanium"
TENABLE = "Tenable"
SYMANTECMAA = "SymantecMAA"
GRR = "GRR"
OSQUERY = "osquery"
MATD3 = "McAfeeATD3"
MATD4 = "McAfeeATD4"
An example response will look like
/*
VALHALLA YARA RULE SET
Retrieved: 2019-02-25 14:54
Generated for User: a67
Number of Rules: 8127
ANY REPRODUCTION OR DISTRIBUTION IS STRICTLY PROHIBITED WITHOUT THE PRIOR WRITTEN CONSENT OF NEXTRON SYSTEMS AND MAY RESULT IN LEGAL ACTION AS WELL AS THE TERMINATION OF THE CONTRACTUAL RELATIONSHIP
*/
import "pe"
rule SUSP_Katz_PDB_RID664 : EXE SUSP DEMO FILE {
meta:
description = "Detects suspicious PDB in file"
author = "Florian Roth"
reference = "Internal Research"
date = "2019-02-04 10:32:31"
score = 70
customer = "demo"
copyright = "Distribution to third parties is not permitted and will be pursued with legal measurements"
minimum_yara = "1.7"
strings:
$s1 = /\\Release\\[a-z]{0,8}katz.pdb/
$s2 = /\\Debug\\[a-z]{0,8}katz.pdb/
condition:
uint16 ( 0 ) == 0x5a4d and filesize < 6000KB and all of them
}
...
Get all subscribed rules with the APT tag as JSON and save them to a file
import json
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_rules_json(tags=['APT'])
with open('valhalla-rules.json', 'w') as fh:
fh.write(json.dumps(response))
An example response will look like
{
"api_version": "1.0",
"copyright": "Nextron Systems GmbH",
"customer": "demo",
"date": "2019-03-07 10:55",
"legal_note": "Any reproduction or distribution is strictly prohibited without the prior written consent of Nextron Systems and may result in legal action as well as the termination of the contractual relationship",
"rules": [
{
"author": "Florian Roth",
"content": "rule EXP_Libre_Office_CVE_2018_16858_RIDBA9 : EXPLOIT OFFICE DEMO FILE APT {\n meta:\n description = \"Detects exploits addressing CVE-2018-16858 in LibreOffice - modified version\"\n author = \"Florian Roth\"\n reference = \"https://insert-script.blogspot.com/2019/02/libreoffice-cve-2018-16858-remote-code.html\"\n date = \"2019-02-05 14:17:21\"\n score = 70\n customer = \"demo\"\n copyright = \"Distribution to third parties is not permitted and will be pursued with legal measurements\" \n minimum_yara = \"1.7\"\n \n strings:\n $x1 = \"tempfilepager\" \n $x2 = \"tempfilepager\" \n $s1 = \"xlink:href=\\\"vnd.sun.star.script:\" ascii nocase\n $s2 = \".py$tempfilepager\" ascii nocase\n $s3 = \"language=Python\" ascii nocase\n condition: \n uint32be ( 0 ) == 0x3c3f786d and all of them or 1 of ( $x* )\n}",
"date": "2019-02-05 12:54:31",
"description": "Detects exploits addressing CVE-2018-16858 in LibreOffice - modified version",
"minimum_yara": "1.7",
"name": "EXP_Libre_Office_CVE_2018_16858_RID9B8",
"reference": "https://insert-script.blogspot.com/2019/02/libreoffice-cve-2018-16858-remote-code.html",
"required_modules": [],
"score": 70,
"tags": [
"EXPLOIT",
"OFFICE",
"DEMO",
"FILE",
"APT"
]
},
...
Get the information for rule Casing_Anomaly_ByPass
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_rule_info(rulename="Casing_Anomaly_ByPass")
Note that the rule info for Casing_Anomaly_ByPass is the only info that you can retrieve with the DEMO API key.
IMPORTANT: The rule info endpoint is rate limited. You can use it for single lookups. Bulk requests lead to bans.
An example output of a rule info request will look like
{
"author": "Florian Roth",
"av_ratio": 16.52,
"av_verdicts": {
"clean": 1,
"malicious": 21,
"suspicious": 27
},
"date": "2019-01-17 11:50:21",
"description": "Detects suspicious casing of bypass statement",
"minimum_yara": "1.7",
"name": "Casing_Anomaly_ByPass_RID837",
"reference": "Internal Research",
"required_modules": [],
"rule_matches": [
{
"hash": "bdde03b5b4f94ec7dbf947f3099f2009efac43b69659f788f513d3e615b98353",
"positives": 24,
"size": 319485,
"timestamp": "Thu, 07 Mar 2019 06:29:06 GMT",
"total": 56
},
{
"hash": "646d446fb11eae76ca8b6e54306bb022431a4f20cc8cef5daa40dd6ec3537aff",
"positives": 3,
"size": 573,
"timestamp": "Thu, 07 Mar 2019 00:15:07 GMT",
"total": 57
}
],
"score": 60,
"tags": [
"SUSP",
"CASING"
]
}
Get the information for hash 8a883a74702f83a273e6c292c672f1144fd1cce8ee126cd90c95131e870744af (only SHA256 hashes are supported)
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_hash_info(hash="8a883a74702f83a273e6c292c672f1144fd1cce8ee126cd90c95131e870744af")
An example output of a hash info request will look like
{
"api_version": "1.0.1",
"results": [
{
"positives": 4,
"rulename": "Casing_Anomaly_ByPass",
"tags": [
"T1027",
"SUSP",
"CASING"
],
"timestamp": "Tue, 11 Jun 2019 23:57:10 GMT",
"total": 58
},
{
"positives": 4,
"rulename": "Casing_Anomaly_Convert_PS",
"tags": [
"T1027",
"CASING",
"SCRIPT",
"T1064"
],
"timestamp": "Tue, 11 Jun 2019 23:57:12 GMT",
"total": 58
},
{
"positives": 4,
"rulename": "Casing_Anomaly_PowerShell",
"tags": [
"T1027",
"CASING",
"SCRIPT",
"T1064",
"T1086"
],
"timestamp": "Tue, 11 Jun 2019 23:57:13 GMT",
"total": 58
}
],
"status": "success"
}
(only available for customers)
Get all rules based on a keyword search (e.g. Turla, Bypass or PlugX)
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_keyword_rules(keyword="Turla")
An example output of a keyword request will look like
{
"api_version": "1.1.0",
"results": [
{
"date": "2020-12-02",
"description": "Detects forensic artefacts as reported in Turla Crutch report",
"name": "APT_RU_Turla_CrutchReport_ForensicArtefacts_Dec20_1",
"reference": "https://www.welivesecurity.com/2020/12/02/turla-crutch-keeping-back-door-open/",
"required_modules": []
},
{
"date": "2020-12-02",
"description": "Detects Turla Crutch malware",
"name": "APT_RU_Turla_CrutchReport_Crutch_Dec20_1",
"reference": "https://www.welivesecurity.com/2020/12/02/turla-crutch-keeping-back-door-open/",
"required_modules": []
},
...
],
"status": "success"
}
(only available for customers)
Get all sample matches of rules selected by keyword search (e.g. Turla, Bypass or PlugX)
from valhallaAPI.valhalla import ValhallaAPI
v = ValhallaAPI(api_key="Your API Key")
response = v.get_keyword_rule_matches(keyword="LuckyMouse")
An example output of a keyword request will look like
{
"api_version": "1.1.0",
"results": [
{
"hash": "00847787ea6568cfaaa762f4ee333b44f35a34e90858c1c8899144be016510ef",
"positives": 44,
"rulename": "APT_MAL_CN_LuckyMouse_Loader_Dec20_2",
"size": 81920,
"timestamp": "Mon, 28 Dec 2020 09:45:12 GMT",
"total": 70
},
{
"hash": "c2dc17bdf16a609cdb5a93bf153011d67c6206f7608931b1ca1c1d316b5ad54f",
"positives": 49,
"rulename": "APT_MAL_CN_LuckyMouse_Loader_Dec20_2",
"size": 81920,
"timestamp": "Thu, 10 Dec 2020 17:04:55 GMT",
"total": 68
},
{
"hash": "2b1d6a8538452e3b315283c124f6ee7e27dfd55f52996d3aa89a5919f80e0ef7",
"positives": 13,
"rulename": "APT_LuckyMouse_Mal_1",
"size": 81920,
"timestamp": "Fri, 23 Oct 2020 16:22:19 GMT",
"total": 70
},
{
"hash": "b85aee07213836bd8784852860ff3b180d71f36fd98d49cc432162aa2234f99d",
"positives": 12,
"rulename": "APT_MAL_LuckyMouse_EmissaryPanda_Gen_May19_1",
"size": 71680,
"timestamp": "Thu, 30 Jan 2020 20:18:48 GMT",
"total": 70
},
{
"hash": "a8a2221814aab518db0a48d9646f598d9da1bd6c749a792a3605a562eac79980",
"positives": 0,
"rulename": "APT_MAL_LuckyMouse_EmissaryPanda_Gen_May19_1",
"size": 45568,
"timestamp": "Sat, 07 Dec 2019 13:45:06 GMT",
"total": 68
},
{
"hash": "2dde8881cd9b43633d69dfa60f23713d7375913845ac3fe9b4d8a618660c4528",
"positives": 43,
"rulename": "APT_MAL_LuckyMouse_EmissaryPanda_Gen_May19_1",
"size": 71680,
"timestamp": "Thu, 30 May 2019 02:37:05 GMT",
"total": 70
}
],
"status": "success"
}
The API client allows you to query the Web API from command line. It requires Python3.
Install Python3 and then run the following command:
```bash pip
$ claude mcp add valhallaAPI \
-- python -m otcore.mcp_server <graph>