Skip to content

Conversation

@tomsonpl
Copy link
Contributor

@tomsonpl tomsonpl commented Nov 20, 2025

LNK File Forensics Artifact

The Windows LNK Shortcut File Forensics artifact provides comprehensive visibility into shortcut files across forensically significant locations, enabling detection of persistence mechanisms, malicious executables, and suspicious user activity. This query extracts full shortcut metadata enriched with hash values and authenticode signatures, with intelligent filtering for threat-relevant indicators.

Core Forensic Artifacts Coverage

# Artifact OS Query File Description
1 LNK File Forensics Windows lnk_forensics_windows_elastic a1b2c3d4 Comprehensive Windows shortcut file forensics with suspicious pattern detection

Queries by Platform


🪟 Windows - LNK Shortcut File Forensics with Persistence & Threat Detection

Description

Comprehensive Windows LNK shortcut file forensics across all critical locations: user/system Startup folders (persistence), Desktop folders, Recent Items (user activity), Quick Launch, SendTo menu, and Start Menu Programs. Extracts full shortcut metadata (target path, target type, location, start_in, run mode, comment/arguments) enriched with hash values and authenticode signatures for both LNK files and their targets.

Detection Focus:

  • Startup Folder Persistence - LNK files in user and system-wide Startup folders for auto-execution
  • LOLBin Targeting - Shortcuts pointing to risky executables (cmd, powershell, pwsh, cscript, wscript, rundll32, regsvr32, mshta, wmic, certutil, bitsadmin)
  • Encoded Command Detection - Base64-encoded PowerShell commands, IEX patterns, download cradles
  • Suspicious Arguments - Hidden windows, download strings, Invoke-WebRequest, Invoke-Expression
  • Network Indicators - HTTP/HTTPS/FTP URLs in targets or arguments, UNC path references
  • Large LNK Files - Files >20KB that may contain embedded payloads or exploitation techniques
  • User Activity Tracking - Recent Items analysis for timeline reconstruction

MITRE ATT&CK Mapping:

Technique Name Tactic
T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder Persistence
T1204.002 User Execution: Malicious File Execution
T1059.001 Command and Scripting Interpreter: PowerShell Execution
T1059.003 Command and Scripting Interpreter: Windows Command Shell Execution
T1021 Remote Services Lateral Movement
T1105 Ingress Tool Transfer Command and Control

Result

Screenshot 2025-12-09 at 12 11 43

Query results include comprehensive LNK metadata with detection flags:

  • Full file path, timestamps (created, modified, accessed, changed)
  • Shortcut target path, type, location, start_in directory, run mode
  • Combined command line (target + arguments)
  • MD5, SHA1, SHA256 hashes of the LNK file
  • Authenticode signature details of the target executable
  • Detection flags: large_size_flag, startup_persistence_flag, risky_executable_flag, suspicious_arguments_flag, http_download_flag, unc_path_flag, large_arguments_flag

Platform

windows

Interval

3600 seconds (1 hour)

Query ID

lnk_forensics_windows_elastic

ECS Field Mappings

Event Fields:

  • event.category["file"] (static)
  • event.type["info"] (static)
  • event.moduleosquery (static)
  • event.datasetosquery.lnk_forensics (static)

Host Fields:

  • host.os.typewindows (static)

File Fields:

  • file.pathpath
  • file.namefilename
  • file.directorydirectory
  • file.sizesize
  • file.createdcreated_time
  • file.mtimemodified_time
  • file.accessedaccessed_time
  • file.ctimechanged_time
  • file.extensionextension
  • file.hash.md5md5
  • file.hash.sha1sha1
  • file.hash.sha256sha256

Code Signature Fields:

  • file.code_signature.subject_namesignature_signer
  • file.code_signature.issuersignature_issuer
  • file.code_signature.statussignature_status

Process Fields:

  • process.executableshortcut_target_path
  • process.command_linecombined_command

Threat Intelligence Fields:

  • threat.frameworkMITRE ATT&CK (static)
  • threat.tactic.id["TA0003", "TA0002", "TA0008", "TA0011"] (static)
  • threat.tactic.name["Persistence", "Execution", "Lateral Movement", "Command and Control"] (static)
  • threat.technique.id["T1547.001", "T1204.002", "T1059.001", "T1059.003", "T1021", "T1105"] (static)
  • threat.technique.name["Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder", "User Execution: Malicious File", "Command and Scripting Interpreter: PowerShell", "Command and Scripting Interpreter: Windows Command Shell", "Remote Services", "Ingress Tool Transfer"] (static)

Tags:

  • osquery, forensics, persistence, file-analysis, malware-detection, mitre_t1547_001, mitre_t1204_002, mitre_t1059_001, mitre_t1059_003, mitre_t1105, windows

SQL Query

