Windows.Detection.TemplateInjection

This content will detect injected templates in Office and RTF documents.

Template injection is a form of defence evasion. For office documents a malicious macro is loaded into an OOXML document via a resource file masquerading as an office template. The OOXML artifact structure will also detect MSHTML RCE Vulnerability #CVE-2021-40444 which has a similar payload technique. For RTF documents a malicious payload can be delivered by modifying document formatting control via the “\*\template” structure.

This artifact can be modified to search for other suspicious rels files:

  • document.xml.rels = macros, ole objects, images.
  • settings.xml.rels = templates.
  • websettings.xml.rels = frames.
  • header#.xml.rels and footer#.xml.rels and others has also been observed hosting image files for canary files or abused for NetNTLM hash collection.

Change TemplateFileRegex to ‘\.xml\.rels$’ for looser file selection. Change TemplateTargetRegex to ‘^(https?|smb|\\|//|mhtml|file)’ for looser Target selection.

This artifact can also be modified to quickly deploy yara based detections on other documents. Simply replace RtfYara with yara of interest and modify glob for targeting.


name: Windows.Detection.TemplateInjection
author: Matt Green - @mgreen27
description: |
    This content will detect injected templates in Office and RTF documents.

    Template injection is a form of defence evasion.
    For office documents a malicious macro is loaded into an OOXML document
    via a resource file masquerading as an office template. The OOXML artifact structure
    will also detect MSHTML RCE Vulnerability #CVE-2021-40444 which has a similar payload technique.
    For RTF documents a malicious payload can be delivered by modifying document
    formatting control via the "\\\*\template" structure.


    This artifact can be modified to search for other suspicious rels files:

    - document.xml.rels = macros, ole objects, images.
    - settings.xml.rels = templates.
    - websettings.xml.rels = frames.
    - header#.xml.rels and footer#.xml.rels and others has also been observed
    hosting image files for canary files or abused for NetNTLM hash collection.

    Change TemplateFileRegex to '\\.xml\\.rels$' for looser file selection.
    Change TemplateTargetRegex to '^(https?|smb|\\\\|//|mhtml|file)' for looser
    Target selection.

    This artifact can also be modified to quickly deploy yara based detections on
    other documents. Simply replace RtfYara with yara of interest and modify glob
    for targeting.



reference:
  - https://attack.mitre.org/techniques/T1221/
  - https://www.sans.org/reading-room/whitepapers/testing/template-injection-attacks-bypassing-security-controls-living-land-38780

type: CLIENT

parameters:
  - name: SearchGlob
    description: Glob to search
    default: C:\Users\**\*.{rtf,doc,dot,docx,docm,dotx,dotm,docb,xls,xlt,xlm,xlsx,xlsm,xltx,xltm,xlsb,ppt,pptx,pptm,potx,potm}
  - name: TemplateFileRegex
    description: Regex to search inside resource section.
    default: '(document|settings)\.xml\.rels$'
    type: regex
  - name: TemplateTargetRegex
    description: Regex to search inside resource section.
    default: '^(https?|smb|\\\\|//|mhtml)'
    type: regex
  - name: UploadDocument
    type: bool
    description: Select to upload document on detection.
  - name: RtfYara
    type: yara
    default: |
        rule RTF_TemplateInjection {
            meta:
                author = "Matt Green - @mgreen27"
                description = "Yara for RTF template injection. Using regex match to extract template information"

            strings:
                $regex1 = /\{\\\*\\template\s+http[^\}]+\}/ nocase
                $regex2 = /\{\\\*\\templates\s+\\u-[^\}]+\}/ nocase
                $regex3 = /\{\\\*\\template\s+file[^\}]+\}/ nocase

            condition:
              // header is {\rt only to also flag on malformed rtf heders
              uint32be(0) == 0x7B5C7274 and 1 of them
        }

sources:
  - precondition:
      SELECT OS From info() where OS = 'windows'

    query: |
      -- Find target docs
      LET office_docs = SELECT OSPath, Mtime, Size
        FROM glob(globs=SearchGlob)
        WHERE NOT IsDir and Size > 0

      LET rtf_injection <= SELECT * FROM foreach(
         row=office_docs,
         query={
                SELECT
                    OSPath AS DocumentPath,
                    hash(path=OSPath) as DocumentHash,
                    Mtime,
                    Size,
                    'YaraHit: ' + Rule  as Section,
                    regex_replace(
                      source=String.Data,
                      re='\{...template\s*|\}',replace='') as TemplateTarget
                FROM yara(files=OSPath, rules=RtfYara)
                WHERE NOT TemplateTarget =~ '^http(s|)://schemas\.microsoft\.com/'

            })

      -- select zip members inside the doc that have some content.
      LET document_parts = SELECT * FROM foreach(
            row={
                SELECT
                    OSPath AS OfficePath,
                    Mtime as OfficeMtime,
                    Size as OfficeSize
                FROM office_docs
                WHERE NOT OSPath in rtf_injection.OSPath
            },
            query= {
                SELECT
                    Mtime, Atime, Ctime,
                    OSPath,
                    OSPath.Path AS ZipMemberPath,
                    OfficePath
                FROM glob(
                  globs="/**",
                  root=pathspec(DelegatePath=OfficePath),
                  accessor='zip')
                WHERE not IsDir
                  AND Size > 0
                  AND ZipMemberPath =~ TemplateFileRegex
            })

      -- parse settings file by line and extract config
      LET template = SELECT * FROM foreach(row=document_parts,
        query={
            SELECT
                OSPath as SectionPath,
                OSPath.DelegatePath as Document,
                OSPath.Path as Section,
                parse_string_with_regex(
                    string=Line,
                    regex=['\\s+Target="(?P<Target>[^"]+)"\\s+TargetMode='
                        ]).Target as TemplateTarget,
                Mtime as SectionMtime,
                Atime as SectionAtime,
                Ctime as SectionCtime
            FROM parse_lines(filename=OSPath, accessor='zip')
            WHERE TemplateTarget
        })

      -- search settings for remote or file templates, format mshtml entries
      LET hits = SELECT * FROM chain(
        rtf = { SELECT * FROM rtf_injection },
        office = {
            SELECT * FROM foreach(row=template,
                query={
                    SELECT
                        OSPath AS DocumentPath,
                        hash(path=OSPath) as DocumentHash,
                        Mtime,
                        Size,
                        Section,
                        regex_replace(source=TemplateTarget,
                            re='.*Target="(mhtml)',
                            replace='mhtml') as TemplateTarget,
                        SectionMtime,
                        hash(path=SectionPath,accessor='zip') as SectionHash
                    FROM stat(filename=Document)
                    WHERE
                        TemplateTarget =~ TemplateTargetRegex
                         AND (( Section=~'/document.xml.rels$' AND TemplateTarget=~'^mhtml:' )
                                OR NOT Section=~'/document.xml.rels$' )
                })
        })

      -- upload hits to server
      LET upload_hits = SELECT *, upload(file=DocumentPath) as Upload
        FROM hits

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