Python黑客编程之类nc工具

目的

  • 用python socket编写一款类似NetCat的工具,可以在服务器上远程执行命令,从服务器上下载文件

代码

  • 服务端和客户端用同一套代码,用-l参数进行区分
import argparse
import shlex
import socket
import subprocess
import sys
import textwrap
import threading


class NetCat:
    def __init__(self, args, buffer=None):
        self.args = args
        self.buffer = buffer
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    def run(self):
        if self.args.listen:
            self.listen()
        else:
            self.send()

    def send(self):
        self.socket.connect((self.args.target, self.args.port))
        if self.buffer:
            self.socket.send(self.buffer)

        if self.args.file:
            file_buffer = b''
            while True:
                data = self.socket.recv(4096)
                data_len = len(data)
                file_buffer += data
                if data_len < 4096:
                    break
            with open(self.args.file, 'wb') as fp:
                fp.write(file_buffer)
            message = "Successfully send file {} to {}".format(self.args.file, socket.gethostbyname(socket.gethostname()))
            self.socket.send(message.encode())
            print("Successfully received file {}".format(self.args.file))

        if not self.args.command:
            return

        try:
            while True:
                print("<NetCat: #>", end="")
                buffer = input()
                buffer += '\n'
                self.socket.send(buffer.encode())
                data_len = 1
                content = ''
                while data_len:
                    data = self.socket.recv(4096)
                    data_len = len(data)
                    content += data.decode()
                    if data_len < 4096:
                        break
                if content:
                    print(content, end="")

        except KeyboardInterrupt:
            print('User terminated.')
            self.socket.close()
            sys.exit()

    def listen(self):
        self.socket.bind((self.args.target, self.args.port))
        self.socket.listen(5)

        while True:
            client_socket, _ = self.socket.accept()
            client_thread = threading.Thread(target=self.handle_client, args=(client_socket,))
            client_thread.start()

    def handle_client(self, client_socket):
        if self.args.file:
            with open(self.args.file, 'rb') as fp:
                client_socket.send(fp.read())
            recv_buffer = client_socket.recv(64)
            print(recv_buffer.decode())

        if self.args.execute:
            result = self.execute(self.args.execute)
            client_socket.send(result.encode())

        if not self.args.command:
            return

        if self.args.command:
            cmd_buffer = b''
            while True:
                try:
                    while '\n' not in cmd_buffer.decode():
                        cmd_buffer += client_socket.recv(64)
                    result = self.execute(cmd_buffer.decode())
                    if result:
                        client_socket.send(result.encode())
                    cmd_buffer = b''
                except Exception as e:
                    print("Server killed {}".format(e))
                    client_socket.close()
                    sys.exit()

    def execute(self, cmd):
        cmd = cmd.strip()
        if not cmd:
            return
        result = subprocess.check_output(shlex.split(cmd), stderr=subprocess.STDOUT)
        return result.decode()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Python Netcat Tool',
                                     formatter_class=argparse.RawDescriptionHelpFormatter,
                                     epilog=textwrap.dedent('''
                                     Example:
                                         netcat.py -t 192.168.1.1 -p 2222 -l -c #command shell
                                         netcat.py -t 192.168.1.1 -p 2222 -l -u=test.txt #upload file
                                         netcat.py -t 192.168.1.1 -p 2222 #connect to server
                                     '''))
    parser.add_argument('-c', '--command', action='store_true', help='open a command shell')
    parser.add_argument('-e', '--execute', help='execute specified command')
    parser.add_argument('-l', '--listen', action='store_true', help='open listening for server')
    parser.add_argument('-p', '--port', type=int, default=8080, help='input port')
    parser.add_argument('-t', '--target', default='127.0.0.1', help='input IP')
    parser.add_argument('-f', '--file', help='upload file')
    args = parser.parse_args()
    if args.listen:
        buffer = ''
    else:
        buffer = sys.stdin.read()

    nc = NetCat(args, buffer.encode())
    nc.run()

遇到的问题

  • 如何结束stdin.read:有时候用ctrl+d,有时候用ctrl+z加回车
  • 建立socket连接前要注意关闭防火墙
  • 对于windows环境下用subprocess开启子进程执行命令,需要指明powershell或者cmd,否则部分命令执行不了
  • 书里是远端发来shell提示符,会导致回显对不上,我改成了本地print提示符,才对上了

效果

  • 传文件-客户端
  • 传文件-服务端
  • 执行命令-客户端
  • 执行命令-服务端

不足之处

  • 这只是一个小demo,功能很单一
  • pyinstaller打包后7M左右,对比C写的几K确实有点大,从外网上传可能时间要比较多
  • 没有使用select,recv和send收发都是阻塞式的,同步通信,回合制游戏...
posted @   z5onk0  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示