проФорт

Форт и всё такое

Простой сканер портов

, ,

Вашему вниманию предлагается простой сканер портов на SPF.

Пример использования библиотеки сокетов и немного бакфорт-кода с подробным описанием.

Задание : получить от пользователя адрес машины для исследования (в виде домена или IP-адреса) и номера портов которые надо просканировать. Требуется отобразить номера открытых на целевой машине портов из указанного диапазона. Сканирование порта - это просто попытка установить соединение. Если на целевой машине запущен какой-то сервис который слушает этот порт (и не применяются техники типа port knocking, etc), то мы сможем законнектиться.

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>ConnectHost </span><span style='color:#000084; '>~ac/lib/win/winsock/sockets.f</span>
<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>PRO </span><span style='color:#000084; '>~profit/lib/bac4th.f</span>
<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>NEXT-PARAM </span><span style='color:#000084; '>~day/common/clparam.f</span>
<span style='color:#808080; '>\ REQUIRE NUMBER ~ygrek/lib/parse.f</span>

<span style='color:#808080; '>\ Преобразовать строку a u в число (только символы текущей системы счисления)</span>
<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>NUMBER</span><span style='color:#808080; '> ( a u -- n -1 | 0 )</span> 
   <span style='color:#008c00; '>0 </span><span style='color:#008c00; '>0 </span><span style='color:#000084; font-weight:bold; '>2SWAP </span><span style='color:#000084; font-weight:bold; '>>NUMBER </span><span style='color:#000084; font-weight:bold; '>NIP </span><span style='color:#800000; '>IF </span><span style='color:#000084; font-weight:bold; '>2DROP </span><span style='color:#000084; font-weight:bold; '>FALSE </span><span style='color:#800000; '>ELSE </span><span style='color:#000084; font-weight:bold; '>D>S </span><span style='color:#000084; font-weight:bold; '>TRUE </span><span style='color:#800000; '>THEN</span><span style='color:#000084; font-weight:bold; '> ;</span> 

<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>tryConnect</span><span style='color:#808080; '> ( a u port -- ? )</span> 
    ConnectHost <span style='color:#000084; font-weight:bold; '>0=</span><span style='color:#808080; '> \ если удаётся установить соединение - ior ноль</span>
    <span style='color:#800000; '>IF</span> 
     CloseSocket <span style='color:#000084; font-weight:bold; '>DROP</span><span style='color:#808080; '> \  тогда корректно закрываем сокет </span>
     <span style='color:#000084; font-weight:bold; '>TRUE</span>
    <span style='color:#800000; '>ELSE</span> 
     <span style='color:#000084; font-weight:bold; '>DROP </span><span style='color:#000084; font-weight:bold; '>FALSE</span><span style='color:#808080; '> \ иначе возвращаем признак неудачи</span>
    <span style='color:#800000; '>THEN</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#808080; '>\ сканируем последовательность портов</span>
<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>tryConnectRange=></span><span style='color:#808080; '> ( a u port1 port2 --> port \ <-- )</span>
   PRO
   <span style='color:#000084; font-weight:bold; '>2DUP </span><span style='color:#000084; font-weight:bold; '>< </span><span style='color:#800000; '>IF </span><span style='color:#000084; font-weight:bold; '>SWAP </span><span style='color:#800000; '>THEN</span><span style='color:#808080; '> \ гарантируем корректность параметров цикла</span>
   <span style='color:#800000; '>?DO</span> 
    <span style='color:#000084; font-weight:bold; '>2DUP </span><span style='color:#800000; '>I</span> tryConnect 
    <span style='color:#800000; '>IF</span> 
      <span style='color:#800000; '>I</span> CONT<span style='color:#808080; '> \ если удача - генерируем вызов с номером порта</span>
    <span style='color:#800000; '>THEN</span>
   <span style='color:#800000; '>LOOP </span><span style='color:#000084; font-weight:bold; '>2DROP</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#808080; '>\ получаем параметры из коммандной строки</span>
