Сканування як метод розтину каналів передачі даних існує вже досить довгий час. Ідея полягає в тому, щоб дослідити як можна більше каналів і відслідковувати ті з них, які перебувають у стані очікування з’єднання і є корисними для исследующего.

Сам по собі термін «сканування» з’явився в процесі злиття комп’ютерів з телефонними системами. В результаті була сформована глобальна мережа телефонних комунікацій, доступ до якої можна отримати, лише набравши номер на телефонному апараті. З одного телефону доступні мільйони абонентів телефонної мережі, однак корисними можуть виявитися лише сотні, а то й десятки абонентів, до телефонами яких підключений модем.

Логічно вірним підходом для пошуку телефонних номерів таких абонентів є «атака в лоб» — перебір всіх можливих номерів АТС і пошук тони несучої частоти, що генерується модем на іншому кінці лінії. Так виник напрямок, зване wardialing. З’явилася маса програм типу ToneLoc, призначених для дослідження великого обсягу телефонних номерів на наявність абонентів, до телефонами яких підключений модем…

Основна ідея проста. Якщо, набравши номер, модем встановив з’єднання (тобто на іншому кінці лінії також знаходиться модем), набраний номер запам’ятовується. В іншому випадку модем «вішає трубку», набирає номер і знову пробує встановити з’єднання.

Wardialing є досить ефективним методом для пошуку входів в різні мережі по комутованій телефонній лінії. З іншого боку, величезна кількість комп’ютерів об’єднані в мережу за допомогою спеціального обладнання (мережевих адаптерів, кабельних модемів) та виділених ліній та не використовують комутовані лінії АТС. У цьому разі програми типу ToneLoc виявляються марними, оскільки потрібно визначити не телефонний номер, а номер порту сервера, очікує запит на з’єднання.

Термін «порт» є абстрактним поняттям, використовуваним для спрощеного опису механізму встановлення з’єднання між хостами, і являє собою потенційний канал передачі даних. Використання механізму портів істотно полегшує процес встановлення з’єднання та обміну інформацією між сервером і хостом. Крім того, є можливість дослідження мережевого оточення сервера методом опитування його портів (т. зв. «сканування портів). На всі можливі номери портів (1-65535) сервера надсилається «лавина» пакетів, і по тому, від яких портів будуть (або не будуть) отримані відповіді, визначаються відкриті порти і служби, що працюють на досліджуваному сервері.

Техніка сканування портів

Було розроблено величезну кількість різних методів для пошуку протоколів і портів, які «прослуховує» віддалена машина. Всі методи мають певні переваги і недоліки. Нижче розглянуті найбільш часто використовувані з них.

Сканування сервера з використанням ICMP-відлуння

Перед безпосереднім початком сканування портів віддаленого хоста необхідно з’ясувати, які хости в мережі є функціонуючими, і визначити їх адреси. Особливо це важливо при скануванні групи хостів або при скануванні певного сегмента мережі.

Даний метод працює аналогічно команді ping. В якості запиту хост посилає серверу ICMP-повідомлення і очікує отримання відповіді, також представляє собою ICMP-повідомлення (т. зв. ICMP-ехо). Варіюючи час очікування відповіді на ping-запит, можна сканувати великі мережі.

Сканування TCP-портів функцією connect()

Даний метод є основним для сканування портів TCP. Функція connect() дозволяє хосту з’єднатися з будь-яким портом сервера. Якщо порт, зазначений у якості параметра функції, прослуховується сервером (тобто порт відкритий для з’єднання), то результатом виконання функції буде встановлення з’єднання з сервером з вказаного порту. В іншому випадку, якщо з’єднання не встановлено, то порт з вказаним номером є закритим.

Цей метод володіє одним серйозним перевагою: його може застосувати будь-який користувач, що не володіє ніякими привілеями на хості. Інша перевага — швидкість дослідження. Послідовний перебір портів шляхом виклику функції connect() для чергового номера порту, визначення його стану та закриття з’єднання — досить довгий процес. Однак його можна прискорити, застосувавши метод «паралельного перегляду» з використанням неблокированного з’єднання (non-blocked socket). Такий метод дозволяє визначити стан практично всіх портів сервера одночасно.

Великим недоліком даного методу є можливість виявлення та фільтрації такого роду сканування, причому зробити це досить легко. Log-файл сканованого сервера вкаже службам, відповідальним за зовнішні підключення, на наявність численних спроб підключення з однієї адреси і помилок встановлення з’єднання (оскільки хост досліджує після з’єднання з сервером, відразу обриває його), а ті, у свою чергу, негайно заблокують доступ до сервера для хоста з даними адресою.

