Newsgroup: it.comp.os.linux.sys
Titolo: DoS in uscita

 1024 ? In teoria nessuno, ma vorrei aver conferma
2) come faccio a sapere da dove parte l'attacco? Il massimo sarebbe
identificare lo script ma non saprei come fare.
 
Sono certo che il problema nasca dentro la mia macchina perchè quando
si verifica l'attacco, il traffico in ingresso è immutato, mentre
quello in uscita arriva a 100mbit (limite dello switch). Se fosse un
DoS proveniente dall'esterno, noterei un mutamento del traffico in
ingresso.
 
Idee?

identificare lo script ma non saprei come fare.
 
Se un controllo dei processi in uso non da' risultato e non ci sono
funzioni di accounting che te lo possano dire, puoi *sperare* in un
find per vedere i file modificati di recente... l'ideale sarebbe un
uso di tripwire.
 
Intanto, se e' uno script fermare apache e farlo ripartire dovrebbe
bloccarlo per un po'. Se non e' agganciato a crontab od index di un
sito legittimo.
 
Anche in quel caso, dai log dovresti poter vedere cos'e' partito da
quando hai dato il re-start al ripristino dell'attacco, e questo ti
limita i posti dove cercare (occhio, contano anche gli include).
 
Su un livello un po' piu' serio, queste connessioni UDP, cosa sono?
Da li' puoi risalire allo strumento usato per crearle, per es. alla
funzione di libreria nel linguaggio X, poi cercare quella dentro ai
siti.
 
Leonardo
 
-- 
Tell us whether you spy, in the light of the morn,
what saluted was fiercely at the fall of the past day:
whose pips and whose bands in the very heart of the fray
bravely floated from the bulwarks to which we were sworn?

 identificare lo script ma non saprei come fare.
 
netstat -naup ti dovrebbe dire i processi che stanno usando UDP.
 
 
-- 
http://blog.mainardi.me
 
http://about.me/lormayna
 
python -c "print 'bG9ybWF5bmFAZ21haWwuY29t'.decode('base64')"

 siti.
 
Sono schifezze varie, penso sia un "normale" flood fatto con fsockopen
di php
 
 
udp      17 28 src=xx.xx.xx.xx dst=173.193.252.52 sport=34729
dport=966 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=966 dport=34729 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 26 src=xx.xx.xx.xx dst=173.193.252.52 sport=60860
dport=653 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=653 dport=60860 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 26 src=xx.xx.xx.xx dst=173.193.252.52 sport=48589
dport=582 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=582 dport=48589 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 25 src=xx.xx.xx.xx dst=173.193.252.52 sport=43277
dport=591 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=591 dport=43277 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 24 src=xx.xx.xx.xx dst=173.193.252.52 sport=43906
dport=194 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=194 dport=43906 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 21 src=xx.xx.xx.xx dst=173.193.252.52 sport=49765
dport=451 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=451 dport=49765 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 28 src=xx.xx.xx.xx dst=173.193.252.52 sport=38922
dport=375 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=375 dport=38922 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 28 src=xx.xx.xx.xx dst=173.193.252.52 sport=39863
dport=410 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=410 dport=39863 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 27 src=xx.xx.xx.xx dst=173.193.252.52 sport=48584
dport=151 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=151 dport=48584 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 22 src=xx.xx.xx.xx dst=173.193.252.52 sport=43326
dport=435 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=435 dport=43326 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 22 src=xx.xx.xx.xx dst=173.193.252.52 sport=48827
dport=562 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=562 dport=48827 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 26 src=xx.xx.xx.xx dst=173.193.252.52 sport=41785
dport=207 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=207 dport=41785 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 24 src=xx.xx.xx.xx dst=173.193.252.52 sport=54186
dport=993 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=993 dport=54186 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 22 src=xx.xx.xx.xx dst=173.193.252.52 sport=60228
dport=882 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=882 dport=60228 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 27 src=xx.xx.xx.xx dst=173.193.252.52 sport=33246
dport=130 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=130 dport=33246 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 26 src=xx.xx.xx.xx dst=173.193.252.52 sport=52557
dport=829 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=829 dport=52557 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 24 src=xx.xx.xx.xx dst=173.193.252.52 sport=39878
dport=684 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=684 dport=39878 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 22 src=xx.xx.xx.xx dst=173.193.252.52 sport=46754
dport=614 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=614 dport=46754 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 16 src=xx.xx.xx.xx dst=173.193.252.52 sport=33304
dport=1000 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=1000 dport=33304 packets=0 bytes=0 mark=0
secmark=0 use=1
udp      17 29 src=xx.xx.xx.xx dst=173.193.252.52 sport=45267
dport=612 packets=8 bytes=65759 [UNREPLIED] src=173.193.252.52
dst=xx.xx.xx.xx sport=612 dport=45267 packets=0 bytes=0 mark=0
secmark=0 use=1
 
 
 
