Block Words
Hay muchos métodos para realizar bloqueos (de sitios webs, archivos, etc). Hoy nos enfocaremos en uno muy particular; el bloqueo por palabras.
Las reglas son sencillas. Por ejemplo, si usamos el proxy Squid-Cache (recomendado) edite su archivo
squid.conf
y agregue: acl bwords url_regex -i "/path_to/blockwords.txt" http_access deny bwordsY si lo va a hacer con el firewall Iptables (no recomendado porque ralentiza el tráfico) edite su script de iptables y agregue:
bwords=/path_to/blockwords.txt for string in `cat $bwords`; do iptables -I FORWARD -m string --string "|$string|" --algo bm -j DROP done
En ambos casos utilizaremos una ACL, la cual, a modo de ejemplo, llamaremos
blockwords.txt
, en la ubicación de su preferencia y dentro pondremos las palabras que queramos bloquear:
Nota: Para Squid no son "palabras" sino "expresiones regulares"
announce announce_peer announce.php?passkey= BitTorrent bittorrent-announce find_node get_peers info_hash MIICdzCCAV netcut owari peer_id= psiphon_ssh .torrent torrent Torrent tracker tuxcut
En este archivo pusimos palabras relacionadas con proxies, trackers, etc., pero el sysadmin puede poner lo que se le ocurra, siempre y cuando vaya sin espacios. Por ejemplo, incluimos la palabra
telemetry
y en los registros saldrá lo siguiente: Toda regla tiene su lado malo y ésta no es la excepción. Por ejemplo, si bloqueamos la palabra
downloads
, sucederá lo mismo que con telemetry
, y si queremos autorizar wetransfer
, este domínio quedará bloqueado, ya que la palabra downloads
se encuentra dentro de la URL: https://wetransfer.com/downloads/path_archivo
Y de nada sirve que pongamos el dominio
.wetransfer.com
en una lista de permitidos antes de esta regla, ya que este tipo de filtrado bloquea la palabra en cualquier parte de la URL. Como podemos ver, este método puede generar una alta incidencia de falsos positivos, pero si revisamos el tráfico periódicamente, podemos ir "ajustando" la salida para evitarlos. A continuación algunas medidas:
- Delimitar la palabra a bloquear. Por ejemplo
downloads.
la cual le hemos agregado un punto al final ( .
) con el cual delimitaremos el bloqueo a dominios o subdominios que la contengan (aplicable a cualquier otra cosa) - Excluir la palabra
/downloads/
(con uno o los dos slash) en una lista de permitidos ( allow
) y que se ubicará antes que la regla de bloqueo: acl allowwords url_regex -i "/path_to/allowwords.txt" http_access allow allowwords acl denywords url_regex -i "/path_to/blockwords.txt" http_access deny denywords
- Poner un horario de la restricción; así los usuarios sabrán cuando pueden acceder al enlace:
acl workdays time MTWHF 08:00-18:00 acl denywords url_regex -i "/path_to/blockwords.txt" http_access deny workdays denywords
- Reducir la lista de palabras y usar como apoyo un filtrado basado en listas de permitidos y denegados
acl allowlist dstdomain -i "/path_to/allowlist.txt" acl denylist dstdomain -i "/path_to/denylist.txt" http_access deny denylist !allowlist acl denywords url_regex -i "/path_to/blockwords.txt" http_access deny denywords
Filtrado del Log
Supongamos que queremos ver nuestra regla en acción y auditar a un usuario (o a toda la red local) para buscar las palabras bloqueadas de nuestra lista y comprobar la fecha y hora del acceso. Para esto, solo debemos revisar el log. Squid tiene una directiva llamada logformat que supuestamente facilita este trabajo, pero no la recomendamos ya que no es compatible con algunas versiones y desde hace algún tiempo muchos usuarios han reportado conflictos con la herramienta generadora de informes de análisis Sarg y buscar directamente en el log de Squid puede algo ser confuso:
Formato de Squid |
perl -p -e 's/^([0-9]*)/"[".localtime($1)."]"/e' /var/log/squid/access.log | grep "FILTRO" # o perl -pe 's/[\d\.]+/localtime($&)/e' /var/log/squid/access.log | grep "FILTRO"
Con el comando anterior veremos la fecha y hora del acceso y reemplazamos la palabra
FILTRO
por alguna de las palabras bloqueadas, por ejemplo video
y eventualmente tendríamos un resultado similar al siguiente:
Nota: Podemos usar
grep
para poner varios filtros. TCP_DENIED
indica bloqueo. Para mayor información sobre estos códigos del log de Squid, visite Squid Log Files
Deny "video" |
sudo apt-get install perl
):
#!/bin/bash l1=("Log Audit: Filtering IP and Words" "Auditoría de Log: Filtrado de IP y Palabras") l2=("Enter IP and press ENTER" "Introduzca la IP y presione ENTER") l3=("Enter the word and press ENTER" "Introduzca la palabra y presione ENTER") l4=("There are no records of:" "No hay registros de:") l5=("e.g." "ej.") l6=("Done" "Terminado") test "${LANG:0:2}" == "en" en=$? clear echo "${l1[${en}]}" read -p "${l2[${en}]} (${l5[${en}]} 192.168.0.10): " IP read -p "${l3[${en}]} (${l5[${en}]} google): " WORD IPNEW=`echo $IP | egrep '^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'` if [ "$IPNEW" ]; then perl -pe 's/[\d\.]+/localtime($&)/e' /var/log/squid/access.log | grep "$IPNEW" | grep -i --color -E "$WORD" else perl -pe 's/[\d\.]+/localtime($&)/e' /var/log/squid/access.log | grep -i --color -E "$WORD" fi if [ $? -gt 0 ]; then echo "${l4[${en}]}" $WORD else echo "${l6[${en}]}" fiEste script nos pedirá que introduzcamos la IP a auditar (se puede omitir con ENTER) y la palabra bloqueada a auditar (o cualquier otra cosa cosa que quiera buscar) y mostrará en pantalla los registros de todas las URL que ha visitado esta IP (o toda la red si omitió la IP) en la fecha actual, que contengan dicha palabra (si existe). De esta manera sabrá si alguna URL se le escapó del bloqueo o si hay algún falso positivo. Puede mandar la salida a un archivo:
sudo ./filter.sh > archivo.txt
Otra manera de validar si el bloqueo de palabras (de expresiones regulares) está funcionando es con el log
cache.log
. Abrimos el terminal y corremos el siguiente comando: sudo grep -i "clientAccessCheckDone" /var/log/squid/cache.log
Y obtendremos todos los registros donde han interactuado nuestras ACL. Si queremos ser más específicos en la búsqueda agregaremos un filtro con
La salida nos indicará, por ejemplo que el sitio
grep
:
sudo grep -i "clientAccessCheckDone" /var/log/squid/cache.log | grep -i "FILTRO"
En este caso reemplazamos
FILTRO
por update
y obtendremos una salida similar a la siguiente: denyword "update" |
windowsupdate.com
(y otros similares que incluyen la palabra update
) está bloqueado ( DENIED
) por la ACL denywords
También podemos obtener una salida con fecha y hora del acceso con el siguiente script:
#!/bin/bash l1=("Log Audit: Regular Expressions Check" "Auditoría de Log: Chequeo de Expresiones Regulares") l3=("Enter the word and press ENTER" "Introduzca la palabra y presione ENTER") l4=("There are no records of:" "No hay registros de:") l5=("e.g." "ej.") l6=("Done" "Terminado") test "${LANG:0:2}" == "en" en=$? clear echo "${l1[${en}]}" read -p "${l3[${en}]} (${l5[${en}]} video): " WORD perl -pe 's/[\d\.]+/localtime($&)/e' /var/log/squid/cache.log | grep -i "clientAccessCheckDone" | grep -i --color -E "$WORD" if [ $? -gt 0 ]; then echo "${l4[${en}]}" $WORD else echo "${l6[${en}]}" fi
Nota: Para que esto funcione debemos tener activada la directiva
debug_log
con la sección 33 del nivel 2 y 28 del nivel 9
debug_options ALL,1 33,2 28,9
Visualización y Validación del Tráfico (dominios)
Como mencionamos anteriormente, una de las maneras de reducir los falsos positivos del bloqueo de palabras es reduciendo la lista y usando como apoyo un filtrado basado en listas de permitidos (allow list) y denegados (deny ist), ya que es más específico y está orientado exclusivamente a dominios.
Podemos crear estas listas depurando el tráfico del log de Squid, pero nos ahorraría mucho tiempo si ya las tuviéramos, al menos con algunos dominios en formato Squid (.domain.tld) y dentro del mismo directorio de trabajo. La idea es que la salida resultante de la depuración solamente muestre los dominios que no están en ambas listas y de paso que tengan un TLD válido. Para efectos de este ejemplo usaremos las listas de permitidos y denegados de nuestro proyecto Blackweb.
Validación TLD
Primero es necesario validar si lo que está en el log de Squid es un archivo descargado, un script, un certificado de seguridad o cualquier otra cosa que no sea un dominio (podemos encontrar muchas cosas raras en el log de Squid).
También hay que tener presente que algunas extensiones de dominio, son a la vez extensiones de archivo, como es el caso de
.cab
(extensión de archivos
cabinet), que también es un
Generic top-level domains (gTLDs)
, y
.zip
(extensión para formato de compresión zip), que es otro
gTLDs, y muchos más y estos resultados aparecerán en nuestro archivo de salida.
Esto se puede subsanar con el siguiente comando (agregue las extensiones a eliminar):
grep -Pvi "(\.cab|\.zip)$" entrada.txt | sort -u > salida.txt
Pero con este comando puede que acabemos eliminando un dominio real en lugar de un archivo con estas extensiones. Entonces, para realizar una correcta validación TLD de la salida hay dos caminos:
1. Lanzar un proceso (en paralelo) de consultas DNS sobre la lista de salida y así excluir aquellas líneas (URLs) que no sean un dominio o subdominio válido.
Afortunadamente con el siguiente script podemos hacer ambas cosas a la vez y así reducimos la carga y tiempo de procesamiento, que automatiza todo el proceso de depuración del log (descarga listas TLD, gTLDs, etc., las compara con la salida, depura el log de Squid y excluye el contenido de nuestras listas de la salida y realiza la consulta DNS para verificar si son o no válidos estos dominios). Pero antes de correrlo asegúrese de que sus listas no contengan duplicados (directorio
LISTAS
): grep -T -r . LISTAS | sort -k 2 | uniq -D -f 1
Y luego corra el script:
Nota: Reemplace su lista en la variable
acls
y ajuste el número de los procesos en paralelo en la variable pp
según los recursos de su hardware (a mayor número mayor consumo)
#!/bin/bash l1=("Squid Log Debugging" "Depuración del Log de Squid") l2=("Obtaining TLD, gTLDs, etc..." "Obteniendo TLD, gTLDs, etc...") l3=("Debugging access.log..." "Depurando access.log...") l4=("DNS lockup..." "Búsqueda DNS...") l5=("Done" "Terminado") test "${LANG:0:2}" == "en" en=$? clear echo "${l1[${en}]}" echo "${l2[${en}]}" function publicsuffix() { wget --no-check-certificate --timeout=10 --tries=1 --method=HEAD "$1" &>/dev/null if [ $? -eq 0 ]; then curl -s "$1" >> tmptld.txt else echo ERROR "$1" fi } publicsuffix 'https://raw.githubusercontent.com/publicsuffix/list/master/public_suffix_list.dat' publicsuffix 'https://data.iana.org/TLD/tlds-alpha-by-domain.txt' publicsuffix 'https://www.whoisxmlapi.com/support/supported_gtlds.php' publicsuffix 'https://raw.githubusercontent.com/maravento/blackweb/master/bwupdate/lst/sourcetlds.txt' grep -v "//" tmptld.txt | sed '/^$/d; /#/d' | grep -v -P "[^a-z0-9_.-]" | sed 's/^\.//' | awk '{print "."$1}' | sort -u > tld.txt echo OK echo "${l3[${en}]}" # example allow list (replace with yours) / lista de permitidos de ejemplo (reemplacela por la suya) wget -c -q https://raw.githubusercontent.com/maravento/blackweb/master/bwupdate/lst/allowurls.txt # example deny list (replace with yours) / lista de denegados de ejemplo (reemplacela por la suya) wget -c -q https://raw.githubusercontent.com/maravento/blackweb/master/bwupdate/lst/blockurls.txt # joining lists / uniendo listas sed '/^$/d; /#/d' {allowurls,blockurls}.txt | sort -u > urls.txt acls="urls.txt" # Steps / Pasos # Extract the domains from access.log / Extraer los dominios de access.log # Compare them with the allowed list / Compararlos con la lista de permitidos # Remove from the output www, protocols and others / Eliminar de la salida www, los protocolos y demás # Remove from the output urls that do not have a valid TLD / Eliminar de la salida las urls que no tengan un TLD válido grep -oP '[a-z]\w+?\.(\w+\.?){1,}' /var/log/squid/access.log | sed -r 's:(^\.*?(www|ftp|ftps|ftpes|sftp|pop|pop3|smtp|imap|http|https)[^.]*?\.|^\.\.?)::gi' | sed -r '/^.\W+/d' | awk '{print "."$1}' | sort -u > clean1.txt grep -x -f <(sed 's/\./\\./g;s/^/.*/' tld.txt) <(grep -v -F -x -f tld.txt clean1.txt) | sort -u > clean2.txt grep -x -f <(sed 's/\./\\./g;s/^/.*/' $acls) <(grep -v -F -x -f $acls clean2.txt) | sort -u > clean3.txt echo OK echo "${l4[${en}]}" # parallel processes (adjust according to your resources) / procesos en paralelo (ajuste según sus recursos) pp="400" sed 's/^\.//g' clean3.txt > clean4.txt if [ -s dnslookup.txt ] ; then awk 'FNR==NR {seen[$2]=1;next} seen[$1]!=1' dnslookup.txt clean4.txt else cat clean4.txt fi | xargs -I {} -P $pp sh -c "if host {} >/dev/null; then echo HIT {}; else echo FAULT {}; fi" >> dnslookup.txt sed '/^FAULT/d' dnslookup.txt | awk '{print $2}' | awk '{print "."$1}' | sort -u > out.txt echo "${l5[${en}]}"
Y finalmente consulte el archivo de salida
out.txt
y obtendrá una depuración de los dominios válidos pertenecientes al tráfico de su red local, que estén en el log de Squid, excluyendo los dominios de su lista de permitidos y denegados.
Post a Comment