Сканування TCP-портів прапором SYN

Цей метод відомий ще як «сканування з встановленням наполовину відкритого з’єднання» (half-open scanning), оскільки встановлення повного TCP-з’єднання не проводиться. Замість цього хост посилає на певний порт сервера SYN-пакет, як би маючи намір створити з’єднання, і чекає на відповідь. Наявність у відповіді прапорів SYN|ACK означає, що порт відкритий і прослуховується сервером. Отримання у відповідь TCP-пакета з прапором RST означає, що порт закритий і не прослуховується.

У разі прийому SYN|ACK-пакет хост негайно відправляє RST-пакет для скидання встановлюється сервером з’єднання. перевага даного методу насамперед полягає в тому, що лише деякі сервери здатні зареєструвати такого роду сканування. На жаль, користувач повинен володіти статусом Root на хості, з якого проводиться сканування. Якщо статус буде нижче Root, то користувач просто не зможе програмно сформувати одиночний SYN-пакет.

Сканування TCP-портів прапором FIN

Як вже говорилося, лише деякі сервери здатні відстежити спробу SYN-сканування їх портів. Так, деякі файрволли і пакетні фільтри «очікують» підроблені SYN-пакети на закриті порти захищається ними сервера, і спеціальне програмне забезпечення типу synlogger або courtney розпізнає спробу SYN-сканування. Якщо сервер «рве» з’єднання після опитування кількох портів, використовується FIN-сканування.

FIN-пакети здатні обійти ці засоби захисту. Ідея полягає в тому, що, згідно RFC 793, на який прибув FIN-пакет на закритий порт сервер повинен відповісти RST-пакет. FIN-пакети на відкриті порти ігноруються сервером. Однак не всі ОС дотримуються цієї рекомендації. Так, ОС Windows 95/98/NT, по всій видимості, мають імунітет до такого сканування, однак більшість ОС є сприйнятливими. Таким чином, спільно використовуючи SYN і FIN-сканування можна з успіхом оминути засоби захисту сервера і просканувати його порти.

Сканування TCP-портів прапорами SYN|FIN з використанням IP-фрагментації

Даний метод являє собою комбінацію SYN і FIN-сканування з невеликим удосконаленням. TCP-пакет (SYN або FIN-пакет, що має невеликий розмір) розбивається на стороні хоста на пару IP-фрагментів меншого розміру, і ця пара IP-фрагментів відправляється сервера. На стороні сервера IP-фрагменти «збираються» в один TCP-пакет і проводиться його обробка (ті ж дії, як і при SYN або FIN-скануванні).

Фрагментація дозволяє зменшити ймовірність виявлення сканування фільтрами пакетів та іншим обладнанням. Однак при цьому слід бути дуже обережним, оскільки деякі програми мають звичай «зависати» при спробі обробки такого маленького IP-фрагмента.

Сканування TCP-портів методом reverse-ident (зворотного ідентифікації)

Протокол ident (RFC 1413) дозволяє визначити ім’я (username або login, вказаний при вході в систему) власника будь-якого запущеного на сервері процесу, пов’язаного з ним, навіть якщо сам цей процес не ініціалізував TCP-з’єднання. Так, наприклад, є можливість підключитися до http-порту і потім використовувати id користувача щоб визначити, чи працює на сервері користувач root. Це може бути зроблено тільки при встановленні «повного» TCP-з’єднання до порту досліджуваного сервера.

Сканування TCP-портів з використанням атаки «Прорив через FTP»

Цікавою можливістю» протоколу FTP (RFC 959) є підтримка так званих «уповноважених» (proxy) сполук. Іншими словами, атакуючий, перебуваючи на сервері source.com може підключитися до інтерпретатору (Protocol Interpreter) протоколу FTP-сервера taregt.com для встановлення контролю над мережевим з’єднанням. Потім атакуючий дає запит PI сервера ініціалізувати активний DTP-сервер (Data Transfer Process) і відправити через нього будь-який файл на будь-який вузол Internet!

Дана особливість (відома, до речі, з 1985 року) може використовуватися для викрадення пошти та новин, «злому» серверів, їх заповнення дисків в обхід файрволів, і на практиці подібну діяльність дуже складно відстежити. У нашому випадку можна здійснити сканування TCP-портів досліджуваного сервера за допомогою proxy-FTP. Так, пройшовши через файрволл, хост з’єднується з FTP-сервером, і потім скануються порти, доступ до яких був заблокований файрволом (наприклад, 139-й порт). Крім того, якщо FTP-сервер дозволяє читати і записувати дані в каталог (наприклад /incoming), є можливість відправляти будь-які дані на виявлений відкритий порт сервера.