la sport è sempre > 1024, quindi esclude l'esecuzione come root (il
che fa pensare proprio ad una esecuzione mediante sito PHP) la dport
invece è anche inferiore a 1024
 
Per ora in uscita blocco tutto l'udp non diretto alla mia rete avente
sport > 1024 e dport != 53.
ho aggiunto il flag --log-uid nella riga iptables, speriamo mi logghi
lo userid. Se si tratta di un
sito, lo userid è univoco per quel virtualhost.

 netstat -naup ti dovrebbe dire i processi che stanno usando UDP.
 
Non ci avevo pensato, adesso faccio salvare anche l'output di questo
comando

 sito, lo userid è univoco per quel virtualhost.
 
PRESO!
Un brasiliano, che richiamava una pagina php dentro un wordpress.
La pagina è un client di qualche server IRC, si logga, non ho ben
capito cosa fa e poi avvia un brutale flood UDP. Penso prenda l'ip dei
server da attaccare dopo essersi loggato ad un servizio sulla porta 20/
tcp.

di php
 
Bon, allora ti basta cercare 'fsockopen'. E magari 'udp:'. Se il gioco
dell'UID non ti funziona.


 dell'UID non ti funziona.
 
Mica vero.
$host = 'udp://pippo';
fsockopen($host);
 
questo non lo troverai mai con un grep.
 
Peggio ancora se il file malevolo caricato è encodato (e non è raro)

 qualche sito) verso host esterni arbitrari.
 
raw table, questa sconosciuta...:)


iptables -t raw -I PREROUTING -s ip_sorgente_bastardo -j NOTRACK
 
Poi ragioni sul resto, ma almeno eviti di dissipare memoria e saturare la tabella di stato.

 Poi ragioni sul resto, ma almeno eviti di dissipare memoria e saturare la tabella di stato.
 
Non posso, l'ip sorgente è sempre il mio, il problema nasce dalla mia
macchina e non da una ruotata/nattata.

Peggio ancora se il file malevolo caricato è encodato (e non è raro)
 
Generalmente i file di questo tipo sono encodati in base64 o poco piu', e
ci sono sistemi per riconoscerli (analisi di frequenza dei whitespace, ad
esempio). In alternativa, il "decoder" è basato sempre sui soliti sistemi
- tipicamente "base64_decode(gzuncompress" è l'idea che il lamerino ha di
un codice efficiente e inviolabile da sistemi automatici.
 
Poi - se ci vogliamo mettere nel caso "Non ho tripwire. Non ho sistemi di
revision control. Non ho[1] accounting. Sistemi Rube Goldberg tipo grep e
find non funzionerebbero", una soluzione continua ad esistere... pero', a
quel punto, e' per forza "cambia (datore di) lavoro".
 
Leonardo
 
[1] "Non posso usarli perche' costano troppi soldi/tempo" equivalgono, in
    termini pratici, a "non ho".


 quel punto, e' per forza "cambia (datore di) lavoro".
 
grep e find funzionano a meraviglia, ma dipende quanti virtualhost hai e
quanti file. Nel mio caso, fare un grep su tutta la /home impiegherebbe
svariate ore. ci ho provato eh ... ma trovare tutti i file che
contengono fsockopen ed udp non va sempre bene. Nel mio caso specifico,
sarebbe stato impossibile trovare il file con un banale grep, l'elenco
degli host da attaccare veniva letto da un file esterno (a dire il vero
da un comando eseguito su un server esterno) pertanto non avevo alcuna
corrispondenza nel mio server. Lo script partiva, si collegava ad un
server esterno (tcp o udp in maniera variabile), scaricava l'elenco
degli host, li ciclava tutti ed li bombardava in modalità random.
 
Io non posso cercare fsockopen su tutti i file (ho milioni di
corrispondenze, sia wordpress che joomla ne fanno uso) e non ho alcuna
discriminante, visto che il protocollo usato era anche TCP, come per
il traffico legittimo di WP e Joomla.
 
-- 
Tu non puoi passare!
Sono un servitore del fuoco segreto e reggo la fiamma di Anor!
Il fuoco oscuro non ti servirà a nulla, fiamma di Udur!
Ritorna nell'ombra! TU NON PUOI PASSARE!

> 1024 ? In teoria nessuno, ma vorrei aver conferma
 
E' cosa buona e giusta, su un server web, bloccare indistintamente TUTTO 
quello che è in uscita, abilitando solo quello che è necessario abilitare.
 
