Sockets usando la red TOR C++

Iniciado por d3adly, Mayo 29, 2020, 09:34:07 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Hola a todos.
Hoy comparto con ustedes el manejo de sockets mediante la red TOR. Suponiendo que ya se tiene tor instalado y corriendo en el puerto por defecto 9050 proseguimos.
Primero debemos entender sobre la negociacion o Handshake que se lleva a cabo al conectar con un proxy. En el Request For Comment RFC 1982 No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, pueden obtener mas información con respecto al proceso de conexión, en este post solo cubriremos conceptos basicos.
El Handshake basico se podria representar de la siguiente manera



Y sigue este flujo:
Primero el cliente en este caso PC A, envia una secuencia de tres bytes (5, 1, 0) al servidor proxy. El primer byte especifica la version de socks a usar en este caso 5, el segundo byte es para propositos de autenticación, especifica los metodos soportados por el cliente para autenticarse 1, y el tercer byte es el tipo de autenticación, en este caso 0 (sin autenticación), si la conexión se quiere realizar mediante usuario/contraseña entonces este ultimo byte seria 2.

Se envia la secuencia de bytes y el servidor responde con dos bytes, en esta caso (5, 0), siendo el primer byte la version de socks a utilizar 5, y el segundo el metodo de autenticación 0 (sin autenticación). Si el servidor requiere de autenticación responderia con 5,2, pero ya que utilizaremos un proxy local sin este metodo deberia de responder siempre con 5,0.

A continuación se envia la secuencia de bytes (5, 1, 0, 3, Host, Puerto), siendo el primer byte 5 como se menciona anteriormente la version de socks, el segundo byte 1 es el codigo de comando, que puede ser uno de los siguientes valores:

1 = Establecer conexión TCP/IP.
2 = Establece un enlace de puerto TCP/IP.
3  = Asocia un puerto UDP.

En este caso usaremos el primero 1 (Establecer conexión TCP/IP) , el tercer byte 0 es un byte reservado y debe ser 0, el cuarto byte 3 es el tipo de direccion del host que puede ser una de las siguientes:

1 = Dirección IPv4, seguida por la IP de 4 bytes
3 = Nombre de dominio, 1 byte para la longitud del nombre seguido del nombre del host.
4 = Dirección IPv6, seguida de la IP de 16 bytes.

Usaremos el byte 3 (Nombre de dominio, 1 byte para la longitud del nombre seguido del nombre del host), y el ultimo byte vendria siendo el numero de puerto en orden de red de 2 bytes No tienes permitido ver los links. Registrarse o Entrar a mi cuenta.

Si todo va bien el servidor proxy responde con la secuencia 5, 0, 0, 1, Host, Puerto , siendo el segundo byte 0 el estado de la negociación, en esta caso el 0 indica que todo ha salido bien, el tercer byte es reservado y es 0, y los ultimos tres vendrian siendo el tipo de dirección, dirección y puerto en orden de red.

Habiendo entrado en lo basico del proceso de comunicación con el servidor veamos como aplicarlo en código

Una vez realizada la conexión inicial con el servidor:
Código: cpp

char buffer[3];
buffer[0] = 0x05;  //Version de socks
buffer[1] = 0x01; //Metodos de autenticacion soportados por el cliente
buffer[2] = 0x00; //Metodo de autenticacion a utilizar : Sin Autenticacion
send(Socket, buffer, 3, 0);

Enviamos la secuencia de tres bytes 0x05, 0x01, 0x00,  (0x05 - Version Socks    0x01 - Metodos soportados de autenticacion por el cliente    0x00 - No usar autenticacion).

Acto seguido recibimos la respuesta del servidor y verificamos si el estado del segundo byte es 0
Código: cpp

char rbuffer[10];
recv(Socket, rbuffer, 10, 0);
if(rbuffer[1] == 0x00){
   //primera parte de negociacion correctamente
}


Ahora se procede a crear la ultima secuencia de bytes con los datos del destino al cual conectarnos
Código: cpp

char fbuff[256];
memset(fbuff, 0, 256);
fbuff[0] = 0x05;  //version de socks
fbuff[1] = 0x01;  //Codigo de comando
fbuff[2] = 0x00;  //Byte reservado
fbuff[3] = 0x03; //Tipo de direccion del host

short host_port = htons(PORT);                  //convierte el numero de puerto a orden de bytes de red
char host_len = (char)strlen(HOSTNAME);        //Se obtiene la longitud del nombre host en un byte
memcpy(fbuff + 4, &host_len, 1);                //Luego se unen los datos junto con la secuencia anterior
memcpy(fbuff + 5, HOSTNAME, host_len);
memcpy(fbuff + 5 + host_len, &host_port, 2);

send(Socket, fbuff, 7 + host_len, 0);         //Se envia la secuencia de bytes


Y por ultimo recibimos la respuesta del servidor proxy, si el segundo byte es 0 significa que el proceso de negociación ha finalizado correctamente
Código: cpp

recv(Socket, rbuffer, 10, 0);
if(rbuffer[1] == 0x00){
    //proceso de negociacion completo
    //Ahora se procede a intercambiar datos con el host de destino
}


Y sin mas mi código de una simple peticion HTTP usando TOR:

Código: cpp

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<netdb.h>
#include<unistd.h>
#include<signal.h>

class TorSocket{
   private:
int SocketD;
   public:
int Connect(const char *cHostname, int iPort, const char *torhost = "127.0.0.1", const char *torport = "9050"){
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = SA_RESTART;
sigaction(SIGPIPE, &act, 0);
struct addrinfo client, *addrs, *addr;
char rBuffer[10];
int iReceived = 0;
memset(&client, 0, sizeof(client));
client.ai_family = AF_UNSPEC;
client.ai_socktype = SOCK_STREAM;
client.ai_protocol = IPPROTO_TCP;
int iStatus = getaddrinfo(torhost, torport, &client, &addrs);
if(iStatus!=0){
std::cout<<"Error getaddrinfo\n";
return -1;
}
for(addr = addrs; addr != nullptr; addr = addr->ai_next){
if((this->SocketD = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) == -1){
continue;
}
if(connect(this->SocketD, addr->ai_addr, addr->ai_addrlen) == -1){
continue;
}
break;
}
freeaddrinfo(addrs);
if(this->SocketD == -1){
std::cout<<"No se pudo conectar al proxy\n";
return -1;
}
char cByteSequense1[3] = {0x05, 0x01, 0x00};
send(this->SocketD, cByteSequense1, 3, 0);
iReceived = recv(this->SocketD, rBuffer, 10, 0);
if(iReceived > 0){
if(rBuffer[0] != 0x05){   
std::cout<<"Version de socks invalida\n";
return -1;
}
if(rBuffer[1] == 0x00){
char cByteSequense2[256];
memset(cByteSequense2, 0, 256);
cByteSequense2[0] = 0x05;
cByteSequense2[1] = 0x01;
cByteSequense2[2] = 0x00;
cByteSequense2[3] = 0x03;
short sHost_Port = htons(iPort);
char cHost_Len = (char)strlen(cHostname);
memcpy(cByteSequense2 + 4, &cHost_Len, 1);
memcpy(cByteSequense2 + 5, cHostname, cHost_Len);
memcpy(cByteSequense2 + 5 + cHost_Len, &sHost_Port, 2);
send(this->SocketD, cByteSequense2, 7 + cHost_Len, 0);
memset(rBuffer, 0, sizeof(rBuffer));
iReceived = recv(this->SocketD, rBuffer, 10, 0);
if(rBuffer[1] == 0x00){
std::cout<<"Conexion satisfatoria\n";
//Ahora se puede enviar datos atraves de este socket
return this->SocketD;
} else {
return -1;
}
}
} else {
return -1;
}
return -1;
}

void CloseSocket(){
close(this->SocketD);
}

int SendData(const char *data, int size){
return send(this->SocketD, data, size, 0);
}

int ReadData(char*& buffer){
buffer = (char *)malloc(2048);
unsigned int so_far = 0;
char u_c[2];
while(recv(this->SocketD, u_c, 1, 0) > 0){
if(so_far >= 2048){
buffer = (char *)realloc(buffer, so_far + 1);
}
buffer[so_far++] = u_c[0];
}
buffer[so_far] = '\0';
return so_far;
}
};

//Simple ejemplo de peticion HTTP a url specificada
int main(int argc, char **argv){
if(argc < 2){
std::cout<<argv[0]<<" url\n";
return 0;
}
TorSocket tor;
char domain[128];
char *response;
strncpy(domain, argv[1], 128);
int stat = tor.Connect(domain, 80);
if(stat == -1){
std::cout<<"No se pudo conectar\n";
return -1;
}
std::cout<<"Conectado\n";
char packet[512];
snprintf(packet, 512, "GET / HTTP/1.1\r\nHost: %s\r\n\r\n", domain);
if(tor.SendData(packet, strlen(packet)) > 0){
unsigned int bytes = tor.ReadData(response);
if(bytes>0){
std::cout<<response<<"\n\n";
} else {
std::cout<<"No se recibio nada\n";
}
free(response);
} else {
std::cout<<"Error al enviar el paquete\n";
}
tor.CloseSocket();
return 0;
}



Una captura de pantalla
         

Espero les haya servido y le den un buen uso, cualquier correcion o duda dejenme saberla.

Saludos
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

Respetos @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta +1, un excelente aporte, sigue compartiendo estos conocimientos  ;D

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF

Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta esa es la idea :)
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn