← На главную

Аудит поверхности атаки VoIP-сервера одним bash-скриптом

Аудит поверхности атаки VoIP-сервера одним bash-скриптом

У любого сервера, торчащего в интернет, есть «поверхность атаки» — набор открытых портов, через которые с ним можно взаимодействовать. Для VoIP-серверов на Asterisk/FreePBX это особенно чувствительная тема: открытый наружу SIP притягивает сканеры и попытки подбора паролей (а значит, риск дорогостоящего toll fraud — мошеннических звонков за ваш счёт), а забытый открытым MySQL или Asterisk Manager Interface (AMI) — это почти готовый вход для злоумышленника.

В этой статье разбираем небольшой bash-скрипт, который быстро показывает, что именно ваш VoIP-сервер демонстрирует наружу. Он ничего не эксплуатирует — только проверяет доступность портов и переводит результат в понятную оценку риска.


Сначала — о легальном использовании

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


Что делает скрипт и чего не делает

Инструмент реализует «лёгкое» сканирование портов средствами самого bash — через псевдоустройства /dev/tcp и /dev/udp, обёрнутые в timeout. Никаких внешних сканеров вроде nmap не требуется: достаточно чистого bash.

Что он делает: пытается установить соединение с набором характерных для VoIP портов, помечает каждый как открытый или закрытый, начисляет открытым «вес риска» и суммирует всё в итоговый балл.

Чего он не делает: не отправляет эксплойтов, не подбирает пароли, не шлёт вредоносных SIP-пакетов и вообще никак не пытается «пробить» сервис. Это чистая проверка достижимости — эквивалент вопроса «этот порт вообще отвечает?».

Идея весов проста: чем опаснее сервис при внешнем доступе, тем выше его вклад в балл. MySQL и AMI весят по 30, RPCBind — по 25, SIP — 20 и так далее. В сумме это даёт грубую, но наглядную метрику «насколько сервер разболтан наружу».


Что происходит по шагам

1. Приём цели. Скрипт берёт IP или хост из первого аргумента. Если аргумента нет — показывает подсказку по использованию и завершается.

2. Функции проверки. Определяются две вспомогательные функции — check_tcp и check_udp. Каждая принимает порт, имя сервиса и вес; пытается достучаться до порта с таймаутом в 2 секунды и, если тот отвечает, прибавляет вес к общему счётчику RISK_SCORE.

3. Проверка по категориям. Дальше порты проверяются группами, отсортированными по опасности:

  • Critical Services — то, что вообще не должно быть доступно из интернета: MySQL (3306), RPCBind (111), Asterisk AMI (5038).
  • High Risk VoIP — сигнализация: SIP по UDP (5060), SIP TLS (5061), IAX2 (4569).
  • RTP/RTCP Media — медиапорты, по которым идёт сам голос.
  • Web Exposure — веб-панели управления (80, 443 и нестандартные).
  • Infra Services — SSH, DNS, TFTP, NTP.

4. Умное определение RTP-диапазона. Медиапорты у Asterisk задаются диапазоном (rtpstartrtpend). Если скрипт запущен прямо на сервере, он вычитывает эти значения из /etc/asterisk/rtp*. При удалённом запуске, когда конфиг недоступен, используется разумный fallback 10000–20000. Проверять весь диапазон целиком смысла нет, поэтому берутся три репрезентативные точки: начало, середина и конец.

5. Итоговый балл. Все веса суммируются и выводится TOTAL RISK SCORE.

6. Уровень опасности. Число переводится в понятную градацию: до 25 — LOW, 25–49 — ELEVATED, 50–79 — HIGH, 80 и выше — CRITICAL.


Тонкость: почему UDP-проверка приблизительна

