DECRYPT is a set of Splunk commands which provide Base64, XOR, ROTX, RC4 and ROL/ROR routines which are commonly used for encrypting and decrypting malware communications and data exfiltration.



These commands can be leveraged in Splunk queries by users or automation to decipher previously indexed communications.

Installation

DECRYPT is a standard Splunk App and requires no special configuration. A restart of Splunk is not required once installed.

Usage

DECRYPT is implemented as a single search command which exposes a number of data manipulation functions. It takes the required field to manipulate and then one or more functions as arguments.

Usage: decrypt [f|field=<name>] FUNCTIONS...

The following example will transform the sourcetype field into its hex representation:

... | decrypt field=sourcetype hex() emit('sourcetype')

Note: Fields must be output via the emit function. The input field is not modified in place.

Arguments

field | f

The field argument specifies the Splunk field to use as input.

... | decrypt field="hostname" ...

If no field argument is passed then _raw will be used by default.

If a field argument is passed and the field does not exist in the current record being processed, no error or warning will be given.

FUNCTIONS

Each function passed as an argument will be executed in order, with the output of the previous function provided as input to the next.

... | decrypt f=hostname atob xor('s\x65cr\x65t') hex emit('decrypted')

The above example can be explained as:

Pass the value of the hostname field to atob as input

Pass the output of atob to xor as input with the argument 's\x65cr\x65t'

Pass the output of xor to hex as input

Pass the output of hex to emit with the argument 'decrypted'

Functions

btoa()

Encodes input to a Base64 string.

atob()

Decodes a Base64 encoded string.

rotx(count)

Implements Caesarian shift. The count argument specifies the amount to shift and must be an integer.

rol(count)

Implements rotate-on-left to each character within the string using an 8 bit boundary. The count argument specifies the amount to rotate and must be an integer.

ror(count)

Implements rotate-on-right to each character within the string using an 8 bit boundary. The count argument specifies the amount to rotate and must be an integer.

xor(key)

Implements basic XOR cipher against the field with the supplied key. The key can be provided as a string or integer.

rc4(key)

Implements the RC4 cipher against the field with the supplied key. The key provided must be a string.

hex()

Transforms input into its hexadecimal representation.

unhex()

Transforms hexadecimal input into its byte form.

save(name)

Saves the current state to memory as name.

load(name)

Recalls the previously saved state name from memory.

emit(name)

Outputs the current state to the field name. Non-printable characters will be replaced with a period.

substr(offset, count)

Returns a substring of the input, starting at the index offset with the number of characters count.

Function Arguments

Strings

Strings can be specified by encapsulating values in apostrophes (single quote). Strings accept Pythonic escape sequences, so hexadecimal and octal values can be specified with \xhh and \ooo respectively.

'This is a valid string' 'This is also \x61 valid string.'

Quotation marks (double quotes) cannot be used.

"This is not a valid string"

Integers

Integers can be specified numerically or as hexadecimal representations by prefixing values with a 0x .

The value 256 could be passed as is or as its hexadecimal representation 0x100 .

Field References

The value of Splunk fields can be used in function parameters by passing the field name as an argument. All referenced fields must be complete words unbroken by whitespace.

... | decrypt r=_raw xor(sourcetype) ...

The above example demonstrates passing the sourcetype field as the key to the xor function.

Style

Functions which take no arguments do not need parenthesis in order for syntax checking to pass. The following examples will pass syntax checks and execute the same.

... | decrypt f=_raw atob hex unhex ... | decrypt f=_raw atob() hex() unhex() ... | decrypt f=_raw atob() hex unhex

New lines can be used to break up command sequences for easier readability.

... | decrypt f=_raw atob hex unhex

Recipes

XOR

... | decrypt f=data xor('secret') emit('result')

ROT13 cipher

... | decrypt f=data rotx(13) emit('result')

Base64 decode, XOR

... | decrypt f=data atob xor('secret') emit('result')

Base64 decode, XOR with first byte

... | decrypt f=data atob save('bin') substr(0, 1) emit('key') load('bin') substr(1, 9999) xor(key) emit('result')

Brute force RC4

... | decrypt f=data atob save('orig') rc4('secret') emit('rc4-secret') load('orig') rc4('password') emit('rc4-password') load('orig') rc4('abc123') emit('rc4-abc123') load('orig') rc4('aabbccdd') emit('rc4-aabbccdd')

Release Notes

2.0

Rearchitected due to a limitation with passing binary data between commands

Introduced SAVE/LOAD/EMIT/HEX/UNHEX functions

1.0