Перед безпосереднім скануванням порту необхідно встановити з’єднання з FTP-сервером і використовувати команду PORT із зазначенням номера інтересуемого порту. Таким чином серверу буде повідомлено, що пасивний User-DTP на стороні хоста очікує прийому через деякий вказаний порт. Потім необхідно дати команду LIST для поточного каталогу, і FTP-сервер відправить дані про каталозі за допомогою Server-DTP, сполученого з User-DTP з вказаного порту.

Якщо зазначений у команді PORT порт сервера відкритий, результат виконання LIST буде успішним (код відповіді в цьому випадку буде 150 і 226). В іншому випадку буде мати місце подібний відповідь:

425 can’t build data connection: Connection Refused
Після цього знову використовується команда PORT із зазначенням іншого порту і операція повторюється.

Переваги цього методу очевидні (неможливість відстеження сканування, обхід файрволів). До недоліків відноситься насамперед низька швидкість сканування і той фактор, що деякі FTP-сервери нарешті закрили цю «дірку».

Сканування портів UDP перевіркою ICMP-повідомлення «Порт недоступний»

Цей метод призначений для визначення стану портів сервера. Основною відмінністю є використання протоколу UDP замість протоколу TCP. Не дивлячись на те, що організація протоколу UDP простіше, ніж TCP, сканувати UDP-порти набагато важче. Це пов’язано насамперед з концепцією протоколу UDP як протоколу з негарантованою доставкою даних. Тому UDP-порт не посилає підтвердження прийому запиту на встановлення з’єднання, і немає ніякої гарантії, що надіслані UDP порту дані успішно дійдуть до нього.

На щастя, більшість серверів у відповідь на пакет, який прибув на закритий порт UDP, відправляють ICMP-повідомлення «Порт недоступний» (Port Unreachable — PU). Таким чином, якщо у відповідь на UDP-пакет прийшло ICMP-повідомлення PU, то сканований порт є закритою, в іншому випадку (при відсутності PU) порт відкритий. Оскільки немає гарантії, що запити від хоста дійдуть до сервера, користувач повинен подбати про повторну передачу UDP-пакета, який, по всій видимості, виявився втраченим.

Цей метод працює дуже повільно через використання на деяких машинах т. н. «компенсації» (RFC 1812 розділ 4.3.2.8), що обмежує частоту генерування ICMP-повідомлення про помилку. Наприклад, ядро Linux обмежує частоту генерування ICMP-повідомлення «адресат недосяжний» (Destination Unreachable) до 80 повідомлень за 4 секунди, з простоєм 0,25 секунди, якщо це обмеження було перевищено. Крім того, для використання даного методу (а саме — для виявлення ICMP-повідомлення про помилку) користувач повинен володіти статусом Root на хості, з якого проводиться сканування.

Може здатися, що сканування портів UDP не дає тієї повноти інформації, яку можна отримати при скануванні TCP-портів. Однак, беручи до уваги існуючі (хоча і численні) «дірки» в службах, які використовують протокол UDP (наприклад, «дірку» в rpcbind-демона ОС Solaris, який може знаходитись на будь-якому UDP-порт з номером вище 32770), сканування портів UDP здається не таким вже безглуздим.

Сканування портів UDP з використанням функцій recvfrom() і write()

Цей метод використовується у випадку, коли користувач, який проводить сканування, не володіє статусом Root на хості. Оскільки не root користувач не може «читати» ICMP-повідомлення PU, в ОС, що підтримують механізм сокетів (наприклад, Linux), є можливість отримання інформації про стан UDP-порти непрямим способом. Так, наприклад, спроба виклику функції write() на закритий порт зазвичай призводить до виникнення помилки.

Функція recvfrom() в цьому плані більш інформативна. Виклик її на неблокированный UDP-сокет сервера зазвичай повертає помилку EAGAIN (Try Again — «спробуйте ще раз», код 13) у разі, коли ICMP-повідомлення не було прийнято, і ECONREFUSED (Connection Refused — «з’єднання закрито», код 111), якщо ICMP-повідомлення було прийнято. Таким чином, за цими ознаками також можливо визначити стан портів сканованого сервера.

