{
  "technique_id": "T1505",
  "name": "Server Software Component",
  "priority": "high",
  "status": "draft",
  "version": "0.1.0",
  "last_reviewed": "2026-07-23",
  "generated_by": "SOC Response Atlas by Basyrix",
  "tactics": [
    "Persistence"
  ],
  "platforms": [
    "Windows",
    "Linux",
    "macOS",
    "Network Devices",
    "ESXi"
  ],
  "summary": "Adversaries may abuse legitimate extensible development features of servers to establish persistent access to systems. Enterprise server applications may include features that allow developers to write and install software or scripts to extend the functionality of the main application. Adversaries may install malicious components to extend and abuse server applications.",
  "soc_recommendation": "Investigate Server Software Component activity in the context of Persistence: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.",
  "d3fend_mappings": [
    {
      "id": "D3-EHB",
      "name": "Endpoint Health Beacon",
      "relationship": "detect",
      "practical_action": "Monitor for Endpoint Health Beacon indicators relevant to this technique.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-FE",
      "name": "File Encryption",
      "relationship": "harden",
      "practical_action": "Apply File Encryption to reduce this technique's viability before an incident occurs.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-FEV",
      "name": "File Eviction",
      "relationship": "evict",
      "practical_action": "Use File Eviction to remove the adversary's foothold once this technique is confirmed.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-SCF",
      "name": "System Call Filtering",
      "relationship": "isolate",
      "practical_action": "Apply System Call Filtering to contain the blast radius once this technique is observed.",
      "tooling": [
        "Defender for Endpoint"
      ]
    }
  ],
  "investigation_steps": {
    "microsoft": [
      "Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.",
      "Check Sentinel analytics rules and incidents correlated with this technique.",
      "Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource."
    ],
    "generic": [
      "Confirm whether the observed server software component activity matches expected administrative or application behaviour.",
      "Identify the host, account, or resource where the activity occurred and its business criticality.",
      "Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.",
      "Real detection reference: \"Web Shell Installed on Web Server\" -- Flags a web-accessible script file (.php/.aspx/.asp/.jsp/etc.) written to a web-accessible path by the web server process or into an upload directory - web shells must never be legitimately written this way. Zero tolerance."
    ]
  },
  "evidence_to_collect": [
    "Host or resource affected",
    "Account or identity involved",
    "Timestamp of the activity",
    "Related process, file, or network artifact",
    "Any preceding or follow-on alerts"
  ],
  "response_actions": [
    {
      "name": "Contain the affected host or account",
      "category": "Containment",
      "risk": "Medium",
      "automation_safe": false,
      "approval_required": true,
      "tool": "Defender for Endpoint / Entra ID",
      "notes": "Requires approval -- confirm malicious intent before isolating a host or disabling an account."
    },
    {
      "name": "Collect and preserve evidence",
      "category": "Investigation",
      "risk": "Low",
      "automation_safe": true,
      "approval_required": false,
      "tool": "Defender for Endpoint",
      "notes": "Safe -- read-only evidence collection."
    }
  ],
  "queries": {
    "kql": [
      {
        "name": "GEN-PS-004 — Web Shell Installed on Web Server",
        "description": "Flags a web-accessible script file (.php/.aspx/.asp/.jsp/etc.) written to a web-accessible path by the web server process or into an upload directory - web shells must never be legitimately written this way. Zero tolerance. (Source: Bell Integration baseline detection library, mapped via sub-technique T1505.003.)",
        "query": "DeviceFileEvents\n| where TimeGenerated >= ago(5m)\n| where ActionType == \"FileCreated\"\n| where FileName has_any (\".php\", \".aspx\", \".asp\", \".jsp\", \".cfm\", \".shtml\", \".ashx\", \".asmx\", \".axd\")\n| where FolderPath has_any (\n    \"wwwroot\", \"inetpub\", \"htdocs\", \"public_html\", \"webroot\", \"www\",\n    \"upload\", \"uploads\", \"files\", \"images\", \"assets\", \"static\", \"media\", \"content\"\n)\n| where InitiatingProcessFileName in~ (\n    \"w3wp.exe\", \"httpd.exe\", \"nginx.exe\", \"php-cgi.exe\", \"tomcat.exe\", \"java.exe\",\n    \"apache.exe\", \"lighttpd.exe\"\n)\n    or FolderPath has_any (\"upload\", \"uploads\", \"user-content\", \"media\")\n| project\n    TimeGenerated, DeviceName, FileName, FolderPath, SHA256,\n    InitiatingProcessFileName, InitiatingProcessAccountName\n| extend timestamp = TimeGenerated,\n         HostCustomEntity = DeviceName,\n         AccountCustomEntity = InitiatingProcessAccountName\n| order by TimeGenerated desc"
      },
      {
        "name": "GEN-IA-008 — Public-Facing App Webshell File Write",
        "description": "Replaces the stale March 2021 ProxyLogon IOC feed rule with a behavior-based detector for webshell-like files written under public web roots, optionally correlated with recent inbound upload/admin requests. (Source: Bell Integration baseline detection library, mapped via sub-technique T1505.003.)",
        "query": "let lookback = 1h;\nlet correlationWindow = 15m;\nlet webRoots = dynamic([\"\\\\inetpub\\\\wwwroot\", \"\\\\wwwroot\", \"\\\\public_html\", \"\\\\htdocs\", \"\\\\site\\\\wwwroot\"]);\nlet suspiciousExtensions = dynamic([\"aspx\", \"ashx\", \"asmx\", \"jsp\", \"jspx\", \"php\", \"phtml\", \"pl\", \"py\", \"ps1\", \"cmd\"]);\nlet suspiciousNames = dynamic([\"shell\", \"cmd\", \"upload\", \"webadmin\", \"backdoor\", \"wso\", \"c99\", \"r57\", \"regeorg\", \"tunnel\"]);\nlet approvedDeploymentTools = dynamic([\"msdeploy.exe\", \"git.exe\", \"runner.exe\", \"octopus.tentacle.exe\", \"kudu.exe\", \"zipdeploy.exe\"]);\nlet fileEventsSource =\n    union isfuzzy=true DeviceFileEvents,\n    (datatable(TimeGenerated:datetime, ActionType:string, DeviceId:string, DeviceName:string, FolderPath:string, FileName:string, SHA256:string, InitiatingProcessFileName:string, InitiatingProcessCommandLine:string, InitiatingProcessAccountName:string)[]);\nlet iisLogsSource =\n    union isfuzzy=true W3CIISLog,\n    (datatable(TimeGenerated:datetime, sComputerName:string, cIP:string, csMethod:string, csUriStem:string, csUserName:string, scStatus:int, csUserAgent:string)[]);\nlet suspiciousFileWrites =\n    fileEventsSource\n    | where TimeGenerated >= ago(lookback)\n    | where ActionType in~ (\"FileCreated\", \"FileModified\", \"FileRenamed\")\n    | where FolderPath has_any (webRoots)\n    | extend FileExtension = tolower(tostring(split(FileName, \".\")[-1])),\n             FileNameLower = tolower(FileName),\n             InitiatingProcessFileName = tostring(InitiatingProcessFileName)\n    | where FileExtension in (suspiciousExtensions) or FileNameLower has_any (suspiciousNames)\n    | where InitiatingProcessFileName !in~ (approvedDeploymentTools)\n    | project WriteTime = TimeGenerated, DeviceId, DeviceName, FolderPath, FileName, FileExtension, SHA256,\n              InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName;\nlet inboundWrites =\n    iisLogsSource\n    | where TimeGenerated >= ago(lookback)\n    | where csMethod in~ (\"POST\", \"PUT\", \"PATCH\")\n    | where csUriStem has_any (\"/upload\", \"/admin\", \"/editor\", \"/api\", \"/wp-admin\", \"/owa\", \"/ecp\")\n    | project RequestTime = TimeGenerated, DeviceName = sComputerName, SrcIP = cIP, csMethod, csUriStem, csUserName, scStatus, csUserAgent;\nsuspiciousFileWrites\n| join kind=leftouter inboundWrites on DeviceName\n| where isnull(RequestTime) or abs(datetime_diff(\"minute\", WriteTime, RequestTime)) <= toint(correlationWindow / 1m)\n| extend CorrelatedInboundRequest = isnotempty(RequestTime)\n| project\n    TimeGenerated = coalesce(RequestTime, WriteTime),\n    WriteTime,\n    RequestTime,\n    DeviceId,\n    DeviceName,\n    FolderPath,\n    FileName,\n    FileExtension,\n    SHA256,\n    InitiatingProcessFileName,\n    InitiatingProcessCommandLine,\n    InitiatingProcessAccountName,\n    CorrelatedInboundRequest,\n    SrcIP,\n    csMethod,\n    csUriStem,\n    csUserName,\n    scStatus,\n    csUserAgent\n| extend timestamp = TimeGenerated,\n         HostCustomEntity = DeviceName,\n         AccountCustomEntity = InitiatingProcessAccountName,\n         IPCustomEntity = SrcIP\n| order by TimeGenerated desc"
      },
      {
        "name": "30206b45-75d2-4c6a-87c5-f0861c1f2870 — CYFIRMA - Attack Surface - Configuration High Rule",
        "description": "This alert is generated when CYFIRMA detects a critical misconfiguration in a public-facing asset or service. Such misconfigurations may include exposed admin interfaces, default credentials, open directory listings, or insecure protocols, which significantly increase the attack surface.\" (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "// High Severity - Attack Surface - Misconfiguration Detected\nlet timeFrame = 5m;\nCyfirmaASConfigurationAlerts_CL\n| where severity == 'Critical' and TimeGenerated between (ago(timeFrame) .. now())\n| extend\n    Description=description,\n    FirstSeen=first_seen,\n    LastSeen=last_seen,\n    RiskScore=risk_score,\n    Domain=sub_domain,\n    TopDomain=top_domain,\n    NetworkIP=ip,\n    AlertUID=alert_uid,\n    UID=uid,\n    Softwares=software,\n    WebAppFirewall=web_app_firewall,\n    ClickJackingDefence=click_jacking_defence,\n    ContentSecurityPolicy=content_security_policy,\n    CookieXssProtection=cookie_xss_protection,\n    DataInjectionDefence=data_injection_defence,\n    DomainStatus=domain_status,\n    MissingEPPCodes=missing_epp_codes,\n    SecureCookie=secure_cookie,\n    SetCookieHttpsOnly=set_cookie_https_only,\n    XFrameOptions=x_frame_options,\n    X_XssProtection=x_xss_protection,\n    ProviderName='CYFIRMA',\n    ProductName='DeCYFIR/DeTCT'\n| project\n    TimeGenerated,\n    Description,\n    Domain,\n    TopDomain,\n    RiskScore,\n    FirstSeen,\n    LastSeen,\n    NetworkIP,\n    AlertUID,\n    UID,\n    Softwares,\n    WebAppFirewall,\n    ClickJackingDefence,\n    ContentSecurityPolicy,\n    CookieXssProtection,\n    DataInjectionDefence,\n    DomainStatus,\n    MissingEPPCodes,\n    SecureCookie,\n    SetCookieHttpsOnly,\n    XFrameOptions,\n    X_XssProtection,\n    ProviderName,\n    ProductName"
      }
    ],
    "spl": [],
    "esql": [
      {
        "name": "f3ac6734-7e52-4a0d-90b7-6847bf4308f2 — Web Server Potential Command Injection Request",
        "description": "(ESQL) This rule detects potential command injection attempts via web server requests by identifying URLs that contain suspicious patterns commonly associated with command execution payloads. Attackers may exploit vulnerabilities in web applications to inject and execute arbitrary commands on the server, often using interpreters like Python, Perl, Ruby, PHP, or shell commands... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "from logs-nginx.access-*, logs-apache.access-*, logs-apache_tomcat.access-*, logs-iis.access-*, logs-traefik.access-*\n| where\n    // Limit to 200 response code to reduce noise\n    http.response.status_code == 200\n\n| eval Esql.url_original_to_lower = to_lower(url.original)\n\n| eval Esql.contains_interpreter = case(Esql.url_original_to_lower like \"*python* -c*\" or Esql.url_original_to_lower like \"*perl* -e*\" or Esql.url_original_to_lower like \"*ruby* -e*\" or Esql.url_original_to_lower like \"*ruby* -rsocket*\" or Esql.url_original_to_lower like \"*lua* -e*\" or Esql.url_original_to_lower like \"*php* -r*\" or Esql.url_original_to_lower like \"*node* -e*\", 1, 0)\n| eval Esql.contains_shell = case(Esql.url_original_to_lower like \"*/bin/bash*\" or Esql.url_original_to_lower like \"*bash*-c*\" or Esql.url_original_to_lower like \"*/bin/sh*\" or Esql.url_original_to_lower rlike \"*sh.{1,2}-c*\", 1, 0)\n| eval Esql.contains_nc = case(Esql.url_original_to_lower like \"*netcat*\" or Esql.url_original_to_lower like \"*ncat*\" or Esql.url_original_to_lower rlike \"\"\".*nc.{1,2}[0-9]{1,3}(\\.[0-9]{1,3}){3}.{1,2}[0-9]{1,5}.*\"\"\" or Esql.url_original_to_lower like \"*nc.openbsd*\" or Esql.url_original_to_lower like \"*nc.traditional*\" or Esql.url_original_to_lower like \"*socat*\", 1, 0)\n| eval Esql.contains_devtcp = case(Esql.url_original_to_lower like \"*/dev/tcp/*\" or Esql.url_original_to_lower like \"*/dev/udp/*\", 1, 0)\n| eval Esql.contains_helpers = case((Esql.url_original_to_lower like \"*/bin/*\" or Esql.url_original_to_lower like \"*/usr/bin/*\") and (Esql.url_original_to_lower like \"*mkfifo*\" or Esql.url_original_to_lower like \"*nohup*\" or Esql.url_original_to_lower like \"*setsid*\" or Esql.url_original_to_lower like \"*busybox*\"), 1, 0)\n| eval Esql.contains_sus_cli = case(Esql.url_original_to_lower like \"*import*pty*spawn*\" or Esql.url_original_to_lower like \"*import*subprocess*call*\" or Esql.url_original_to_lower like \"*tcpsocket.new*\" or Esql.url_original_to_lower like \"*tcpsocket.open*\" or Esql.url_original_to_lower like \"*io.popen*\" or Esql.url_original_to_lower like \"*os.execute*\" or Esql.url_original_to_lower like \"*fsockopen*\", 1, 0)\n| eval Esql.contains_privileges = case(Esql.url_original_to_lower like \"*chmod*+x\", 1, 0)\n| eval Esql.contains_downloader = case(Esql.url_original_to_lower like \"*curl *\" or Esql.url_original_to_lower like \"*wget *\" , 1, 0)\n| eval Esql.contains_file_read_keywords = case(Esql.url_original_to_lower like \"*/etc/shadow*\" or Esql.url_original_to_lower like \"*/etc/passwd*\" or Esql.url_original_to_lower like \"*/root/.ssh/*\" or Esql.url_original_to_lower like \"*/home/*/.ssh/*\" or Esql.url_original_to_lower like \"*~/.ssh/*\" or Esql.url_original_to_lower like \"*/proc/self/environ*\", 1, 0)\n| eval Esql.contains_base64_cmd = case(Esql.url_original_to_lower like \"*base64*-d*\" or Esql.url_original_to_lower like \"*echo*|*base64*\", 1, 0)\n| eval Esql.contains_suspicious_path = case(Esql.url_original_to_lower like \"*/tmp/*\" or Esql.url_original_to_lower like \"*/var/tmp/*\" or Esql.url_original_to_lower like \"*/dev/shm/*\" or Esql.url_original_to_lower like \"*/root/*\" or Esql.url_original_to_lower like \"*/home/*/*\" or Esql.url_original_to_lower like \"*/var/www/*\" or Esql.url_original_to_lower like \"*/etc/cron.*/*\", 1, 0)\n\n| eval Esql.any_payload_keyword = case(\n    Esql.contains_interpreter == 1 or Esql.contains_shell == 1 or Esql.contains_nc == 1 or Esql.contains_devtcp == 1 or\n    Esql.contains_helpers == 1 or Esql.contains_sus_cli == 1 or Esql.contains_privileges == 1 or Esql.contains_downloader == 1 or\n    Esql.contains_file_read_keywords == 1 or Esql.contains_base64_cmd == 1 or Esql.contains_suspicious_path == 1, 1, 0)\n\n| keep\n    @timestamp,\n    Esql.url_original_to_lower,\n    Esql.any_payload_keyword,\n    Esql.contains_interpreter,\n    Esql.contains_shell,\n    Esql.contains_nc,\n    Esql.contains_devtcp,\n    Esql.contains_helpers,\n    Esql.contains_sus_cli,\n    Esql.contains_privileges,\n    Esql.contains_downloader,\n    Esql.contains_file_read_keywords,\n    Esql.contains_base64_cmd,\n    Esql.contains_suspicious_path,\n    source.ip,\n    destination.ip,\n    agent.id,\n    http.request.method,\n    http.response.status_code,\n    user_agent.original,\n    agent.name,\n    data_stream.dataset,\n    data_stream.namespace\n\n| stats\n    Esql.event_count = count(),\n    Esql.url_path_count_distinct = count_distinct(Esql.url_original_to_lower),\n\n    // General fields\n\n    Esql.agent_name_values = values(agent.name),\n    Esql.agent_id_values = values(agent.id),\n    Esql.url_path_values = values(Esql.url_original_to_lower),\n    Esql.http.response.status_code_values = values(http.response.status_code),\n    Esql.user_agent_original_values = values(user_agent.original),\n    Esql.data_stream_dataset_values = values(data_stream.dataset),\n    Esql.data_stream_namespace_values = values(data_stream.namespace),\n\n    // Rule Specific fields\n    Esql.any_payload_keyword_max = max(Esql.any_payload_keyword),\n    Esql.contains_interpreter_values = values(Esql.contains_interpreter),\n    Esql.contains_shell_values = values(Esql.contains_shell),\n    Esql.contains_nc_values = values(Esql.contains_nc),\n    Esql.contains_devtcp_values = values(Esql.contains_devtcp),\n    Esql.contains_helpers_values = values(Esql.contains_helpers),\n    Esql.contains_sus_cli_values = values(Esql.contains_sus_cli),\n    Esql.contains_privileges_values = values(Esql.contains_privileges),\n    Esql.contains_downloader_values = values(Esql.contains_downloader),\n    Esql.contains_file_read_keywords_values = values(Esql.contains_file_read_keywords),\n    Esql.contains_base64_cmd_values = values(Esql.contains_base64_cmd),\n    Esql.contains_suspicious_path_values = values(Esql.contains_suspicious_path)\n\n    by source.ip, agent.id\n\n| where\n    // Filter for potential command injection attempts with low event counts to reduce false positives\n    Esql.any_payload_keyword_max == 1 and Esql.event_count < 5"
      },
      {
        "name": "f7d588ba-e4b0-442e-879d-7ec39fbd69c5 — Potential SAP NetWeaver WebShell Creation",
        "description": "(EQL) Identifies suspicious Java file creation in the IRJ directory of the SAP NetWeaver application. This may indicate an attempt to deploy a webshell. (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "file where host.os.type in (\"linux\", \"windows\") and event.action == \"creation\" and\n file.extension : (\"jsp\", \"java\", \"class\") and\n file.path : (\"/*/sap.com/*/servlet_jsp/irj/root/*\",\n              \"/*/sap.com/*/servlet_jsp/irj/work/*\",\n              \"?:\\\\*\\\\sap.com\\\\*\\\\servlet_jsp\\\\irj\\\\root\\\\*\",\n              \"?:\\\\*\\\\sap.com\\\\*\\\\servlet_jsp\\\\irj\\\\work\\\\*\")"
      }
    ]
  },
  "automation": {
    "safe": [
      "Add recommendation as Sentinel incident comment.",
      "Run enrichment queries.",
      "Create ServiceNow SecOps task."
    ],
    "approval_required": [
      "Contain or disable the affected host/account.",
      "Any change to production configuration."
    ]
  },
  "escalation_criteria": [
    "Server Software Component activity observed on a privileged account or critical system.",
    "Activity follows or precedes other suspicious behaviour in the same investigation.",
    "Automated triage cannot confidently rule out malicious intent."
  ],
  "false_positive_considerations": [
    "Legitimate administrative or maintenance activity matching this pattern.",
    "Approved security testing or red team exercise.",
    "Known benign software producing similar telemetry."
  ],
  "confluence": {
    "title": "T1505 - Server Software Component Response Guidance",
    "labels": [
      "mitre",
      "attack",
      "d3fend",
      "secops",
      "basyrix"
    ],
    "sections": [
      "summary",
      "d3fend_mappings",
      "investigation_steps",
      "response_actions",
      "queries",
      "automation",
      "escalation_criteria",
      "false_positive_considerations"
    ]
  }
}