Skip to main content

Fluency SIEM APIs

Fluency's own SIEM API functions are also exposed and accessed via FPL.

Fluency_EntityinfoCheck

  • Fluency_EntityinfoCheck(entity, key)
    • checks if key exists in the entity table
    • return true if key exists in the table and false otherwise
let hit = Fluency_EntityinfoCheck("HOME_NET", "20.0.0.1")
if (hit) {
printf("home net")
} else {
printf("internet")
}

Fluency_EntityinfoLookup

  • Fluency_EntityinfoLookup(entityinfo_tablename, keyCol, key, valueCol)
    • check value from one column based on key column value
    • return an object {exist, value}
    • all arguments are type "string"

Example Code:

  // eid = 4719
let eventID = sprintf("%v",eid)
let {exist, value} = fluencyEntityinfoLookup("AD_EventID", "Event ID", eventID, "Description")
if (exist) {
printf("value '%s'", value)
}

Example EntityInfo Table: AD_EventID

Event IDDescription
1100The event logging service has shut down
......
4719System audit policy was changed
......

Example Output:

printf: value 'System audit policy was changed'

Platform_EntityProvider_Lookup

  • Platform_EntityProvider_Lookup(plugin, customer, key)
    • gets the entity infos for the plugin, customer and key
    • returns an array of entity info entries
      • each entry uses the default entity info format, {id, obj, entity}
  let agentInfos = Platform_EntityProvider_Lookup("SentinelOne", "*", agentID)
if len(agentInfos) > 0 {
let agentInfo = agentInfos[0]
newObj.agent = agentInfo.obj
newObj.uuid = agentID
envelop.obj["entity"] = agentInfo.entity
} else {
// printf("agentID lookup missing: %s", agentID)
}

Platform_EntityProvider_Refresh

  • Platform_EntityProvider_Refresh(plugin, customer, entries)
    • the default entity info entry: {id, obj, entity}
      • id is the entity key: EDR agent uuid, device name or username. Must be unique for each integration
      • obj is the entity object from the vendor
      • entity is the normalized fields for UEBA correlation: {agentID, username, asset, ADAsset, ADUser, privateIP, publicIP}
      • typical use case is to run Platform_EntityProvider_Refresh as a hourly cronjob. Then run Platform_EntityProvider_Lookup in FPL parser or rule.
function main(doc) {
Platform_PluginLambda("SentinelOne", "*", (customer) => {
let agents = Plugin_SentinelOne_LoadAgent()
let agentInfos = agents.Map( (_, obj) => {
// printf("uuid %s", obj.uuid)
let entity = {
agentID: obj.uuid,
username: obj.externalId,
asset: obj.computerName,
ADAsset: obj.activeDirectory?.computerDistinguishedName,
ADUser: obj.activeDirectory?.lastUserDistinguishedName
}
if obj.machineType == "server" {
entity.privateIP = obj.lastIpToMgmt
}
return {
id: obj.uuid,
obj: obj,
entity: entity
}
})
Platform_EntityProvider_Refresh("SentinelOne", customer, agentInfos)
return {}
})
return {}
}

Fluency_LavadbFpl

  • Fluency_LavadbFpl(searchText)
    • Search LavaDB in FPL (v1)
    • typically the searchText uses the template function
    • return the search result in the form of a table
    • this function will throw an exception if there is an error in the fplv1 search
      • aggregate on a column that does not exist will cause an exception
let office_aad_by_ops_fpl = `
search {from="{{.from}}", to="{{.to}}"} sContent("@sender","office365") and sContent("@source","Audit.AzureActiveDirectory")
let { {{ .groupBy }} } = f("@fields")
aggregate events = count() by {{ .groupBy }}
sort 15 events
`

let office_aad_by_ops = fluencyLavadbFpl(
template(office_aad_by_ops_fpl, {from:"-24h", to:"@h", groupBy: "Operation"})
)

return {office_aad_by_ops}

NOTE: Returns exception: exception: ServiceError: fluencyLavadbFpl: function search error

Fluency_LavadbQuery

  • Fluency_LavadbQuery(query, options, ()=>{})
    • Search LavaDB with Lucene query
    • options: {from, to, dataType}
    • from, to could be relative time "@h", "@m", "@d" or absolute time "2021-01-01T00:00:00Z", OR unix epoch time in millisecond
    • dataType: "event" or "metaflow"
let hits = Fluency_LavadbQuery("", {from:"-4h@m", to:"@m"}, (obj) => {
return {sender:obj["@sender"], source:obj["@source"]}
})
return {hits}

