Header Ads

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 bwords
Y 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: 
Deny "telemetry"
Falsos Positivos
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
Entonces, para poder ver nuestras palabras bloqueadas en el log de Squid, en un formato amigable, ejecutamos con privilegios cualquiera de los siguientes comandos:
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"
Para facilitar las cosas, podemos correr el siguiente script con privilegios sudo (en inglés y español) (dependencia 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}]}"
fi
Este 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 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"
La salida nos indicará, por ejemplo que el sitio 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. 
2. Descargar las listas oficiales y alternativas de  TLDgTLDs, etc., y compararlas con la salida.
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.
Con la tecnología de Blogger.