[python] 记录一次简单网络工具“netcat”的编程

本文介绍了使用Python基于socket实现Netcat的基本功能,包括命令行参数控制的接收和发送数据模式,执行命令以及上传文件。通过创建NetCat类处理socket和数据,定义handle函数处理参数和命令,listen和send函数分别用于监听和发送数据。文章还展示了如何通过argparse模块规范化脚本参数,并提供了使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Netcat作为一款被广泛使用的计算机网络工具,为了提高个人编程水平和加深对网络的理解,今天我就基于socket来对其进行简单的实现

目录

一 需要使用到的库

 二 思路

三 分块实现

四 大功告成,现在来试试效果

 五 写在最后的话


一 需要使用到的库

import argparse  
import socket
import shlex      #Split command
import subprocess
import sys
import textwrap
import threading

 二 思路

1)作为一个可以连接和被连接的工具,首先应该具备两种模式,即收数据和发数据,在脚本中可以通过指定参数的方式进行控制

2)应该要有一个可以执行命令行指令的功能,同样可以使用参数控制,最终达到的效果应该是可以通过客户端发送指令让服务器端(指在单次连接中有客户端和服务器端的区别)执行指令

3)最后应该有办法从客户端向服务器端(与上同理)传输文件

三 分块实现

为了方便调用应该先考虑建立一个类NetCat来对socket和所要发送的数据进行处理,也就是我们的工具应该能够管理套接字和所要发送的数据。建立一个buffer 缓冲方便后续存储数据

class NetCat:
    #use args and buffer to initialize the NetCat
    def __init__(self,args,buffer = None):
        self.args = args
        self.buffer = buffer
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#create a socket
        self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        #when a socket come to a close state , it may get into a TIME_WAIT state,SO_REUSEADDR 
        # can restart the socket immediately

接下来我们应该定义一个处理函数用于处理我们传进来的参数和命令(类似于“192.168.169.12 122 -c 。。。。”)

def handle(self,client_sock):
        if self.args.execute:
            output = execute(self.args.execute)
            client_sock.send(output.encode())
        elif self.args.upload:
            file_buffer = b''#create a file buffer
            while True:
                data = client_sock.recv(4096)
                if data:
                    file_buffer +=data
                else:
                    break
            

            with open(self.args.upload,'wb') as f:
                f.write(file_buffer)
            message = f'Save file{self.args.upload}'
            client_sock.send(message.encode())
        elif self.args.command:
            cmd_buffer = b''
            while True:
                try:
                    client_sock.send(b'BHP: #>>')
                    while '\n' not in cmd_buffer.decode():
                        cmd_buffer += client_sock.recv(64)
                    response = execute(cmd_buffer.decode())
                    if response:
                        client_sock.send(response.encode())
                    cmd_buffer = b''
                except Exception as e:
                    print(1)
                    print(f'Server killed {e}')
                    self.socket.close()
                    sys.exit()

(上面的代码中的 execute函数实际上是未定义的)

def execute(cmd):
    cmd = cmd.strip() #remove whitespace at the b and e of the string
    if not cmd:#if is a an empty string
        return
    output = subprocess.check_output(shlex.split(cmd),stderr=subprocess.STDOUT)# to run instructions on this  machine and assign the returned content to the output
    return output.decode()

(上面补上了execute函数)

在定义的处理函数之后,我们接下来定义发送函数send

def listen(self):
        self.socket.bind((self.args.target,self.args.port))#bind port and ip to the socket
        self.socket.listen(5)#listen 5 
        while True:
            cilent_socket,adds = self.socket.accept()
            print(f'[*]Connect from {adds}')
            client_thread = threading.Thread(target=self.handle,
            args=(cilent_socket,))#create a thread to excute the command
            client_thread.start()

和listen函数

def send(self):
        self.socket.connect((self.args.target,self.args.port))
        if self.buffer:
            self.socket.send(self.buffer)#if there has data in the buffer , send it out first
        try:
            while True:
            #When the hot key is not triggered, a large loop continues
                recv_len = 1
                respose = ''
            #When the messages in the current socket have not been received completely, a small loop continues
                while recv_len:
                    data = self.socket.recv(4096)
                    recv_len = len(data)
                    respose += data.decode()
                    if recv_len<4096:
                        break
                if respose:
                    print(respose)
                    buffer = input(">>>")
                    buffer += '\n'
                    self.socket.send(buffer.encode())
        except KeyboardInterrupt:
            print("User Quit")
            self.socket.close()
            sys.exit()

最后定义一个run函数作为调用的入口

def run(self):# to excute te program,as the window between sender and receicer
        if self.args.listen:
            self.listen()
        else:
            self.send()

在主函数中利用argparse对脚本进行规范化,其封装的函数能够帮助我们更加简单制作脚本

并在初始化时添加对于参数的解释

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="A Net Tool from a freshman",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog= textwrap.dedent('''Example:
        netcat.py -t 192.168.1.108 -p 5555 -l -c #command shell
        netcat.py -t 192.168.1.108 -p 5555 -l -u=test.txt  #upload file
        netcat.py -t 192.168.1.108 -p 5555 -l -e=\"cat/etc/passwd\" #execute command
        echo 'ABC'  | ./netcat.py -t 192.168.1.108 -p 135 #echo text tp server port 135
        netcat.py -t 192.168.1.108 -p 5555 #connect to server
        '''))
    parser.add_argument('-c','--command',action='store_true',help='command shell')
    parser.add_argument('-e','--execute',help='execute specified command')
    parser.add_argument('-l','--listen',action='store_true',help='listen')
    parser.add_argument('-p','--port',type= int,default= 5555,help='specifide port')
    parser.add_argument('-t','--target',default= '192.168.1.108',help='specified IP')
    parser.add_argument('-u','--upload',help='upload file')
    args = parser.parse_args()#Analysis the command and save the results in args
    if args.listen:
        buffer = ''
    else:
        buffer = sys.stdin.read()
    nc = NetCat(args,buffer.encode())#to define a class NetCat
    nc.run()

四 大功告成,现在来试试效果

首先先在虚拟机上打开监听,并且打开命令行的执行权限

 在WSL中打开另一个相同的脚本,并将目标指向虚拟机

 由于在编写的时候使用STD进行读取故在开始时需要为命令读入一个EOF命令才会继续运行

 按下Ctrl +D后 (输入一个EOF命令),可以看见虚拟机接收到了来着WSL的连接,并且在WSL中已经可以远程向虚拟机执行指令了(不过要注意由于没有设计容错所以命令不能打错,不然虚拟机上的程序会直接退出)

 

尝试执行创建文件指令

成功

 重新连接,再测试一下只执行一条指令的功能

 

成功,在WSL中收到了打开文件的内容

 五 写在最后的话

还可以改进的地方:增加对于同一主机其他端口的扫描功能

增加对于输入命令错误时服务器端的容错率

 写注释的时候几乎全部是用翻译软件写的,英语大退步(bushi

python很多语法也忘了,不得不说还是要加强对于编程的练习,不过最后看到程序能够正常运行,还是挺开心的

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值