Основи роботи з Linux. / Скануємо порти на хостах. / Скануємо порти на хостах.
Cкануємо порти.
Просканувати віддалений хост можна такою командою
nmap -P0 192.168.9.240
Подивитися хто слухає певний порт.
netstat -anp | grep LISTEN | grep 620
Завдання сканування відкритих портів на хостах, взятих зі списку у файлі hostlist.
Далі провести аналіз та порівняти з попереднім скануванням, з’ясувати зміни та скласти звіт.
Розіб’ємо завдання на 3 файли.
scan.sh - скануватиме порти (від 1 до 1024), приймаючи на stdin ім’я хоста;
compare.sh - порівнюватиме результати з попереднім скануванням;
report.sh - запускатиме 1 і 2 і формуватиме файл звіту.
Створення циклу з вхідних хостів.
Файл scan.sh
while read HOSTNAME
do
echo $HOSTNAME
done
read - читає рядок зі stdin.
Передаємо дані з файлу hostlist
Файл report.sh
./scan.sh < hostlist
Формуємо назву файлу із результатами сканування.
scan.sh
printf -v TODAY 'scan_%(%F)T' -1
echo $TODAY
%()T - специфікатор функції printf позначає дату-час.
%F - специфікатор системної функції strftime описуючий формат “рік-місяць-день”
-1 - означає “зараз”
Змінимо scan.sh додамо функцію та її викличемо.
printf -v TODAY 'scan_%(%F)T' -1
function scan() {
host=$1
printf '%s' "$host"
}
while read HOSTNAME
do
scan $HOSTNAME
done
В bash явно не вказуються параметри функції, вони забираються через $1,2 тощо.
printf – не виводить символ перенесення рядка.
Робимо цикл по портах.
function scan() {
host=$1
printf '%s' "$host"
for ((port=1;port<1024;port++)){
echo $port
}
}
Або так
for ((port=1;port<1024;port++)) do echo $port done
Доопрацюємо функцію спробою створити підключення на сокет
function scan() {
host=$1
printf '%s' "$host"
for ((port=1;port<1024;port++))
do
echo >/dev/null 2>&1 < /dev/tcp/${host}/${port}
if (($? == 0)) ; then printf ' %d' "${port}" ; fi
done
echo
}
echo без аргументів виведе stdout символ перенесення рядка і ми його ігноруємо перекладаючи /dev/null.
Однак перенаправлення з stdin буде виконуватися bash, незважаючи на те, що це не використовується командою echo.
2>&1 < /dev/tcp/${host}/${port} - тут ми переправляємо вміст і помилки з передбачуваного файлового дескриптора сокет-з’єднання, причому дані не будуть раховані т.к. команді echo це не потрібно. Просто перевірить, чи є файл (дескриптор з’єднання).
Пересилання результатів сканування у файл.
while read HOSTNAME
do
scan $HOSTNAME
done > $TODAY
Можна було б переправити всередині циклу, але так зручніше. нам не потрібно дбати про обрізання файлу в циклі перенаправленням >. Навіть якби ми використовували >> у циклі, потрібно було перед ним обрізати файл.
Порівняння з попереднім скануванням.
Використання
./compare.sh <file1> <file2>
Визначаємо функцію пошуку порту
function NotInList ()
{
for port in "$@"
do
if [[ $port == $LOOKFOR ]]
then
return 1
fi
done
return 0
}
$@ - розгортає параметри функції за одним окремими значеннями
Нагадуємо, що ненульове значення вважається хибним.
Читаємо вміст 2 файлів за файловими дескрипторами.
while true
do
read aline <&4 || break # EOF
read bline <&5 || break # EOF, для симметрии
echo $aline
echo $bline
done 4< $1 5< $2
4< $1 5< $2 - Тут ми створюємо файлові дескриптори, переправляючи у яких вміст файлів першого і другого параметра
<&4 - & показує що ми використовуємо дескриптор файлу, а не файл з ім’ям 4
|| - логічне OR воно виконати breack тільки якщо read поверне помилку, що відбувається на другий ітерації циклу, коли досягається кінець файла.
Перевіримо рівність двох рядків і якщо вони рівні переходимо на нову ітерацію циклу.
[[ $aline == $bline ]] && continue;
Вилучення хоста та портів.
HOSTA=${aline%% *}
PORTSA=( ${aline#* } )
HOSTB=${bline%% *}
PORTSB=( ${bline#* } )
${string#substring} - видаляє найкоротший збіг підрядка від початку.
${string##substring} - видаляє найдовший збіг підрядка від початку.
% - працює з кінця рядка
HOSTA=${aline%% *} - видалити всі символи з кінця рядка до першого пробілу
PORTSA=( ${aline#* } ) - створить масив портів видаляючи всі символи від початку до першого пропуску
Далі ми робимо дві перевірки на порти, які були відкриті та закриті.
for porta in ${PORTSA[@]}
do
LOOKFOR=$porta
NotInList ${PORTSB[@]} && echo " closed: $porta"
done
for portb in ${PORTSB[@]}
do
LOOKFOR=$portb
NotInList ${PORTSA[@]} && echo " new: $portb"
done
NotInList ${PORTSB[@]} && echo ” closed: $porta” - виводить лише у разі успішного виконання виразу зліва від &&
Формування звіту
Файл report.sh
./scan.sh < hostlist
FILELIST=$(ls scan_* | tail -2)
FILES=( $FILELIST )
./compare.sh ${FILES[0]} ${FILES[1]}
$(ls scan_* | tail -2) - выбираем два последних отчета, ls сортирует файлы в порядке их создания.
Щоб полегшити поділ на дві частини, помістимо імена у масив.