Можливості RuNmap

До виникнення ідеї про створення програми Nmap були досліджені можливості багатьох сканерів, таких, як strobe (автор — Julian Assange), netcat (Hobbit), stcp (Uriel Maimon), pscan (Pulvius) ident-scan (Dave Goldsmith) і Satan (Wietse Venema). Всі вони — чудові сканери. Спочатку були спроби доопрацювати код одних сканерів для підтримки кращих можливостей інших. Потім було вирішено написати абсолютно новий сканер, який використовував б кращі можливості його попередників, і, звичайно, мав нові, такі, як «фрагментоване» сканування та ін Так вийшов мережевий сканер Nmap — the Network Mapper. Програма RuNmap являє собою русифіковану та доопрацьовану версію Nmap. Нижче наведені найбільш характерні її можливості.

Динамічне обчислення часу затримки. Деяким сканерів для роботи необхідно вказати час затримки між передачею двох пакетів. Як вам дізнатися його? Природно, можна використовувати дані ping-запит, але це займе досить багато часу, і, крім того, час затримки постійно змінюється і залежить від «завантаженості» хоста, стану мережі і т. д. RuNmap самостійно визначає час затримки, і підлаштовує його в процесі сканування. Для root-користувачів використовується найкращий спосіб визначення часу затримки — функція ping. Для інших цей параметр визначається функцією connect () на закритий порт. Крім того, у користувача є можливість самостійно встановити час затримки, але зазвичай робити це немає необхідності.

Повторна передача пакетів. Деякі сканери відразу відправляють всі запити, а потім «збирають» відповіді на них. Дуже некоректний підхід, оскільки при цьому не береться до уваги той факт, що іноді пакети можуть просто не дійти до адресата по самим різним причинам. У такій ситуації сканер прийме рішення про відсутність відповіді і помилково вкаже, що сканований порт закритий. Найбільше помилок виникає при використанні «негативного» сканування типу UDP або FIN, рішення яких приймається на основі відсутності відповіді. RuNmap автоматично вибирає число повторних передач пакетів на порти, від яких не було отримано відповідь.

Паралельне сканування портів. Деякі сканери послідовно сканують всі 65535 портів за один раз. Цей метод нормально працює лише при скануванні TCP-портів в високошвидкісних локальних мережах. Глобальні мережі типу Internet високою швидкістю не відрізняються. RuNmap використовує неблокированный введення/виведення (non-blocked i/o) і паралельне сканування у всіх режимах TCP і UDP. Ви можете задати число паралельних процесів сканування самостійно. На дуже швидких мережах ефективність сканування зменшується при вказівці цього значення більше 18. На повільних мережах — навпаки, чим більше значення, тим вище ефективність.

Гнучке вказівку сканованих портів. Часто буває необхідно відсканувати які-небудь конкретні порти, а не всі 65535 портів відразу. Більшість сканерів дозволяє задавати діапазон портів типу 1-N, що також не завжди прийнятно. RuNmap дозволяє задати будь-яку кількість довільних діапазонів і портів, наприклад ’21-25,80,113,6000-‘. При використанні «швидкого» режиму RuNmap буде сканувати тільки порти, перераховані у файлі /etc/services.

Гнучке завдання мети сканування. Часто необхідно просканувати більш ніж один хост, однак більшість сканерів дозволяють задати лише одна адреса. Все, що не є опцією або її аргументом, RuNmap сприймає як адреса хоста. Таким чином, ви можете абсолютно довільно вказати адреси та діапазони адрес, які потрібно просканувати. Крім того, ви можете використовувати маску для сканування груп адрес різних класів.

Визначення неактивних хостів. Деякі сканери дозволяють сканувати великі мережі, проте вони витрачають дуже багато часу на сканування 65535 портів хоста, який з якихось причин не функціонує. За замовчуванням, перед скануванням RuNmap опитує кожен хост і визначає його стан, для того, щоб не витрачати часу на сканування неактивних хостів.

Визначення IP-адреси скануючого хоста. З деяких причин більшість сканерів вимагають вказати використовуваний скануючим хостом IP-адресу в якості одного з параметрів. RuNmap автоматично визначає IP-адресу машини, на якій він працює, на стадії ping-опитування, і використовує ту адресу, на який надійшла відповідь. Якщо він не зміг це зробити (наприклад, користувач відключив ping-опитування), RuNmap пробує визначити первинний мережевий інтерфейс і використовує його IP-адресу. Нарешті, користувач сам може вказати IP-адресу хоста.