Fluency_BehaviorSearch

  • Fluency_BehaviorSearch(query, from, to, ()⇒{})
    • Search Fluency Behavior Event database

NOTE: This function is limited to returning 8192 entries per call. The from and to window should be made smaller to stay under this limit.

NOTE: 'from' and 'to' are inclusive for this API

function main() {
let query = `behaviorRule:"O365_AzureAD_Add_Member_To_Group"`
let matchingEvents = Fluency_BehaviorSearch(query, "-2d@d", "@d", (obj) => {
let ActorIDs = obj.attributes.Find((_, x) => x.aliase == "ActorIDs").value
let GroupDisplayName = obj.attributes.Find((_, x) => x.aliase == "GroupDisplayName").value
let Operation = obj.attributes.Find((_, x) => x.aliase == "Operation").value
let Username = obj.attributes.Find((_, x) => x.aliase == "Username").value

let ts = new Time(obj.timestamp)

return {Username, Operation, ActorIDs, GroupDisplayName, ActorIDs, Date: ts.Format("2006-01-02T15:04:05Z07:00")}
})
return {matchingEvents}
}
function main(){
let behaviorEvents = Fluency_BehaviorSearch("riskScore: [100 TO *]", "-10d@m", "@m", (obj) => {
let {behaviorRule, behavior, riskScore, key } = obj
return {behaviorRule, behavior, riskScore, key}
})
return {behaviorEvents}
}

Fluency_SummarySearch

  • Fluency_SummarySearch(query, from, to, ()⇒{})
    • Search Fluency Behavior Summary database
function main() {
let behaviorSummary = Fluency_SummarySearch("riskScore: [3000 TO *] AND NOT (status:new)", "-10d@m", "@m", (obj) => {
let {id, behaviorRules, riskScore, key, dayIndex, status } = obj
return {id, obj, behaviorRules, riskScore, key, dayIndex, status}
})

return {behaviorSummary}
}

Fluency_ResourceLoad

  • Fluency_ResourceLoad(vendor, resource, customer, (obj <,customer>)⇒ {})
    • loads the resource from a vendor with customer where each vendor has their own type of resources
    • throws a ServiceError exception if no results are found
    • vendor: Office365: resource: user, group, device, application, installedApp
    • vendor Sentinelone: resource: agent, threat, application
    • vendor AD: resource: user, asset
    • vendor fehx (FireEyeHx): resource: device
    • vendor Qualys: resource: host
    • using "*" on customer will get results from all customers
function main() {
let users = Fluency_ResourceLoad("office365", "user", "*", (obj, customer) => {
let fields = obj["@office365User"]
let {userType, userPrincipalName, roles, accountEnabled, createdDateTime} = fields
return {customer, userType, userPrincipalName, roles, accountEnabled, createdDateTime}
})
return {users}
}

Fluency_DeviceSearch

  • Fluency_DeviceSearch(query, from, to, ()=>{})
    • Search Fluency Import Device database for devices created within the time frame
let newDevices = Fluency_DeviceSearch("", "-7d@m", "@m", (obj) => {
let {name, group, device:{name:devName, category}, ips, createdOn} = obj
return {name, group, devName, category, ips, createdOn}
})

Fluency_Device_Lookup

  • Fluency_Device_Lookup(ipAddress)
    • Lookup device information by ipAddress from Fluency Device database

Fluency_Device_LookupName

  • Fluency_Device_LookupName(deviceName)
    • Lookup device information by name from Fluency Device database

Fluency_Device_Add

  • Fluency_Device_Add(device)
    • Add device information to Fluency Device database

Fluency_Device_Update

  • Fluency_Device_Update(ipAddress, newName)
    • assigns ipAddress to a new name
function main({obj, size}) {

let sender = obj["@sender"]
let deviceEntry = Fluency_Device_Lookup(sender)

if (deviceEntry) {
printf("%s", deviceEntry)
} else {
printf("device not found")
deviceEntry = {
name:"$name",
description:"Added by FPL processor",
ips: [sender],
group:"$group",
device: {
name:"$subCategory",
category:"$category"
}
}
Fluency_Device_Add(deviceEntry)
}
// call platform metric api...

return "pass"
}

Fluency_FusionEvent

  • Fluency_FusionEvent(partition, source)
    • Send Fusion Event to Fluency Fusion Service (legacy)
let t = new Time()
let partition={
partition: "default",
dataType: "event",
time_ms: t.UnixMilli()
}
let source={
logon: {
ip:"10.132.47.10",
domain:"TERPLAB.COM",
username:"foobar"
},
dtype:"windows-logon"
}
Fluency_FusionEvent(partition, source)