-- Windows LNK Shortcut File Forensics with Suspicious Pattern Detection
-- Source: file table with native Windows shortcut parsing + authenticode signatures
-- Focus: Risky executables (LOLBins), malicious arguments, large files, persistence mechanisms
-- Scope: Comprehensive coverage of forensically significant LNK locations (startup, desktop, recent, quick launch, sendto, start menu)
-- Workaround: Uses path LIKE instead of directory = to ensure shortcut metadata is populated (osquery #8727)

WITH user_lnk_paths AS (
    -- Per-user LNK locations
    SELECT
        u.username,
        u.directory || '\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup' AS user_startup,
        u.directory || '\Desktop' AS user_desktop,
        u.directory || '\AppData\Roaming\Microsoft\Windows\Recent' AS user_recent,
        u.directory || '\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch' AS user_quicklaunch,
        u.directory || '\AppData\Roaming\Microsoft\Windows\SendTo' AS user_sendto,
        u.directory || '\AppData\Roaming\Microsoft\Windows\Start Menu\Programs' AS user_startmenu
    FROM users u
    WHERE u.directory LIKE 'C:\Users\%'
      AND u.username NOT IN ('Default', 'Default User', 'Public', 'All Users')
),
lnk_files AS (
    -- User Startup folders (highest priority - persistence)
    -- Uses path LIKE instead of directory = to get shortcut metadata (osquery #8727 workaround)
    SELECT f.*, 'user_startup' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_startup || '\%.lnk'

    UNION ALL

    -- System-wide Startup folder (persistence)
    SELECT f.*, 'system_startup' AS location_type
    FROM file f
    WHERE f.path LIKE 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\%.lnk'

    UNION ALL

    -- User Desktop folders
    SELECT f.*, 'user_desktop' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_desktop || '\%.lnk'

    UNION ALL

    -- Public Desktop
    SELECT f.*, 'public_desktop' AS location_type
    FROM file f
    WHERE f.path LIKE 'C:\Users\Public\Desktop\%.lnk'

    UNION ALL

    -- Recent Items (user activity tracking)
    SELECT f.*, 'recent_items' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_recent || '\%.lnk'

    UNION ALL

    -- Quick Launch
    SELECT f.*, 'quick_launch' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_quicklaunch || '\%.lnk'

    UNION ALL

    -- SendTo menu
    SELECT f.*, 'sendto' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_sendto || '\%.lnk'

    UNION ALL

    -- Start Menu Programs (user)
    SELECT f.*, 'user_startmenu' AS location_type
    FROM user_lnk_paths p
    CROSS JOIN file f
    WHERE f.path LIKE p.user_startmenu || '\%.lnk'

    UNION ALL

    -- Start Menu Programs (system-wide)
    SELECT f.*, 'system_startmenu' AS location_type
    FROM file f
    WHERE f.path LIKE 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\%.lnk'
),
lnk_enriched AS (
    SELECT
        lnk.path,
        lnk.filename,
        lnk.directory,
        lnk.size,
        datetime(lnk.btime, 'unixepoch') AS created_time,
        datetime(lnk.mtime, 'unixepoch') AS modified_time,
        datetime(lnk.atime, 'unixepoch') AS accessed_time,
        datetime(lnk.ctime, 'unixepoch') AS changed_time,
        lnk.type,
        lnk.shortcut_target_path,
        lnk.shortcut_target_type,
        lnk.shortcut_target_location,
        lnk.shortcut_start_in,
        lnk.shortcut_run,
        lnk.shortcut_comment,
        lnk.location_type,
        'lnk' AS extension,
        CASE
            WHEN lnk.shortcut_target_path IS NOT NULL AND lnk.shortcut_comment IS NOT NULL
            THEN lnk.shortcut_target_path || ' ' || lnk.shortcut_comment
            WHEN lnk.shortcut_target_path IS NOT NULL
            THEN lnk.shortcut_target_path
            ELSE lnk.shortcut_comment
        END AS combined_command
    FROM lnk_files lnk
)
SELECT
    lnk.path,
    lnk.filename,
    lnk.directory,
    lnk.size,
    lnk.created_time,
    lnk.modified_time,
    lnk.accessed_time,
    lnk.changed_time,
    lnk.type,
    lnk.shortcut_target_path,
    lnk.shortcut_target_type,
    lnk.shortcut_target_location,
    lnk.shortcut_start_in,
    lnk.shortcut_run,
    lnk.shortcut_comment,
    lnk.combined_command,
    lnk.location_type,
    lnk.extension,
    h.md5,
    h.sha1,
    h.sha256,
    a.subject_name AS signature_signer,
    a.issuer_name AS signature_issuer,
    a.result AS signature_status,
    a.serial_number AS signature_serial,
    CASE WHEN lnk.size > 20000 THEN 1 ELSE 0 END AS large_size_flag,
    CASE WHEN lnk.location_type IN ('user_startup', 'system_startup') THEN 1 ELSE 0 END AS startup_persistence_flag,
    CASE
        WHEN lnk.shortcut_target_path LIKE '%\cmd.exe'
            OR lnk.shortcut_target_path LIKE '%\powershell.exe'
            OR lnk.shortcut_target_path LIKE '%\pwsh.exe'
            OR lnk.shortcut_target_path LIKE '%\cscript.exe'
            OR lnk.shortcut_target_path LIKE '%\wscript.exe'
            OR lnk.shortcut_target_path LIKE '%\rundll32.exe'
            OR lnk.shortcut_target_path LIKE '%\regsvr32.exe'
            OR lnk.shortcut_target_path LIKE '%\mshta.exe'
            OR lnk.shortcut_target_path LIKE '%\wmic.exe'
            OR lnk.shortcut_target_path LIKE '%\conhost.exe'
            OR lnk.shortcut_target_path LIKE '%\certutil.exe'
            OR lnk.shortcut_target_path LIKE '%\bitsadmin.exe'
        THEN 1 ELSE 0
    END AS risky_executable_flag,
    CASE
        WHEN lnk.combined_command LIKE '%\AppData\%'
            OR lnk.combined_command LIKE '%\Users\Public\%'
            OR lnk.combined_command LIKE '%\Temp\%'
            OR lnk.combined_command LIKE '%comspec%'
            OR lnk.combined_command LIKE '%&cd&echo%'
            OR lnk.combined_command LIKE '% -NoP %'
            OR lnk.combined_command LIKE '% -nop %'
            OR lnk.combined_command LIKE '% -W Hidden %'
            OR lnk.combined_command LIKE '% -w hidden %'
            OR lnk.combined_command LIKE '% -WindowStyle Hidden %'
            OR lnk.combined_command LIKE '% -decode %'
            OR lnk.combined_command LIKE '% /decode %'
            OR lnk.combined_command LIKE '% -e %JAB%'
            OR lnk.combined_command LIKE '% -e %SUVYI%'
            OR lnk.combined_command LIKE '% -e %SQBFAFgA%'
            OR lnk.combined_command LIKE '% -e %aWV4I%'
            OR lnk.combined_command LIKE '% -e %aQBlAHgA%'
            OR lnk.combined_command LIKE '% -enc %'
            OR lnk.combined_command LIKE '% -EncodedCommand %'
            OR lnk.combined_command LIKE '%start /b%'
            OR lnk.combined_command LIKE '%start \b%'
            OR lnk.combined_command LIKE '%.downloadstring(%'
            OR lnk.combined_command LIKE '%.downloadfile(%'
            OR lnk.combined_command LIKE '%Invoke-WebRequest%'
            OR lnk.combined_command LIKE '%iwr %'
            OR lnk.combined_command LIKE '%iex %'
            OR lnk.combined_command LIKE '%Invoke-Expression%'
        THEN 1 ELSE 0
    END AS suspicious_arguments_flag,
    CASE
        WHEN lnk.combined_command LIKE '%http://%'
            OR lnk.combined_command LIKE '%https://%'
            OR lnk.combined_command LIKE '%ftp://%'
            OR lnk.combined_command LIKE '%ftps://%'
        THEN 1 ELSE 0
    END AS http_download_flag,
    CASE
        WHEN lnk.combined_command LIKE '% \\%'
            OR lnk.shortcut_start_in LIKE '\\%'
        THEN 1 ELSE 0
    END AS unc_path_flag,
    CASE
        WHEN LENGTH(lnk.shortcut_comment) > 250
        THEN 1 ELSE 0
    END AS large_arguments_flag
FROM lnk_enriched lnk
LEFT JOIN hash h ON lnk.path = h.path
LEFT JOIN authenticode a ON a.path = lnk.shortcut_target_path
WHERE (
    -- Always include startup locations (persistence focus)
    lnk.location_type IN ('user_startup', 'system_startup')
    -- For other locations, filter for suspicious indicators
    OR lnk.size > 20000
    OR lnk.shortcut_target_path LIKE '%\cmd.exe'
    OR lnk.shortcut_target_path LIKE '%\powershell.exe'
    OR lnk.shortcut_target_path LIKE '%\pwsh.exe'
    OR lnk.shortcut_target_path LIKE '%\cscript.exe'
    OR lnk.shortcut_target_path LIKE '%\wscript.exe'
    OR lnk.shortcut_target_path LIKE '%\rundll32.exe'
    OR lnk.shortcut_target_path LIKE '%\regsvr32.exe'
    OR lnk.shortcut_target_path LIKE '%\mshta.exe'
    OR lnk.shortcut_target_path LIKE '%\wmic.exe'
    OR lnk.shortcut_target_path LIKE '%\conhost.exe'
    OR lnk.shortcut_target_path LIKE '%\certutil.exe'
    OR lnk.shortcut_target_path LIKE '%\bitsadmin.exe'
    OR lnk.combined_command LIKE '%\AppData\%'
    OR lnk.combined_command LIKE '%\Users\Public\%'
    OR lnk.combined_command LIKE '%\Temp\%'
    OR lnk.combined_command LIKE '%comspec%'
    OR lnk.combined_command LIKE '%&cd&echo%'
    OR lnk.combined_command LIKE '% -NoP %'
    OR lnk.combined_command LIKE '% -nop %'
    OR lnk.combined_command LIKE '% -W Hidden %'
    OR lnk.combined_command LIKE '% -w hidden %'
    OR lnk.combined_command LIKE '% -WindowStyle Hidden %'
    OR lnk.combined_command LIKE '% -decode %'
    OR lnk.combined_command LIKE '% /decode %'
    OR lnk.combined_command LIKE '% -e %JAB%'
    OR lnk.combined_command LIKE '% -e %SUVYI%'
    OR lnk.combined_command LIKE '% -e %SQBFAFgA%'
    OR lnk.combined_command LIKE '% -e %aWV4I%'
    OR lnk.combined_command LIKE '% -e %aQBlAHgA%'
    OR lnk.combined_command LIKE '% -enc %'
    OR lnk.combined_command LIKE '% -EncodedCommand %'
    OR lnk.combined_command LIKE '%start /b%'
    OR lnk.combined_command LIKE '%start \b%'
    OR lnk.combined_command LIKE '%.downloadstring(%'
    OR lnk.combined_command LIKE '%.downloadfile(%'
    OR lnk.combined_command LIKE '%Invoke-WebRequest%'
    OR lnk.combined_command LIKE '%iwr %'
    OR lnk.combined_command LIKE '%iex %'
    OR lnk.combined_command LIKE '%Invoke-Expression%'
    OR lnk.combined_command LIKE '%http://%'
    OR lnk.combined_command LIKE '%https://%'
    OR lnk.combined_command LIKE '%ftp://%'
    OR lnk.combined_command LIKE '%ftps://%'
    OR lnk.combined_command LIKE '% \\%'
    OR lnk.shortcut_start_in LIKE '\\%'
    OR LENGTH(lnk.shortcut_comment) > 250
)
-- Exclude common legitimate shortcuts (noise reduction)
AND lnk.filename NOT IN (
    'Excel.lnk', 'Word.lnk', 'PowerPoint.lnk', 'Outlook.lnk', 'OneNote.lnk',
    'Access.lnk', 'Publisher.lnk', 'Visio.lnk', 'Project.lnk', 'Teams.lnk',
    'Windows Media Player.lnk', 'Windows Explorer.lnk', 'Internet Explorer.lnk',
    'Microsoft Edge.lnk', 'Google Chrome.lnk', 'Firefox.lnk', 'Safari.lnk',
    'Notepad.lnk', 'Calculator.lnk', 'Paint.lnk', 'Snipping Tool.lnk',
    'Control Panel.lnk', 'Task Manager.lnk', 'File Explorer.lnk',
    'Visual Studio Code.lnk', 'Visual Studio.lnk', 'Slack.lnk', 'Zoom.lnk',
    'Adobe Acrobat.lnk', 'Adobe Reader.lnk', 'Spotify.lnk', 'Discord.lnk'
)
ORDER BY
    -- Priority: Startup locations first
    CASE WHEN lnk.location_type IN ('user_startup', 'system_startup') THEN 1 ELSE 2 END,
    -- Then by risky executable
    CASE
        WHEN lnk.shortcut_target_path LIKE '%\cmd.exe'
            OR lnk.shortcut_target_path LIKE '%\powershell.exe'
            OR lnk.shortcut_target_path LIKE '%\pwsh.exe'
            OR lnk.shortcut_target_path LIKE '%\cscript.exe'
            OR lnk.shortcut_target_path LIKE '%\wscript.exe'
            OR lnk.shortcut_target_path LIKE '%\rundll32.exe'
            OR lnk.shortcut_target_path LIKE '%\regsvr32.exe'
            OR lnk.shortcut_target_path LIKE '%\mshta.exe'
            OR lnk.shortcut_target_path LIKE '%\wmic.exe'
            OR lnk.shortcut_target_path LIKE '%\conhost.exe'
            OR lnk.shortcut_target_path LIKE '%\certutil.exe'
            OR lnk.shortcut_target_path LIKE '%\bitsadmin.exe'
        THEN 1 ELSE 2
    END,
    lnk.location_type,
    lnk.modified_time DESC;

@tomsonpl tomsonpl marked this pull request as ready for review November 20, 2025 11:22
@tomsonpl tomsonpl requested a review from a team as a code owner November 20, 2025 11:22
@tomsonpl tomsonpl requested review from joeypoon and pzl and removed request for a team November 20, 2025 11:22
@andrewkroh andrewkroh added Integration:osquery_manager Osquery Manager documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. labels Nov 20, 2025
@tomsonpl tomsonpl changed the title lnk artifact [Osquery_manager] LNK artifacts saved query Nov 20, 2025
@andrewkroh andrewkroh added the Team:Defend Workflows Security team for Endpoint and OSQuery workflows [elastic/security-defend-workflows] label Nov 25, 2025
@raqueltabuyo
Copy link

Verify if the folders for LNK files are only startup or Desktop, I believe you can store LNK files anywhere.

@tomsonpl
Copy link
Contributor Author

I think there's a limitation or a BUG in osquery itself, created an issue: osquery/osquery#8725 let's see what they say :)

- Expand LNK file locations coverage with users table enumeration
- Add cross-reference to YARA-based detection query
- Document known limitation: shortcut_target_path may return empty
- List affected ECS fields in description for transparency
- Add SQL comments explaining limitation and workaround
- Add content-based detection scanning LNK binary for malicious patterns
- Detect LOLBins: powershell, cmd, wscript, mshta, rundll32, certutil
- Detect encoded commands, hidden execution, download cradles
- Detect network indicators (http/https URLs)
- Use CTE + JOIN pattern for YARA path constraints
- Use scalar subqueries for hash enrichment (JOIN breaks YARA)
- Bypasses osquery shortcut_target_path parsing limitation
- Cross-reference to lnk_forensics_windows_elastic for enumeration
- Add lnk_yara_detection query (#28) to additional queries table
- Update total query count from 31 to 32
- Update LNK files entry in User Activity section
- Note YARA-based binary content scanning capability
Copy link
Contributor

@ferullo ferullo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see many columns returned in results from my host that are not mapped and do not have any values. What about pruning down the columns to just those being mapped or that you can provide screenshot data for to confirm what content will be in them?

{
"key": "file.created",
"value": {
"field": "btime"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be converted to a datetime string for usability/readability and because file.created is mapped as a datestring.

{
"key": "file.mtime",
"value": {
"field": "mtime"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as btime

{
"key": "file.accessed",
"value": {
"field": "atime"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as btime

{
"key": "file.ctime",
"value": {
"field": "ctime"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as btime

{
"key": "file.type",
"value": {
"field": "type"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't what file.type is defined as. I only see regular in results from my results. What else are valid values? Maybe just don't map it?

Comment on lines +62 to +72
"key": "file.hash.md5",
"value": {
"field": "md5"
}
},
{
"key": "file.hash.sha1",
"value": {
"field": "sha1"
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other queries sha1 is not returned. What do you think about standardizing which hashes are returned across all these queries. Perhaps just sha256?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After refactoring, all 3 hash fields should be available when possible. Do you think it's too much?

@tomsonpl
Copy link
Contributor Author

tomsonpl commented Dec 5, 2025

Thanks for the review, this artifact will have to be done again. I used yara scanning here, because there is a bug in Osquery. Described here: osquery/osquery#8727 . However - we might get the proper results if I adjust the query a little bit and then we could get directly from lnk.

@tomsonpl tomsonpl marked this pull request as draft December 5, 2025 14:35
@tomsonpl tomsonpl requested review from pzl and removed request for joeypoon and pzl December 8, 2025 14:25
… ECS mappings

- Apply path LIKE pattern instead of directory= to ensure shortcut metadata is populated
- Add event.* ECS fields (category, type, module, dataset)
- Add MITRE ATT&CK threat context fields (framework, tactic, technique)
- Add human-readable datetime() formatting for timestamp columns
- Fix column aliasing (authenticode_* → signature_*) for proper ECS mapping
- Remove Shellbags cross-reference for cleaner query execution
- Update coreMigrationVersion to 9.2.0
- Delete lnk_yara_detection_windows_elastic saved query
- Update artifacts_matrix.md to remove YARA LNK references
- Update query count from 32 to 31
- Consolidate LNK forensics to single comprehensive query
Address review feedback from @ferullo: osquery's file.type column
returns 'regular' while ECS file.type expects 'file', causing
semantic mismatch. Remove the mapping to maintain ECS compliance.

The type column remains in query results for raw data visibility.
@tomsonpl tomsonpl marked this pull request as ready for review December 9, 2025 11:12
@elasticmachine
Copy link

💚 Build Succeeded

History

"id": "lnk_forensics_windows_elastic",
"interval": "3600",
"platform": "windows",
"query": "-- Windows LNK Shortcut File Forensics with Suspicious Pattern Detection\n-- Source: file table with native Windows shortcut parsing + authenticode signatures\n-- Focus: Risky executables (LOLBins), malicious arguments, large files, persistence mechanisms\n-- Scope: Comprehensive coverage of forensically significant LNK locations (startup, desktop, recent, quick launch, sendto, start menu)\n-- Workaround: Uses path LIKE instead of directory = to ensure shortcut metadata is populated (osquery #8727)\n\nWITH user_lnk_paths AS (\n -- Per-user LNK locations\n SELECT \n u.username,\n u.directory || '\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup' AS user_startup,\n u.directory || '\\Desktop' AS user_desktop,\n u.directory || '\\AppData\\Roaming\\Microsoft\\Windows\\Recent' AS user_recent,\n u.directory || '\\AppData\\Roaming\\Microsoft\\Internet Explorer\\Quick Launch' AS user_quicklaunch,\n u.directory || '\\AppData\\Roaming\\Microsoft\\Windows\\SendTo' AS user_sendto,\n u.directory || '\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs' AS user_startmenu\n FROM users u\n WHERE u.directory LIKE 'C:\\Users\\%'\n AND u.username NOT IN ('Default', 'Default User', 'Public', 'All Users')\n),\nlnk_files AS (\n -- User Startup folders (highest priority - persistence)\n -- Uses path LIKE instead of directory = to get shortcut metadata (osquery #8727 workaround)\n SELECT f.*, 'user_startup' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_startup || '\\%.lnk'\n \n UNION ALL\n \n -- System-wide Startup folder (persistence)\n SELECT f.*, 'system_startup' AS location_type\n FROM file f\n WHERE f.path LIKE 'C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\%.lnk'\n \n UNION ALL\n \n -- User Desktop folders\n SELECT f.*, 'user_desktop' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_desktop || '\\%.lnk'\n \n UNION ALL\n \n -- Public Desktop\n SELECT f.*, 'public_desktop' AS location_type\n FROM file f\n WHERE f.path LIKE 'C:\\Users\\Public\\Desktop\\%.lnk'\n \n UNION ALL\n \n -- Recent Items (user activity tracking)\n SELECT f.*, 'recent_items' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_recent || '\\%.lnk'\n \n UNION ALL\n \n -- Quick Launch\n SELECT f.*, 'quick_launch' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_quicklaunch || '\\%.lnk'\n \n UNION ALL\n \n -- SendTo menu\n SELECT f.*, 'sendto' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_sendto || '\\%.lnk'\n \n UNION ALL\n \n -- Start Menu Programs (user)\n SELECT f.*, 'user_startmenu' AS location_type\n FROM user_lnk_paths p\n CROSS JOIN file f\n WHERE f.path LIKE p.user_startmenu || '\\%.lnk'\n \n UNION ALL\n \n -- Start Menu Programs (system-wide)\n SELECT f.*, 'system_startmenu' AS location_type\n FROM file f\n WHERE f.path LIKE 'C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\%.lnk'\n),\nlnk_enriched AS (\n SELECT\n lnk.path,\n lnk.filename,\n lnk.directory,\n lnk.size,\n datetime(lnk.btime, 'unixepoch') AS created_time,\n datetime(lnk.mtime, 'unixepoch') AS modified_time,\n datetime(lnk.atime, 'unixepoch') AS accessed_time,\n datetime(lnk.ctime, 'unixepoch') AS changed_time,\n lnk.type,\n lnk.shortcut_target_path,\n lnk.shortcut_target_type,\n lnk.shortcut_target_location,\n lnk.shortcut_start_in,\n lnk.shortcut_run,\n lnk.shortcut_comment,\n lnk.location_type,\n 'lnk' AS extension,\n CASE \n WHEN lnk.shortcut_target_path IS NOT NULL AND lnk.shortcut_comment IS NOT NULL \n THEN lnk.shortcut_target_path || ' ' || lnk.shortcut_comment\n WHEN lnk.shortcut_target_path IS NOT NULL \n THEN lnk.shortcut_target_path\n ELSE lnk.shortcut_comment\n END AS combined_command\n FROM lnk_files lnk\n)\nSELECT \n lnk.path,\n lnk.filename,\n lnk.directory,\n lnk.size,\n lnk.created_time,\n lnk.modified_time,\n lnk.accessed_time,\n lnk.changed_time,\n lnk.type,\n lnk.shortcut_target_path,\n lnk.shortcut_target_type,\n lnk.shortcut_target_location,\n lnk.shortcut_start_in,\n lnk.shortcut_run,\n lnk.shortcut_comment,\n lnk.combined_command,\n lnk.location_type,\n lnk.extension,\n h.md5,\n h.sha1,\n h.sha256,\n a.subject_name AS signature_signer,\n a.issuer_name AS signature_issuer,\n a.result AS signature_status,\n a.serial_number AS signature_serial,\n CASE WHEN lnk.size > 20000 THEN 1 ELSE 0 END AS large_size_flag,\n CASE WHEN lnk.location_type IN ('user_startup', 'system_startup') THEN 1 ELSE 0 END AS startup_persistence_flag,\n CASE \n WHEN lnk.shortcut_target_path LIKE '%\\cmd.exe' \n OR lnk.shortcut_target_path LIKE '%\\powershell.exe'\n OR lnk.shortcut_target_path LIKE '%\\pwsh.exe'\n OR lnk.shortcut_target_path LIKE '%\\cscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\wscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\rundll32.exe'\n OR lnk.shortcut_target_path LIKE '%\\regsvr32.exe'\n OR lnk.shortcut_target_path LIKE '%\\mshta.exe'\n OR lnk.shortcut_target_path LIKE '%\\wmic.exe'\n OR lnk.shortcut_target_path LIKE '%\\conhost.exe'\n OR lnk.shortcut_target_path LIKE '%\\certutil.exe'\n OR lnk.shortcut_target_path LIKE '%\\bitsadmin.exe'\n THEN 1 ELSE 0 \n END AS risky_executable_flag,\n CASE \n WHEN lnk.combined_command LIKE '%\\AppData\\%'\n OR lnk.combined_command LIKE '%\\Users\\Public\\%'\n OR lnk.combined_command LIKE '%\\Temp\\%'\n OR lnk.combined_command LIKE '%comspec%'\n OR lnk.combined_command LIKE '%&cd&echo%'\n OR lnk.combined_command LIKE '% -NoP %'\n OR lnk.combined_command LIKE '% -nop %'\n OR lnk.combined_command LIKE '% -W Hidden %'\n OR lnk.combined_command LIKE '% -w hidden %'\n OR lnk.combined_command LIKE '% -WindowStyle Hidden %'\n OR lnk.combined_command LIKE '% -decode %'\n OR lnk.combined_command LIKE '% /decode %'\n OR lnk.combined_command LIKE '% -e %JAB%'\n OR lnk.combined_command LIKE '% -e %SUVYI%'\n OR lnk.combined_command LIKE '% -e %SQBFAFgA%'\n OR lnk.combined_command LIKE '% -e %aWV4I%'\n OR lnk.combined_command LIKE '% -e %aQBlAHgA%'\n OR lnk.combined_command LIKE '% -enc %'\n OR lnk.combined_command LIKE '% -EncodedCommand %'\n OR lnk.combined_command LIKE '%start /b%'\n OR lnk.combined_command LIKE '%start \\b%'\n OR lnk.combined_command LIKE '%.downloadstring(%'\n OR lnk.combined_command LIKE '%.downloadfile(%'\n OR lnk.combined_command LIKE '%Invoke-WebRequest%'\n OR lnk.combined_command LIKE '%iwr %'\n OR lnk.combined_command LIKE '%iex %'\n OR lnk.combined_command LIKE '%Invoke-Expression%'\n THEN 1 ELSE 0\n END AS suspicious_arguments_flag,\n CASE \n WHEN lnk.combined_command LIKE '%http://%'\n OR lnk.combined_command LIKE '%https://%'\n OR lnk.combined_command LIKE '%ftp://%'\n OR lnk.combined_command LIKE '%ftps://%'\n THEN 1 ELSE 0\n END AS http_download_flag,\n CASE \n WHEN lnk.combined_command LIKE '% \\\\\\\\%'\n OR lnk.shortcut_start_in LIKE '\\\\\\\\%'\n THEN 1 ELSE 0\n END AS unc_path_flag,\n CASE \n WHEN LENGTH(lnk.shortcut_comment) > 250 \n THEN 1 ELSE 0\n END AS large_arguments_flag\nFROM lnk_enriched lnk\nLEFT JOIN hash h ON lnk.path = h.path\nLEFT JOIN authenticode a ON a.path = lnk.shortcut_target_path\nWHERE (\n -- Always include startup locations (persistence focus)\n lnk.location_type IN ('user_startup', 'system_startup')\n -- For other locations, filter for suspicious indicators\n OR lnk.size > 20000\n OR lnk.shortcut_target_path LIKE '%\\cmd.exe'\n OR lnk.shortcut_target_path LIKE '%\\powershell.exe'\n OR lnk.shortcut_target_path LIKE '%\\pwsh.exe'\n OR lnk.shortcut_target_path LIKE '%\\cscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\wscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\rundll32.exe'\n OR lnk.shortcut_target_path LIKE '%\\regsvr32.exe'\n OR lnk.shortcut_target_path LIKE '%\\mshta.exe'\n OR lnk.shortcut_target_path LIKE '%\\wmic.exe'\n OR lnk.shortcut_target_path LIKE '%\\conhost.exe'\n OR lnk.shortcut_target_path LIKE '%\\certutil.exe'\n OR lnk.shortcut_target_path LIKE '%\\bitsadmin.exe'\n OR lnk.combined_command LIKE '%\\AppData\\%'\n OR lnk.combined_command LIKE '%\\Users\\Public\\%'\n OR lnk.combined_command LIKE '%\\Temp\\%'\n OR lnk.combined_command LIKE '%comspec%'\n OR lnk.combined_command LIKE '%&cd&echo%'\n OR lnk.combined_command LIKE '% -NoP %'\n OR lnk.combined_command LIKE '% -nop %'\n OR lnk.combined_command LIKE '% -W Hidden %'\n OR lnk.combined_command LIKE '% -w hidden %'\n OR lnk.combined_command LIKE '% -WindowStyle Hidden %'\n OR lnk.combined_command LIKE '% -decode %'\n OR lnk.combined_command LIKE '% /decode %'\n OR lnk.combined_command LIKE '% -e %JAB%'\n OR lnk.combined_command LIKE '% -e %SUVYI%'\n OR lnk.combined_command LIKE '% -e %SQBFAFgA%'\n OR lnk.combined_command LIKE '% -e %aWV4I%'\n OR lnk.combined_command LIKE '% -e %aQBlAHgA%'\n OR lnk.combined_command LIKE '% -enc %'\n OR lnk.combined_command LIKE '% -EncodedCommand %'\n OR lnk.combined_command LIKE '%start /b%'\n OR lnk.combined_command LIKE '%start \\b%'\n OR lnk.combined_command LIKE '%.downloadstring(%'\n OR lnk.combined_command LIKE '%.downloadfile(%'\n OR lnk.combined_command LIKE '%Invoke-WebRequest%'\n OR lnk.combined_command LIKE '%iwr %'\n OR lnk.combined_command LIKE '%iex %'\n OR lnk.combined_command LIKE '%Invoke-Expression%'\n OR lnk.combined_command LIKE '%http://%'\n OR lnk.combined_command LIKE '%https://%'\n OR lnk.combined_command LIKE '%ftp://%'\n OR lnk.combined_command LIKE '%ftps://%'\n OR lnk.combined_command LIKE '% \\\\\\\\%'\n OR lnk.shortcut_start_in LIKE '\\\\\\\\%'\n OR LENGTH(lnk.shortcut_comment) > 250\n)\n-- Exclude common legitimate shortcuts (noise reduction)\nAND lnk.filename NOT IN (\n 'Excel.lnk', 'Word.lnk', 'PowerPoint.lnk', 'Outlook.lnk', 'OneNote.lnk',\n 'Access.lnk', 'Publisher.lnk', 'Visio.lnk', 'Project.lnk', 'Teams.lnk',\n 'Windows Media Player.lnk', 'Windows Explorer.lnk', 'Internet Explorer.lnk',\n 'Microsoft Edge.lnk', 'Google Chrome.lnk', 'Firefox.lnk', 'Safari.lnk',\n 'Notepad.lnk', 'Calculator.lnk', 'Paint.lnk', 'Snipping Tool.lnk',\n 'Control Panel.lnk', 'Task Manager.lnk', 'File Explorer.lnk',\n 'Visual Studio Code.lnk', 'Visual Studio.lnk', 'Slack.lnk', 'Zoom.lnk',\n 'Adobe Acrobat.lnk', 'Adobe Reader.lnk', 'Spotify.lnk', 'Discord.lnk'\n)\nORDER BY \n -- Priority: Startup locations first\n CASE WHEN lnk.location_type IN ('user_startup', 'system_startup') THEN 1 ELSE 2 END,\n -- Then by risky executable\n CASE \n WHEN lnk.shortcut_target_path LIKE '%\\cmd.exe' \n OR lnk.shortcut_target_path LIKE '%\\powershell.exe'\n OR lnk.shortcut_target_path LIKE '%\\pwsh.exe'\n OR lnk.shortcut_target_path LIKE '%\\cscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\wscript.exe'\n OR lnk.shortcut_target_path LIKE '%\\rundll32.exe'\n OR lnk.shortcut_target_path LIKE '%\\regsvr32.exe'\n OR lnk.shortcut_target_path LIKE '%\\mshta.exe'\n OR lnk.shortcut_target_path LIKE '%\\wmic.exe'\n OR lnk.shortcut_target_path LIKE '%\\conhost.exe'\n OR lnk.shortcut_target_path LIKE '%\\certutil.exe'\n OR lnk.shortcut_target_path LIKE '%\\bitsadmin.exe'\n THEN 1 ELSE 2 \n END,\n lnk.location_type,\n lnk.modified_time DESC;",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The block

-- Exclude common legitimate shortcuts (noise reduction)
AND lnk.filename NOT IN (
    'Excel.lnk', 'Word.lnk', 'PowerPoint.lnk', 'Outlook.lnk', 'OneNote.lnk',
    'Access.lnk', 'Publisher.lnk', 'Visio.lnk', 'Project.lnk', 'Teams.lnk',
    'Windows Media Player.lnk', 'Windows Explorer.lnk', 'Internet Explorer.lnk',
    'Microsoft Edge.lnk', 'Google Chrome.lnk', 'Firefox.lnk', 'Safari.lnk',
    'Notepad.lnk', 'Calculator.lnk', 'Paint.lnk', 'Snipping Tool.lnk',
    'Control Panel.lnk', 'Task Manager.lnk', 'File Explorer.lnk',
    'Visual Studio Code.lnk', 'Visual Studio.lnk', 'Slack.lnk', 'Zoom.lnk',
    'Adobe Acrobat.lnk', 'Adobe Reader.lnk', 'Spotify.lnk', 'Discord.lnk'
)

would skip reporting LNK files with a target path that would point to cmd.exe / powershell.exe / mshta.exe / etc.

This is effectively allowing attackers to hide malicious LNKs since there is no reason for any item in that list to execute cmd.exe for instance. Should we consider removing this block?

Copy link

@calladoum-elastic calladoum-elastic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor change (remove the AND lnk.filename block) and LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:osquery_manager Osquery Manager Team:Defend Workflows Security team for Endpoint and OSQuery workflows [elastic/security-defend-workflows]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants