Kosmous beyond the clouds: Sviluppo, Formazione e Consulenza Informatica

FireWall in java

Spesso e volentieri quando ci connettiamo da casa in Internet o con un modem analogico a 56K o con una linea ADSL non ci facciamo mai caso se siamo al sicuro o no, se proviamo ad aprire una shell unix (o shell dos a seconda se usate linux o windows da casa), tramite il comando netstat possiamo vedere quali servizi di rete sono in ascolto sulle nostre porte.

Il problema inizia a nascere quando qualche malintenzionato vuole iniziare a fare un operazione di portscanning sul nostro PC per vedere se qualche porta è rimasta aperta o se abbiamoinstallato a nostra insaputa una backdoor.

Il programma che vi sto per spiegare si mette in ascolto su una porta data come parametro al momento del lancio e chiude tutti i socket che si mettono in ascolto su quella porta.

Ho realizzato tale programma con java 1.1 in modo tale che avesse una compatibilità retroattiva con tutte(o quasi) le java virtual machine installate sui i PC di casa indifferentemente che si stia utilizzando Linux o Windows.

La struttura del programma è formata da due classi private e la classe pubblica che naturalmente contiene solo il metodo main; vediamo quindi la prima classe:

/*
MyFirewall v 0.1.1
Autore Marra Cristiano
Si mette in ascolto dei socket multi-threading
sulla porta data da parametro e rileva indirizzo IP
nome dell' host e da che porta si connette
*/

import java.io.*;
import java.net.*;
class SingoloSocket extends Thread {
private Socket canale;
private BufferedReader in;
private PrintWriter out;
private int porta;

Innanzitutto vediamo che ho incluso due librerie: la java.io e la java.net. La prima ci servirà per gestire lo streaming di input della richiesta di scanning e stampare in output i dati del malintenzionato che si vuole connettere alla macchina. Notiamo subito che la classe SingoloSocket fa uso dei Thread, essi vedremo in seguito che giocheranno un grosso ruolo per la gestione dei socket in entrata usando le tecniche di multi-threading. La classe SingoloSocket ha 4 membri privati la variabile porta che ` lla porta dalla quale parte il socket del malintenzionato, la variabile canale che è il socket che tenta di fare lo scanning, una variabile in la stringa che il malintenzionato scriverà per tentare qualche comando una volta che avrà lanciato il telnet su quella determinata porta che è una variabile out che immagazinerà tale stringa.




Passiamo al costruttore:

public SingoloSocket(Socket s) throws IOException {
canale = s;
in =
new BufferedReader(new InputStreamReader(canale.getInputStream()));
out =
new PrintWriter(new BufferedWriter(new OutputStreamWriter(canale.getOutputStream())), true);
start();
}

Il costruttore accetta come parametro il Socket che interrogherà il vostro PC e la passa alla variabile canale, inizializza le variabili in e out sui stream del socket rispettivamente in input e in output(noterete che tale inizializzazione di queste variabili viene fatta senza inserirle dentro l' eccezione IOException dato che viene lanciata dal costruttore stesso ed infine viene lanciato il metodo start() il quale imposta automaticamente i thread che dovranno gestire i socket, tale metodo è di proprietà della classe Thread che è stata precedentemente estesa alla classe SingoloSocket in cui ci troviamo.

Adesso passiamo al metodo run(), cioè l' altro metodo di proprietà della classe Thread che farà partire i thread e soprattutto è la parte pi importante dell' intero programma:

public void run() {
try {
while (true) {
String str = in.readLine();
porta = canale.
getPort();
InetAddress ia = canale.getInetAddress();
if (str.equals(null)) break;
System.out.println("La macchina: " + ia.getHostName() +
" con indirizzo IP " + ia.getHostAddress() +
" dalla porta " + porta + " si e` connessa!");
canale.
close();
out.
println(str);
}
System.out.println("chiudi... ");
}
catch (IOException e) {
}
finally {
try {
canale.
close();
}
catch(IOException e) {}
}
}
}

