Ultima modifica:
Ho scritto questa "guida" per comprendere in maniera basilare il funzionamento dei socket, argomento fondamentale non solo per programmare applicazioni di rete ma anche per capire le reverse shell e le backdoor.
Per scriverla ho preso spunto da diversi libri e materiale vario che studiavo alle superiori anni fa e che sto studiando anche ora, ho cercato di essere il più preciso possibile nella scrittura, se in certi passaggi avessi sbagliato qualcosa accetto consigli per migliorare la qualità della discussione per il bene di tutti i frequentatori del forum.
Per scriverla ho preso spunto da diversi libri e materiale vario che studiavo alle superiori anni fa e che sto studiando anche ora, ho cercato di essere il più preciso possibile nella scrittura, se in certi passaggi avessi sbagliato qualcosa accetto consigli per migliorare la qualità della discussione per il bene di tutti i frequentatori del forum.
1 Introduzione
Il nucleo di un'applicazione di rete consiste in due programmi: un programma cliente uno server.
Queste sono dette applicazioni client/server cioè un tipo di applicazione distribuita divisa in due parti:
un'applicazione server che offre servizi a un'applicazione client.
Questi due programmi quando sono in esecuzione creano un processo client e un processo server che dovranno comunicare tra loro attraverso la rete tramite le rispettive socket,i rispettivi indirizzi IP e un determinato protocollo di trasporto (solitamente TCP o UDP).
Un socket detto semplicemente è la porta tra il processo dell'applicazione e il protocollo di rete che si trovano sia sui server che sui client, i quali sono identificati in rete tramite il rispettivo indirizzo IP.
I socket rappresentano un punto di connessione di una rete TCP/IP; sono un punto a cui collegarsi per comunicare con altre applicazioni sulla rete.
Per fare un esempio pratico il processo è come se fosse una casa e il socket del processo è la porta d'ingresso.
- TCP socket detti Stream socket
- UDP socket detti Datagram socket
- Raw Socket utilizzati per lo sviluppo di particolari protocolli.
La scelta del tipo di socket dipende dall'applicazione che si intende realizzare, se abbiamo bisogno di un servizio affidabile oppure di un servizio che punta sulla velocità di trasmissione a discapito dell'affidabilità.
Quindi un socket identifica un computer e un processo in esecuzione su quel determinato computer ed è formato da hostname (o indirizzo IP che indentifica l'host in rete) e da un numero di porta TCP (che identifica un processeo all'interno della macchina).
2 Comunicazione client / server
La comunicazione in rete tra un server e un client avviene secondo questi passaggi:
- Server
1.Crea il socket
socket()
e gli assegna un local address bind()
;2.Setta il socket all'ascolto e rimane in attesa di una richiesta
listen()
;3.Accetta una nuova connessione
accept()
, invia e riceve i dati read() write()
;4.Chiude la connessione
close()
.- Client
1.Crea il socket
socket()
e si connette al server connect()
;2.Invia e riceve i dati
write() read()
;3.Chiude la connessione
close()
;Il client ha il compito di iniziare il contatto con il server e poichè il server possa rispondere, deve essere pronto.
Quindi sul server deve essere attivo e in ascolto un processo con il relativo socket altrimenti sarà impossibile per il client instaurare la connessione, riprendendo l'esempio iniziale della casa e della porta potremmo riferirci al contatto iniziale del client come al bussare alla porta.
Dopo la creazione di un oggetto Quindi sul server deve essere attivo e in ascolto un processo con il relativo socket altrimenti sarà impossibile per il client instaurare la connessione, riprendendo l'esempio iniziale della casa e della porta potremmo riferirci al contatto iniziale del client come al bussare alla porta.
socket()
, il client inizia un handshake a tre vie e stabilisce una connessione TCP con il server.Essendo la connessione TCP va da se che questa sia instaurata con un three way handshake (completamente trasparente ai programmi client e server).
Una volta instaurata la connessione verranno scambiati i dati tramite le funzioni
read()
e write()
finchè questa non verrà chiusa close()
.3 Programmazione java dei socket con protocollo TCP
I socket possono essere implementati tramite vari linguaggi di programmazione (c++,python,java ecc...).
Preferisco spiegare il funzionamento in Java perché si hanno a disposizione classi già predefinite che permettono la realizzazione dei socket sia della macchina client che della macchina server in maniera più semplice.
Per spiegare le istruzioni riporto l'esempio di una semplice applicazione client che invia una stringa al server, il quale risponde inviando la stessa stringa ma modificata con i caratteri maiuscoli.
Per creare un'applicazione client/server che usa TCP si usano le classi Socket e ServerSocket del package java.net.
Seguendo i passaggi descritti sopra, per creare l'applicazione server bisogna:
- Creare una istanza della classe
ServerSocket()
indicando la porta su cui il server è in ascoltoServerSocket server = new ServerSocket(int numero_porta)
; - Usare il metodo
accept()
per bloccare il programma in attesa di una richiesta di connessione, quando un client si connette il metodo restituisce il socket usato per la connessione dal lato del server:Socket connectionSocket = welcomeSocket.accept()
; - Usare i metodi
getInputStream()
egetOutputStream()
della classe Socket per ottenere dal socket un InputStream per ricevere dati e un OutputStream per inviare dati:connectionSocket.getInputStream()
econnectionSocket.getOutputStream()
; - Usare i metodi degli stream per gestire la comunicazione:
outToClient.writeBytes(capitalizedSentence)
; - Chiudere il socket al termine dopo avere chiuso gli stream;
Mentre per l'applicazione client, assumendo il processo server in esecuzione, il processo client può iniziare la connessione TCP verso il server.
Per fare ciò bisogna:
Per fare ciò bisogna:
- Creare un socket indicando l'indirizzo del server (hostname o IP) del server e la porta su cui il server è in ascolto:
Socket clientSocket = new Socket(String hostname, int porta)
; - Usare i metodi
getInputStream()
egetOutputStream()
della classe Socket per ottenere dal socket un InputStream per ricevere dati e un OutputStream per inviare dati; - Usare i metodi degli stream per gestire la comunicazione:
outToServer.writeBytes(sentence + '\n');
modifiedSentence = inFromServer.readLine();
; - Chiudere il socket al termine:
clientSocket.close();
;
4 Codici java degli applicativi Server e Client
Codice server:
Java:
//dichiaro i package java per usare i metodi delle classi Socket e String
import java.io.*; // metodi e classi per le stringhe
import java.net.*; // metodi e classi per il socket
class TCPServer{
public static void main(String argv[]) throws Exception //programma main
{
String clientSentence; //dichiaro la variabile clientSentence di tipo String
String capitalizedSentence; //dichiaro la variabile capitalizedSentence di tipo String
//creo l'oggetto welcomeSocket di tipo ServerSocket con numero di porta 6789
ServerSocket welcomeSocket = new ServerSocket(6789);
while(true){
//creo un nuovo Socket in ascolto e accetto la connessione quando si connette un client
Socket connectionSocket = welcomeSocket.accept();
//variabile inFromClient per leggere la stringa inviata dal client
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
//variabile outToClient per inviare la stringa trasformata in maiuscolo al client
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
//leggo lo stream in arrivo dal client e lo metto nella variabile clientSentence
clientSentence = inFromClient.readLine();
/*Trasformo i caratteri della stringa in maiuscolo con la funzione toUpperCase()
e metto il risultato nella variabile capitalizedSentence*/
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence); //invio la stringa elaborata al client
}
}
}
Di seguito l'esempio di codice in Java per la parte client:
Java:
import java.io.*;
import java.net.*;
class TCPClient{
public static void main(String argv[]) throws Exception
{
String sentence; //dichiaro la variabile sentence di tipo String
String modifiedSentece; //dichiaro la variabile modifiedSentence di tipo String
//variabile inFromUser per leggere lo stream dalla tastiera
BufferedReader inFromuser = new BufferedReader(new InputStreamReader(System.in));
//creo il socket con i parametri hostname e porta per identificare il server e fare la connessione
// n.b. il port number è uguale a quello del codice server
Socket clientSocket = new Socket("hostname", 6789); //sostituire hostname con l'ip o il nome del server a cui connettersi
//variabile per inviare la stringa acquisita da tastiera AL server
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
//variabile per ricevere la stringa convertita in maiuscolo DAL server
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
sentence = inFromUser.readLine(); //leggo l'input della tastiera e lo metto nella variabile sentence
outToServer.writeBytes(sentence + '\n'); //invio la stringa ricevuta in input dalla tastiera al server
modifiedSentence = inFromServer.readLine();//leggo il risultato che arriva dal server e lo metto in modifiedSentece
system.out.println("FROM SERVER : " + modifiedSentence);//stampo a video il risultato
clientSocket.close();//chiudo la connessione
}
}
Per ora mi fermo qui, se trovate il materiale interessante potrei procedere per scrivere una seconda parte descrivendo la comunicazione con il protocollo UDP.
Se qualcuno ha da aggiungere un contributo o correggere degli errori ben venga.
Spero abbiate gradito quanto ho scritto finora.