Detection rules › Splunk
PingID New MFA Method Registered For User
The following analytic detects the registration of a new Multi-Factor Authentication (MFA) method for a PingID (PingOne) account. It leverages JSON logs from PingID, specifically looking for successful device pairing events. This activity is significant as adversaries who gain unauthorized access to a user account may register a new MFA method to maintain persistence. If confirmed malicious, this could allow attackers to bypass existing security measures, maintain long-term access, and potentially escalate their privileges within the compromised environment.
Known false positives
- False positives may be generated by normal provisioning workflows for user device registration.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation | |
| Defense Impairment | |
| Credential Access |
Rule body
name: PingID New MFA Method Registered For User
id: 892dfeaf-461d-4a78-aac8-b07e185c9bce
version: 8
creation_date: '2023-12-20'
modification_date: '2026-05-13'
author: Steven Dick
status: production
type: TTP
description: The following analytic detects the registration of a new Multi-Factor Authentication (MFA) method for a PingID (PingOne) account. It leverages JSON logs from PingID, specifically looking for successful device pairing events. This activity is significant as adversaries who gain unauthorized access to a user account may register a new MFA method to maintain persistence. If confirmed malicious, this could allow attackers to bypass existing security measures, maintain long-term access, and potentially escalate their privileges within the compromised environment.
data_source:
- PingID
search: "`pingid` \"result.message\"=\"Device Paired*\" result.status=\"SUCCESS\" | rex field=result.message \"Device (Unp)?(P)?aired (?<device_extract>.+)\" | eval src = coalesce('resources{}.ipaddress','resources{}.devicemodel'), user = upper('actors{}.name'), reason = 'result.message' | eval object=CASE(ISNOTNULL('resources{}.devicemodel'),'resources{}.devicemodel',true(),device_extract) | eval action=CASE(match('result.message',\"Device Paired*\"),\"created\",match('result.message', \"Device Unpaired*\"),\"deleted\") | stats count min(_time) as firstTime, max(_time) as lastTime by src,user,object,action,reason | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)` | `pingid_new_mfa_method_registered_for_user_filter`"
how_to_implement: Target environment must ingest JSON logging from a PingID(PingOne) enterprise environment, either via Webhook or Push Subscription.
known_false_positives: False positives may be generated by normal provisioning workflows for user device registration.
references:
- https://twitter.com/jhencinski/status/1618660062352007174
- https://attack.mitre.org/techniques/T1098/005/
- https://attack.mitre.org/techniques/T1556/006/
- https://docs.pingidentity.com/r/en-us/pingoneforenterprise/p14e_subscriptions?tocId=3xhnxjX3VzKNs3SXigWnQA
finding:
title: An MFA configuration change was detected for [$user$], the device [$object$] was $action$.
entity:
field: user
type: user
score: 50
intermediate_findings:
entities:
- field: src
type: system
score: 50
message: An MFA configuration change was detected for [$user$], the device [$object$] was $action$.
analytic_story:
- Compromised User Account
asset_type: Identity
mitre_attack_id:
- T1621
- T1556.006
- T1098.005
product:
- Splunk Enterprise
- Splunk Enterprise Security
- Splunk Cloud
category: application
security_domain: access
Stages and Predicates
Stage 1: search
`pingid` "result.message"="Device Paired*" result.status="SUCCESS"
Stage 2: rex
| rex field=result.message "Device (Unp)?(P)?aired (?<device_extract>.+)"
Stage 3: eval
| eval src = coalesce('resources{}.ipaddress','resources{}.devicemodel'), user = upper('actors{}.name'), reason = 'result.message'
Stage 4: eval
| eval object=CASE(ISNOTNULL('resources{}.devicemodel'),'resources{}.devicemodel',true(),device_extract)
object =if
isnotnull('resources{}.devicemodel')'resources{}.devicemodel'else
device_extractStage 5: eval
| eval action=CASE(match('result.message',"Device Paired*"),"created",match('result.message', "Device Unpaired*"),"deleted")
action =if
match('result.message', "Device Paired*")"created"else
"deleted"Stage 6: stats
| stats count min(_time) as firstTime, max(_time) as lastTime by src,user,object,action,reason
Stage 7: search
| `security_content_ctime(firstTime)`
Stage 8: search
| `security_content_ctime(lastTime)`
Stage 9: search
| `pingid_new_mfa_method_registered_for_user_filter`
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
result.message | eq |
| field:"result.message" kind:eq |
result.status | eq |
| field:"result.status" kind:eq |