Il metodo principalmente è formato da una struttura try ... catch .... finally, nel corpo della try osserviamo un while che gira all'infito dato che il nostro firewall dovrà essere sempre all' erta da malintenzionati, nel ciclo la variabile str immagazina il tentativo di comando dell' intruso e la variabile porta immagazina la porta del socket dell'intruso e la variabile ia immagazzina le informazioni dell' host dell' intruso. Incontriamo un if che controlla se il comando viene effettuato dall' intruso dopodichè ci viene stampato a console il nome dell' host l' indirizzo IP e la porta della macchina dell' intruso, dopodichè facciamo cascare la connessione dell' intruso e chiudiamo la try tramite una finally che immagazzina a sua volta un' altra try...catch. Le ultime parentesi graffe chiudono rispettivamente il while, la try...catch...finally, il metodo run() e la classe SingoloSocket.

Ora vediamo la classe GestConn, la quale è formata da un solo metodo chiamato LanciaPolling che accetta come parametro la porta da difendere da eventuali attacchi anch' essa lancia un eccezione IOException:

class GestConn {
public void LanciaPolling(int portaServizio) throws IOException {
ServerSocket s = new ServerSocket(portaServizio);
try {
while(true) {
Socket canale = s.accept();
try {
new SingoloSocket(canale);
}
catch(IOException e) {
canale.
close();
}
}
}
finally {
s.
close();
}
}
}

All' inizio vediamo che viene inizializzata la variabile s essa è una variabile di tipo ServerSocket ciò ci servirà per intercettare la richiesta su quella porta, entro nella try...finally faccio partire il while infinito(sono costretto a renderlo inifinito per il semplice motivo che se ciò non fosse dopo il primo tentativo di connessione sul nostro PC, il nostro firewall si chiuderebbe e quindi addio sicurezza), inizio il socket che tenta la connessione al nostro PC ed entro nell try...catch che lancerà il thread creato prima con la classe SingoloSocket che gestirà il canale per chiudere la connessione all' intruso dopodichè è chiaro nel codice che segue vi sono tutte le chiusure delle procedure annidate nel metodo LanciaPolling e nella classe GestConn.

Arriviamo finalmente al main:

public class MyFirewall {
public static void main(String[] args) throws IOException {
GestConn gs =
new GestConn();
gs.LanciaPolling(
Integer.parseInt(args[0]));
}
}

Chiaramente creiamo la classe pubblica che darà il nome al programma e dopdichè entriamo nel main che anch' esso lancerà un' eccezione di tipo IOException, inizializziamo una variabile gs di tipo GestConn e lanciamo il metodo LanciaPolling con parametro il primo intero dato a linea di comando al lancio del programma; d' ora in avanti qualunque intruso che tenterà di pentrare quella porta non ce la farà

Facciamo una prova:

lanciamo il nostro programma e cerchiamo di difendere la porta 5000:

java MyFirewall 5000 &

dopodichè da un PC che tenterà l' attacco digitiamo:

telnet NomeHostRemoto 5000

oppure:

telnet xxx.xxx.xxx.xxx 5000

dove naturalmente xxx.xxx.xxx.xxx è un indirizzo IP.

Ora sulla shell del computer attaccato apparirà la seguente scritta:

Trying...
Connected to 127.0.0.1.
Escape character is '^]'.

L'intruso pensando di essersi connesso tenterà un comando particolare, quindi una volta che avrà digitato una qualsiasi stringa e premuto invio ecco cosa apparirà a lui sulla shell:

Connection closed.

Dopodichè sarà disconnesso automaticamente da noi, mentre sulla nostra shell apparirà la seguente frase:

La macchina: HostIntruso con indirizzo IP xxx.xxx.xxx.xxx dalla porta 63621 si e` connessa!

Dove HostIntruso è il nome della macchina dell' intruso, xxx.xxx.xxx.xxx è il suo indirizzo IP e 63621 è la porta dalla quale l' intruso ha fatto partire il suo socket.

Nel caso noi volessimo difendere pi porte basterà creare un file .sh o .bat (sempre a seconda di che OS avete installato sul vostro PC) e scrivere le seguenti stringhe:

java MyFirewall 5000 &
java MyFirewall 5040 &
java MyFirewall 6002 &
java MyFirewall 7103 &
java MyFirewall 7109 &
.............
.............
.............

E lanciarlo.

Conclusione:

Come avete visto il programma che vi ho proposto è molto semplice e da ciò il mio obiettivo era appunto quello di far capire tramite utilizzo di librerie standard di java alcuni rudimenti di Thread nella programmazione di rete, e come è facilmente intuibile tale programma da ampie possibilità ad implemntazioni miglioramenti che possono portare il nostro firewall ad essere sempre più efficiente.

Articolo di: Cristiano Marra
Commenti (0)2003-11-18