Стоит честно отметить ограничение метода. TCP-проверка надёжна: соединение либо устанавливается, либо нет. А вот с UDP сложнее — этот протокол без установления соединения, и «молчание» порта неотличимо от «порт открыт, но не отвечает на пустую датаграмму». Поэтому UDP-результаты (SIP, RTP, DNS и прочее) стоит воспринимать как индикатор достижимости, а не как стопроцентный вердикт. Для точной картины по UDP нужны специализированные проверки на уровне протокола — но для быстрой самооценки этого достаточно.


Как читать результат

Чем выше балл — тем больше лишнего видно из интернета. Ориентир для публично доступного VoIP-сервера такой: наружу открыто только то, что действительно нужно для звонков (обычно SIP и диапазон RTP), а всё остальное — MySQL, AMI, RPCBind — либо закрыто фаерволом, либо слушает исключительно localhost.

Если аудит показал открытыми критические сервисы, типичные действия такие: закрыть их в UFW/iptables, привязать MySQL и AMI к 127.0.0.1, ограничить SSH и веб-панель доступом по списку доверенных IP, а для SIP — включить fail2ban и, по возможности, перевести сигнализацию на TLS.


Использование

bash voip_security_audit.sh 203.0.113.10

Запуск на самом сервере даёт более точную проверку RTP, потому что скрипт прочитает реальный диапазон из конфига Asterisk. Удалённый запуск тоже работает — просто с fallback-диапазоном.


Полный код скрипта

#!/usr/bin/env bash
###############################################################################
#
#  voip_security_audit.sh — аудит открытых портов VoIP/Asterisk-сервера
#
#  Пассивная проверка «поверхности атаки»: скрипт смотрит, какие типовые
#  TCP/UDP-порты доступны снаружи, начисляет открытым «вес риска» и выдаёт
#  итоговую оценку. Ничего не эксплуатирует — только проверяет достижимость.
#
#  ⚠️  Сканируйте ТОЛЬКО свои системы или те, на тест которых есть разрешение.
#
#  Использование: bash voip_security_audit.sh <IP сервера>
#
###############################################################################

# ─── 1. Аргументы: адрес цели обязателен ────────────────────────────────────
TARGET_IP="$1"
[ -z "$TARGET_IP" ] && echo "Использование: $0 <IP сервера>" && exit 1

# ─── 2. Палитра и счётчик риска ─────────────────────────────────────────────
RED="\e[31m"; GREEN="\e[32m"; YELLOW="\e[33m"; CYAN="\e[36m"; RESET="\e[0m"
RISK_SCORE=0

echo -e "${CYAN}=============================================="
echo -e " VOIP SECURITY AUDIT: $TARGET_IP"
echo -e "==============================================${RESET}"

# ─── 3. Функции проверки портов ─────────────────────────────────────────────
# TCP: соединение через /dev/tcp; успех = порт открыт → +вес к RISK_SCORE.
check_tcp() {
    local port=$1; local name=$2; local weight=$3
    timeout 2 bash -c "</dev/tcp/$TARGET_IP/$port" &>/dev/null
    if [ $? -eq 0 ]; then
        echo -e "${RED}[OPEN] TCP $port ($name)${RESET}"
        RISK_SCORE=$((RISK_SCORE + weight))
    else
        echo -e "${GREEN}[CLOSED] TCP $port ($name)${RESET}"
    fi
}

# UDP: грубая проверка достижимости через /dev/udp (без соединения).
check_udp() {
    local port=$1; local name=$2; local weight=$3
    timeout 2 bash -c "echo >/dev/udp/$TARGET_IP/$port" &>/dev/null
    if [ $? -eq 0 ]; then
        echo -e "${RED}[OPEN] UDP $port ($name)${RESET}"
        RISK_SCORE=$((RISK_SCORE + weight))
    else
        echo -e "${GREEN}[CLOSED] UDP $port ($name)${RESET}"
    fi
}

# ─── 4. Критические сервисы (не должны торчать наружу) ───────────────────────
echo -e "\n${YELLOW}--- CRITICAL SERVICES ---${RESET}"
check_tcp 3306 "MySQL"        30
check_tcp 111  "RPCBind TCP"  25
check_udp 111  "RPCBind UDP"  25
check_tcp 5038 "Asterisk AMI" 30

# ─── 5. Высокий риск: VoIP-сигнализация ─────────────────────────────────────
echo -e "\n${YELLOW}--- HIGH RISK VOIP ---${RESET}"
check_udp 5060 "SIP UDP"   20
check_udp 5061 "SIP TLS"   15
check_udp 4569 "IAX2"      15

# ─── 6. Медиа-диапазон RTP/RTCP ─────────────────────────────────────────────
echo -e "\n${YELLOW}--- RTP / RTCP MEDIA RANGE ---${RESET}"
RTP_START=$(grep -h rtpstart /etc/asterisk/rtp* 2>/dev/null | head -1 | cut -d= -f2 | tr -d ' ')
RTP_END=$(grep -h rtpend   /etc/asterisk/rtp* 2>/dev/null | head -1 | cut -d= -f2 | tr -d ' ')
[ -z "$RTP_START" ] && RTP_START=10000     # fallback при удалённом запуске
[ -z "$RTP_END"   ] && RTP_END=20000

MID=$(( (RTP_START + RTP_END) / 2 ))
TEST_PORTS=($RTP_START $MID $RTP_END)      # проверяем начало/середину/конец

for p in "${TEST_PORTS[@]}"; do
    timeout 2 bash -c "echo >/dev/udp/$TARGET_IP/$p" &>/dev/null
    if [ $? -eq 0 ]; then
        echo -e "${CYAN}[REACHABLE] RTP/RTCP UDP $p${RESET}"
    else
        echo -e "${GREEN}[FILTERED] RTP/RTCP UDP $p${RESET}"
    fi
done

# ─── 7. Веб-поверхность (панели управления) ─────────────────────────────────
echo -e "\n${YELLOW}--- WEB EXPOSURE ---${RESET}"
check_tcp 80   "HTTP GUI"       10
check_tcp 443  "HTTPS GUI"      10
check_tcp 5000 "Custom Web/App" 10
check_tcp 6002 "Custom HTTP"    10

# ─── 8. Инфраструктурные сервисы ────────────────────────────────────────────
echo -e "\n${YELLOW}--- INFRA SERVICES ---${RESET}"
check_tcp 22   "SSH"   5
check_udp 53   "DNS"   5
check_udp 69   "TFTP" 10
check_udp 123  "NTP"   5

# ─── 9. Итоговая оценка риска ────────────────────────────────────────────────
echo -e "\n${CYAN}==============================================${RESET}"
echo -e "${CYAN}TOTAL RISK SCORE: $RISK_SCORE${RESET}"

if [ $RISK_SCORE -ge 80 ]; then
    echo -e "${RED}RISK LEVEL: CRITICAL (HIGH DANGER)${RESET}"
elif [ $RISK_SCORE -ge 50 ]; then
    echo -e "${RED}RISK LEVEL: HIGH${RESET}"
elif [ $RISK_SCORE -ge 25 ]; then
    echo -e "${YELLOW}RISK LEVEL: ELEVATED${RESET}"
else
    echo -e "${GREEN}RISK LEVEL: LOW${RESET}"
fi

Итог

Скрипт — это быстрый «медосмотр» внешней доступности VoIP-сервера. Его ценность в простоте: чистый bash, никаких зависимостей, наглядная балльная оценка вместо простыни портов. Его ограничения тоже честны — приблизительность UDP-проверки и то, что балл отражает лишь факт открытости порта, а не реальную уязвимость сервиса за ним. Используйте его как отправную точку: прогнали аудит на своём сервере, увидели лишнее наружу — закрыли фаерволом и перепроверили. И, повторюсь, только на своей инфраструктуре.

💬 Обсуждение и вопросы

Комментарии и обсуждение — на интерактивной версии статьи.

Перейти к обсуждению →