You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

252 lines
11 KiB

'''
渗透测试任务管理类 一次任务的闭合性要检查2025-3-10 一次任务后要清理LLM和InstrM的数据
'''
from TargetManager import TargetManager # 从模块导入类
from LLMManager import LLMManager # 同理修正其他导入
from myutils.FileManager import FileManager
from InstructionManager import InstructionManager
from mycode.DBManager import DBManager
from myutils.MyTime import get_local_timestr
import queue
import time
import os
import threading
class TaskManager:
def __init__(self):
self.TargetM = TargetManager()
# 生成功能对象
self.LLMM = LLMManager(1)
self.InstrM = InstructionManager()
self.DBM = DBManager() #主进程一个DBM
self.DBM.connect()
# 控制最大并发指令数量
self.max_thread_num = 2
self.task_id = 0 #任务id --
self.do_sn = 0 #指令执行顺序号--暂时已执行完成顺序记录
self.workth_list = [] #线程句柄list
self.batch_num = 0 #一个批次的指令数量
self.long_instr_num = 0 #耗时指令数量
self.long_time_instr = ['nikto'] #耗时操作不计入批量执行的数量,不加不减
self.instr_queue = queue.Queue() #线程安全 --待执行指令
self.user_instr = queue.Queue() #需要用确认或手动执行的命令--待执行指令
self.user_done_instr = queue.Queue() #执行完成需要用户确认的指令
self.doing_instr = queue.Queue()#执行中的指令
self.done_instr = queue.Queue() #执行完成的指令
self.res_queue = queue.Queue() #结果队列
self.lock = threading.Lock() #线程锁
self.do_sn_lock = threading.Lock() #指令执行顺序号锁
self.brun = True
def is_user_instr(self,instr):
'''
过滤需要人工确认或手动执行的指令 ---- 待完善
:param instr:
:return:
'''
#if instr.startswith("curl") or instr.startswith("http") or instr.startswith("wget"):
if instr.startswith("http") or instr.startswith("wget") or instr.startswith("ssh"):
return True
def instr_in_quere(self,instr_list):
'''
对于运行需要较长时间的不强求同一批次返回给LLM
:param instr_list:
:return:
'''
for instr in instr_list:
if self.is_user_instr(instr):
self.user_instr.put(instr)
print(f"需要人工确认的指令{instr}")
else:
matched =False
for prefix in self.long_time_instr:
if instr.startswith(prefix):
matched =True
if not matched:
with self.lock:
self.batch_num += 1 #非耗时指令+1
print(f"&&&&&&当前batch_num:{self.batch_num}")
else:
with self.lock:
self.long_instr_num +=1 #耗时指令数量+1
# 指令入队列
self.instr_queue.put(instr)
#入数据库放哪一层要待定-TaskManager , InstructionM,ToolBase-2025-3-10
def res_in_db(self,bres,instr,reslut,start_time,end_time,th_DBM,source_result,ext_params):
if th_DBM.ok:
with self.do_sn_lock:
self.do_sn += 1 #指令的执行序列是一个任务共用,要线程锁,错误问题也不大
th_DBM.insetr_result(self.task_id,instr,reslut,self.do_sn,start_time,end_time,source_result,ext_params)
else:
print("数据库连接失败!!")
def res_in_quere(self,bres,instr,reslut,start_time,end_time,th_DBM,source_result,ext_params):
'''
执行结果入队列,若批量执行的指令都完成,则提交LLM生成下一步指令
:param bres:
:param instr:
:param reslut:
:return:
'''
matched = False
bover = False
#入数据库 -- bres True和False 都入数据库2025-3-10
self.res_in_db(bres,instr,reslut,start_time,end_time,th_DBM,source_result,ext_params)
#结果入队列
if bres:
res = {'instr':instr,'reslut':reslut}
self.res_queue.put(res) #入队列
else: #对于不需要再提交给LLM的结果,如何处理待定。有执行false、未知工具
pass
#判断批次指令是否都执行完
for prefix in self.long_time_instr:
if instr.startswith(prefix):
matched = True
if not matched:
with self.lock:
self.batch_num -= 1 #非耗时指令-1
print(f"&&&&&&当前batch_num:{self.batch_num}")
if self.batch_num ==0: #只会轮询到最后一个线程才会是0
bover = True
else:
#这里会有个问题,若耗时指令执行完,结果入队列后,但LLM没有进一步的指令下发,会造成结果不会提交
#需要在生成“生成报告”的指令时进行研判--该点很重要
with self.lock:
self.long_instr_num -=1 #耗时指令数量-1
if bover:
#整合结果提交 -- 需要确保只有一个线程会执行
self.batch_res_post(th_DBM)
def batch_res_post(self,th_DBM):
'''
组合批量指令的结果,一起提交到LLM,生成下一步具体指令
:return:
'''
post_string = ""
while not self.res_queue.empty():
res = self.res_queue.get()
str = f"执行指令:{res['instr']}的结果是:{res['reslut']}"
post_string = post_string + "\n"
post_string = post_string + str
if post_string:
post_string = post_string + "\n请根据这些结果生成下一步具体的指令。"
print(f"***************\n{post_string}")
with open("res","w",encoding="utf-8") as f:
f.write(post_string)
#*****测试时中断下一步指令的获取
# 提交提示词,得到下一步指令
# instr_list = self.LLMM.get_llm_instruction(post_string,th_DBM)
# if instr_list:
# if instr_list[0] == "生成报告": #“生成报告”要特殊处理#?
# self.brun = False
# print("生成报告--退出工作线程")
# else: # 继续工作
# self.instr_in_quere(instr_list)
def do_worker_th(self):
#线程的dbm需要一个线程一个
th_DBM = DBManager()
th_DBM.connect()
while self.brun:
try:
instruction = self.instr_queue.get(block=False) #quere线程安全,block=false非阻塞get
self.doing_instr.put(instruction) #入执行队列
#执行中会对指令进行微调,并有可能不执行直接返回空结果
start_time = get_local_timestr() #指令执行开始时间
bres,instr,reslut,source_result,ext_params = self.InstrM.execute_instruction(instruction)
end_time = get_local_timestr() #指令执行结束时间
self.res_in_quere(bres,instr,reslut,start_time,end_time,th_DBM,source_result,ext_params) #执行结果入队列
self.done_instr.put(instruction) #执行完成队列
#执行情况是否需要用户确认
if ext_params["is_user"]:
pass
#print("该指令执行需要用户确认")
except queue.Empty:
time.sleep(10)
#函数结束,局部变量自动释放
def start_task(self,target_name,target_in):
#判断目标合法性
bok,target,type = self.TargetM.validate_and_extract(target_in)
if bok:
self.target = target
self.type = type #1-IP,2-domain
self.task_id = self.DBM.start_task(target_name,target_in) #数据库新增任务记录
#获取基本信息: 读取数据库或预生成指令,获取基本的已知信息
know_info = "" #?
#启动--初始化指令
prompt = self.LLMM.build_initial_prompt(target,know_info)
instr_list = self.LLMM.get_llm_instruction(prompt,self.DBM)
self.instr_in_quere(instr_list) #指令入队列
#创建工作线程
for i in range(self.max_thread_num):
w_th = threading.Thread(target=self.do_worker_th)
w_th.start()
self.workth_list.append(w_th)
#等待线程结束--执行生成报告
for t in self.workth_list:
t.join()
#生成报告
pass
else:
return False,"{target}检测目标不合规,请检查!"
def stop_task(self):
self.brun = False
self.LLMM.init_data() #清空一些全局变量
self.InstrM.init_data()
#结束任务需要收尾处理#?
if __name__ == "__main__":
import json
TM = TaskManager()
FM = FileManager()
current_path = os.path.dirname(os.path.realpath(__file__))
strMsg = FM.read_file("test",1)
TM.LLMM.test_old_message(strMsg) #先设置message的值
test_type = 3
if test_type == 1:
#测试执行指令
# instrS = ['gobuster dir -u https://58.216.217.70 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -k -t 20 --timeout 10s',
# 'searchsploit SoftEther VPN',
# 'curl -kv -X POST -d "username=admin&password=admin" https://58.216.217.70/vpn/index.html --connect-timeout 10',
# 'gobuster dir -u http://58.216.217.70:10001 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 20 --timeout 10s']
#instrS = ['nmap -sV -sC -p- -Pn 192.168.204.137']
with open("test", "r", encoding="utf-8") as f:
messages = json.load(f)
text = messages[-1]["content"]
#list = TM.LLMM.fetch_instruction(text)[9:10]
list = TM.LLMM.fetch_instruction(text)
#print(list)
TM.instr_in_quere(list)
#创建线程执行指令
for i in range(TM.max_thread_num):
w_th = threading.Thread(target=TM.do_worker_th)
w_th.start()
TM.workth_list.append(w_th)
# 等待线程结束--执行生成报告
for t in TM.workth_list:
t.join()
elif test_type ==2:
#测试LLM返回下一步指令
with open("res", "r", encoding="utf-8") as f:
prompt = f.read()
if prompt:
instr_list = TM.LLMM.get_llm_instruction(prompt,TM.DBM)
TM.instr_in_quere(instr_list) # 指令入队列问题不大,任务执行线程没有起
elif test_type ==3: #新目标测试
prompt = TM.LLMM.build_initial_prompt("192.168.204.137","")
if prompt:
instr_list = TM.LLMM.get_llm_instruction(prompt,TM.DBM)
TM.instr_in_quere(instr_list) # 指令入队列问题不大,任务执行线程没有起
else:
#完整过程测试---要设定终止条件
pass