
инструмент для пентестеров, помогающий найти вкусные конфеты, от @l0ss и @Sh3r4 ( Twitter: @/mikeloss и @/sh3r4_hax )

Snaffler — это инструмент для пентестеров и редтимеров, помогающий найти вкусные конфетные иголки (в основном учетные данные, но он гибкий) в куче ужасно скучных стогов сена (огромная среда Windows/AD).
Он также может быть полезен другим людям, занимающимся другими вещами, но он явно НЕ предназначен для использования в качестве инструмента «аудита».
Уф, ладно. Но мы не несём ответственности за результаты. Мы написали всё это для вас, но ничего страшного. Мы не злимся, просто разочарованы.
snaffler.exe -s -o snaffler.log
В общих чертах — он получает список компьютеров Windows из Active Directory, затем распространяет свои «снаффлерные» щупальца на все эти компьютеры, чтобы выяснить, на каких из них есть общие файловые ресурсы и можете ли вы их прочитать.
Затем ЕЩЁ БОЛЬШЕ «снаффлерных» щупалец перечисляют все файлы в этих общих ресурсах и используют ОБУЧЕННЫЙ АРТЕФАКТНЫЙ ИНТЕЛЛЕКТ для МАШИН, чтобы выяснить, какие из них могут заинтересовать такого грязного маленького хакера, как вы.
На самом деле он не делает никаких ML-штук, потому что для правильного выполнения этого потребуются обучающие данные, а это потребовало бы огромного количества времени, которого у нас нет. Вместо этого, как и все хорошие «ML»-проекты, он просто использует кучу if-выражений и регулярок.
Вот так!
Если вы «просто запустите EXE-шник на машине, входящей в домен, в контексте доменного пользователя» (как людям было сказано делать с Grouper2, сразу после чего они запускали его со всеми включенными ключами verbose/debug, так что он выплёвывал несколько сотен мегабайт трассировок стека), то он в основном ничего не сделает. Это наша идея шутки™ над людьми, которые не читают README-файлы, потому что мы монстры.
ОДНАКО... если добавить правильные заклинания, то включится вышеупомянутый L.A.I.M. и вывалятся пути к файлам, где могут быть конфетки.
Ключевые заклинания:
-o Включает вывод результатов в файл. Вероятно, это нужно, если вы не используете -s. Например, -o C:\users\thing\snaffler.log
-s Включает вывод результатов в stdout сразу после их обнаружения. Вероятно, это нужно, если вы не используете -o.
-v Управляет уровнем детализации. Варианты: Trace (самый подробный), Degub (менее подробный, меньше «губ»), Info (ещё менее подробный, по умолчанию) и Data (только результаты). Например, -v debug.
-m Включает и назначает выходной каталог, в который Snaffler будет автоматически копировать (или «Снаффлить», если хотите) любые найденные файлы, которые ему понравятся.
-l Максимальный размер файлов (в байтах) для «Снаффлинга». По умолчанию 10000000, что составляет примерно 10 МБ.
-i Отключает обнаружение компьютеров и общих ресурсов, требует указать путь к каталогу для поиска файлов.
-n Отключает обнаружение компьютеров, принимает список хостов через запятую или входной файл для поиска общих ресурсов и файлов. Обратите внимание: если указан файл, входные данные должны быть путём, например, C:\targets.txt или .\targets.txt.
-y Форматирует вывод в TSV.
-b Пропускает правила LAIM, которые находят менее интересные вещи; настройте число от 0 до 3.
-f Ограничивает поиск общих файловых ресурсов через DFS (Distributed File System) — это должно быть значительно незаметнее, чем по умолчанию, при этом охватывая самые большие общие ресурсы во многих организациях.
-a Пропускает перечисление файлов и просто выдаёт список читаемых общих ресурсов на целевых хостах.
-u Заставляет Snaffler извлечь список имён учётных записей из AD, выбрать наиболее интересные и использовать их в правиле поиска.
-d Домен для поиска компьютеров для поиска общих ресурсов для поиска файлов. Легко.
-c Контроллер домена для запроса списка компьютеров домена.
-r Максимальный размер файла (в байтах), внутри которого будет производиться поиск интересных строк. По умолчанию 500k.
-j Сколько байт контекста по обе стороны от найденных строк в файлах показывать, например, -j 200.
-z Путь к конфигурационному файлу, который определяет всё вышеперечисленное и многое другое! Подробнее см. ниже. Укажите -z generate, чтобы сгенерировать пример конфигурационного файла с именем .\default.toml.
-t Тип лога для вывода. В настоящее время поддерживаются варианты: plain и JSON. По умолчанию plain.
-x Максимальное количество потоков. Не устанавливайте ниже 4, иначе всё сломается.
-p Путь к каталогу, полному правил в формате .toml. Snaffler загрузит все эти правила вместо набора правил по умолчанию.
Надеюсь, этот аннотированный пример поможет:
Эту запись лога следует читать примерно слева направо:
... а остальная часть строки (серым цветом) — это небольшой фрагмент контекста из файла, где было совпадение.
В данном случае мы нашли значения ASP.NET validationKey и decryptionKey, которые могут позволить нам выполнить RCE веб-приложения с помощью какой-нибудь хацкерской десериализации. Ура!
Примечание: после создания этого скриншота Sh3r4 добавил функцию, которая добавляет имя текущего пользователя и имя хоста в начало каждой строки. Но я не хочу переделывать скриншот.
Каждый магический метод поиска файлов L.A.I.M. делает такие вещи, как:
Поиск по точному совпадению расширения файла, то есть любой файл с расширением, совпадающим с соответствующим списком слов, будет возвращён. Это предназначено для расширений файлов, которые почти всегда содержат конфетки, например .kdbx, .vmdk, .ppk и т.д.
Поиск по точному совпадению имени файла (без учёта регистра). Это предназначено для имён файлов, которые почти всегда содержат конфетки, например id_rsa, shadow, NTDS.DIT и т.д.
Поиск по точному совпадению расширения файла (ещё один список слов), ЗАТЕМ «греппинг» содержимого любых совпадающих файлов на предмет определённых ключевых слов (ещё один, ещё один список слов). Это предназначено для расширений файлов, которые иногда содержат конфетки, но где, скорее всего, будет много мусора. Например, web.config иногда содержит учётные данные базы данных, но часто также содержит скучную ерунду конфигурации IIS без паролей. Это (например) найдёт всё, оканчивающееся на .config, затем выполнит grep по этим строкам, включая (но не ограничиваясь): connectionString, password, и т.д.
Snaffler использует систему «классификаторов», каждый из которых исследует общие ресурсы, папки, файлы или содержимое файлов, передавая одни элементы дальше по цепочке следующему классификатору, а другие отбрасывая. Каждый классификатор использует набор правил, чтобы решить, что делать с классифицируемыми элементами.
Эти правила могут быть очень простыми, например: «если расширение файла — .kdbx, сообщить мне о нём» или «если путь содержит windows\sxs, прекратить просмотр подкаталогов и файлов внутри этого пути».
Правила также могут использовать регулярные выражения, что позволяет осуществлять относительно сложное сопоставление с образцом. Это особенно полезно при просмотре содержимого файлов, хотя следует соблюдать осторожность, чтобы избежать регулярных выражений, значительно снижающих производительность. В больших средах эти правила могут проверяться буквально миллионы раз, поэтому незначительные проблемы с производительностью могут значительно усиливаться.
Настоящая сила Snaffler заключается в его способности объединять несколько правил в цепочку и даже создавать ветвящиеся цепочки. Это позволяет нам использовать «дешёвые» правила (например, проверку имён и расширений файлов) для принятия решения о том, когда использовать «дорогие» правила (например, запуск регулярных выражений по содержимому файлов, разбор сертификатов для проверки, содержат ли они закрытые ключи, и т.д.). Именно это позволяет Snaffler достигать достаточно глубокой проверки файлов там, где это необходимо, и при этом быть удивительно быстрым для инструмента, написанного на высокоуровневом языке, таком как C#.
Например, очень простой набор правил может содержать:
.dmp и их «снаффлинга».ps1 и отправляет все совпадающие файлы как второму, так и третьему правилам.cmd.exe, как это может быть в файлах .bat или .cmd, поскольку они также часто используются внутри PowerShell-скриптов.Такой подход также позволяет поддерживать относительно управляемый и читаемый набор правил, а также значительно упрощает конечному пользователю (вам) настройку правил по умолчанию или разработку собственных наборов правил.
Ты прав, так и было.
Snaffler поставляется с набором правил по умолчанию, встроенных в .exe. Вы можете увидеть их в ./Snaffler/SnaffRules/DefaultRules.
Без проблем, огромный чудак. У вас есть 2 варианта.
DefaultRules, затем соберите новый Snaffler. .toml-файлы в этом каталоге будут встроены в .exe в качестве ресурсов и загружены во время выполнения, если вы не укажете другие правила для использования.-p .\path\to\rules. Snaffler проанализирует все .toml-файлы в этом каталоге и использует полученный набор правил. Это также будет работать, если у вас всё в одном большом .toml-файле.Вот несколько аннотированных примеров, которые, надеюсь, помогут прояснить ситуацию. Если это кажется очень сложным, вы можете просто использовать наши правила, и они, скорее всего, найдут для вас что-нибудь хорошее.
Это пример правила, которое заставит Snaffler игнорировать все файлы и подкаталоги внутри каталога с определённым именем.```toml [[ClassifierRules]] EnumerationScope = "DirectoryEnumeration" # This defines which phase of the discovery process we're going to apply the rule. # In this case, we're looking at directories. # Valid values include ShareEnumeration, DirectoryEnumeration, FileEnumeration, ContentsEnumeration RuleName = "DiscardLargeFalsePosDirs" # This can be whatever you want. We've been following a rough naming scheme, but you can call it "Stinky" if you want. ¯_(ツ)_/¯ MatchAction = "Discard"# What to do with things that match the rule. In this case, we want to discard anything that matches this rule. # Valid options include: Snaffle (keep), Discard, Relay (example of this below), and CheckForKeys (example below) Description = "File paths that will be skipped entirely." # Not used in the code, just a place for notes really. MatchLocation = "FilePath" # What part of the file/dir/share to look at to check for a match. In this case we're looking at the whole path. # Valid options include: ShareName, FilePath, FileName, FileExtension, FileContentAsString, FileContentAsBytes, # although obviously not all of these will apply in all EnumerationScopes. WordListType = "Contains" # What matching logic to apply, valid options are: Exact, Contains, EndsWith, StartsWith, or Regex. # Under the hood these all get turned into regexen one way or another. MatchLength = 0 WordList = [
"\\\\puppet\\\\share\\\\doc",
"\\\\lib\\\\ruby",
"\\\\lib\\\\site-packages",
"\\\\usr\\\\share\\\\doc",
"node_modules",
"vendor\\\\bundle",
"vendor\\\\cache",
"\\\\doc\\\\openssl",
"Anaconda3\\\\Lib\\\\test",
"WindowsPowerShell\\\\Modules",
"Python27\\\\Lib"
] Triage = "Green" # If we find a match, what severity rating should we give it. Valid values are Black, Red, Yellow, Green. This value is ignored for Discard MatchActions.
Это правило, с другой стороны, будет смотреть на расширения файлов и немедленно отбрасывать те, которые нам не нравятся.
В данном случае я в основном отбрасываю шрифты, изображения, CSS и т.д.```toml
[[ClassifierRules]]
EnumerationScope = "FileEnumeration" # We're looking at the actual files, not the shares or dirs or whatever.
RuleName = "DiscardExtExact" # just a name
MatchAction = "Discard" # We're discarding these
MatchLocation = "FileExtension" # This time we're only looking at the file extension part of the file's name.
WordListType = "Exact" # and we only want exact matches.
WordList = [".bmp", ".eps", ".gif", ".ico", ".jfi", ".jfif", ".jif", ".jpe", ".jpeg", ".jpg", ".png", ".psd", ".svg", ".tif", ".tiff", ".webp", ".xcf", ".ttf", ".otf", ".lock", ".css", ".less"] # list of file extensions.
Вот пример очень простого правила для вещей, которые нам нравятся и которые мы хотим сохранить.```toml [[ClassifierRules]] EnumerationScope = "FileEnumeration" # Still looking at files RuleName = "KeepExtExactBlack" # Just a name MatchAction = "Snaffle" # This time we are 'snaffling' these. This usually just means send it to the output, # but if you turn on the appropriate option it will also grab a copy. MatchLocation = "FileExtension" # We're looking at file extensions again WordListType = "Exact" # With Exact Matches WordList = [".kdbx", ".kdb", ".ppk", ".vmdk", ".vhdx", ".ova", ".ovf", ".psafe3", ".cscfg", ".kwallet", ".tblk", ".ovpn", ".mdf", ".sdf", ".sqldump"] # and a bunch of fun file extensions. Triage = "Black" # these are all big wins if we find them, so we're giving them the most severe rating.
Этот в основном такой же, но мы смотрим на полное имя файла. Просто!```toml
[[ClassifierRules]]
EnumerationScope = "FileEnumeration"
RuleName = "KeepFilenameExactBlack"
MatchAction = "Snaffle"
MatchLocation = "FileName"
WordListType = "Exact"
WordList = ["id_rsa", "id_dsa", "NTDS.DIT", "shadow", "pwd.db", "passwd"]
Triage = "Black"
Этот довольно хитрый, зацени...```toml [[ClassifierRules]] EnumerationScope = "FileEnumeration" # we're looking for files... RuleName = "KeepCertContainsPrivKeyRed" MatchLocation = "FileExtension" # specifically, ones with certain file extensions... WordListType = "Exact" WordList = [".der", ".pfx"] # specifically these ones... MatchAction = "CheckForKeys" # and any that we find, we're going to parse them as x509 certs, and see if the file includes a private key! Triage = "Red" # cert files aren't very sexy, and you'll get huge numbers of them in most wintel environments, but this check gives us a way better SNR!
Ок, вот где начинается самое мощное. У нас тут пара правил, выстроенных в цепочку.
Файлы с расширениями, соответствующими первому правилу, будут отправлены второму правилу, которое выполнит «grep» (то есть String.Contains()) по содержимому на наличие записей из определённого списка слов.
Вы можете выстраивать их в цепочку сколько угодно, хотя, полагаю, производительность начнёт страдать, если увлекаться излишней вложенностью.```toml
[[ClassifierRules]]
EnumerationScope = "FileEnumeration" # this one looks at files...
RuleName = "ConfigGrepExtExact"
MatchLocation = "FileExtension" # specifically the extensions...
WordListType = "Exact"
WordList = [".yaml", ".xml", ".json", ".config", ".ini", ".inf", ".cnf", ".conf"] # these ones.
MatchAction = "Relay" # Then any files that match are handed downstream...
RelayTargets = ["KeepConfigGrepContainsRed"] # To the rule with this RuleName! This can also be an array of RuleNames if you want to get real wild and start writing branching rulesets.
[[ClassifierRules]]
RuleName = "KeepConfigGrepContainsRed" # Anyway, this is the target rule. Following a naming convention really helps to make sure you're using the right targets.
EnumerationScope = "ContentsEnumeration" # this one looks at file content!
MatchAction = "Snaffle" # it keeps files that match
MatchLocation = "FileContentAsString" # it's looking at the contents as a string (rather than a byte array)
WordListType = "Contains" # it's using simple matching
WordList = ["password=", " connectionString=\"", "sqlConnectionString=\"", "validationKey=", "decryptionKey=", "NVRAM config last updated"]
Triage = "Red"
Надеюсь, это передает идею. Я рекомендую взять несколько правил по умолчанию и повозиться с ними, пока вы не почувствуете, что разобрались с ними достаточно хорошо.
Многие хотели иметь возможность заглядывать внутрь форматов файлов, которые не были просто плоским текстом, таких как документы Word, PDF, .eml и т.д. К сожалению, самая простая библиотека для реализации этой функциональности увеличила итоговый размер файла Snaffler.exe примерно на 1200%, что было плохо для многих популярных методов выполнения в памяти, которые имели верхние ограничения на размер файла, с которым их можно было использовать.
Решением стал UltraSnaffler, который представляет собой просто второй файл .sln, включающий необходимую библиотеку и соответствующий код. Соберите UltraSnaffler.sln, получите UltraSnaffler.
ПРЕДУПРЕЖДЕНИЕ: правила Snaffler по умолчанию не включают те, которые будут заглядывать внутрь документов Office или PDF, потому что было очень трудно написать правила, которые не заняли бы годы на выполнение в типичной корпоративной среде. Будьте предупреждены: заглядывание внутрь этих документов происходит гораздо медленнее, чем заглядывание в старые добрые текстовые файлы, и в типичной среде будет просто гора низкокачественных документов Office и PDF.
На самом деле, это довольно круто, на мой взгляд.
Если добавить -z generate в конец командной строки Snaffler, Snaffler сериализует объект конфигурации (включая любые аспекты конфигурации, заданные вашими аргументами) в файл конфигурации .toml, который затем можно легко (или не очень) отредактировать вручную и использовать по своему усмотрению
Например, если вы сделаете:
Snaffler.exe -s -o C:\mydir\snaffler.log -v trace -i \\host.lol.domain\share -p C:\users\someguy\myrules -z generate
Snaffler проанализирует все ваши многочисленные аргументы, преобразует их в объект конфигурации, сериализует этот объект конфигурации в следующий файл конфигурации .toml:```toml
PathTargets = ["\\host.lol.domain\share"]
ComputerTargetsLdapFilter = "(objectClass=computer)"
ScanSysvol = true
ScanNetlogon = true
ScanFoundShares = true
InterestLevel = 0
DfsOnly = false
DfsShareDiscovery = false
DfsNamespacePaths = []
CurrentUser = "l0sslab\l0ss"
RuleDir = "C:\users\someguy\myrules"
MaxThreads = 60
ShareThreads = 20
TreeThreads = 20
FileThreads = 20
MaxFileQueue = 200000
MaxTreeQueue = 0
MaxShareQueue = 0
LogToFile = true
LogFilePath = "C:\mydir\snaffler.log"
LogType = "Plain"
LogTSV = false
Separator = 32
LogToConsole = true
LogLevelString = "trace"
ShareFinderEnabled = false
LogDeniedShares = false
DomainUserRules = false
DomainUserMinLen = 6
DomainUserNameFormats = ["sAMAccountName"]
DomainUserMatchStrings = ["sql", "svc", "service", "backup", "ccm", "scom", "opsmgr", "adm", "adcs", "MSOL", "adsync", "thycotic", "secretserver", "cyberark", "configmgr"]
DomainUsersWordlistRules = ["KeepConfigRegexRed"]
MaxSizeToGrep = 1000000
Snaffle = false
MaxSizeToSnaffle = 10000000
MatchContextBytes = 200
You may notice that there are many items in here that you didn't pass arguments for. Those values are the default config items, some of which can only be edited easily in the source or via a config file, usually because it didn't seem worth it to add an argument for them.
## This sucks, do you have plans to make it suck less?
No it doesn't, you suck.
Also, yes we do.
We're also going to:
- Add parsing of archive files, ideally treating them as just another dir to walk through looking for goodies.
- Keep refining the rules and regexen. **More words for the wordlists! `string[]`s for the `string` throne!**

## Who did you steal code from?
The share enumeration bits were snaffled (see what I did there?) from SharpShares, which was written by the exceedingly useful Dwight Hohnstein. (https://github.com/djhohnstein/SharpShares/)
Dwight's GitHub profile is like that amazing back aisle at a hardware store that has a whole bunch of tools that make you go "oh man I can't wait til I have an excuse to try this one for realsies..." and you should definitely check it out.
While no code was taken (mainly cos it's Ruby lol) we did steal a bunch of nifty ideas from `plunder2` (http://joshstone.us/plunder2/)
Wordlists were also curated from those found in some other similar-ish tools like trufflehog, shhgit, gitrobber, and graudit.
## Is it OPSEC safe? (Whatever the hell that means)
Pffft, no. It's noisy as fuck.
Look let's put it this way... If it's the kind of environment where you'd feel confident running BloodHound in its default mode, then uhhh, yeah man... It's real stealthy.
## I thought you used this thing on red team gigs?
*sigh*
OK, I'll give you the real answer.
In default mode, Snaffler looks an awful lot like SharpHound, in a lot of ways. It talks a bunch of LDAP to AD, then it goes out and tries to talk SMB to every Windows machine in the domain. This kind of behaviour is pretty much guaranteed to get you busted in an org that has their shit even slightly together.
HOWEVER...
Snaffler's more-targeted options (especially `-i`) are a *lot* less likely to trigger detections.
I am particularly fond of running `Snaffler.exe -s -i C:\` on a freshly compromised server or workstation, and I've not seen this behaviour get detected.
Yet.
## How can I help or get help?
If you want to discuss via Slack you can ping us (@l0ss or @Sh3r4) on the BloodHound Slack, joinable at https://bloodhoundgang.herokuapp.com/, or chat with a group of contributors in the #snaffler channel.
You can also ping us on Twitter - @mikeloss and @sh3r4_hax
Otherwise file an issue; we'll try.
PRIVATE KEYПоиск по частичному совпадению имени файла (о боже, ещё списки слов). Это в основном предназначено для поиска таких файлов, как Jeff's Password File 2019 (Copy).docx или Privileged Access Management System Design - As-Built.docx и т.п., путём сопоставления любых файлов, имя которых содержит подстроки passw, handover, secret, secure, as-built и т.д.
Также есть списки пропуска (skip-lists), чтобы пропустить все файлы с определёнными расширениями или любой файл, путь которого содержит заданную строку.