CrowdStrike SIEM FreeRADIUS Syslog Parser
There is no native syslog parser for FreeRADIUS syslog inputs in the CrowdStrike SIEM. In this article, we will create a parser for FreeRADIUS syslogs to turn them into searchable inputs in the CrowdStrike SIEM.
Get HanSolo71’s stories in your inbox
Join Medium for free to get updates from this writer.
Here is the parser in all its glory:
// FreeRADIUS radius.log parser - Falcon Next-Gen SIEM / LogScale
// Parser.version 1.0.0
// 1. Static metadata (CPS)
Vendor := "freeradius"
| event.module := "freeradius"
| event.kind := "event"
| event.dataset := "freeradius.log"
| observer.vendor := "FreeRADIUS"
| observer.product := "FreeRADIUS"
| ecs.version := "8.11.0"
| Cps.version := "1.0.0"
| Parser.version := "1.0.0"
// 2. Common prefix: timestamp, level, request ID, message
| case {
@rawstring = /(?:(?<_ts>(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+[A-Z][a-z]{2}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s+:\s+)?(?:(?<_lvl>Auth|Info|Error|ERROR|Warn|WARNING|Proxy|Debug):\s+)?\((?<_reqid>\d+)\)\s+(?<_msg>.*)$/ ;
@rawstring = /(?:(?<_ts>(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+[A-Z][a-z]{2}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s+:\s+)?(?<_lvl>Auth|Info|Error|ERROR|Warn|WARNING|Proxy|Debug):\s+(?<_msg>.*)$/ ;
* | _msg := @rawstring ;
}
// 3. Timestamp (FreeRADIUS writes local time with no zone)
| case {
_ts = *
| _ts := replace(regex=" +", with=" ", field=_ts)
| parseTimestamp(format="EEE MMM d HH:mm:ss yyyy", field=_ts, timezone="America/Detroit") ;
* ;
}
| case { _lvl = * | lower(field=_lvl, as=log.level) ; * ; }
// 4. Authentication results
| case {
_msg = /(?<_result>Login OK|Login incorrect|Invalid user)(?:\s+\((?<_reason>.*?)\))?:\s+\[(?<_user>[^\]]*)\]\s+\(from client\s+(?<_client>\S+)\s+port\s+(?<_port>\S+)(?:\s+cli\s+(?<_cli>[^\s)]+))?(?:\s+via\s+(?<_via>[^)]+))?\)/
| event.dataset := "freeradius.auth"
| array:append(array="event.category[]", values=["authentication"])
| radius.result := _result
| case {
_result = "Login OK"
| event.outcome := "success"
| event.action := "login-ok"
| array:append(array="event.type[]", values=["start"]) ;
_result = "Login incorrect"
| event.outcome := "failure"
| event.action := "login-incorrect"
| array:append(array="event.type[]", values=["info"]) ;
*
| event.outcome := "failure"
| event.action := "invalid-user"
| array:append(array="event.type[]", values=["info"]) ;
}
// [user], [user/password] or [user/<via Auth-Type = eap>]
| _user = /^(?<_uname>[^\/]*)(?:\/(?<_after>.*))?$/
| user.name := _uname
| case {
_after = /^<(?<_hint>.*)>$/ | radius.auth_type_hint := _hint ;
* ; // anything else after "/" is a logged password: never stored
}
// Normalise MAC to ECS format (E6-0A-41-89-97-38)
| case {
_cli = /^(?:[0-9A-Fa-f]{2}[:\-]){5}[0-9A-Fa-f]{2}$/
| _mac := replace(regex=":", with="-", field=_cli)
| upper(field=_mac, as=source.mac) ;
* ;
} ;
* ;
}
// 5. Final field names and cleanup
| rename(field=[[_reqid, radius.request_id], [_msg, message], [_reason, event.reason], [_client, radius.client.shortname], [_port, radius.nas_port], [_cli, radius.calling_station_id], [_via, radius.tunnel]])
| drop([_ts, _lvl, _result, _user, _uname, _after, _hint, _mac])This will take a raw syslog input like this:
Tue Nov 10 17:51:46 2026 : Auth: (319071) Login OK: [first.last] (from client company-ap1 port 1 cli 4a-d8-33-b9-xx-xx-xx)And create a output log with the following formatting:
#Cps.version:1.0.0
#ecs.version:8.11.0
#error:true
#event.dataset:freeradius.auth
#event.kind:event
#event.module:freeradius
#event.outcome:success
#repo:3pi_auto_raptor_1780967367223
#repo.cid:7ed24ffd469d4f5faa5f776a43d98e04
#type:RadiusLogs
#Vendor:freeradius
@collect.file:/var/log/freeradius/radius.log
@collect.host:usfitrad04
@collect.id:f0e55514-1b65-4cf5-xxxx-xxxxxxxxxxx
@collect.source_name:RadiusLogs
@collect.source_type:file
@collect.timestamp:1794333106834
@collect.timezone:UTC
@dataConnectionID:5a70a1aba55545108aee6exxxxxxxxx
@dataConnectionReceiveID:8974294766e2582500f24xxxxxxx
@dataConnectionReceiveTimestamp:1794333107996
@error:true
@error_msg:timestamp was set to a value in the future. Setting it to now
@error_msg[0]:timestamp was set to a value in the future. Setting it to now
@id:o7bUnjdXHXNYDFT5z0lVKieX_1_9_1794333108
@ingesttimestamp:1794333108022
@rawstring:Tue Nov 10 17:51:46 2026 : Auth: (319071) Login OK: [first.last] (from client company-ap1 port 1 cli 4a-d8-33-xx-xx-xx)
@source:PlatformEvents
@sourcetype:RadiusLogs
@timestamp:1794333108022
@timestamp.nanos:0
@timezone:America/Detroit
event.action:login-ok
event.category[0]:authentication
event.type[0]:start
log.level:auth
message:Login OK: [first.last] (from client company-ap1 port 1 cli 4a-d8-33-xx-xx-xx)
observer.product:FreeRADIUS
observer.vendor:FreeRADIUS
Parser.version:1.0.0
radius.calling_station_id:4a-d8-33-xx-xx-xx
radius.client.shortname:company-ap1
radius.nas_port:1
radius.request_id:319071
radius.result:Login OK
source.mac:4A-D8-33-B9-F4-06
user.name:first.last