Va gestita solo una whitelist per aggiornare i pacchetti  (via apt, ad 
esempio) e poca roba verso roba tipo facebook o twitter o in generale, 
servizi erogati tramite API con traporto HTTP.
 

 servizi erogati tramite API con traporto HTTP.
 
Non posso che quotare.


 macchina e non da una ruotata/nattata.
 
Non è un problema.
iptables -t raw -A OUTPUT -j NOTRACK
(specificando il protocollo udp e le porte alte, eventualmente, per non influenzare altro
tipo di traffico)

 tipo di traffico)
 
Uhm, grazie del consiglio, lo terrò a mente, a questo non avevo proprio
pensato.


il traffico legittimo di WP e Joomla.
 
Hum, il caso allora è più serio di come mi figuravo. Direi che come prima
cosa serva un sistema di logging/auditing "proattivo". Su quelle moli non
credo sia pensabile di usare neanche inotify.
 
Leonardo


 credo sia pensabile di usare neanche inotify.
 
Brrr non ci provo nemmeno, si ammazza il server, ne sono certo.


Brrr non ci provo nemmeno, si ammazza il server, ne sono certo.
 
Ora m'hai fatto venire voglia di fare la prova :-)


 servizi erogati tramite API con traporto HTTP.
 
Il massimo sarebbe poter filtrare, tramite iptables, tutti gli UID > $x.
Al momento il modulo owner che sto usando permette di filtrare un uid
per volta e non un dato range.
 
Sarebbe bello poter fare qualcosa tipo:
$ipt -A OUTPUT -m owner --uid-owner 0:999 -j ACCEPT
$ipt -A OUTPUT -j DROP
 
in modo da tagliar fuori automaticamente tutti gli utenti dei
virtualhost o eventuali utenti non di sistema, che sono,
nel 99.99% dei casi, la fonte di problemi.


 casi, la fonte di problemi.
 
Che io sappia non si può fare ma non ho mai approfondito molto.
Di base ho come policy di output TUTTO in drop tranne qualcosina di 
necessario:
 
- apt per root (quindi verso i repository)
- la 53 verso i MIEI dns per tutti gli utenti
- la 25 verso i MIEI server di posta dove faccio rate limiting
- la 3306 verso mysql
- la 123 verso il server NTP
 
e fondamentalmente, niente altro, se la memoria non mi inganna.
 
L'unica cosa è un redirect di tutte le connessioni in uscita dirette alla 
80/443 TCP verso un http proxy trasparente dove vado a filtrare (in un 
unico posto) cosa far uscire e cosa no.
 
Così, se qualcuno vuole comunicare con le API di facebook o google lo può 
fare senza preventiva autorizzazione.
Se altri vogliono invece andare a fare qualcosa di malevolo, lo loggo 
subito e lo blocco di default.
 
Max

 subito e lo blocco di default.
 
L'idea è buona, ma genererebbe un ulteriore SPOF. Se il proxy è in
comune tra più server, ti muore il proxy e ti ritrovi con tutti i
clienti di tutti i server alla porta. Meglio filtrare sul server stesso.


 clienti di tutti i server alla porta. Meglio filtrare sul server stesso.
 
Io ce l'ho ridondato (no doppi sensi).
 
L'idea di metterlo locale comunque non è sbagliata, se non fosse per la 
rottura di scatole di distribuire le "access list" del proxy.
 

 Io ce l'ho ridondato
 
Doh.
Ma li usi in bilanciamento o in failover?


 nel 99.99% dei casi, la fonte di problemi.
 
[!] --uid-owner userid[-userid]
              Matches if the packet socket's file structure (if it has one) is
              owned by the given user. You may also specify a  numerical  UID,
              or an UID range.
 
e, in effetti,
 
iptables -I OUTPUT -m owner --uid-owner 1000-2000  -j DROP
 
funziona perfettamente.
 
iptables versione 1.4.10

 Ma li usi in bilanciamento o in failover?
 
Puoi fare ambo le cose, volendo.
Con pacemaker/corosync/cman ho di recente realizzato un cluster active-active
di terminatori TLS/reverse-proxy (stunnel+haproxy) con ip condiviso...

 funziona perfettamente.
 
Ma pensa te.
Quando l'ho implementato ho perso 1 ora a capire quale sistema poter
usare per filtrare solo determinati UID in modo sicuro senza dover
fare un brutale elenco di regole.


 di terminatori TLS/reverse-proxy (stunnel+haproxy) con ip condiviso...
 
Era una battuta la mia, tant'è che ho rimosso il "no doppi sensi"


 Era una battuta la mia, tant'è che ho rimosso il "no doppi sensi"
 
ScIemo. :)