Синтаксис запросов
В данном разделе описаны правила и синтаксис для составления задач на сканирование.
Основы
Для запуска сканирования необходимо составить задание для выполнения или использовать уже готовый шаблон. Используется формат Yaml.
Пример:
tasks:- uses: tcp/probe@v1default:ports:- 1-65535runPolicy: always- uses: http@v1events:- event: tcp/probe@v1mutate:port: ${{ value.port }}scheme: '${{ value.isTls ? "https": "http" }}'condition: value.banner == ""default:port: 80runPolicy: triggered
Строение запроса
Любой запрос начинается с родительского блока tasks. В этом блоке перечисляются задачи, которые будут выполняться в рамках данного сканирования.
Важно! Все задачи и события запускаются в порядке их указания сверху вниз.
uses
- обязательное поле в рамках задачи, обозначает модуль (задачу), который вызывается в рамках сканирования.
runPolicy
- обязательное поле в рамках задачи. Поле может принимать значения always (запускается всегда) и triggered (запускается по какому-либо событию).
default
- определяет настройки по умолчанию, которые будут применяться для задачи.
events
- используется для определения событий, которые должны произойти для запуска текущей задачи (uses). Применяется если свойство runPolicy выставлено в triggered.
condition
- логическое условие для запуска текущей задачи (uses). Пример: value.port == 22
- проверяется, что порт равен 22.
Каждый модуль имеет ограниченное количество параметров по умолчанию и параметров, которые могут быть указаны и переданы для выполнения в другой модуль. Подробное описание параметров содержится в описании каждого модуля в соответствующем разделе документации.
Мутации
Мутацией является изменение значений переменных в ходе выполнения задачи. Это позволяет динамически манипулировать значениями, чтобы они соответствовали нужным параметрам.
mutate - свойство, которое позволяет изменить параметры задачи перед её выполнением.
Пример:
- uses: http@v1events:- event: tcp/probe@v1mutate:port: ${{ value.port }}scheme: '${{ value.isTls ? "https": "http" }}'condition: value.banner == ""default:port: 80runPolicy: triggered
В данном случае это означает, что значения переменных port и scheme задачи http@v1 будут изменены перед ее запуском. Значения параметров будут взяты из задачи tcp/probe@v1.
value в примере относится к тому модулю, в котором используется. В данном примере ${{ value.port }}
value объект относится к tcp/probe@v1.
Через объект value можно использовать любые доступные поля модуля. Подробнее какие поля доступны для использования можно посмотреть в соответствующей документации к модулю в разделе Результат сканирования.
Матрицы
Матрица — это способ автоматического создания комбинаций значений для нескольких параметров, что позволяет выполнять один и тот же шаг с разными входными данными. Используется для параллельной обработки множества вариантов, не нужно вручную прописывать каждый шаг для каждого варианта.
В основном матрицы используются для выполнения задач с параметрами - списками.
Пример:
events:- event: tcp/probe@v1matrix:probe: ${{ value.probes }}mutate:port: ${{ value.port }}probe: ${{ matrix.probe }}condition: len(value.probes) > 0
Оператор матрица matrix создает матрицу значений для переменной probe. Значения для матрицы берутся из value.probes, которые были получены в предыдущем шаге. value.probes — это список (или массив), содержащий несколько значений. Матрица работает следующим образом:
- Каждый элемент в списке value.probes будет обработан отдельно.
- Когда матрица с параметром probe создается, она проходит через все элементы в value.probes (например, если value.probes содержит [1000, 2000, 3000], то для каждого из этих значений будет выполнен отдельный шаг).
- Для каждого элемента из value.probes будет создаваться новый набор значений для параметров, который будет передан в mutate.
В рамках матрицы в данном примере используется мутация. Это позволяет для каждого элемента из value.probes использовать его как значение для переменной probe и передать в дальнейшую обработку.
Например:
- В первом проходе probe будет равно 1000.
- Во втором проходе probe будет равно 2000.
- В третьем проходе probe будет равно 3000.
- Одновременно port остается таким же, как изначально заданное значение в value.port.
Используемые операторы
Категория | Операторы |
---|---|
Арифметические | + , - , * , / , % (остаток от деления), ^ или ** (возведение в степень) |
Сравнение | == , != , < , > , <= , >= |
Логические | not или ! , and или && , or или || |
Условные | ?: (тернарный оператор), ?? (оператор сравнения с nil) |
Доступ к элементам | [] , . , ?. , in |
Строковые | + (конкатенация), contains (содержит), startsWith (начинается с), endsWith (заканчивается на) |
Регулярные выражения | matches (сопоставление регулярному выражению) |
Конвейер | | |
Доступ к элементам
Поля структур и элементы карт (maps) могут быть доступны с помощью оператора .
или оператора []
. Следующие два выражения эквивалентны:
value.portvalue["port"]
Элементы массивов можно получать с помощью оператора []
. Поддерживаются отрицательные индексы, где -1
означает последний элемент.
array[0] // первый элементarray[-1] // последний элемент
Оператор in
можно использовать для проверки наличия элемента в массиве или карте.
"192.168.1.2" in ["192.168.1.2", "10.10.0.123"]"192.168.1.2" in {"ipv4": "192.168.1.2", "interface": "lo0"}
Опциональная цепочка
Оператор ?.
используется для доступа к полю объекта или элементу карты (map) без необходимости проверять, является ли объект или карта nil
.
Если объект или карта равны nil
, результатом выражения также будет nil
.
value.request?.portvalue.request != nil ? value.request.port : nil
Сравнение с nil
Оператор ??
используется для возврата левого операнда, если он не nil, в противном случае возвращается правый операнд. Следующие два выражения эквивалентны:
value.request?.port ?? 80value.request != nil ? value.request.port : 80
Оператор конвейера
Оператор |
используется для передачи результата выражения слева в качестве первого аргумента функции справа. Следующие два выражения эквивалентны:
value.title | lower() | split(" ")split(lower(value.title), " ")
Строковые функции
trim(str[, chars])
Удаляет пробелы с обоих концов строки str
. Если передан необязательный аргумент chars
, он указывает строку с набором символов, которые нужно удалить.
trim(" Title ") == "Title"trim("__Title__", "_") == "Title"
upper(str)
Преобразует все символы в строке str в верхний регистр.
upper("title") == "TITLE"
lower(str)
Преобразует все символы в строке str в нижний регистр.
lower("TITLE") == "title"
split(str, delimiter[, n])
Разбивает строку str по указанному разделителю delimiter и возвращает массив подстрок.
split("path/to/site", "/") == ["path", "to", "site"]split("path/to/site", ",", 2) == ["path", "to,site"]
replace(str, old, new)
Заменяет все вхождения подстроки old в строке str на new.
replace("param=bad_value", "bad_value", "good_value") == "param=good_value"
hasPrefix(str, prefix)
Возвращает true, если строка str начинается с указанного префикса prefix.
hasPrefix("OpenSSH_9.2", "OpenSSH") == true
hasSuffix(str, suffix)
Возвращает true, если строка str заканчивается на указанный суффикс suffix.
hasSuffix("OpenSSH_9.2", "9.2") == true
Числовые функции
max(n1, n2)
Возвращает максимальное из двух чисел n1 и n2.
max(5, 7) == 7
min(n1, n2)
Возвращает минимальное из двух чисел n1 и n2.
max(5, 7) == 5
abs(n)
Возвращает абсолютное значение числа n.
abs(-5) == 5
round(n)
Возвращает ближайшее целое число, округляя в большую сторону при значении 0.5.
round(1.5) == 2.0
Функции для массивов
all(array, predicate)
Возвращает true, если все элементы удовлетворяют выражению. Если массив пуст, возвращает true.
all(value.cookies, {.key contains "host"})
any(array, predicate)
Возвращает true, если какие-либо элементы удовлетворяют выражению. Если массив пуст, возвращает false.
any(value.cookies, {.key startsWith "host"})
one(array, predicate)
Возвращает true, если ровно один элемент удовлетворяет выражению. Если массив пуст, возвращает false.
one(value.cookies, {.key == "host.local"})
none(array, predicate)
Возвращает true, если все элементы не удовлетворяют выражению. Если массив пуст, возвращает true.
none(value.cookies, {.key == "host.com"})
filter(array, predicate)
Возвращает новый массив путем фильтрации элементов массива по выражению.
filter(value.publicKeys, .type startsWith "rsa-")
find(array, predicate)
Находит первый элемент в массиве, удовлетворяющий выражению.
find([1, 2, 3, 4], # > 2) == 3
count(array[, predicate])
Возвращает количество элементов, удовлетворяющих выражению. Следующие два выражения эквивалентны:
count(value.publicKeys, .type == "ssh-rsa")len(filter(value.publicKeys, .type == "ssh-rsa"))
Разные функции
len(v)
Возвращает длину массива, карты или строки.
len([1, 2, 3]) == 3len({"ipv4": "192.168.1.2", "interface": "lo0"}) == 2len("Title") == 5
get(v, index)
Извлекает элемент по указанному индексу из массива или карты v. Если индекс выходит за пределы диапазона, возвращает nil. Или ключ не существует, возвращает nil.
get([1, 2, 3], 1) == 2get({"ipv4": "192.168.1.2", "interface": "lo0"}, "interface") == "lo0"