Socks Protocol Versión 5
Por Yo_Soy
 

INTRODUCCION

El uso de firewalls ha permitido separar estructuras de redes internas del exterior de la misma. Muchos de estos firewalls no son equipos físicos sino aplicaciones que actúan sobre la capa de aplicación del modelo OSI, actuando como proxy entre las maquinas que se comunican entre si.

El protocolo SOCKS fue creado para satisfacer esta necesidad que cada vez era mayor, permitiendo una mejor autentificación entre las maquinas y logrando así un mejor y mas fuerte control sobre el acceso.

SOCKS permite a los servidores detrás de un firewall ganar acceso a Internet. Reenvía los paquetes de los sitios de Internet al Server interno, permitiendo la transferencia hacia atrás y hacia adelante. Generalmente la aplicación cliente envía la petición al servidor SOCKS, con la dirección de la maquina destino, el tipo de conexión, y la identidad del usuario.

Esto lo podemos representar fácilmente en el siguiente diagrama:


   .----------<--------.
   |                   |     <------------------.
localhost            socks_server           Internet
   |                   |     '----------------->
   '---------->--------'


Después de que el servidor SOCKS recibe la petición, establece un canal de comunicación con el servidor de la aplicación. Un circuito se establece y el servidor SOCKS (que representaría el cliente), reenvía los datos entre el cliente y el servidor.

SOCKS realiza diferentes funciones de negociación mientras el circuito es establecido.

SOCKS 5 realiza cuatros operaciones básicas:

* negociación
* autentificación
* petición de conexión
* Establecimiento del circuito
* Reenvió de datos

El protocolo SOCKS 5 expande las características de SOCKS 4, ya que además de incluir el protocolo TCP, también soporta UDP y el formato de direcciones de IP V6.

Generalmente el demonio del servidor SOCKS estará corriendo en el puerto 1080.

En el presente articulo veremos tan solo el procedimiento para clientes TCP (siendo el mas común), pero si tu deseas profundizar en el proceso para clientes UDP, puedes leer el RFC 1928 y/o visitar la pagina oficial http://www.socks.nec.com

PROCEDIMIENTO PARA CLIENTES TCP

Negociación:

El cliente se conecta al servidor SOCKS, y envía el formato de negociación, que puede verse así:

.-------.------------.-----------.
|  VER  |  NMETHODS  |  METHODS  |
+-------+------------+-----------+
|   1   |      1     |  1 a 255  |
'-------+------------+-----------'

Nota: Los números abajo indicados representan la longitud en octetos de cada paquete.

Posibles valores de cada paquete:

     VER : 0x05    Versión del Protocolo
NMETHODS : [valor] Representa el numero de métodos.
 METHODS :
           0x00    Sin autentificacion
           0x01    GSSAPI
           0x02    Username/Password
           0xff    Ningún método aceptable


En el proceso de negociación GSSAPI (Generic Security Service Application Program Interface), los clientes negocian con el servicio SOCKS acerca de la seguridad de los mensajes.

La integridad y privacidad son las opciones que pueden aplicarse al resto de los mensajes, incluyendo las peticiones al proxy provenientes de la aplicación cliente.


Peticiones:

Una vez que la subnegociacion de los métodos ha sido completada, el cliente envía los detalles de la petición como sigue:


.-------.-------.-------.--------.------------.------------.
|  VER  |  CMD  |  RSV  |  ATYP  |  DST.ADDR  |  DST.PORT  |
+-------+-------+-------+--------+------------+------------+
|   1   |   1   |  0x00 |    1   |  Variable  |     2      |
'-------+-------+-------+--------+------------+------------+


Posibles valores de cada paquete:

     VER : 0x05 Versión del Protocolo

     CMD : Comando
           0x01 Connect
           0x02 Bind
           0x03 UDP

     RSV : 0x00 Valor reservado

    ATYP : Tipo de dirección
           0x01 dirección IP V4
           0x03 Nombre de dominio
           0x04 dirección IP V6

DST.ADDR : dirección de destino
           [valor] Longitud de la dirección de dominio
           [direcc] Nombre de dominio o dirección de 4 octetos.

DST.PORT : Puerto de destino.

SOCKS CHAINS

Nosotros podemos utilizar el protocolo SOCKS para actué efectivamente como proxy/firewall en nuestras conexiones salientes.

Sockscap es una excelente utilidad para estos propósitos ya que intercepta todas las salidas de nuestras maquinas por medio de un servidor SOCKS, por lo que podemos utilizarlo para la mayoría de los clientes (aun aquellos que no tengan la opción definida), logrando que nuestras conexiones sean mas 'anónimas'.

Sockscap puede encontrarse en -> http://www.socks.nec.com/reference/sockscap.html
Un socks chainer puede encontrarse en -> http://www.ufasoft.com/socks

SOCKS EN PERL

Programar socks en Perl es relativamente sencillo ya que ya existe un modulo creado para tal efecto, el autor es Clinton Wong y el modulo puede encontrarse en CPAN http://www.perl.com/CPAN/modules/by-module/Net/ y actualmente solo soporta conexiones TCP.

