Windows.Carving.BRc4
Windows.Carving.BRc4
This artifact extracts Brute Ratel C4 (BRc4) configuration from a byte stream, process or file on disk. BRc4 is an emerging red-teaming and adversarial attack simulation tool.
The User can define bytes, file glob, process name or pid regex as a target. The artifact firstly discovers BruteRatel configuration and extracts bytes, before parsing with Velociraptor Binary Parser.
- BRc4’s configuration consists of 8 characters inside several sections.
- Character lists reversed in order
- This list of characters is: either base64 + RC4 encoded or in clear text.
This content simply carves the configuration and does not unpack files on disk. That means pointing this artifact as a packed or obfuscated file may not obtain the expected results.
name: Windows.Carving.BRc4
author: Matt Green - @mgreen27
description: |
This artifact extracts Brute Ratel C4 (BRc4) configuration from a byte stream,
process or file on disk. BRc4 is an emerging red-teaming and adversarial
attack simulation tool.
The User can define bytes, file glob, process name or pid regex as a target.
The artifact firstly discovers BruteRatel configuration and extracts bytes,
before parsing with Velociraptor Binary Parser.
* BRc4's configuration consists of 8 characters inside several sections.
* Character lists reversed in order
* This list of characters is: either base64 + RC4 encoded or in clear text.
This content simply carves the configuration and does not unpack files on
disk. That means pointing this artifact as a packed or obfuscated file may not
obtain the expected results.
reference:
- https://unit42.paloaltonetworks.com/brute-ratel-c4-tool/
- https://github.com/Immersive-Labs-Sec/BruteRatel-DetectionTools
parameters:
- name: TargetBytes
default:
- name: TargetFileGlob
default:
- name: PidRegex
default: .
type: regex
- name: ProcessRegex
default: .
type: regex
- name: DecodeKey
default: "bYXJm/3#M?:XyMBF"
- name: FindConfig
type: hidden
description: Final Yara option and the default if no other options provided.
default: |
rule BruteRatelConfig
{
strings:
$config_block = { 50 48 b8 [8] 50 68}
$split_marker = { 50 48 b8 [8] 50 48 b8 }
condition:
$config_block and #split_marker > 30
}
sources:
- precondition:
SELECT OS From info() where OS = 'windows'
query: |
-- dynamic functions to reverse list order
LET _Reverse(data) = SELECT *, count() as Count FROM foreach(row=data) ORDER BY Count desc
LET Reverse(data) = _Reverse(data=data)._value
-- binary parse profile to extract BRc4 configuration. NOTE: need reverse dynamic fuctions above
LET PROFILE = '''[
[BRc4Config, 0, [
["__FindConfig",0, "String",{term_hex: "5048b8"}],
["Reversed","x=>len(list=x.__FindConfig) + 3", "String", { term_hex: "5068" }],
["ConfigData",0,"Value",{ "value": "x=>join(array=Reverse(data=split(string=x.Reversed,sep_string=unhex(string='5048b8'))))" }],
["DecodedConfig",0,"Value",{ "value": "x=>crypto_rc4(string=base64decode(string=x.ConfigData),key=DecodeKey)" }],
["Config",0,"Value",{ "value": "x=>if(condition= x.DecodedConfig, then=x.DecodedConfig, else=x.ConfigData)" }],
]
]]'''
-- Bytes usecase: scan DataBytes for BRc4 config
LET ByteConfiguration = SELECT
Rule,
len(list=TargetBytes) as Size,
hash(path=TargetBytes,accessor='data') as Hash,
String.Offset as HitOffset,
parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
FROM yara(
files=TargetBytes,
accessor='data',
rules=FindConfig,
number=1,
context=1000
)
-- Glob usecase: find target files
LET TargetFiles = SELECT OSPath,Size
FROM glob(globs=TargetFileGlob) WHERE NOT IsDir
-- Glob usecase: Extract config from files in scope
LET FileConfiguration = SELECT * FROM foreach(row=TargetFiles,
query={
SELECT
Rule,
OSPath, Size,
hash(path=OSPath) as Hash,
String.Offset as HitOffset,
parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
FROM yara(
files=OSPath,
rules=FindConfig,
number=1,
context=1000
)
})
-- find velociraptor process
LET me <= SELECT * FROM if(condition= NOT ( TargetFileGlob OR TargetBytes ),
then = { SELECT Pid FROM pslist(pid=getpid()) })
-- find all processes and add filters
LET processes = SELECT Name as ProcessName, Exe, CommandLine, Pid
FROM pslist()
WHERE
Name =~ ProcessRegex
AND format(format="%d", args=Pid) =~ PidRegex
AND NOT Pid in me.Pid
-- scan processes in scope with our rule, limit 1 hit and extract context to parse
LET ProcessConfiguration = SELECT * FROM foreach(
row=processes,
query={
SELECT
Rule,
Pid, ProcessName, CommandLine,
String.Offset as HitOffset,
parse_binary(accessor="data",filename=String.Data,profile=PROFILE,struct='BRc4Config').Config as _RawConfig
FROM yara(
files=format(format="/%d", args=Pid),
accessor='process',
rules=FindConfig,
number=1,
context=1000
)
})
-- generate results remove any FPs
SELECT *,
{
SELECT _value
FROM foreach(row=split(string=_RawConfig,sep_string='|'))
WHERE _value
} as BRc4Config,
_RawConfig
FROM if(condition=TargetBytes,
then=ByteConfiguration,
else= if(condition=TargetFileGlob,
then= FileConfiguration,
else= ProcessConfiguration))