У любого сервера, торчащего в интернет, есть «поверхность атаки» — набор открытых портов, через которые с ним можно взаимодействовать. Для 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. Проверка по категориям. Дальше порты проверяются группами, отсортированными по опасности:
4. Умное определение RTP-диапазона. Медиапорты у Asterisk задаются диапазоном (rtpstart–rtpend). Если скрипт запущен прямо на сервере, он вычитывает эти значения из /etc/asterisk/rtp*. При удалённом запуске, когда конфиг недоступен, используется разумный fallback 10000–20000. Проверять весь диапазон целиком смысла нет, поэтому берутся три репрезентативные точки: начало, середина и конец.
5. Итоговый балл. Все веса суммируются и выводится TOTAL RISK SCORE.
6. Уровень опасности. Число переводится в понятную градацию: до 25 — LOW, 25–49 — ELEVATED, 50–79 — HIGH, 80 и выше — CRITICAL.
Стоит честно отметить ограничение метода. 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-проверки и то, что балл отражает лишь факт открытости порта, а не реальную уязвимость сервиса за ним. Используйте его как отправную точку: прогнали аудит на своём сервере, увидели лишнее наружу — закрыли фаерволом и перепроверили. И, повторюсь, только на своей инфраструктуре.
Комментарии и обсуждение — на интерактивной версии статьи.
Перейти к обсуждению →