class: center, middle # TCP SERVER IN PHP ## stream, protocolli e trojan didattici --- # TCP NON È A PACCHETTI -- - La connessione TCP è uno **stream di byte** -- - questo stream passa per una porta 0 - 65535. Le porte fino a 1023 sono privilegiate -- - (occorre essere admin per poterle bindare) -- - Non esistono "messaggi", tcp è un tubo che porta un flusso di dati -- - I messaggi li **decide il protocollo applicativo**, cioè chi scrive l'applicazione decide il protocollo da usare. -- - il server deve sapere **quando fermarsi a leggere** --- # DUE STRATEGIE CLASSICHE -- ## 1. Terminatore -- - newline `\n` -- - riga vuota `\r\n\r\n` -- - \n = LF = Line Feed = 10 (0x0A) : Scende di una riga -- - \r = CR = Carriage Return = 13 (0x0D) : Torna all'inizio della riga -- Storicamente: -- - Unix/Linux usa LF (\n) -- - Windows usa CRLF (\r\n) -- - Telnet pretende CRLF come fine linea --- ## 2. Lunghezza prefissata -- - prima leggi N byte di intestazione fissa -- - in questi N byte è presente la lunghezza del payload -- - sapendo la lunghezza viene letto il payload --- # STRATEGIA 1: TERMINATORE -- Usata da: -- - TELNET (viene trasmesso ogni tasto premuto ed il terminatore è il CRLF) -- - SMTP -- - richiesta HTTP (Browser o curl o wget) -- Vantaggi: -- - semplice -- - leggibile -- - perfetta per la didattica --- # ECHO SERVER TCP (TELNET) -- - Un comando = una riga -- - Terminatore = `\n` -- ```php $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($server, "0.0.0.0", 4444); socket_listen($server); while ($client = socket_accept($server)) { while (($line = socket_read($client, 1024, PHP_NORMAL_READ)) !== false) { $cmd = trim($line); if ($cmd === '') continue; socket_write($client, "Echo: $cmd\r\n"); } socket_close($client); } ``` --- # TEST CON TELNET -- - telnet -host- 4444 -- - hello -- - Echo: hello -- - Protocollo tutto in chiaro -- - perfetto per Wireshark --- # TCP STREAM: COSA PUÒ SUCCEDERE -- - un read = mezzo comando -- - una read = due comandi -- - non possiamo supporre che ogni volta che invochiamo il "socket_read" corrisponda a tutto un massaggio o un comando -- - occorre un loop -- - sappiamo pero' che l'ordine è preservato -- - Non ci sono confini prestabiliti -- - il protocollo è responsabilità di chi lo scrive --- #DAL SERVER ECHO AL TROJAN -- - La struttura è IDENTICA: -- - accept() -- - read -- - interpreta -- - rispondi -- - Cambia solo l’intento --- # TROJAN DIDATTICO (C2 TESTUALE) -- - C2 = C&C = Command and Control -- - Comandi ammessi: -- - ping -- - uptime -- - info -- - quit -- - Niente persistenza -- - Niente evasione --- ```php $start = time(); switch ($cmd) { case "ping": $out = "pong"; break; case "uptime": $out = time() - $start . " seconds"; break; case "info": $out = PHP_OS . " / PHP " . PHP_VERSION; break; case "quit": socket_write($client, "bye\r\n"); break 2; default: $out = "wat ? $cmd"; } socket_write($client, $out . "\r\n"); ``` --- # STRATEGIA 2: LUNGHEZZA PREFISSATA -- - Usata da: -- - protocolli binari -- - malware moderni -- - TLS internamente --- - Formato: [4 byte lunghezza][payload] -- ```php function read_exact($s, $n) { $buf = ''; while (strlen($buf) < $n) { $chunk = socket_read($s, $n - strlen($buf)); if ($chunk === false) return false; $buf .= $chunk; } return $buf; } ``` --- # PERCHÉ HTTP È INTERESSANTE -- HTTP è: -- - testuale -- - basato su righe -- - la richiesta è terminato da riga vuota -- - perfetto per mascherare un C2 --- # MINI WEB SERVER TCP -- - lettura richiesta -- - leggiamo un grosso numero di byte tutto in una volta -- - in realtà dovremmo fare un ciclo finche non troviamo una linea vuota, ma complicherebbe il codice -- - il browser si aspetta una risposta rapida -- ```php $req = socket_read($client, 8192); ``` -- - la richiesta è ad esempio: ``` GET / HTTP/1.1 Host: sguaff.com:4444 ... ``` --- - la risposta minimale è: -- ```php $risposta = "Hello from PHP TCP server\n"; $lunghezza = strlen($risposta); socket_write($client, "HTTP/1.1 200 OK\r\n" . "Content-Type: text/plain\r\n" . "Content-Length: $lunghezza\r\n" . "\r\n" . $risposta ); ``` --- Test: -- - Dal browser: http://host:4444 --- # STESSO SERVER, TRE USI -- 1. Echo server -- 2. Trojan didattico (C2) -- 3. Web server minimale -- - stessa socket -- - stesso TCP -- - cambia il protocollo --- # PUNTI CHIAVE -- - TCP non è messaggi, ma è uno flusso di byte -- - Telnet invia un carattere alla volta, con terminatore un CRLF -- - Un trojan è un client/server. Il protocollo lo decidiamo noi. -- - HTTP prevede una richiesta su piu' rìghe, il terminatore è l'ultima vuota -- - La fin