Evitando Spoofing no Asterisk® SCF™

O uso malicioso do CALLERID(name)<number> pode ser uma forma de spoofing, onde o atacante tenta enganar o sistema ou usuários ao passar um número falso — como delphini<1234>. Isso pode ser usado para:
  • Burlar regras de acesso;
  • Fazer chamadas fraudulentas;
  • Injetar comandos em logs, bancos de dados ou URAs, se não houver tratamento adequado.

Como evitar ataques via CALLERID(number) no Asterisk

1. Sanitizar o CALLERID no dialplan

Você pode limpar o número, mantendo apenas dígitos:

exten => _X.,1,Set(CALLERID(num)=${FILTER(0-9,${CALLERID(num)})})

Ou, para armazenar em variável segura:

exten => _X.,1,Set(SAFE_CALLERID=${FILTER(0-9,${CALLERID(num)})})


Assim, qualquer caractere estranho (letras, símbolos, espaços, etc) será removido.


2. Verificar padrões válidos antes de usar

exten => _X.,n,GotoIf($["${CALLERID(num)}" :!^ [0-9]+$] ?hangup,s,1)

Isso envia para um contexto de hangup se o número tiver algo além de dígitos.

3. Bloquear chamadas com CALLERID suspeito

Você pode negar chamadas que tenham nomes/números suspeitos:

exten => _X.,1,ExecIf($["${CALLERID(name)}" = "delphini"]?Hangup())

exten => _X.,n,ExecIf($["${CALLERID(num)}" = "1234"]?Hangup())

Ou usar expressões mais robustas com ${REGEX(...)}.

4. Forçar um novo CALLERID confiável

Se você sabe que as chamadas vêm de uma operadora confiável, pode substituir o CallerID:

exten => _X.,1,Set(CALLERID(num)=0123456789)

exten => _X.,n,Set(CALLERID(name)=EmpresaX)

5. No sip.conf ou pjsip.conf: Controlar permissões
SIP (chan_sip):
[ataque]
callerid=unknown
trustrpid=no
sendrpid=no


PJSIP (chan_pjsip):
[ataque]
trust_id_inbound=no
send_pai=no
send_rpid=no

Esses parâmetros evitam que o Asterisk confie no CALLERID vindo do peer.

6. Logs e proteção contra injeções

Nunca jogue o CALLERID(num) diretamente em banco de dados, logs ou AGI sem limpar. Exemplo:

exten => _X.,n,Set(SAFE_CID=${FILTER(0-9,${CALLERID(num)})})

7. iptables / fail2ban para SIP

Monitore tentativas suspeitas com fail2ban (regex em /var/log/asterisk/messages).

Pode criar regras para bloquear IPs que tentam registrar ou enviar chamadas com CALLERID inválido.

Segue um Validador de Chamadas Suspeitas por CallerID (Python)
  • Bloquear IPs no IPTABLES (associados ao CallerID suspeito).
  • Gravar os eventos em um banco de dados MariaDB.

Pré-requisitos

  • Python:

    • pyodbc (ou mysql-connector-python)

    • Acesso sudo (para executar iptables)

  • Banco de dados MariaDB com tabela:

CREATE TABLE chamadas_suspeitas (
    id INT AUTO_INCREMENT PRIMARY KEY,
    callerid VARCHAR(50),
    ip VARCHAR(50),
    datahora DATETIME,
    motivo VARCHAR(255)
);

Código Python

import re
import logging
import subprocess
import mysql.connector
from datetime import datetime

# Configurações
DB_CONFIG = {
    'host': 'localhost',
    'user': 'usuario',
    'password': 'senha',
    'database': 'seu_banco'
}

PATTERNS_SUSPEITOS = [
    r'^00\d{6,}', r'^1\d{2,}$', r'^\d{10,}$', r'^[*#]\d+',
    r'^(.)\1{5,}$', r'^(1234|1111|0000)$', r'^anonymous$', r'^restricted$', r'^$',
]

def eh_callerid_suspeito(callerid):
    callerid = callerid.strip().lower()
    for padrao in PATTERNS_SUSPEITOS:
        if re.match(padrao, callerid):
            return padrao
    return None

def bloquear_ip(ip):
    try:
        subprocess.run(['sudo', 'iptables', '-A', 'INPUT', '-s', ip, '-j', 'DROP'], check=True)
        logging.warning(f"IP bloqueado via iptables: {ip}")
    except subprocess.CalledProcessError as e:
        logging.error(f"Erro ao bloquear IP: {ip} - {e}")

def registrar_no_banco(callerid, ip, motivo):
    try:
        conn = mysql.connector.connect(**DB_CONFIG)
        cursor = conn.cursor()
        query = """
            INSERT INTO chamadas_suspeitas (callerid, ip, datahora, motivo)
            VALUES (%s, %s, %s, %s)
        """
        valores = (callerid, ip, datetime.now(), motivo)
        cursor.execute(query, valores)
        conn.commit()
        cursor.close()
        conn.close()
        logging.info(f"Registro salvo no banco: {callerid}, {ip}, motivo: {motivo}")
    except Exception as e:
        logging.error(f"Erro ao salvar no banco: {e}")

def processar_chamada(callerid, ip):
    motivo = eh_callerid_suspeito(callerid)
    if motivo:
        bloquear_ip(ip)
        registrar_no_banco(callerid, ip, motivo)

# Exemplo de chamadas
chamadas = [
    {"callerid": "anonymous", "ip": "192.168.1.100"},
    {"callerid": "5511999999999", "ip": "192.168.1.101"},
    {"callerid": "999999", "ip": "192.168.1.102"},
    {"callerid": "normaluser", "ip": "192.168.1.103"}
]

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    for chamada in chamadas:
        processar_chamada(chamada["callerid"], chamada["ip"])

Dicas finais:

  • ⚙️ Para o sudo funcionar sem senha com iptables, edite /etc/sudoers com:

youruser ALL=NOPASSWD: /sbin/iptables.




Nenhum comentário

Toda vez que um homem supera os reveses, torna-se mentalmente e espiritualmente mais forte!

Tecnologia do Blogger.