<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>getParameters</span><span style='color:#808080; '> ( -- a u port1 port2 )</span>
   NEXT-PARAM <span style='color:#000084; font-weight:bold; '>2DROP</span><span style='color:#808080; '> \ первый параметр - путь к исполняемому файлу - игнорируем</span>
  <span style='color:#808080; '> \ если параметров не хватает - выкидываем исключение</span>
   NEXT-PARAM <span style='color:#000084; font-weight:bold; '>DUP </span><span style='color:#000084; font-weight:bold; '>0= </span><span style='color:#000084; font-weight:bold; '>THROW</span> 
   NEXT-PARAM <span style='color:#000084; font-weight:bold; '>DUP </span><span style='color:#000084; font-weight:bold; '>0= </span><span style='color:#000084; font-weight:bold; '>THROW</span> NUMBER <span style='color:#000084; font-weight:bold; '>0= </span><span style='color:#000084; font-weight:bold; '>THROW</span>
   NEXT-PARAM <span style='color:#000084; font-weight:bold; '>DUP </span><span style='color:#000084; font-weight:bold; '>0= </span><span style='color:#800000; '>IF </span><span style='color:#000084; font-weight:bold; '>2DROP </span><span style='color:#000084; font-weight:bold; '>DUP </span><span style='color:#000084; font-weight:bold; '>1+ </span><span style='color:#800000; '>ELSE</span> NUMBER <span style='color:#000084; font-weight:bold; '>0= </span><span style='color:#000084; font-weight:bold; '>THROW </span><span style='color:#800000; '>THEN</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>printUsage</span><span style='color:#808080; '> ( -- )</span>
   <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>Usage: portscan.exe host port_from [port_to]</span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>TYPE</span> 
   <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>host - IP address or domain to scan ports</span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>TYPE</span> 
   <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>port_from port_to - port range to scan</span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>TYPE</span>
      <span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>, if port_to is omitted only port_from is checked</span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>TYPE</span> 
<span style='color:#000084; font-weight:bold; '>;</span>

<span style='color:#808080; '>\ для каждой удавшейся попытки соединения просто печатаем номер порта</span>
<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>performScan</span><span style='color:#808080; '> ( a u port1 port2 -- )</span>
   tryConnectRange=> <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>Port is open : </span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>.</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>main</span>
  <span style='color:#800000; '>['] </span><span style='color:#000084; font-weight:bold; '>getParameters </span><span style='color:#000084; font-weight:bold; '>CATCH</span><span style='color:#808080; '> \ ловим исключения от обработки комстроки</span>
  <span style='color:#800000; '>IF</span> 
   printUsage <span style='color:#000084; font-weight:bold; '>BYE</span><span style='color:#808080; '> \ если ошибка в параметрах то пишем информацию по использованию</span>
  <span style='color:#800000; '>THEN</span> 
 <span style='color:#808080; '> \ </span><span style='color:#ffffff; background:#808000; '>!!!</span><span style='color:#808080; '>   не забываем проинициализировать систему сокетов   </span><span style='color:#ffffff; background:#808000; '>!!!</span>
  SocketsStartup <span style='color:#000084; font-weight:bold; '>THROW</span> 
  <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>Performing scan on : </span><span style='color:#000084; font-weight:bold; '>"</span>
  <span style='color:#000084; font-weight:bold; '>2OVER </span><span style='color:#000084; font-weight:bold; '>TYPE</span> 
  <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>Port range : </span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>2DUP </span><span style='color:#000084; font-weight:bold; '>SWAP </span><span style='color:#000084; font-weight:bold; '>. </span><span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>- </span><span style='color:#000084; font-weight:bold; '>" </span><span style='color:#000084; font-weight:bold; '>.</span>
  performScan 
  <span style='color:#000084; font-weight:bold; '>CR </span><span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>Finished</span><span style='color:#000084; font-weight:bold; '>"</span>
  <span style='color:#000084; font-weight:bold; '>KEY </span><span style='color:#000084; font-weight:bold; '>DROP </span><span style='color:#000084; font-weight:bold; '>BYE</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>save</span>
  <span style='color:#008c00; '>0</span><span style='color:#800000; '> </span><span style='color:#000084; font-weight:bold; '>TO</span> SPF-INIT?<span style='color:#808080; '> \ выключаем интерпретацию комстроки spf-ом</span>
  <span style='color:#800000; '>['] </span><span style='color:#000084; font-weight:bold; '>main</span> MAINX <span style='color:#000084; font-weight:bold; '>!</span><span style='color:#808080; '> \ устанавливаем нашу точку входа</span>
  <span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>portscan.exe</span><span style='color:#000084; font-weight:bold; '>"</span> SAVE<span style='color:#000084; font-weight:bold; '> ;</span><span style='color:#808080; '> \ сохраняем программу в exe-файл</span>

save <span style='color:#000084; font-weight:bold; '>BYE</span>



Главное слово - tryConnect ( a u port -- ? ) которое проверяет соединение с хостом a u на указанный порт. Внимание на tryConnectRange=> ( a u port1 port2 --> port \ <-- ) - это бакфорт[/COLOR] слово, что и отражено в стековой нотации. Ничего сложного :
  1. слово берёт четыре параметра со стека - строку в виде a u и два числа
  2. стрелка --> port обозначает что при успехе генерируется вызов с одним параметром на стеке
  3. пустое место за обратной стрелкой <-- ) значит, что сгенерированный вызов ничего не должен возвратить, т.е. условно стековая диаграмма для бакфорт-вызова выглядит так : ( port -- )
  4. после завершения работы слово tryConnectRange=> ничего не возвращает - это следует из пустого места перед обратной стрелкой \ <--.
Остался один неясный момент - что значит генерируется вызов? Это ключевой момент для понимания бакфорта.. На самом деле происходит просто передача управления - но несколько непривычным образом. Посмотрим на слово :
: performScan ( a u port1 port2 -- )
   tryConnectRange=> CR ." Port is open : " . ;
По сути, бакфорт вызов передаёт управление на условный выполнимый токен соответствующий последовательности CR ." Port is open : " . Проверим стековый эффект для нашего "условного" xt : слово CR ( -- ) слово ." ( -- ) слово . ( n -- ) Итого общий эффект : ( n -- ), как раз то что требует слово tryConnectRange=> для своих бакфорт вызовов - ( port -- ). Так выглядит использование бакфорт-итераторов снаружи. Изнутри же это выглядит так : слово-итератор подготавливает почву для бэктрекинга словом PRO в начале своего определения. А вызовы генерируются словом CONT. По сути вызов CONT просто передаёт управление на условный xt который передаётся неявным образом. Подставьте мысленно вместо CONT последовательность CR ." Port is open : " . и это будет точным эквивалентом того что происходит в момент исполнения этого слова. Использование бакфорта в этой ситуации позволило отделить мух от котлет - проверка события "открытый порт" и реакция на него (напечатать номер порта) разделены. Этого можно было достичь и явной передачей вышеописанного "условного xt" в слово tryConnectRange=>. Слово NEXT-PARAM ( -- a u ) даёт параметры коммандной строки. Также обращаю внимание на обязательную инициализацию библиотеки winsock помощью SocketsStartup THROW иначе слова для работы с сокетами не будут работать! После выполнения получим portscan.exe, который запускаем например так :
portscan.exe forth.org.ru 25 81
Performing scan on : forth.org.ru
Port range : 25 - 81
Port is open : 25
Port is open : 53
Port is open : 80
Finished
Отметим, что сканирование идёт очень медленно. Причина в том что в каждый момент времени активно только одно соединение. Если мы это дело распараллелим в несколько потоков, то очевидно получим прирост в скорости. Что мы и проделаем в следующий раз smile

Сначало было словоПростой сканер портов - 2

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies