← All rules
IOI-004 · IoI Rule · Structural
VSS Directory Presence Check
✓ Validated Structural $MFT $UsnJrnl
Contributed by @ioi-framework · 2025-01-01 · v1.0 · View scenario →
Invariant predicate φ
If VSS infrastructure files are present under System Volume Information, the corresponding GUID snapshot directories must also be present.
Download ioi-004.rq ↗
Tested on: Virtuoso 7.2 (OpenLink OSE)

Dependency specification

  1. $MFT — files under System Volume Information: infrastructure files (tracking.log, IndexerVolumeGuid, _OnDiskSnapshotProp) and GUID snapshot directories
  2. $UsnJrnlFileDelete, FileDeleteClose, or DataTruncation records matching bare {GUID} filenames

If VSS infrastructure files exist under System Volume Information, the corresponding GUID snapshot directories must also be present.

This rule requires the full infrastructure triad (tracking.log, IndexerVolumeGuid, _OnDiskSnapshotProp) to be present before correlating to GUID deletion evidence, to reduce false positives from generic GUID churn.

Contradiction condition

Fires when infrastructure files are present and no bare {GUID} snapshot directories appear in the MFT and USN records confirm GUID-format deletion activity.

SPARQL signature

PREFIX core: <https://ontology.unifiedcyberontology.org/uco/core/>
PREFIX observable: <https://ontology.unifiedcyberontology.org/uco/observable/>
PREFIX ioi-ext: <https://ioi-framework.github.io/ns/ioi-ext/>

SELECT DISTINCT ?vss_infrastructure ?deleted_guid ?usn_evidence
WHERE {
  {
    SELECT (GROUP_CONCAT(DISTINCT ?vss_file; separator=" ; ") AS ?vss_infrastructure)
    WHERE {
      GRAPH <mft_case4> {
        ?mft_entry a observable:File ;
                   core:hasFacet ?file_facet, ?mft_facet .
        ?file_facet a observable:FileFacet ;
                    observable:fileName ?vss_file .
        ?mft_facet a ioi-ext:MftFacet ;
                   ioi-ext:parentPath ?parent_path .
        FILTER(CONTAINS(?parent_path, "System Volume Information"))
        FILTER(
          CONTAINS(?vss_file, "tracking.log") ||
          CONTAINS(?vss_file, "IndexerVolumeGuid") ||
          CONTAINS(?vss_file, "_OnDiskSnapshotProp")
        )
      }
    }
  }

  FILTER(BOUND(?vss_infrastructure))
  FILTER(CONTAINS(STR(?vss_infrastructure), "tracking.log"))
  FILTER(CONTAINS(STR(?vss_infrastructure), "IndexerVolumeGuid"))
  FILTER(CONTAINS(STR(?vss_infrastructure), "_OnDiskSnapshotProp"))

  {
    FILTER NOT EXISTS {
      GRAPH <mft_case4> {
        ?guid_entry a observable:File ;
                    core:hasFacet ?guid_file_facet, ?guid_mft_facet .
        ?guid_file_facet a observable:FileFacet ;
                         observable:fileName ?guid_name .
        ?guid_mft_facet a ioi-ext:MftFacet ;
                        ioi-ext:parentPath ?guid_parent .
        FILTER(CONTAINS(?guid_parent, "System Volume Information"))
        FILTER(STRSTARTS(STR(?guid_name), "{"))
        FILTER(STRENDS(STR(?guid_name), "}"))
        FILTER(STRLEN(STR(?guid_name)) = 38)
      }
    }
    GRAPH <usn_case4> {
      ?usn_file a observable:File ;
                core:hasFacet ?usn_file_facet, ?usn_facet .
      ?usn_file_facet a observable:FileFacet ;
                      observable:fileName ?usn_filename .
      ?usn_facet a ioi-ext:UsnFacet ;
                 ioi-ext:updateReasons ?update_reasons .
      FILTER(STRSTARTS(STR(?usn_filename), "{"))
      FILTER(STRENDS(STR(?usn_filename), "}"))
      FILTER(STRLEN(STR(?usn_filename)) = 38)
      VALUES ?reason_term { "FileDelete" "FileDeleteClose" "DataTruncation" }
      FILTER(CONTAINS(?update_reasons, ?reason_term))
      BIND(?usn_filename AS ?deleted_guid)
      BIND(?update_reasons AS ?usn_evidence)
    }
  }
}
ORDER BY ?deleted_guid

Graph IRI substitution

Replace <mft_case4> and <usn_case4> with your named graph IRIs.

Expected output

Variable Description
?vss_infrastructure Infrastructure files found in MFT
?usn_filename Deleted directory names from USN
?update_reasons USN update-reason flags confirming deletion