|
| 1 | +name: Windows.Detection.Honeyfiles |
| 2 | +author: Zane Gittins & Matt Green (@mgreen27). |
| 3 | +description: | |
| 4 | + This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using etw. The process tracker must be enabled, we use this to enrich etw events. Honeyfiles created by this artifact are removed at exit. |
| 5 | +
|
| 6 | + * TargetPath - Location to create honeyfile. |
| 7 | + * Enabled - Only generate the honeyfile if this is set to 'Y' |
| 8 | + * MagicBytes - The starting magic bytes of the honeyfile. |
| 9 | + * MinSize,MaxSize - The size of the honeyfile will be a random value between MinSize and MaxSize. |
| 10 | +
|
| 11 | +type: CLIENT_EVENT |
| 12 | + |
| 13 | +parameters: |
| 14 | + - name: Honeyfiles |
| 15 | + description: The honeyfiles to generate and monitor. |
| 16 | + type: csv |
| 17 | + default: | |
| 18 | + TargetPath,Enabled,MagicBytes,MinSize,MaxSize |
| 19 | + "%USERPROFILE%\Documents\KeePass\KeePass.kdbx",Y,03D9A29A67FB4BB5,10249,20899 |
| 20 | + "%USERPROFILE%\AppData\Local\KeePass\KeePass.config.xml",Y,3C3F786D6C,512,1024 |
| 21 | + "%USERPROFILE%\AppData\Local\LastPass\lastpass.conf",Y,3C3F786D6C,512,1024 |
| 22 | + "%USERPROFILE%\AppData\Roaming\LastPass\loginState.xml",Y,3C3F786D6C,512,1024 |
| 23 | + "%USERPROFILE%\AppData\Roaming\WinSCP\WinSCP.ini",Y,5B436F6E66696775726174696F6E5D,512,1024 |
| 24 | + "%USERPROFILE%\.aws\credentials",Y,5B64656661756C745D,512,2048 |
| 25 | + "%USERPROFILE%\.aws\config",Y,5B64656661756C745D,512,2048 |
| 26 | + "%USERPROFILE%\.ssh\my_id_rsa",Y,2D2D2D2D2D424547494E205253412050524956415445204B45592D2D2D2D2D,1024,4096 |
| 27 | + "%USERPROFILE%\.gcloud\credentials.db",Y,53514c69746520666f726d6174203300,512,2048 |
| 28 | + "%USERPROFILE%\.azure\azureProfile.json",Y,7B0D0A,512,2048 |
| 29 | + - name: ProcessExceptionsRegex |
| 30 | + description: Except these processes from detections when they access honeyfiles. |
| 31 | + type: string |
| 32 | + default: "SearchProtocolHost.exe|Explorer.exe" |
| 33 | + - name: HoneyUserRegex |
| 34 | + description: User name regex that will be used to host honeyfiles. |
| 35 | + type: string |
| 36 | + default: "." |
| 37 | +sources: |
| 38 | + - precondition: |
| 39 | + SELECT OS From info() where OS = 'windows' |
| 40 | + |
| 41 | + query: | |
| 42 | + LET RandomChars(size) = SELECT |
| 43 | + format(format="%02x", args=rand(range=256)) AS HexByte |
| 44 | + FROM range(end=size) |
| 45 | + |
| 46 | + LET check_exist(path) = SELECT |
| 47 | + OSPath, |
| 48 | + Size, |
| 49 | + IsDir, |
| 50 | + if(condition=read_file(filename=OSPath)[-7:] =~ 'VRHoney', |
| 51 | + then=True, |
| 52 | + else=False) AS IsHoneyFile |
| 53 | + FROM stat(filename=path) |
| 54 | + |
| 55 | + LET enumerate_path = SELECT |
| 56 | + regex_replace(source=TargetPath, |
| 57 | + re='''\%USERPROFILE\%''', |
| 58 | + replace=Directory) AS TargetPath, |
| 59 | + *, |
| 60 | + check_exist(path=regex_replace(source=TargetPath, |
| 61 | + re='''\%USERPROFILE\%''', |
| 62 | + replace=Directory))[0] AS Exists, |
| 63 | + MaxSize - rand(range=(MaxSize - MinSize)) - len( |
| 64 | + list=unhex(string=MagicBytes)) - 7 AS _PaddingSize |
| 65 | + FROM Honeyfiles |
| 66 | + |
| 67 | + LET target_users = SELECT Name, |
| 68 | + Directory, |
| 69 | + UUID |
| 70 | + FROM Artifact.Windows.Sys.Users() |
| 71 | + WHERE NOT UUID =~ '''^(S-1-5-18|S-1-5-19|S-1-5-20)$''' |
| 72 | + AND Name =~ HoneyUserRegex |
| 73 | + |
| 74 | + LET show_honeyfiles = SELECT TargetPath, |
| 75 | + Enabled, |
| 76 | + MagicBytes, |
| 77 | + MinSize, |
| 78 | + MaxSize, |
| 79 | + _PaddingSize, |
| 80 | + Exists.Size AS Size, |
| 81 | + Exists.IsHoneyFile AS IsHoneyFile |
| 82 | + FROM foreach(row=target_users, query=enumerate_path) |
| 83 | + |
| 84 | + LET copy_honeyfiles = SELECT |
| 85 | + *, if(condition=Enabled =~ "^(Y|YES)$" |
| 86 | + AND (NOT Size OR IsHoneyFile), |
| 87 | + then=log(message="Creating file %v", dedup=-1, args=TargetPath) |
| 88 | + && copy(dest=TargetPath, |
| 89 | + create_directories='y', |
| 90 | + accessor='data', |
| 91 | + filename=unhex( |
| 92 | + string=MagicBytes + join( |
| 93 | + array=RandomChars(size=_PaddingSize).HexByte) + |
| 94 | + format(format='%x', args='VRHoney'))), |
| 95 | + else="File does not exist") AS CreateHoneyFile |
| 96 | + FROM show_honeyfiles |
| 97 | + |
| 98 | + LET remove_honeyfiles = SELECT |
| 99 | + *, _PaddingSize, |
| 100 | + if(condition=IsHoneyFile, |
| 101 | + then=log(message="Removing %v", args=TargetPath, dedup=-1) |
| 102 | + && rm(filename=TargetPath), |
| 103 | + else="File does not exist") AS RemoveHoneyFile |
| 104 | + FROM show_honeyfiles |
| 105 | + |
| 106 | + LET add_honeyfiles = SELECT |
| 107 | + TargetPath, |
| 108 | + Enabled, |
| 109 | + MagicBytes, |
| 110 | + MinSize, |
| 111 | + MaxSize, |
| 112 | + check_exist(path=TargetPath)[0].Size AS Size, |
| 113 | + check_exist(path=TargetPath)[0].IsHoneyFile AS IsHoneyFile |
| 114 | + FROM copy_honeyfiles |
| 115 | + |
| 116 | + LET _ <= atexit(query={ SELECT * FROM remove_honeyfiles }) |
| 117 | + |
| 118 | + LET WatchFiles <= to_dict(item={ |
| 119 | + SELECT TargetPath AS _key, |
| 120 | + IsHoneyFile AS _value |
| 121 | + FROM add_honeyfiles |
| 122 | + WHERE IsHoneyFile |
| 123 | + }) |
| 124 | + |
| 125 | + LET Keyword <= 5264 |
| 126 | + |
| 127 | + LET CurrentPid <= getpid() |
| 128 | + |
| 129 | + LET TargetEvents = SELECT * |
| 130 | + FROM watch_etw(guid='{edd08927-9cc4-4e65-b970-c2560fb5c289}', |
| 131 | + description="Microsoft-Windows-Kernel-File", |
| 132 | + any=Keyword) |
| 133 | + WHERE System.ID = 12 |
| 134 | + AND System.ProcessID != CurrentPid |
| 135 | + |
| 136 | + LET AuditEvents = SELECT |
| 137 | + timestamp(string=System.TimeStamp) AS Timestamp, |
| 138 | + get(item=WatchFiles, field=EventData.FileName) AS IsHoneyFile, |
| 139 | + * |
| 140 | + FROM TargetEvents |
| 141 | + WHERE IsHoneyFile != NULL |
| 142 | + |
| 143 | + LET Events = SELECT |
| 144 | + Timestamp, |
| 145 | + IsHoneyFile, |
| 146 | + System.ProcessID AS Pid, |
| 147 | + EventData.FileName AS TargetPath, |
| 148 | + process_tracker_get(id=System.ProcessID).Data AS ProcInfo, |
| 149 | + join(array=process_tracker_callchain(id=System.ProcessID).Data.Name, |
| 150 | + sep="->") AS CallChain |
| 151 | + FROM AuditEvents |
| 152 | + WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex |
| 153 | + |
| 154 | + SELECT * |
| 155 | + FROM delay(query=Events, delay=5) |
0 commit comments