Skip to content

Commit f4a5cb9

Browse files
committed
Haag's SQL Server Story Time: Tales of SQLCMD and Suspicious Queries 📚
1 parent bc334de commit f4a5cb9

11 files changed

+807
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: Windows PowerShell Invoke-Sqlcmd Execution
2+
id: 5eb76fe2-a869-4865-8c4c-8cff424b18a1
3+
version: 1
4+
date: '2025-02-03'
5+
author: Michael Haag, Splunk
6+
status: production
7+
type: Anomaly
8+
description: This detection identifies potentially suspicious usage of Invoke-Sqlcmd PowerShell cmdlet, which can be used for database operations and potential data exfiltration. The detection looks for suspicious parameter combinations and query patterns that may indicate unauthorized database access, data theft, or malicious database operations. Threat actors may prefer using PowerShell Invoke-Sqlcmd over sqlcmd.exe as it provides a more flexible programmatic interface and can better evade detection.
9+
data_source:
10+
- Powershell Script Block Logging 4104
11+
search: '`powershell` EventCode=4104 ScriptBlockText="*invoke-sqlcmd*"
12+
| eval script_lower=lower(ScriptBlockText)
13+
| eval
14+
has_query=case(
15+
match(script_lower, "(?i)-query\\s+"), 1,
16+
match(script_lower, "(?i)-q\\s+"), 1,
17+
true(), 0
18+
),
19+
has_input_file=case(
20+
match(script_lower, "(?i)-inputfile\\s+"), 1,
21+
match(script_lower, "(?i)-i\\s+"), 1,
22+
true(), 0
23+
),
24+
has_url_input=case(
25+
match(script_lower, "(?i)-inputfile\\s+https?://"), 1,
26+
match(script_lower, "(?i)-i\\s+https?://"), 1,
27+
match(script_lower, "(?i)-inputfile\\s+ftp://"), 1,
28+
match(script_lower, "(?i)-i\\s+ftp://"), 1,
29+
true(), 0
30+
),
31+
has_admin_conn=case(
32+
match(script_lower, "(?i)-dedicatedadministratorconnection"), 1,
33+
true(), 0
34+
),
35+
has_suspicious_auth=case(
36+
match(script_lower, "(?i)-username\\s+sa\\b"), 1,
37+
match(script_lower, "(?i)-u\\s+sa\\b"), 1,
38+
match(script_lower, "(?i)-username\\s+admin\\b"), 1,
39+
match(script_lower, "(?i)-u\\s+admin\\b"), 1,
40+
true(), 0
41+
),
42+
has_suspicious_query=case(
43+
match(script_lower, "(?i)(xp_cmdshell|sp_oacreate|sp_execute_external|openrowset|bulk\\s+insert)"), 1,
44+
match(script_lower, "(?i)(master\\.\\.\\.sysdatabases|msdb\\.\\.\\.backuphistory|sysadmin|securityadmin)"), 1,
45+
match(script_lower, "(?i)(select.*from.*sys\\.|select.*password|dump\\s+database)"), 1,
46+
match(script_lower, "(?i)(sp_addextendedproc|sp_makewebtask|sp_addsrvrolemember)"), 1,
47+
match(script_lower, "(?i)(sp_configure.*show\\s+advanced|reconfigure|enable_xp_cmdshell)"), 1,
48+
match(script_lower, "(?i)(exec.*master\\.dbo\\.|exec.*msdb\\.dbo\\.)"), 1,
49+
match(script_lower, "(?i)(sp_password|sp_control_dbmasterkey_password|sp_dropextendedproc)"), 1,
50+
match(script_lower, "(?i)(powershell|cmd\\.exe|rundll32|regsvr32|certutil)"), 1,
51+
true(), 0
52+
),
53+
has_data_exfil=case(
54+
match(script_lower, "(?i)-outputas\\s+(dataset|datatables)"), 1,
55+
match(script_lower, "(?i)-as\\s+(dataset|datatables)"), 1,
56+
match(script_lower, "(?i)(for\\s+xml|for\\s+json)"), 1,
57+
match(script_lower, "(?i)(select.*into.*from|select.*into.*outfile)"), 1,
58+
true(), 0
59+
),
60+
has_cert_bypass=case(
61+
match(script_lower, "(?i)-trustservercertificate"), 1,
62+
true(), 0
63+
)
64+
65+
| eval risk_score=0
66+
| eval risk_score=case(
67+
has_suspicious_query=1 AND has_data_exfil=1, risk_score + 90,
68+
has_url_input=1, risk_score + 80,
69+
has_suspicious_query=1, risk_score + 60,
70+
has_data_exfil=1, risk_score + 60,
71+
has_admin_conn=1, risk_score + 50,
72+
has_suspicious_auth=1, risk_score + 40,
73+
has_cert_bypass=1, risk_score + 20,
74+
true(), risk_score
75+
)
76+
77+
| eval command_type=case(
78+
match(script_lower, "xp_cmdshell"), "xp_cmdshell abuse",
79+
match(script_lower, "https?://"), "Remote file execution",
80+
match(script_lower, "sys\\.server_principals"), "System enumeration",
81+
match(script_lower, "fn_my_permissions"), "Permission enumeration",
82+
match(script_lower, "username\\s+sa\\b"), "SA account usage",
83+
match(script_lower, "show\\s+advanced\\s+options"), "Configuration change attempt",
84+
match(script_lower, "select.*from\\s+customers"), "Large data export",
85+
match(script_lower, "select.*password"), "Sensitive data query",
86+
match(script_lower, "sp_configure.*xp_cmdshell"), "Enable xp_cmdshell",
87+
1=1, "General database access"
88+
)
89+
90+
| eval risk_factors=mvappend(
91+
if(has_suspicious_query=1 AND has_data_exfil=1, "High-risk query with data extraction: ".command_type, null()),
92+
if(has_url_input=1, "Remote file input detected in command", null()),
93+
if(has_suspicious_query=1, "Suspicious SQL query pattern: ".command_type, null()),
94+
if(has_data_exfil=1, "Potential data exfiltration using ".command_type, null()),
95+
if(has_admin_conn=1, "Administrative database connection", null()),
96+
if(has_suspicious_auth=1, "Suspicious authentication method used", null()),
97+
if(has_cert_bypass=1, "Certificate validation bypassed", null())
98+
)
99+
| eval risk_message="PowerShell Invoke-Sqlcmd execution with risk factors: ".mvjoin(risk_factors, ", ")
100+
101+
| where risk_score >= 30
102+
| stats count min(_time) as firstTime max(_time) as lastTime by EventCode ScriptBlockText UserID Computer risk_message risk_score command_type
103+
| rename Computer as dest, UserID as user
104+
| `security_content_ctime(firstTime)`
105+
| `security_content_ctime(lastTime)`
106+
| `windows_powershell_invoke_sqlcmd_execution_filter`'
107+
how_to_implement: To successfully implement this detection, you need to be ingesting PowerShell logs with Script Block Logging and Module Logging enabled. The detection looks for Invoke-Sqlcmd usage in PowerShell scripts and evaluates the parameters and queries for suspicious patterns. Configure your PowerShell logging to capture script block execution and ensure the logs are mapped to the PowerShell node of the Endpoint data model.
108+
known_false_positives: Database administrators and developers frequently use Invoke-Sqlcmd as a legitimate tool for various database management tasks. This includes running automated database maintenance scripts, performing ETL (Extract, Transform, Load) processes, executing data migration jobs, implementing database deployment and configuration scripts, and running monitoring and reporting tasks. To effectively manage false positives in your environment, consider implementing several mitigation strategies. First, establish a whitelist of known administrator and service accounts that regularly perform these operations. Second, create exceptions for approved script paths where legitimate database operations typically occur. Additionally, it's important to baseline your environment's normal PowerShell database interaction patterns and implement monitoring for any deviations from these established patterns. Finally, consider adjusting the risk score thresholds based on your specific environment and security requirements to achieve an optimal balance between security and operational efficiency.
109+
references:
110+
- https://learn.microsoft.com/en-us/powershell/module/sqlserver/invoke-sqlcmd
111+
- https://attack.mitre.org/techniques/T1059.001/
112+
- https://attack.mitre.org/techniques/T1059.003/
113+
drilldown_searches:
114+
- name: View process details for suspicious Invoke-Sqlcmd execution
115+
search: '%original_detection_search% | search dest="$dest$" user="$user$"'
116+
earliest_offset: $info_min_time$
117+
latest_offset: $info_max_time$
118+
- name: View risk events for the last 7 days for - "$dest$" and "$user$"
119+
search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$dest$", "$user$") starthoursago=168 | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
120+
earliest_offset: $info_min_time$
121+
latest_offset: $info_max_time$
122+
rba:
123+
message: A PowerShell script contains Invoke-Sqlcmd command with EventCode $EventCode$ on host $dest$
124+
risk_objects:
125+
- field: dest
126+
type: system
127+
score: 49
128+
- field: user
129+
type: user
130+
score: 49
131+
threat_objects: []
132+
tags:
133+
analytic_story:
134+
- SQL Server Abuse
135+
asset_type: Endpoint
136+
mitre_attack_id:
137+
- T1059.001
138+
- T1059.003
139+
product:
140+
- Splunk Enterprise
141+
- Splunk Enterprise Security
142+
- Splunk Cloud
143+
security_domain: endpoint
144+
tests:
145+
- name: True Positive Test
146+
attack_data:
147+
- data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1059.003/atomic_red_team/invokesqlcmd_powershell.log
148+
source: XmlWinEventLog:Microsoft-Windows-PowerShell/Operational
149+
sourcetype: XmlWinEventLog
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Windows SQL Server Configuration Option Hunt
2+
id: 8dc9efd5-805a-460e-889e-bc79e5477af9
3+
version: 1
4+
date: '2025-02-06'
5+
author: Michael Haag, Splunk
6+
status: production
7+
type: Hunting
8+
description: This detection helps hunt for changes to SQL Server configuration options that could indicate malicious activity. It monitors for modifications to any SQL Server configuration settings, allowing analysts to identify potentially suspicious changes that may be part of an attack, such as enabling dangerous features or modifying security-relevant settings.
9+
data_source:
10+
- Windows Event Log Application
11+
search: '`wineventlog_application` EventCode=15457
12+
| rex field=EventData_Xml "<Data>(?<config_name>[^<]+)</Data><Data>(?<new_value>[^<]+)</Data><Data>(?<old_value>[^<]+)</Data>"
13+
| rename host as dest
14+
| eval change_type=case(
15+
old_value="0" AND new_value="1", "enabled",
16+
old_value="1" AND new_value="0", "disabled",
17+
true(), "modified"
18+
)
19+
| eval risk_score=case(
20+
change_type="enabled", 90,
21+
change_type="disabled", 60,
22+
true(), 70
23+
)
24+
| eval risk_message="SQL Server ".config_name." was ".change_type." on host ".dest
25+
| stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode config_name change_type risk_message risk_score
26+
| `security_content_ctime(firstTime)`
27+
| `security_content_ctime(lastTime)` | `windows_sql_server_configuration_option_hunt_filter`'
28+
how_to_implement: To successfully implement this detection, you need to be ingesting Windows Application Event Logs from SQL Server instances. The detection specifically looks for EventID 15457 which indicates configuration changes to SQL Server settings. Ensure proper logging is enabled for SQL Server configuration changes and that the logs are being forwarded to your SIEM.
29+
known_false_positives: Database administrators frequently make legitimate configuration changes for maintenance, performance tuning, and security hardening. To reduce false positives, establish a baseline of normal configuration changes, document approved configuration modifications, implement change control procedures, and maintain an inventory of expected settings.
30+
references:
31+
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/server-configuration-options-sql-server
32+
- https://attack.mitre.org/techniques/T1505/001/
33+
- https://www.netspi.com/blog/technical/network-penetration-testing/sql-server-persistence-part-1-startup-stored-procedures/
34+
drilldown_searches:
35+
- name: View configuration changes on this host
36+
search: '%original_detection_search% | search dest="$dest$"'
37+
earliest_offset: $info_min_time$
38+
latest_offset: $info_max_time$
39+
- name: View all SQL Server configuration changes in the last 7 days
40+
search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$dest$") starthoursago=168 | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
41+
earliest_offset: -7d
42+
latest_offset: now
43+
tags:
44+
analytic_story:
45+
- SQL Server Abuse
46+
asset_type: Windows
47+
mitre_attack_id:
48+
- T1505.001
49+
- T1505
50+
product:
51+
- Splunk Enterprise
52+
- Splunk Enterprise Security
53+
- Splunk Cloud
54+
security_domain: endpoint
55+
cve: []
56+
tests:
57+
- name: True Positive Test
58+
attack_data:
59+
- data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1505.001/simulation/windows-application.log
60+
sourcetype: XmlWinEventLog
61+
source: XmlWinEventLog:Application
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Windows SQL Server Critical Procedures Enabled
2+
id: d0434864-b043-41e3-8c08-30e53605e9cb
3+
version: 1
4+
date: '2025-02-06'
5+
author: Michael Haag, Splunk
6+
status: production
7+
type: TTP
8+
description: This detection identifies when critical SQL Server configuration options are modified, including "Ad Hoc Distributed Queries", "external scripts enabled", "Ole Automation Procedures", "clr enabled", and "clr strict security". These features can be abused by attackers for various malicious purposes - Ad Hoc Distributed Queries enables Active Directory reconnaissance through ADSI provider, external scripts and Ole Automation allow execution of arbitrary code, and CLR features can be used to run custom assemblies. Enabling these features could indicate attempts to gain code execution or perform reconnaissance through SQL Server.
9+
data_source:
10+
- Windows Event Log Application
11+
search: '`wineventlog_application` EventCode=15457
12+
| rex field=EventData_Xml "<Data>(?<config_name>[^<]+)</Data><Data>(?<new_value>[^<]+)</Data><Data>(?<old_value>[^<]+)</Data>"
13+
| where config_name IN ("Ad Hoc Distributed Queries", "external scripts enabled", "Ole Automation Procedures", "clr enabled", "clr strict security")
14+
| rename host as dest
15+
| eval change_type=case(
16+
old_value="0" AND new_value="1", "enabled",
17+
old_value="1" AND new_value="0", "disabled",
18+
true(), "modified"
19+
)
20+
| eval risk_score=case(
21+
change_type="enabled", 90,
22+
change_type="disabled", 60,
23+
true(), 70
24+
)
25+
| eval risk_message="SQL Server critical procedure ".config_name." was ".change_type." on host ".dest.", which may indicate attempts to gain code execution or perform reconnaissance"
26+
| stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode config_name change_type risk_message risk_score
27+
| `security_content_ctime(firstTime)`
28+
| `security_content_ctime(lastTime)` | `windows_sql_server_critical_procedures_enabled_filter`'
29+
how_to_implement: To successfully implement this detection, you need to be ingesting Windows Application Event Logs from SQL Server instances where SQL Server is installed. The detection specifically looks for EventID 15457 which indicates configuration changes to SQL Server features. Ensure proper logging is enabled for SQL Server configuration changes and that the logs are being forwarded to your SIEM.
30+
known_false_positives: Database administrators may legitimately enable these features for valid business purposes such as cross-database queries, custom CLR assemblies, automation scripts, or application requirements. To reduce false positives, document when these features are required, monitor for unauthorized changes, create change control procedures for configuration modifications, and consider alerting on the enabled state rather than configuration changes if preferred.
31+
references:
32+
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/ad-hoc-distributed-queries-server-configuration-option
33+
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/external-scripts-enabled-server-configuration-option
34+
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/ole-automation-procedures-server-configuration-option
35+
- https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/clr-enabled-server-configuration-option
36+
- https://www.netspi.com/blog/technical/network-penetration-testing/enumerating-domain-accounts-via-sql-server-using-adsi/
37+
- https://attack.mitre.org/techniques/T1505/001/
38+
drilldown_searches:
39+
- name: View critical procedure configuration changes on this host
40+
search: '%original_detection_search% | search host="$dest$"'
41+
earliest_offset: $info_min_time$
42+
latest_offset: $info_max_time$
43+
- name: View all SQL Server configuration changes on this host in the last 7 days
44+
search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$dest$") starthoursago=168 | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
45+
earliest_offset: -7d
46+
latest_offset: now
47+
rba:
48+
message: SQL Server critical procedure "$config_name$" was $change_type$ on host $dest$, which could indicate an attempt to gain code execution or perform reconnaissance
49+
risk_objects:
50+
- field: dest
51+
type: system
52+
score: 90
53+
- field: config_name
54+
type: other
55+
score: 90
56+
threat_objects: []
57+
tags:
58+
analytic_story:
59+
- SQL Server Abuse
60+
asset_type: Windows
61+
mitre_attack_id:
62+
- T1505.001
63+
product:
64+
- Splunk Enterprise
65+
- Splunk Enterprise Security
66+
- Splunk Cloud
67+
security_domain: endpoint
68+
tests:
69+
- name: True Positive Test
70+
attack_data:
71+
- data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1505.001/simulation/adhocdq_windows_application.log
72+
sourcetype: XmlWinEventLog
73+
source: XmlWinEventLog:Application

0 commit comments

Comments
 (0)