Se carga el modulo Net::SOCKS, después se crea el constructor así:

$sockout = new Net::SOCKS(socks_addr => '192.168.1.3',
socks_port => 1080,
user_id => 'the_user',
user_password => 'the_password',
force_nonanonymous => 1,
protocol_version => 5);

socks_addr = dirección del servidor socks
socks_port = puerto del servicio socks
user_id = (opcional) nombre de usuario
user_password = (opcional) password de usuario
protocol_version = la versión del protocolo (4 o 5)
force_nonanonymous = fuerza la conexión a no ser anónima


Después nos conectamos mediante:

$sock->connect(peer_addr => '192.168.1.3', peer_port => 79);

peer_addr es la dirección destino y peer_port es el puerto.

así, un cliente que haga finger en perl se vería así:


<++> socks/safefinger.pl
#!/usr/local/bin/perl -w

use strict;

use Net::SOCKS;

print "Attempting to connect to 192.168.1.3 at port 79 using the socks\n";
print "server at 192.168.1.3 port 1080\n";

my $sock = new Net::SOCKS(socks_addr => '192.168.1.3',
socks_port => 1080,
#user_id => 'the_user',
#user_password => 'the_password',
#force_nonanonymous => 1,
protocol_version => 5);
my $f= $sock->connect(peer_addr => '192.168.1.3', peer_port => 79);
print "connect status: ",
Net::SOCKS::status_message($sock->param('status_num')), "\n";

if ($sock->param('status_num') == SOCKS_OKAY) {
print $f "clintdw\n";
while (<$f>) { print }
$sock->close();
}

print "Attempting to listen() using the server at 192.168.1.3 port 1080\n";

$sock = new Net::SOCKS(socks_addr => '192.168.1.3',
socks_port => 1080,
#user_id => 'the_user',
#user_password => 'the_password',
#force_nonanonymous => 1,
protocol_version => 5);

my ($ip, $ip_dot_dec, $port) = $sock->bind(peer_addr => "192.168.1.3",
peer_port => 9999);
print "bind status: ",
Net::SOCKS::status_message($sock->param('status_num')), "\n";

if ($sock->param('status_num') == SOCKS_OKAY) {
print "Listening at the IP of ", $ip_dot_dec, " at port ", $port, "\n";
$f= $sock->accept();
}
print "accept status: ",
Net::SOCKS::status_message($sock->param('status_num')), "\n";

if ($sock->param('status_num') == SOCKS_OKAY) {
while (<$f>) { print }
}
$sock->close();
<-->


SOCKS EN C

Programar clientes SOCKS en C es mas complicado debido a que tenemos que trabajar a un nivel mas bajo. así si recordamos lo primero que debemos hacer es enviar la negociación (si vamos a enviar una negociación de usuario y contraseña mirar el RFC 1929) y luego enviar la petición.

Como ejemplo ponemos una aplicación que permite enviar correo mediante un
servidor SOCKS:


<++> socks/rm-sm.c
/*
| Raza Mexicana Team 2001 - http://www.raza-mexicana.org
|
| (rm-sm.c) Sends e-mail thru a socks proxy server.
|
| Yo_Soy - <yo_soy@raza-mexicana.org>
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of the GNU General Public License
| as published by the Free Software Foundation; either version
| 2 of the License, or (at your option) any later version.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "socks5.h"

void uso (void);

int main (int argc, char *argv[]) {

struct sockaddr_in sin;
unsigned int smtpuerto = 25,
socksport = 1080,
sockout;
char *mailfrom = argv[1],
*destino = argv[2],
*sockserv = argv[5],
*smtpserv = argv[4],
*mensaje,
respuesta[256],
sendbuff[256];
FILE *archivo;

if (argc < 5) uso();

printf ("[++] -> Raza Mexicana - MailSock\n");

printf ("\n[+] Mail from....: %s\n", mailfrom);
printf ("[+] Mail to......: %s\n", destino);
printf ("[+] Smtp Server..: %s\n", smtpserv);
printf ("[+] Socks server.: %s\n", sockserv);

if (argc > 5) {
socksport = atoi(argv[6]);
printf ("[+] Socks port...: %d\n", socksport); }

if ((archivo = fopen (argv[3], "r")) == NULL) {
printf ("ERROR: Can't open file %s\n", argv[3]);
exit (EXIT_FAILURE); }

if ((sockout = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
printf ("ERROR: Can't create socket.\n");
exit (EXIT_FAILURE); }

sin.sin_family = AF_INET;
sin.sin_port = htons(socksport);
sin.sin_addr.s_addr = inet_addr(sockserv);

if ((connect(sockout, (struct sockaddr *)&sin, sizeof(sin))) == -1) {
printf ("ERROR: Can't connect to host %s\n", sockserv);
exit (EXIT_FAILURE);
}

/* Negociacion */
sprintf (sendbuff, "%c%c%c", SOCKS_VER, 1, METHOD_NOAUTH);
send (sockout, sendbuff, sizeof(sendbuff), 0);

