Bloccare le richieste proxy verso apache (provenienti da botnet)

Questo articolo nasce da un esperienza personale, che ha causato diversi problemi al server su cui ospito i miei siti (e anche di altre persone). 

Quindi partiamo dall’inizio, e veniamo alle origini del problema, tutto nasce da una svista, nell’abilitare il mod_ajp sul server apache, abilitiamo per errore il parametro:

ProxyRequest On
DDOS

Dapprima non succede niente, ma qualche ora iniziano ad arrivare connessioni che ci sfruttano come proxy, e nel giro di 24 ore il nostro server è entrato di diritto in qualche botnet/rete di proxy o chissá cosa, fatto sta che oggi siamo arrivati ad avere centinaia di richieste al secondo, che in pratica saturavano il nostro server e impedivano la normale fruibilitá dei siti ospitati (tempi di risposta sull’ordine dei minuti si avevano).

E qui comincia la fase di indagine. Mettendoci in “tail -f” sul  file /var/log/apache2/error_log, riscontravamo un continuo flusso di errori del tipo:

[Sun Apr 06 15:49:21 2014] [error] [client 216.144.249.216] proxy: DNS lookup failure for: ads.yahoo.com 
returned by http://ads.yahoo.com/get-user-id?ver=2&s=5426229&ts=1396792101&sig=7409dd0b6294e8f2, 
referer: http://ads.yahoo.com/st?ad_type=iframe&ad_size=728x90&section=5426229&pub_url=${PUB_URL}

E nell’access.log invece compariva una corrispondente riga con la richiesta:

08.115.242.253 - - [07/Apr/2014:16:31:32 +0200] 
"GET http://ads.yahoo.com/st?ad_type=iframe&ad_size=728x90&section=3730175&pub_url=${PUB_URL} 
HTTP/1.0" 403 523 
"http://www.domarketings.com/index.php?option=com_content&view=article&id=2772:Gold-Trading:-The-Original-Heavy-Metal-Tops-the-Charts-Again&catid=161" 
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.216 Safari/534.10 ChromePlus/1.5.1.0alpha1"

(in questo esempio le richieste sono differenti, ma solo per comoditá)

Ovviamente la dimensione del log era gia arrivata intorno a 600mb per l’access.log e 200mb per l’error.log. Quindi il primo intervento é stato quello di disabilitare le funzionalitá proxy (e in particolare la ProxyRequest, che ripeto era stata accidentalmente abilitata).

Come ci si aspetta sono terminate le richieste di questo tipo, ma ahinoi sono state sostituite da altri messaggi di errore:

[Mon Apr 07 10:48:31 2014] [error] [client 69.162.102.181] File does not exist: /var/www/st, referer: http://www.bestonlinebizs.com/index.php?option=com_content&view=article&id=776:Bad-Credit-Secured-Personal-Loans:-Money-to-Mend-Credit-Turf&catid=29

Questo probabilmente causato dal fatto che la nostra macchina oramai era stata assorbita da qualche rete misteriosa :). E nell’access.log restavano quel tipo di richieste. Quindi il problema persisteva, perchè ora si non facevamo più da proxy, ma la nostra macchina da sola non era in grado di sopperire a tutte quelle richieste che continuavano ad arrivare.

A questo punto inizia la ricerca su internet. La prima soluzione che viene proposta è quella di abilitare un modulo di apache, chiamato mod_envise, che si occupa di bloccare temporaneamente le richieste che in un certo intervallo di tempo superano una certa soglia, impostabile.

Qui di seguito vi riporto brevemente come l’abbiamo configurata per debian, anche se ha prodotto scarsissimi risultati.

Prima di tutto è un modulo che va installato, il comando apt-get è il seguente:

apt-get install libapache2-mod-evasive

Dopo di che creiamo in /etc/apache2/mods_available un file chiamato mod_evasive.con e inseriamo le seguenti entry:

<IfModule mod_evasive20.c>
DOSHashTableSize    3097
DOSPageCount        2
DOSSiteCount        50
DOSPageInterval     1
DOSSiteInterval     1
DOSBlockingPeriod   60
DOSEmailNotify your@email.it
DOSLogDir /var/log/apache2/evasive
</IfModule>

Mentre il file mod_evasive.load, nella stessa cartella dovrebbe essere gia presente. A questo punto diamo il comando:

a2enmond mod_evasive

