Windows.Detection.WS_FTP

This is an artifact to detect exploitation of a Progress Software’s WS_FTP critical vulnerability observed in the wild.

CVE-2023–40044 is a severe .NET deserialization vulnerability in WS_FTP Server’s Ad Hoc Transfer module, allowing a pre-authenticated attacker to execute remote commands on the server’s operating system.

CVE-2023–42657 is a directory traversal vulnerability, enabling attackers to perform file operations outside their authorized WS_FTP folder path and operate on the underlying OS.

Both vulnerabilities are critical, with CVSS scores of 8.8 and 9.9 respectively, and affect versions prior to 8.7.4 and 8.8.2​.

The artifact enables detection via:

  • Yara: IIS logs
  • Evtx: Application Event Logs IIS exception

Both methods target observed IPs and the string /AHT/AhtApiService.asmx which is part of the vulnerable module. Note: no direct evidence of exploitation observed in application logs, only exceptions that otherwise seem rare around the time of exploitation.

Last updated: 2023-10-01T13:15Z



name: Windows.Detection.WS_FTP
author: Matt Green - @mgreen27
description: | 
   This is an artifact to detect exploitation of a Progress Software's WS_FTP 
   critical vulnerability observed in the wild.
   
   CVE-2023–40044 is a severe .NET deserialization vulnerability in WS_FTP 
   Server’s Ad Hoc Transfer module, allowing a pre-authenticated attacker to 
   execute remote commands on the server’s operating system.   
   
   CVE-2023–42657 is a directory traversal vulnerability, enabling attackers to 
   perform file operations outside their authorized WS_FTP folder path and 
   operate on the underlying OS.   
   
   Both vulnerabilities are critical, with CVSS scores of 8.8 and 9.9 
   respectively, and affect versions prior to 8.7.4 and 8.8.2​.
   
   The artifact enables detection via:
   
   - Yara: IIS logs
   - Evtx: Application Event Logs IIS exception   
   
   Both methods target observed IPs and the string /AHT/AhtApiService.asmx which 
   is part of the vulnerable module.
   Note: no direct evidence of exploitation observed in application logs, only 
   exceptions that otherwise seem rare around the time of exploitation.
   
   
   Last updated: 2023-10-01T13:15Z
   
reference:
  - https://www.rapid7.com/blog/post/2023/09/29/etr-critical-vulnerabilities-in-ws_ftp-server/

type: CLIENT
resources:
  timeout: 1800

parameters:
  - name: EvtxGlob
    default: '%SystemRoot%\System32\Winevt\Logs\Application.evtx'
  - name: IocRegex
    type: regex
    description: "IOC Regex in evtxHunt"
    default: '/AHT/|86\.48\.3\.172'
  - name: DateAfter
    type: timestamp
    default: 1685232000
    description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
  - name: DateBefore
    type: timestamp
    description: "Search for events or Modification time after this date. YYYY-MM-DDTmm:hh:ssZ"
  - name: AllDrives
    type: bool
    description: "By default we target yara at all drives"
    default: Y
  - name: DriveLetter
    description: "Target yara drive. Default is a C: if not AllDrives"
    default: "C:"
  - name: LogYara
    default: |
        rule LOG_ws_ftp_exploit {
          meta:
            description = "Detects potential exploitation of Progress Software WS_FTP Server in IIS logs"
            author = "Matt Green - @mgreen27"
            reference = "https://www.rapid7.com/blog/post/2023/09/29/etr-critical-vulnerabilities-in-ws_ftp-server/"
            date = "2023-10-01"
            score = 80
      
         strings:
           $post = /\n.{1,50} POST \/AHT\/.{1,250}\n/
           $ip = " 86.48.3.172 " ascii
      
          condition:
            any of them
        }
  - name: NumberOfHits
    description: This artifact will stop by default at one hit. This setting allows additional hits
    default: 1
    type: int64
  - name: ContextBytes
    description: Include this amount of bytes around hit as context.
    default: 0
    type: int
  - name: UploadYaraHits
    type: bool

sources:
  - precondition:
      SELECT OS From info() where OS = 'windows'
    
    name: Yara
    query: |
      -- check which Yara to use
      LET yara_rules <= LogYara

      -- first find all matching files mft
      LET files = SELECT OSPath, IsDir
        FROM Artifact.Windows.NTFS.MFT(MFTDrive=DriveLetter, AllDrives=AllDrives,
            FileRegex='^u_.+\.log$',
            PathRegex='inetpub' )
        WHERE NOT IsDir
            AND NOT OSPath =~ '''.:\\<Err>\\'''
            AND (FileName=~ '^u_.+\.log$' AND OSPath =~ 'inetpub' )
            AND if(condition=DateAfter,
                then= LastRecordChange0x10 > DateAfter,
                else= True)
            AND if(condition=DateBefore,
                then= LastRecordChange0x10 < DateBefore,
                else= True)

      -- scan files and only report a single hit.
      LET hits = SELECT * FROM foreach(row=files,
            query={
                SELECT
                    FileName, OSPath,
                    File.Size AS Size,
                    File.ModTime AS ModTime,
                    Rule, Tags, Meta,
                    String.Name as YaraString,
                    String.Offset as HitOffset,
                    upload( accessor='scope', 
                            file='String.Data', 
                            name=format(format="%v-%v-%v", 
                            args=[
                                OSPath,
                                if(condition= String.Offset - ContextBytes < 0,
                                    then= 0,
                                    else= String.Offset - ContextBytes),
                                if(condition= String.Offset + ContextBytes > File.Size,
                                    then= File.Size,
                                    else= String.Offset + ContextBytes) ]
                            )) as HitContext
                FROM yara(rules=yara_rules, files=OSPath, context=ContextBytes,number=NumberOfHits)
            })

      -- upload files that have hit
      LET upload_hits=SELECT *,
            upload(file=OSPath) AS Upload
        FROM hits
        GROUP BY OSPath

      -- return rows
      SELECT * FROM if(condition=UploadYaraHits,
        then={ SELECT * FROM upload_hits},
        else={ SELECT * FROM hits})


  - name: Evtx
    query: |
      SELECT EventTime,Computer,Channel,Provider,EventID,EventRecordID,
        EventData,
        OSPath
      FROM Artifact.Windows.EventLogs.EvtxHunter(
                        EvtxGlob=EvtxGlob,
                        IocRegex=IocRegex,
                        IdRegex='^1309$',
                        DateAfter=DateAfter,
                        DateBefore=DateBefore )
      
column_types:
  - name: HitContext
    type: preview_upload
  - name: ModTime
    type: timestamp
  - name: EventTime
    type: timestamp