mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Merge pull request #740 from splunk/cloud_crypto_spl_bugs
spl bugfixes for Mustang Beta
This commit is contained in:
@@ -7,11 +7,12 @@ description: This search builds a table of previously seen users that have launc
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
and have the proper TAs installed.
|
||||
author: Rico Valdez, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created AND All_Changes.object_category=instance
|
||||
by All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")` | outputlookup previously_seen_cloud_compute_creations_by_user
|
||||
| stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created AND All_Changes.object_category=instance
|
||||
by All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| outputlookup previously_seen_cloud_compute_creations_by_user
|
||||
| stats count'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -7,12 +7,15 @@ description: This search builds a table of previously seen users that have launc
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
and have the proper TAs installed.
|
||||
author: Rico Valdez, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created AND All_Changes.object_category=instance
|
||||
by All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")` | inputlookup append=t previously_seen_cloud_compute_creations_by_user
|
||||
| stats min(firstTime) as firstTime max(lastTime) as lastTime by user
|
||||
| outputlookup previously_seen_cloud_compute_creations_by_user | stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created AND All_Changes.object_category=instance
|
||||
by All_Changes.user| `drop_dm_object_name("All_Changes")`
|
||||
| inputlookup append=t previously_seen_cloud_compute_creations_by_user
|
||||
| stats min(firstTimeSeen) as firstTimeSeen max(lastTimeSeen) as lastTimeSeen by user
|
||||
| where lastTimeSeen > relative_time(now(), "-90d@d")
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-7d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_creations_by_user'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
name: Previously Seen Cloud Compute Images - Initial
|
||||
id: 7744597f-d07a-4cea-94a7-e0f8aaebc410
|
||||
version: 1
|
||||
date: '2018-03-12'
|
||||
date: '2020-10-08'
|
||||
description: This search builds a table of previously seen images used to launch cloud
|
||||
compute instances
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
and have the Security Research cloud data model installed.
|
||||
and have the latest Change Datamodel accelerated
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created `previously_seen_cloud_compute_image_input_filter`
|
||||
by All_Changes.Instance_Changes.image_id | `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| eventstats min(firstTime) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_images
|
||||
| stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change where All_Changes.action=created by All_Changes.Instance_Changes.image_id
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| `drop_dm_object_name("Instance_Changes")`
|
||||
| where image_id != "unknown"
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-7d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_images'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -6,16 +6,17 @@ description: This search builds a table of previously seen images used to launch
|
||||
compute instances
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created `previously_seen_cloud_compute_image_input_filter` by All_Changes.Instance_Changes.image_id
|
||||
| `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| inputlookup append=t previously_seen_cloud_compute_images
|
||||
| stats min(firstTime) as firstTime max(lastTime) as lastTime by image_id
|
||||
| where lastTime > relative_time(now(), `previously_seen_cloud_compute_images_forget_window`)
|
||||
| eventstats min(firstTime) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_images
|
||||
| stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created by All_Changes.Instance_Changes.image_id
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| `drop_dm_object_name("Instance_Changes")`
|
||||
| where image_id != "unknown"
|
||||
| inputlookup append=t previously_seen_cloud_compute_images
|
||||
| stats min(firstTimeSeen) as firstTimeSeen max(lastTimeSeen) as lastTimeSeen by image_id
|
||||
| where lastTimeSeen > relative_time(now(), `previously_seen_cloud_compute_images_forget_window`)
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-7d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_images'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -7,12 +7,14 @@ description: This search builds a table of previously seen cloud compute instanc
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
and have the Security Research cloud data model installed.
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created `previously_seen_cloud_compute_instance_types_input_filter`
|
||||
by All_Changes.Instance_Changes.instance_type | `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| eventstats min(firstTime) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_instance_types | stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created
|
||||
by All_Changes.Instance_Changes.instance_type
|
||||
| `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| where instance_type != "unknown"
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_instance_types'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -6,15 +6,17 @@ description: This search builds a table of previously seen cloud compute instanc
|
||||
types
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime from datamodel=Change
|
||||
where All_Changes.action=created `previously_seen_cloud_compute_instance_types_input_filter`
|
||||
by All_Changes.Instance_Changes.instance_type | `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| inputlookup append=t previously_seen_cloud_compute_instance_types
|
||||
| stats min(firstTime) as firstTime max(lastTime) as lastTime by instance_type
|
||||
| where lastTime > relative_time(now(), `previously_seen_cloud_compute_instance_type_forget_window`)
|
||||
| eventstats min(firstTime) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_instance_types | stats count'
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created
|
||||
by All_Changes.Instance_Changes.instance_type
|
||||
| `drop_dm_object_name("All_Changes.Instance_Changes")`
|
||||
| where instance_type != "unknown"
|
||||
| inputlookup append=t previously_seen_cloud_compute_instance_types
|
||||
| stats min(firstTimeSeen) as firstTimeSeen max(lastTimeSeen) as lastTimeSeen by instance_type
|
||||
| where lastTimeSeen > relative_time(now(), `previously_seen_cloud_compute_instance_type_forget_window`)
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_compute_instance_types'
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -10,7 +10,7 @@ how_to_implement: You must be ingesting the approrpiate cloud infrastructure log
|
||||
and have the Security Research cloud data model installed.
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where (All_Changes.action=started OR All_Changes.action=created) by All_Changes.vendor_region
|
||||
where All_Changes.action=created by All_Changes.vendor_region
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
|
||||
@@ -9,14 +9,16 @@ description: This search looks for cloud compute events where a compute instance
|
||||
how_to_implement: You must be ingesting the approrpiate cloud infrastructure logs
|
||||
and have the Security Research cloud data model installed.
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change where (All_Changes.action=started OR All_Changes.action=created) by All_Changes.vendor_region
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| inputlookup append=t previously_seen_cloud_regions
|
||||
| stats min(firstTimeSeen) as firstTimeSeen max(lastTimeSeen) as lastTimeSeen by vendor_region
|
||||
| where lastTimeSeen > relative_time(now(), `previously_seen_cloud_region_forget_window`)
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_regions'
|
||||
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen from datamodel=Change
|
||||
where All_Changes.action=created by All_Changes.vendor_region
|
||||
| `drop_dm_object_name("All_Changes")` | inputlookup append=t previously_seen_cloud_regions
|
||||
| stats min(firstTimeSeen) as firstTimeSeen max(lastTimeSeen) as lastTimeSeen by vendor_region
|
||||
| where lastTimeSeen > relative_time(now(), `previously_seen_cloud_region_forget_window`)
|
||||
| eventstats min(firstTimeSeen) as globalFirstTime
|
||||
| eval enough_data = if(globalFirstTime <= relative_time(now(), "-14d@d"), 1, 0)
|
||||
| outputlookup previously_seen_cloud_regions | stats count'
|
||||
|
||||
tags:
|
||||
analytics_story:
|
||||
- Cloud Cryptomining
|
||||
|
||||
@@ -10,14 +10,18 @@ how_to_implement: You must be ingesting the appropriate cloud-infrastructure log
|
||||
type: ESCU
|
||||
references: []
|
||||
author: Rico Valdez, Splunk
|
||||
search: '| tstats `security_content_summariesonly` earliest(_time) as firstTimeSeen, latest(_time)
|
||||
as lastTimeSeen values(All_Changes.object) as dest from datamodel=Change
|
||||
where All_Changes.action=created by All_Changes.user | `drop_dm_object_name("All_Changes")`
|
||||
| lookup previously_seen_cloud_compute_creations_by_user user as user OUTPUT firstTime
|
||||
| where isnull(firstTime) OR firstTime > relative_time(now(), "-70m@m")
|
||||
| `security_content_ctime(firstTimeSeen)`
|
||||
| table firstTimeSeen, user, dest
|
||||
| `cloud_compute_instance_created_by_previously_unseen_user_filter`'
|
||||
search: '| tstats `security_content_summariesonly` count earliest(_time) as firstTime, latest(_time)
|
||||
as lastTime values(All_Changes.object) as dest from datamodel=Change
|
||||
where All_Changes.action=created by All_Changes.user All_Changes.vendor_region
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| lookup previously_seen_cloud_compute_creations_by_user user as user OUTPUTNEW firstTimeSeen, enough_data
|
||||
| eventstats max(enough_data) as enough_data
|
||||
| where enough_data=1
|
||||
| eval firstTimeSeenUser=min(firstTimeSeen)
|
||||
| where isnull(firstTimeSeenUser) OR firstTimeSeenUser > relative_time(now(), "-24h@h")
|
||||
| table firstTime, user, dest, count vendor_region
|
||||
| `security_content_ctime(firstTime)`
|
||||
| `cloud_compute_instance_created_by_previously_unseen_user_filter`'
|
||||
known_false_positives: It's possible that a user will start to create compute instances
|
||||
for the first time, for any number of reasons. Verify with the user launching instances
|
||||
that this is the intended behavior.
|
||||
|
||||
@@ -14,7 +14,15 @@ how_to_implement: "You must be ingesting your cloud infrastructure logs from you
|
||||
type: ESCU
|
||||
references: []
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, values(All_Changes.object_id) as dest, count from datamodel=Change where All_Changes.action=created by All_Changes.vendor_region, All_Changes.user | `drop_dm_object_name("All_Changes")`| lookup previously_seen_cloud_regions vendor_region as vendor_region OUTPUT firstTime | where isnull(firstTime) OR firstTime > relative_time(now(), "-70m@m") | `security_content_ctime(firstTimeSeen)`| table firstTimeSeen, user, vendor_region, count, dest | `cloud_compute_instance_created_in_previously_unused_region_filter`'
|
||||
search: '| tstats earliest(_time) as firstTime latest(_time) as lastTime values(All_Changes.object_id) as dest, count from datamodel=Change where All_Changes.action=created by All_Changes.vendor_region, All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")` | lookup previously_seen_cloud_regions vendor_region as vendor_region OUTPUTNEW firstTimeSeen, enough_data
|
||||
| eventstats max(enough_data) as enough_data
|
||||
| where enough_data=1
|
||||
| eval firstTimeSeenRegion=min(firstTimeSeen)
|
||||
| where isnull(firstTimeSeenRegion) OR firstTimeSeenRegion > relative_time(now(), "-24h@h")
|
||||
| table firstTime, user, dest, count , vendor_region
|
||||
| `security_content_ctime(firstTime)`
|
||||
| `cloud_compute_instance_created_in_previously_unused_region_filter`'
|
||||
known_false_positives: It's possible that a user has unknowingly started an instance
|
||||
in a new region. Please verify that this activity is legitimate.
|
||||
tags:
|
||||
|
||||
@@ -13,15 +13,20 @@ how_to_implement: "You must be ingesting your cloud infrastructure logs from you
|
||||
type: ESCU
|
||||
references: []
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen values(All_Changes.object_id) as dest, count
|
||||
from datamodel=Change where All_Changes.action=created `previously_seen_cloud_compute_instance_types_input_filter`
|
||||
by All_Changes.Instance_Changes.image_id, All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")` | `drop_dm_object_name("Instance_Changes")`
|
||||
| lookup previously_seen_cloud_compute_images image_id as image_id OUTPUT firstTime
|
||||
| where isnull(firstTime) OR firstTime > relative_time(now(), "-70m@m")
|
||||
| `security_content_ctime(firstTimeSeen)`
|
||||
| table firstTimeSeen, user, image_id, count, dest
|
||||
| `cloud_compute_instance_created_with_previously_unseen_image_filter`'
|
||||
search: '| tstats count earliest(_time) as firstTime, latest(_time) as lastTime values(All_Changes.object_id) as dest
|
||||
from datamodel=Change where All_Changes.action=created
|
||||
by All_Changes.Instance_Changes.image_id, All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| `drop_dm_object_name("Instance_Changes")`
|
||||
| where image_id != "unknown"
|
||||
| lookup previously_seen_cloud_compute_images image_id as image_id OUTPUT firstTimeSeen, enough_data
|
||||
| eventstats max(enough_data) as enough_data
|
||||
| where enough_data=1
|
||||
| eval firstTimeSeenImage=min(firstTimeSeen)
|
||||
| where isnull(firstTimeSeenImage) OR firstTimeSeenImage > relative_time(now(), "-24h@h")
|
||||
| table firstTime, user, image_id, count, dest
|
||||
| `security_content_ctime(firstTime)`
|
||||
| `cloud_compute_instance_created_with_previously_unseen_image_filter`'
|
||||
known_false_positives: After a new image is created, the first systems created with
|
||||
that image will cause this alert to fire. Verify that the image being used was
|
||||
created by a legitimate user.
|
||||
|
||||
@@ -12,15 +12,20 @@ how_to_implement: "You must be ingesting your cloud infrastructure logs from you
|
||||
type: ESCU
|
||||
references: []
|
||||
author: David Dorsey, Splunk
|
||||
search: '| tstats earliest(_time) as firstTimeSeen, latest(_time) as lastTimeSeen values(All_Changes.object_id) as dest, count
|
||||
from datamodel=Change where All_Changes.action=created `previously_seen_cloud_compute_instance_types_input_filter`
|
||||
by All_Changes.Instance_Changes.instance_type, All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")` | `drop_dm_object_name("Instance_Changes")`
|
||||
| lookup previously_seen_cloud_compute_instance_types instance_type as instance_type OUTPUT firstTime
|
||||
| where isnull(firstTime) OR firstTime > relative_time(now(), "-70m@m")
|
||||
| `security_content_ctime(firstTimeSeen)`
|
||||
| table firstTimeSeen, user, instance_type, count, dest
|
||||
| `cloud_compute_instance_created_with_previously_unseen_instance_type_filter`'
|
||||
search: '| tstats earliest(_time) as firstTime, latest(_time) as lastTime values(All_Changes.object_id) as dest, count
|
||||
from datamodel=Change where All_Changes.action=created
|
||||
by All_Changes.Instance_Changes.instance_type, All_Changes.user
|
||||
| `drop_dm_object_name("All_Changes")`
|
||||
| `drop_dm_object_name("Instance_Changes")`
|
||||
| where instance_type != "unknown"
|
||||
| lookup previously_seen_cloud_compute_instance_types instance_type as instance_type OUTPUTNEW firstTimeSeen, enough_data
|
||||
| eventstats max(enough_data) as enough_data
|
||||
| where enough_data=1
|
||||
| eval firstTimeSeenInstanceType=min(firstTimeSeen)
|
||||
| where isnull(firstTimeSeenInstanceType) OR firstTimeSeenInstanceType > relative_time(now(), "-24h@h")
|
||||
| table firstTime, user, dest, count, instance_type
|
||||
| `security_content_ctime(firstTime)`
|
||||
| `cloud_compute_instance_created_with_previously_unseen_instance_type_filter`'
|
||||
known_false_positives: It is possible that an admin will create a new system using
|
||||
a new instance type that has never been used before. Verify with the creator that
|
||||
they intended to create the system with the new instance type.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
firstTime,lastTime,src_user
|
||||
|
@@ -1,4 +1,4 @@
|
||||
description: A table of source IPs, geographic locations, and the first and last time that they have that done cloud provisioning activities
|
||||
description: A table of previously seen users creating cloud instances
|
||||
collection: previously_seen_cloud_compute_creations_by_user
|
||||
name: previously_seen_cloud_compute_creations_by_user
|
||||
fields_list: _key, firstTime, lastTime, user, enough_data
|
||||
fields_list: _key, firstTimeSeen, lastTimeSeen, user, enough_data
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
firstTime,lastTime,image_id
|
||||
|
@@ -1,5 +1,4 @@
|
||||
default_match: 'false'
|
||||
description: A place holder for a list of used cloud compute images
|
||||
filename: previously_seen_cloud_compute_images.csv
|
||||
min_matches: 1
|
||||
description: A table of previously seen Cloud image IDs
|
||||
collection: previously_seen_cloud_compute_images
|
||||
name: previously_seen_cloud_compute_images
|
||||
fields_list: _key, firstTimeSeen, lastTimeSeen, image_id, enough_data
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
firstTime,lastTime,instance_type
|
||||
|
@@ -1,5 +1,4 @@
|
||||
default_match: 'false'
|
||||
description: A place holder for a list of used cloud compute instance types
|
||||
filename: previously_seen_cloud_compute_instance_types.csv
|
||||
min_matches: 1
|
||||
collection: previously_seen_cloud_compute_instance_types
|
||||
name: previously_seen_cloud_compute_instance_types
|
||||
fields_list: _key, firstTimeSeen, lastTimeSeen, instance_type, enough_data
|
||||
|
||||
@@ -1 +1 @@
|
||||
firstTime,lastTime,region
|
||||
firstTimeSeen, lastTimeSeen, vendor_region, enough_data
|
||||
|
@@ -1,4 +1,4 @@
|
||||
description: A table of vendor_region values and the first and last time that they have been observed in cloud provisioning activities
|
||||
collection: previously_seen_cloud_regions
|
||||
name: previously_seen_cloud_regions
|
||||
fields_list: _key, firstTime, lastTime, vendor_region, enough_data
|
||||
fields_list: _key, firstTimeSeen, lastTimeSeen, vendor_region, enough_data
|
||||
|
||||
Reference in New Issue
Block a user