Загрузить файлы в «src»
This commit is contained in:
21
src/ai_analyser.py
Normal file
21
src/ai_analyser.py
Normal file
@@ -0,0 +1,21 @@
|
||||
def analyze_threat(self, packet_text, context):
|
||||
prompt = f"""
|
||||
ROLE: Senior CyberSecurity Researcher (Wireless Networks).
|
||||
DATA: Current packet: {packet_text}
|
||||
HISTORY_CONTEXT: {context}
|
||||
|
||||
TASK:
|
||||
1. Проверь пакет на признаки известных атак:
|
||||
- Deauthentication Flood (уязвимость 802.11w)
|
||||
- Rogue AP / Evil Twin (несоответствие RSSI/MAC)
|
||||
- WPA Handshake sniffing (EAPOL flow)
|
||||
- WPS Pixie Dust / Brute Force
|
||||
2. Если это атака, укажи её название и CVE (если есть).
|
||||
3. Оцени риск по шкале от 1 до 10.
|
||||
4. Предложи команду для исправления (например, 'enable 802.11w' или 'disable WPS').
|
||||
|
||||
ОТВЕТЬ КРАТКО И ТЕХНИЧЕСКИ ТОЧНО.
|
||||
"""
|
||||
# Вызов Ollama API...
|
||||
# Временная заглушка - в реальном приложении здесь будет вызов API
|
||||
return "Анализ не реализован в текущей версии"
|
||||
14
src/embedder.py
Normal file
14
src/embedder.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import requests
|
||||
import os
|
||||
|
||||
class Embedder:
|
||||
def __init__(self, model_name="qwen3-embedding:8b"):
|
||||
self.model_name = model_name
|
||||
self.ollama_url = os.getenv("OLLAMA_URL", "http://localhost:11434")
|
||||
|
||||
def get_vector(self, text):
|
||||
response = requests.post(
|
||||
f"{self.ollama_url}/api/embeddings",
|
||||
json={"model": self.model_name, "prompt": text}
|
||||
)
|
||||
return response.json()["embedding"]
|
||||
66
src/main.py
Normal file
66
src/main.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import sys
|
||||
import uuid
|
||||
import json
|
||||
import socket
|
||||
from scapy.all import sniff
|
||||
import os
|
||||
from parser import PacketParser
|
||||
from embedder import Embedder
|
||||
from vector_store import VectorDB
|
||||
from ai_analyser import AIAnalyser
|
||||
|
||||
# Настройки моделей из вашего списка
|
||||
EMBEDDING_MODEL = "qwen3-embedding:8b"
|
||||
ANALYSIS_MODEL = "qwen3.5:35b-a3b" # или Qwen3-Coder для глубокого тех-анализа
|
||||
|
||||
# Инициализация
|
||||
embedder = Embedder(model_name=EMBEDDING_MODEL)
|
||||
db = VectorDB(collection_name="wifi_lab", vector_size=4096) # Размерность Qwen 8B
|
||||
ai = AIAnalyser()
|
||||
parser = PacketParser()
|
||||
|
||||
def process_packet(pkt):
|
||||
# 1. Извлекаем признаки
|
||||
text_desc = parser.parse_to_text(pkt)
|
||||
if not text_desc: return
|
||||
|
||||
# 2. Генерируем вектор через Ollama
|
||||
vector = embedder.get_vector(text_desc)
|
||||
|
||||
# 3. Ищем аномалии в Qdrant
|
||||
# Мы смотрим на "дистанцию". Если похожих векторов нет (score низкий),
|
||||
# значит поведение сети изменилось.
|
||||
search_results = db.find_similar(vector)
|
||||
|
||||
# Порог аномалии (экспериментально для Косинусного сходства < 0.7)
|
||||
is_anomaly = len(search_results) == 0 or search_results[0].score < 0.7
|
||||
|
||||
# 4. Сохраняем в Qdrant для истории
|
||||
db.add_packet(str(uuid.uuid4()), vector, {"subtype": pkt.subtype}, text_desc)
|
||||
|
||||
if is_anomaly:
|
||||
print(f"\n[!] ОБНАРУЖЕНА УЯЗВИМОСТЬ/АНОМАЛИЯ: {text_desc}")
|
||||
# 5. Анализ через мощную Qwen 35B
|
||||
context = [res.payload['text'] for res in search_results]
|
||||
report = ai.analyze_threat(text_desc, context)
|
||||
print(f"[AI REPORT]:\n{report}\n" + "-"*50)
|
||||
|
||||
def main():
|
||||
HOST = '0.0.0.0'
|
||||
PORT = 9999
|
||||
|
||||
print(f"[*] Анализатор слушает на {HOST}:{PORT}...")
|
||||
|
||||
# Создаем серверный сокет
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind((HOST, PORT))
|
||||
s.listen(1)
|
||||
conn, addr = s.accept()
|
||||
with conn:
|
||||
print(f"[*] Соединение установлено с {addr}")
|
||||
# Превращаем сокет в объект файла для Scapy
|
||||
fileobj = conn.makefile(mode='rb')
|
||||
sniff(opened_socket=fileobj, prn=process_packet, store=0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
31
src/parser.py
Normal file
31
src/parser.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from scapy.all import Dot11, Dot11Deauth, Dot11Beacon, raw
|
||||
|
||||
class PacketParser:
|
||||
@staticmethod
|
||||
def parse_to_text(pkt):
|
||||
"""Превращает пакет в текстовое описание для эмбеддинга"""
|
||||
if not pkt.haslayer(Dot11):
|
||||
return None
|
||||
|
||||
# Извлекаем базовые параметры
|
||||
info = {
|
||||
"type": pkt.type,
|
||||
"subtype": pkt.subtype,
|
||||
"addr1": pkt.addr1, # Получатель
|
||||
"addr2": pkt.addr2, # Отправитель
|
||||
"rssi": getattr(pkt, 'dBm_AntSignal', 'N/A') # Мощность сигнала
|
||||
}
|
||||
|
||||
# Определяем тип фрейма человеческим языком
|
||||
frame_types = {0: "Management", 1: "Control", 2: "Data"}
|
||||
type_str = frame_types.get(pkt.type, "Unknown")
|
||||
|
||||
# Формируем строку-описание
|
||||
text_desc = f"Type: {type_str}, Subtype: {pkt.subtype}, From: {info['addr2']}, To: {info['addr1']}, RSSI: {info['rssi']}"
|
||||
|
||||
# Добавляем часть полезной нагрузки (payload) если есть
|
||||
payload = raw(pkt.payload).hex()[:64]
|
||||
if payload:
|
||||
text_desc += f", Payload: {payload}"
|
||||
|
||||
return text_desc
|
||||
36
src/vector_store.py
Normal file
36
src/vector_store.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import os
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PointStruct
|
||||
|
||||
class VectorDB:
|
||||
def __init__(self, collection_name="wifi_lab", vector_size=4096):
|
||||
host = os.getenv("QDRANT_HOST", "localhost")
|
||||
port = int(os.getenv("QDRANT_PORT", 6333))
|
||||
self.client = QdrantClient(host=host, port=port)
|
||||
self.collection_name = collection_name
|
||||
|
||||
# Создаем коллекцию, если её нет (размерность 4096 для Qwen 8B Embedding)
|
||||
self.client.recreate_collection(
|
||||
collection_name=self.collection_name,
|
||||
vectors_config=VectorParams(size=vector_size, distance=Distance.COSINE),
|
||||
)
|
||||
|
||||
def add_packet(self, pkt_id, vector, metadata, text):
|
||||
self.client.upsert(
|
||||
collection_name=self.collection_name,
|
||||
points=[
|
||||
PointStruct(
|
||||
id=pkt_id,
|
||||
vector=vector,
|
||||
payload={"metadata": metadata, "text": text}
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def find_similar(self, vector):
|
||||
return self.client.search(
|
||||
collection_name=self.collection_name,
|
||||
query_vector=vector,
|
||||
limit=3,
|
||||
with_payload=True
|
||||
)
|
||||
Reference in New Issue
Block a user