Dove:

  • DOSSiteCount indica le richieste oltre il quale un ip viene bloccato, e
  • DOSBlockingPeriod indica quanto deve durare questo blocco
  • DOSSiteCount Indica invece la soglia del numero di richieste sulla stessa pagina
  • DOSSiteInterval Indica invece la soglia di tempo per il DOSSiteCount
  • DOSPageInterval fa lo stesso per DosPageCount

A questo punto si può riavviare apache con:

service apache2 restart

 

Ma come dicevo questo non ha prodotto grandi risultati, infatti le richieste erano calate di un numero abbastanza irrisorio, e le performance non accennavano a migliorare.

Altri siti suggerivano di utilizzare mod_security, ma a quanto riportato anche sul sito di apache, questa soluzione aveva risultati minimi, quindi ho deciso di non perdere tempo nell’abilitare anche questo modulo.

Un altro accorgimento che è stato usato, è stato di dare un errore 403 a tutti i tentativi di accesso a qualsasi url che non era gestito dal nostro server, questo è stato fatto creando un virtual host generico, che gestiva tutti i casi non coperti dagli altri virtual host:

<VirtualHost *:80>
DocumentRoot "/var/www"
ServerName 195.154.235.160
<Directory "/var/www/">
deny from all
</Directory>
 
ErrorLog        /var/log/apache2/dummy.log
CustomLog       /var/log/apache2/dummy-access.log       combined
 
</VirtualHost>

In questo modo tutto il traffico non lecito o non corretto veniva rifiutato, e tutto inviato in un log specifico.

In alcune mailing list si suggeriva di aspettare che il fenomeno scemasse da solo, ma diceva anche che poteva durare ore/giorni/settimane, e non volevo aspettare così tanto. Ma ogni ip faceva diverse centinaia di richieste nell’arco di una giornata, e questo  era l’unico aspetto su cui intervenire, cercare di non far arrivare queste richieste all’apache. E qui entra in gioco l’idea di far intervenire il firewall. Perchè non usare lui per fargli bloccare le richieste? E quindi anche con l’aiuto di google, metto a punto uno script per far bloccare le richieste proxy di apache direttamente da iptables:

 

#!/bin/bash
tail -f /var/log/apache2/dummy-access.log | awk '
BEGIN { blocked_ips="" }
/ http/ {
  if (! index(blocked_ips, $1)) {
    blocked_ips = blocked_ips " " $1
 
    "date" | getline current_time
    close("date")
 
    print current_time " :: blocking " $1
    iptables_block = "iptables -I INPUT -s " $1 " -j DROP"
    system(iptables_block)
    close(iptables_block)
  }
}'

In pratica questo script a partire dal file dummy-access.log considera tutte le linee che contenevano una richiesta che iniziava per http (e quindi indicava che si trattava di un tentativo di usare il server come proxy. A questo punto visto che il primo elemento della riga di log è proprio l’ip, controlliamo se non si trova gia nella lista di ip bloccati, se non lo è lo aggiungiamo, e inoltre aggiungiamo una regola a iptables che ignora tutte le richieste provenienti da quell’ip. Il comando iptables in questo script è:

iptables -I INPUT -s ipaddressdabloccare -j DROP

Ora salvate questo script su un file, date il comando:

chmod +x scriptname

Dove scriptname è il nome che avete dato al file che contiene il vostro script, e lanciatelo con

./scriptname

E aspettate, vedrete che appena questo script inizierá a macinare ip molto velocemente, ma man mano che passano i minuti, sempre meno ip verranno aggiunti al firewall, e dopo una decina vedrete la situazione tornare pressochè alla normalitá, e i vostri tempi di risposta tornare umani. E soprattuto se ora controllerete i log, i tentativi di accesso come proxy saranno crollati drasticamente, se prima erano molte centinaia al secondo ora sono poche decine al minuto

Sono convinto che non si tratta di una delle soluzioni migliori, ma sicuramente in questa situazione è stata l’unica arma che ho trovato in grado di far tornare i miei siti utilizzabili.
Lo script non è tutto farina del mio sacco (ho modificato uno script esistente trovato qua: https://www.gosquared.com/blog/how-to-stop-a-botnet-attack che era specifico per ubuntu ufw)
Che dire spero che questo articolo vi aiuti se vi trovate in situazioni di emergenza come la mia!

Leave a Reply

Your email address will not be published. Required fields are marked *