This API's response data reflects information about the security configuration that intercepted the request. These configurations contain component rules that are represented in a raw form of URL- and base64-encoded data, partly to accommodate a potentially arbitrary character set used in the attack. Encoded data for these rules appears within each response object's attackData section:

"attackData": {
    "configId": "14227",
    "policyId": "qik1_26545",
    "clientIP": "",
    "rules": "OTUwMDAy%3bOTUwMDA2%3bQ01ELUlOSkVDVElPTi1BTk9NQUxZ",
    "ruleVersions": "NA%3d%3d%3bNA%3d%3d%3bMQ%3d%3d",
    "ruleMessages": "U3lzdGVtIENvbW1hbmQgQWNjZXNz%3bU3lzdGVtIENvbW1hbmQgSW5qZWN0aW9u%3bQW5vbWFseSBTY29yZSBFeGNlZWRlZCBmb3IgQ29tbWFuZCBJbmplY3Rpb24%3d",
    "ruleData": "dGVsbmV0LmV4ZQ%3d%3d%3bdGVsbmV0LmV4ZQ%3d%3d%3bVmVjdG9yIFNjb3JlOiAxMCwgREVOWSB0aHJlc2hvbGQ6IDksIEFsZXJ0IFJ1bGVzOiA5NTAwMDI6OTUwMDA2LCBEZW55IFJ1bGU6ICwgTGFzdCBNYXRjaGVkIE1lc3NhZ2U6IFN5c3RlbSBDb21tYW5kIEluamVjdGlvbg%3d%3d",
    "ruleSelectors": "QVJHUzpvcHRpb24%3d%3bQVJHUzpvcHRpb24%3d%3b",
    "ruleActions": "YWxlcnQ%3d%3bYWxlcnQ%3d%3bZGVueQ%3d%3d"

Each rule-prefixed member represents a conceptual array of one facet of these rules, but encoded as a string. All rule members list facets of data for the same number of rules, or else empty data items. If you need to relate the data set to your configuration's set of component rules, you need to decode and collate the values.

Follow these steps for data members that appear within the event's attackData section:

  1. If the member name is prefixed rule, URL-decode the value. The result is a series of base64-encoded chunks delimited with semicolons, such as YWxlcnQ=;YWxlcnQ=;ZGVueQ==.


Some URL decoder libraries, like Java URLDecoder, replace + with a space. Spaces will corrupt the data. If your payload fields contain a +, make sure it's parsed correctly.

  1. Split the value at semicolon (;) characters.
  2. base64-decode each chunk of split data. The example from the first step would yield a sequence of alert, alert, and deny.

As a shortcut when processing large data sets, cache encoded strings that correspond to significant values you're looking for. For example, an encoded ZGVueQ%3d%3d string within a ruleActions indicates the request was denied.

The JSON array below reflects a conversion using the steps above, based on the encoded rule members within the sample object's attackData section. In this example, each collated member name is adapted from the original set of data:

        "rule": "950002",
        "ruleAction": "alert",
        "ruleData": "telnet.exe",
        "ruleMessage": "System Command Access",
        "ruleSelector": "ARGS:option",
        "ruleVersion": "4"
        "rule": "950006",
        "ruleAction": "alert",
        "ruleData": "telnet.exe",
        "ruleMessage": "System Command Injection",
        "ruleSelector": "ARGS:option",
        "ruleVersion": "4"
        "rule": "CMD-INJECTION-ANOMALY",
        "ruleAction": "deny",
        "ruleData": "Vector Score: 10, DENY threshold: 9, Alert Rules: 950002:950006, Deny Rule: , Last Matched Message: System Command Injection",
        "ruleMessage": "Anomaly Score Exceeded for Command Injection",
        "ruleSelector": "",
        "ruleVersion": "1"

This sample Python code produces the preceding JSON array:

import json, urllib, base64, re

# Get a JSON string for a SIEM event:
f = open("siem_event.json")
json_string =

event = json.loads(json_string)
attack_section = event['attackData']
rules_array = []

for member in attack_section:
    if member[0:4] != 'rule': continue
    # Alternate field name converted from plural:
    member_as_singular = re.sub("s$", "", member)
    url_decoded = urllib.unquote(attack_section[member]).decode('utf8')
    member_array = url_decoded.split(";")
    if not len(rules_array):
        for i in range(len(member_array)):
    i = 0
    for item in member_array:
        rules_array[i][member_as_singular] = base64.b64decode(item)
        i += 1

print json.dumps(rules_array, indent=4, ensure_ascii=True)