Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
nmap-vulners — Скрипт NSE для Nmap, который запрашивает API Vulners для выявления известных уязвимостей (CVE) для обнаруженных сетевых служб, расширяя стандартное сканирование портов автоматизированным поиском CVE и оценкой CVSS. | Kitploit
Инструменты/GitHubGitHub/vulnerscom/nmap-vulners
Сканеры уязвимостейАнализ уязвимостейСбор информацииСетевая безопасность
GitHubvulnerscom/nmap-vulners

nmap-vulners

Скрипт NSE для Nmap, который запрашивает API Vulners для выявления известных уязвимостей (CVE) для обнаруженных сетевых служб, расширяя стандартное сканирование портов автоматизированным поиском CVE и оценкой CVSS.

Репозиторий
3.4k5595129 дней назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
<div align="center">

# nmap-vulners

**Превращает сканирование сервисов nmap в ранжированный список CVE, эксплойтов и того, что атакуется в дикой природе.**

Один NSE-скрипт, который берёт программное обеспечение, уже идентифицированное nmap, запрашивает базу данных [Vulners](https://vulners.com) о том, что о нём известно, и выводит ответ внутри отчёта сканирования — сначала худшее, по тому, что реально эксплуатируемо.

[![tests](https://img.shields.io/github/actions/workflow/status/vulnersCom/nmap-vulners/ci.yml?branch=master&label=tests&logo=github)](https://github.com/vulnersCom/nmap-vulners/actions)
[![license](https://img.shields.io/badge/license-Nmap%20Public%20Source-0e7c86)](LICENSE)
[![nmap](https://img.shields.io/badge/nmap-7.x-4b8bbe?logo=gnu)](https://nmap.org)
[![data](https://img.shields.io/badge/data-vulners.com-ff5f56)](https://vulners.com)
[![stars](https://img.shields.io/github/stars/vulnersCom/nmap-vulners?logo=github&color=yellow)](https://github.com/vulnersCom/nmap-vulners/stargazers)

<img src="https://assets.kitploit.com/production/public/readmes/1680/0a17fe209e2ad4d8bbd8bf49c72243a8c8b3f0fb9e603317b21c8a2cd6982b0f.gif" alt="Три сканирования: SSH-порт без API-ключа, тот же порт с ключом и веб-порт, где обход называет Tomcat за баннером Coyote" width="900">

<sub>Реальные сканирования хостов, опубликованных для сканирования. Без ключа, затем с ключом, затем веб-порт: nmap <code>-sV</code> сообщает о баннере Coyote, а обход называет Tomcat и jQuery за ним.</sub>

</div>

---

## Что он делает

Для каждого открытого порта он ищет программное обеспечение, идентифицированное nmap — CPE, которые создал `-sV`, — и выводит то, что Vulners знает о нём: сначала худшее по тому, что эксплуатируется, а не только по оценке, и каждая строка — ссылка на страницу за ней.

На HTTP-порту он также снимает отпечатки самого веб-стека, что называет программное обеспечение, которое `-sV` не может увидеть — фреймворк приложения, CMS, версию PHP за обратным прокси. 721 правило читает части ответа, несущие версию: заголовок `Server`, `X-Powered-By`, cookie, заголовок страницы, теги `<meta>`, имена файлов `<script src>` и тело. Эти идентичности также ищутся и публикуются на порту, чтобы остальная часть сканирования могла их использовать.

Две вещи, которые он делает помимо обхода:

* **он читает собственный баннер сервиса nmap.** Когда `-sV` не смог назвать сервис, сырой баннер сопоставляется с правилами для FTP, SMTP, SSH, MySQL, DNS, NTP, LDAP и других. Это не стоит дополнительного запроса, и это тот случай, когда порт в противном случае не сообщил бы вообще ничего.
* **он спрашивает продукт, который не скажет.** CMS, которая называет себя и скрывает свою версию, — обычное дело, и никакое сопоставление с образцом не извлечёт число, которого нет на странице. Когда продукт распознан, а версия нет, один запрос идёт в место, которое отвечает — `/CHANGELOG.txt` для Drupal, `/administrator/manifests/files/joomla.xml` для Joomla. Хосту, на котором не запущен ни один из шести проверяемых продуктов, ничего лишнего не отправляется.```sh
nmap -sV --script vulners <target>
```
Это весь интерфейс. Он работает без API-ключа; с ним он сообщает вам больше информации. Режима переключения нет.```
PORT      STATE SERVICE VERSION
80/tcp    open  http    Apache httpd 2.4.7 ((Ubuntu))
| vulners: cpe:/a:apache:http_server:2.4.7  272 findings, 56 exploitable
|   SEVERITY  CVSS    AI  FLAGS    LINK
|   ========  ====  ====  =======  ==============================================================
|   CRITICAL  10.0   8.8  EXP      https://vulners.com/gitee/3E6BA608-776F-5B1F-9BA5-589CD2A5A351
|   CRITICAL   9.8   9.9  EXP      https://vulners.com/zdt/1337DAY-ID-39214
|   CRITICAL   9.8   9.6  EXP      https://vulners.com/packetstorm/PACKETSTORM:171631
|   CRITICAL   9.8   9.9           https://vulners.com/cve/CVE-2021-44790
|   CRITICAL   9.8   9.8           https://vulners.com/cve/CVE-2023-25690
|_  262 more not shown; -v shows all, -vv adds where each was found
```
С ключом один и тот же скан одного и того же хоста отвечает по-разному — `KEV` означает, что CISA зафиксировала эксплуатацию уязвимости в реальных атаках, а `EPSS` — это опубликованная вероятность того, что она будет эксплуатироваться:```
| vulners: cpe:/a:apache:http_server:2.4.7  272 findings, 78 exploitable
|   SEVERITY  CVSS  EPSS  FLAGS    LINK
|   ========  ====  ====  =======  ==============================================================
|   CRITICAL   9.1  >99%  KEV EXP  https://vulners.com/cve/CVE-2024-38475
|   CRITICAL   9.0  >99%  KEV EXP  https://vulners.com/cve/CVE-2021-40438
|   CRITICAL   9.1  >99%  KEV      https://vulners.com/cnvd/CNVD-2024-36387
|   CRITICAL  10.0   71%  EXP      https://vulners.com/gitee/3E6BA608-776F-5B1F-9BA5-589CD2A5A351
|   CRITICAL   9.8   97%  EXP      https://vulners.com/cve/CVE-2021-44790
|_  262 more not shown; -v shows all, -vv adds where each was found
```
Те же 272 находки, другой порядок, другая верхняя строка — и ещё 22 из них
известно как эксплуатируемые, потому что ключ связывает каждый эксплойт с CVE,
которые он эксплуатирует. Оба этих ответа — реальные результаты с vulners.com,
полученные против локального сервера, показывающего этот баннер.

## Ранжирование

Факты важнее прогнозов. Находки упорядочены:

1. **CISA KEV** — зафиксировано как эксплуатируемое в дикой природе
2. **SSVC `active`** — суждение координатора о том, что эксплуатация происходит
3. **существует эксплойт** — код опубликован, для этой уязвимости или для CVE, которое она называет
4. **высокий EPSS** — модель ожидает эксплуатации
5. всё остальное

CVSS разрешает ничьи внутри группы, а не между ними: эксплуатируемая 7.5 — это
худшая проблема, чем неэксплуатируемая 9.8, и именно такой порядок это отражает.

Колонки следуют за данными. Сигнал, который ответ не нёс, теряет свою колонку,
а не показывает пустую ячейку, потому что пустой EPSS читается как «тихо»,
а это утверждение, которое отсутствующее поле не может поддержать.

## Что добавляет ключ API

| | |
|---|---|
| **Без ключа** | Каждый CPE, найденный nmap, проверяется на бесплатном endpoint. Находки, оценки, флаги эксплойтов и собственный AI-скор Vulners. Без кредитов, без аккаунта |
| **Ключ, без кредитов** | Каждая находка получает то, что знает id endpoint: заголовки, даты, ссылку на upstream-совет или страницу эксплойта, связь эксплойт-к-CVE, CISA KEV и — в зависимости от лицензии — EPSS и SSVC |
| **Ключ, один кредит** | ПО, которое бесплатный путь вообще не мог назвать, идентифицируется по его сырому баннеру. Это единственное здесь, что что-то стоит, и только для сервиса без CPE |

Порт, который уже несёт CPE, никогда не стоит кредита: по замерам на четырёх
продуктах бесплатный поиск возвращает те же **CVE**, что и платный, для CPE.
Что покупает кредит — это идентификация, а не больше уязвимостей.

Бесплатные ключи — на [vulners.com/userinfo](https://vulners.com/userinfo).

## Установка

**macOS, Linux, Kali, WSL** — одна строка, без аргументов:```sh
curl -fsSL https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.sh | sh
```
**Windows** — PowerShell от имени администратора:```powershell
irm https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.ps1 | iex
```
Установщик спрашивает nmap, где он хранит свои данные, копирует туда скрипты и их файлы данных, пересобирает базу данных скриптов, а затем проверяет, что `--script vulners` действительно разрешается в то, что он только что установил — nmap поставляется с собственным `vulners.nse`, и этот заменяет его.

<details>
<summary><b>Без root и другие параметры</b></summary>```sh
# into ~/.nmap, no sudo; the installer prints the NMAPDIR line to add to your profile
curl -fsSL https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.sh | sh -s -- --user

# a specific directory
./install.sh --prefix /usr/local/share/nmap

# a specific release
./install.sh --ref v2.0

# remove everything it installed
./install.sh --uninstall
```
PowerShell принимает те же параметры: `-User`, `-Prefix`, `-Ref`, `-Uninstall`.

</details>

<details>
<summary><b>Из локальной копии репозитория</b></summary>```sh
git clone https://github.com/vulnersCom/nmap-vulners
cd nmap-vulners
./install.sh
```
Установщик использует файлы, находящиеся рядом с ним, поэтому устанавливается именно то, что вы
склонировали. Запуск скриптов напрямую из рабочей копии также работает:```sh
nmap -sV --script "$PWD/vulners.nse" <target>
```
> При запуске из рабочей копии используйте **абсолютный** путь. nmap сначала
> разрешает относительный `--script ./vulners.nse` через собственную `script.db`
> и незаметно запускает копию, поставляемую с nmap, а не вашу.

</details>

<details>
<summary><b>Вручную</b></summary>

Один файл: скопируйте `vulners.nse` в `<каталог данных nmap>/scripts/` и выполните
`sudo nmap --script-updatedb`. Больше ничего размещать не нужно — скрипт
загружает свои словари во время сканирования и ничего не записывает на диск —
а значит, и забывать нечего, что раньше приводило к скрипту, который запускался,
ничего не находил и ничего не сообщал о причине.

Если вы обновляетесь с версии 1.x, удалите также `vulners_enterprise.nse` и
`http-vulners-regex.nse` из этого каталога. Оставшийся
`http-vulners-regex.nse` по-прежнему несёт категорию `default` и продолжает
сканировать цели при обычном `-sC`. Установщик делает это за вас.

Каталог данных nmap обычно находится в `/usr/share/nmap` (Debian, Ubuntu, Kali),
`/usr/local/share/nmap` (сборка из исходников), `/opt/homebrew/share/nmap`
(Homebrew) или `C:\Program Files (x86)\Nmap` (Windows). Чтобы убедиться наверняка, спросите у nmap:```sh
nmap -d2 --script-help probe 2>&1 | grep nse_main.lua
```
Каталог, в котором находится `nse_main.lua`, — это тот, который использует данный nmap.

</details>

## Аргументы скрипта

| Аргумент | По умолчанию | Назначение |
|---|---|---|
| `vulners.mincvss` | `0` | Скрывать находки с оценкой ниже этого значения. Бюллетени без оценки и всё, что имеет известный эксплойт, показываются независимо от порога |
| `vulners.paths` | опубликованные 939 путей | Пути для веб-обхода: список Lua, одна строка с именем файла, содержащего по одному пути на строку, или `none` для отключения обхода. Файл, который вы указали и который невозможно прочитать, останавливает обход и сообщает об этом, а не откатывается к опубликованному списку |
| `vulners.width` | `80` | Ширина терминала, под которую свёрстана таблица |
| `vulners.max_items` | `32` | Потолок на оплачиваемые элементы для всего сканирования |
| `vulners.api_key` | - | Токен API. Утечка: nmap копирует собственную командную строку в `-oX` |
| `vulners.api_key_file` | - | Абсолютный путь к файлу, первая строка которого — токен |
| `vulners.api_host` | `vulners.com` | Имя хоста API |
| `vulners.api_port` | `443` | Порт на `api_host` |

Голое имя тоже работает, так что `--script-args mincvss=7` достаточно.

Префиксы аргументов версии 1.x — `vulners_enterprise.*` и
`http-vulners-regex.paths` — принимаются в течение одного релиза и выводят
уведомление об устаревании.

## Где хранить ключ API

В порядке предпочтения:

1. `~/.nmap/vulners.key`, одна строка, режим 600 — установщик предлагает записать его
2. `VULNERS_API_KEY` в окружении
3. `--script-args vulners.api_key_file=/absolute/path`
4. `--script-args vulners.api_key=<token>`

Последний вариант удобен, но утекает: nmap копирует собственную командную строку в каждый
отчёт, поэтому токен попадает в атрибут `args` вывода `-oX` и в вашу
историю shell. Сам скрипт никогда не записывает токен куда-либо, включая свой
отладочный вывод — об этом говорит регрессионный тест.

Файл ключа, который вы указали явно и который невозможно прочитать, останавливает запуск, а не
тихо откатывается — оператор, назвавший файл, имеет в виду именно этот файл — и
отчёт сообщает, какой это был файл. Ошибочно введённый путь не может выглядеть как чистое
сканирование.

## Откуда берутся отпечатки

Скрипт не носит их с собой. Он загружает три словаря один раз за сканирование,
до того как будет затронут первый хост:```
https://raw.githubusercontent.com/vulnersCom/nmap-vulners/catalog/
    index.json          what exists, at which serial
    fingerprints.json   721 product and version rules
    paths.json          939 paths the sweep requests
    probes.json         targeted version probes
```
Это четыре запроса на сканирование — по одному на файл, а не на хост и не на порт —
для 40 КБ сжатых данных из 250 КБ JSON, на этапе предварительного сканирования nmap. Измерено
относительно опубликованной ветки. Поэтому установленный скрипт подхватывает новые
отпечатки без обновления.

**Он ничего не записывает в вашу файловую систему.** Словари хранятся в течение
сканирования и затем отбрасываются — так ведёт себя каждый скрипт, поставляемый с nmap:
из 611 таких скриптов 26 открывают файл для записи, и каждый пишет только туда, куда
указал аргумент скрипта. Ни один не хранит кэш, и этот тоже.

**Если их нельзя загрузить, сканирование всё равно выполняется.** Словари питают
веб-распознавание отпечатков и больше ничего, поэтому машина без маршрута к GitHub
теряет эту возможность и сохраняет всё остальное: программное обеспечение, которое
сам nmap идентифицировал, всё равно проверяется, а отчёт сообщает, какая возможность
отсутствовала, а не оставляет вас читать пустой результат как чистую сеть.

| аргумент | что он делает |
|---|---|
| `vulners.catalog_url=<url>` | загрузить с зеркала вместо этого — для изолированной сети. Имя хоста или IPv6-адрес в квадратных скобках, `http://[fd00::1]/catalog/` |
| `vulners.catalog=none` | не загружать вовсе; искать только то, что назвал nmap |

## Обход, и насколько он шумный

На HTTP-порту скрипт запрашивает каждый путь, который публикует каталог — 939
путей — и сопоставляет все 721 правила с каждым ответом. Пути взяты из
WhatWeb, nuclei и FingerprintHub: места, где продукт распознаётся, а не
предполагается. Даже путь, принадлежащий программному обеспечению, которое вы не запускаете, стоит
запроса, потому что ответ всё равно несёт `Server`, `X-Powered-By`, cookie и
заголовок, и именно в них правила находят стек перед ним.

**Насколько быстро это идёт — это ваш `-T`**, а не наша настройка. Список никогда не
сокращается; меняется скорость:

| | пакеты | ожидание между ними | измерено, один веб-порт |
|---|---|---|---|
| `-T0` paranoid | 188 x 5 | 2 с | 11 м 22 с |
| `-T1` sneaky | 94 x 10 | 1 с | 1 м 56 с |
| `-T2` polite | 38 x 25 | 0.5 с | 26.2 с |
| `-T3` normal | 10 x 100 | 0.1 с | 7.6 с |
| `-T4` aggressive | 4 x 250 | нет | 6.7 с |
| `-T5` insane | 1 | нет | 6.6 с |

Все шесть измерены в одном прогоне против одного и того же локального сервера. Только `-sV` против
него занимает 6.1 с, так что обход стоит полторы секунды по умолчанию. Две медленные
строки — это `-T0` и `-T1`, выполняющие свою работу: 188 и 94 пакета с намеренным
ожиданием между каждым.

Запросы конвейеризируются через 34–48 соединений с максимум четырьмя открытыми
одновременно, что является `pipeline_go` из nselib — тот же механизм, который использует
собственный `http-enum` nmap, учитывающий `Keep-Alive: max=` сервера и
`--script-args http.max-pipeline=N`.

`--script-args vulners.paths=none` полностью отключает обход.

## Как это работает```
nmap -sV
   |
   +-- service fingerprint --> port.version.cpe --------------+
   |                                                          |
   +-- vulners.nse                                            |
         reads nmap's banner for services -sV could not name   |
         on an HTTP port: requests the path list in one        |
         pipeline, matches 721 rules against the header, the   |
         title, the meta tags, the scripts and the body        |
         probes for a version when a product hid it            |
         publishes everything it recognised ------------------+
                                                               |
                                                               v
                                        GET /api/v3/burp/software/  per identity
                                          free, no key, CDN-cached
                                                               |
                                        POST /api/v3/search/id/ per 100 findings
                                          free, needs a key: enrichment
                                                               |
                                        POST /api/v4/audit/smart  only for a
                                          service with no CPE: 1 credit
                                                               |
                                                   ranked, filtered, printed
```
Ответы кэшируются для всего сканирования, привязываясь к каждой идентичности, поэтому сотня
одинаковых серверов стоит одного запроса. Обогащение кэшируется по идентификатору находки, поэтому два
веб-порта с перекрывающимся программным обеспечением загружают каждый документ один раз.

## Машиночитаемый вывод

Всё, что выводится, также структурировано, поэтому `-oX` можно разбирать, не касаясь
человекочитаемого текста. Идентификатор скрипта, два уровня таблиц и пять исходных
ключей элементов не изменились с версии 1.x — именно это читают DefectDojo, Faraday,
nmap2csv и raven:```xml
<script id="vulners">
  <elem key="schema">2.0</elem>
  <elem key="mode">keyed</elem>
  <table key="cpe:/a:apache:http_server:2.4.7">
    <table>
      <elem key="id">CVE-2021-40438</elem>
      <elem key="type">cve</elem>
      <elem key="severity">CRITICAL</elem>
      <elem key="cvss">9.0</elem>
      <elem key="cvss_type">cvss3.1</elem>
      <elem key="is_exploit">false</elem>
      <elem key="exploit_known">true</elem>
      <elem key="kev">true</elem>
      <elem key="epss">0.99612</elem>
      <elem key="exploitation">active</elem>
      <elem key="title">Apache HTTP Server SSRF in mod_proxy</elem>
      <elem key="href">https://vulners.com/cve/CVE-2021-40438</elem>
      <elem key="source_href">https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-40438</elem>
    </table>
  </table>
</script>
```
Новое в 2.0: `schema`, `mode`, `severity`, `exploit_known`, `kev`, `epss`,
`epss_percentile`, `exploitation`, `ai_score`, `title`, `published`, `href`,
`source_href` и `found_on`. Каждое поле либо присутствует, либо отсутствует, но никогда не бывает пустым.
Ничего не вложено глубже, чем раньше, потому что третий уровень таблицы
невидим для любого проверенного импортёра.

`href` — это всегда страница vulners.com для находки, в обоих режимах. Собственный
`href` конечной точки — это **вышестоящий** адрес: nvd.nist.gov для CVE,
github.com для собранного эксплойта — и он передаётся отдельно, как
`source_href`, так что смысл ни одного из полей не зависит от того, какой режим его создал.

Структурированный вывод всегда содержит каждую находку, прошедшую `mincvss`, даже
те, которые лестница подробности скрывает из текста, — так что ни одна автоматизация не
теряет находки, не передавая `-v`.

**Отображаемый текст — это разрыв.** Токены `*EXPLOIT*` и `*HAS EXPLOIT*`
и табулированная раскладка исчезли, заменённые выровненной таблицей выше. 
Ссылка на vulners.com в каждой строке осталась: это последний столбец, и это единственная ячейка,
которую раскладка не будет сокращать, потому что половина URL — это не URL. Потребителям,
скрейпящим текст, нужно обновление; потребителям `-oX` — нет.

## Вежливое сканирование

Сканирование сети запрашивает у API гораздо меньше, чем кажется:

* один запрос на каждую идентичность ПО, и ответы кэшируются на всё сканирование
* уже выполняющийся поиск ожидается, а не повторяется
* обнаружение идёт на конечную точку с **CDN-кэшем**, без ключа, даже когда он
  настроен, так что оно остаётся на общем кэше вместо обращения к источнику
* обход 939 путей выполняется через несколько **конвейерных соединений**, а не
  по одному на путь, запрашивает
  сжатые страницы и прекращает сопоставление, как только исчерпает свой бюджет байтов
* ограничение скорости или сбой останавливают эту часть сканирования вместо повторов на
  каждый хост, а отклонённый ключ переходит на бесплатный путь, а не заставляет сканирование замолчать
* кредиты тратятся только там, где бесплатный путь вообще не может ответить

## Разработка

Тесты, шлюз гигиены и `CONTRIBUTING.md` находятся только в git-репозитории;
архив релиза поставляет скрипты и их данные. Восемь шлюзов, все офлайн, кроме
отмеченных особо, и CI запускает именно их:```sh
nmap -sn -Pn --script ./tests/run.nse --script-args testdir=tests,root=. 127.0.0.1
python3 tests/e2e/run_e2e.py
python3 tools/check.py
python3 tools/catalog.py --check
python3 tools/xml_contract.py --selftest
python3 tools/fingerprints/selftest.py
python3 tools/catalog_diff.py --selftest
python3 tools/nmap_style.py
```
270 модульных тестовых случаев выполняются внутри nmap против реальных библиотек NSE; 64 сквозных
случая запускают реальный бинарник nmap против локального веб-сервера и подставного
API Vulners, который принудительно применяет то же, что и реальный; гигиенический шлюз не допускает
секреты, вывод сканирования и мусор редактора в дерево и отказывает в глобальном чтении,
которое NSE превратило бы в потерянный результат; а последние четыре содержат данные и
инструменты, которые их публикуют — форму каталога, XML-контракт, который читает каждый
импортёр, транслятор шаблонов и шлюз, который решает, что пересборку безопасно публиковать. Последний удерживает весь репозиторий в соответствии с
[собственными стандартами кода Nmap](https://secwiki.org/w/Nmap/Code_Standards), которые
`HACKING` называет авторитетом для скрипта, желающего жить в дереве nmap:
никаких табуляций, никаких завершающих пробелов, строки короче 80 столбцов, никаких точек с запятой,
приватный NSEdoc, открывающийся с `--;`, PEP 8 для Python.
`python3 tests/e2e/run_e2e.py --live` добавляет проверки против реального сервиса.
См. [CONTRIBUTING.md](https://github.com/vulnerscom/nmap-vulners/blob/master/CONTRIBUTING.md).

## FAQ

**Эксплуатирует ли он что-либо?** Нет. Он читает баннеры и страницы и обращается к
```

---

[Read more](https://github.com/vulnerscom/nmap-vulners)
Скачать инструмент