/* Request */
printf ("Sendbuff = %s\n", sendbuff);
sprintf (sendbuff, "%c%c%c%c%s%c%c", SOCKS_VER, CMD_CONNECT,
SOCKS_RSV, strlen(smtpserv), smtpserv,
(smtpuerto >> 8) & 0xFF, smtpuerto & 0xFF);
send (sockout, sendbuff, sizeof(sendbuff), 0);

/* Checamos las posibles respuestas del sock_server */
recv (sockout, respuesta, 100, 0);
switch (respuesta[1]) {
case R_SUCCEDED:
break;
case R_FAILURE:
printf ("ERROR: general socks server failure\n");
exit (EXIT_FAILURE);
break;
case R_NOALLOWED:
printf ("ERROR: connection not allowed\n");
exit (EXIT_FAILURE);
break;
case R_NET_UNR:
case R_HOST_UNR:
printf ("ERROR: network / host unreachable\n");
exit (EXIT_FAILURE);
break;
case R_REFUSED:
printf ("ERROR: connection refused\n");
exit (EXIT_FAILURE);
break;
case R_TTLEXPIRED:
printf ("ERROR: TTL expired\n");
exit (EXIT_FAILURE);
break;
case R_NOCMD:
printf ("ERROR: command not supported\n");
exit (EXIT_FAILURE);
break;
case R_NOADDR:
printf ("ERROR: address type not supported\n");
exit (EXIT_FAILURE);
break;
default:
printf ("ERROR: %d\n", respuesta[1]);
exit (EXIT_FAILURE);
break;
}

/* Si llegamos aqui, todo esta bien */

/* ahora enviamos el mensaje */
sprintf (sendbuff, "HELO RMHT\n");
send (sockout, sendbuff, sizeof(sendbuff), 0);

sprintf (sendbuff, "MAIL FROM <%s>\n", mailfrom);
send (sockout, sendbuff, sizeof(sendbuff), 0);

sprintf (sendbuff, "RCPT TO: <%s>\n", destino);
send (sockout, sendbuff, sizeof(sendbuff), 0);

sprintf (sendbuff, "DATA\n");
send (sockout, sendbuff, sizeof(sendbuff), 0);

while (! feof(archivo)) {
if (fgets(mensaje, 255, archivo)) {
send (sockout, mensaje, sizeof(mensaje), 0); }
}
fclose (archivo);

sprintf (sendbuff, "\n.\n");
send (sockout, sendbuff, sizeof(sendbuff), 0);

sprintf (sendbuff, "QUIT\n");
send (sockout, sendbuff, sizeof(sendbuff), 0);

printf ("[+] Message sent to %s!\n", destino);

return (0);
}

void uso(void) {
puts("\n[+] Raza Mexicana SocksMail - http://www.raza-mexicana.org

Usage:

rm-sm <from> <to> <message> <smtp> <socks_proxy> <socks_port>

<from> from mail address
<to> destination mail address
<message> the file with the message
<smtp> relaying smtp server
<socks_proxy> socks proxy server
<socks_port> default 1080 if not defined
");
exit(EXIT_SUCCESS); }
<-->


y la cabecera necesaria con las constantes definidas en el RFC (socks5.h):


<++> socks/socks5.h
/*
| Socks Protocol Versión 5 // RFC 1928
| by Yo_Soy <yo_soy@raza-mexicana.org>
*/

#define SOCKS_VER 0x05 /* socks protocol version 5 */
#define SOCKS_RSV 0x00 /* socks reserved */

enum METHODS {
METHOD_NOAUTH = 0x00, /* no authentication required */
METHOD_GSSAPI = 0x01, /* GSAAPI */
METHOD_AUTH = 0x02, /* username / password */
METHOD_NOACCM = 0xff /* no acceptable methods */
} sockmethods;


enum COMMANDS {
CMD_CONNECT = 0x01, /* connect */
CMD_BIND = 0x02, /* bind */
CMD_UDP = 0x03 /* udp associate */
} sockcmds;


enum ADDRESS {
ADDR_IPV4 = 0x01, /* IP V4 address */
ADDR_DOMAIN = 0x03, /* domain name */
ADDR_IPV6 = 0x04 /* IP V6 address */
} sockatyp;


enum REPLIES {
R_SUCCEDED = 0x00, /* succeeded */
R_FAILURE = 0x01, /* general socks server failure */
R_NOALLOWED = 0x02, /* connection not allowed */
R_NET_UNR = 0x03, /* network unreacheable */
R_HOST_UNR = 0x04, /* host unreacheable */
R_REFUSED = 0x05, /* connection refused */
R_TTLEXPIRED = 0x06, /* TTL expired */
R_NOCMD = 0x07, /* command not supported */
R_NOADDR = 0x08 /* address type not supported */
} sockreply;
<-->

RMHT en el WWW
El lado humano

 

 
Comentarios a : yo_soy@raza-mexicana.org