mirror of
https://github.com/norandom/log2ml.git
synced 2026-10-20 08:49:27 +00:00
25 KiB
25 KiB
In [ ]:
import requests
import pandas as pd
import json
# Function to recursively normalize nested columns in a DataFrame
def recursively_normalize(data):
df = pd.json_normalize(data)
while True:
nested_cols = [col for col in df.columns if isinstance(df[col].iloc[0], (dict, list))]
if not nested_cols:
break
for col in nested_cols:
if isinstance(df[col].iloc[0], dict):
normalized = pd.json_normalize(df[col])
df = df.drop(columns=[col]).join(normalized)
elif isinstance(df[col].iloc[0], list):
df = df.explode(col)
normalized = pd.json_normalize(df[col])
df = df.drop(columns=[col]).join(normalized)
return df
# Function to fetch the next batch using the cursor
def fetch_next_batch(cursor):
response = requests.post(
f"{base_url}/_sql?format=json",
headers={"Content-Type": "application/json"},
json={"cursor": cursor}
).json()
return response
# Elasticsearch base URL
base_url = "http://192.168.20.106:9200"
# Index name
index = "winlogbeat-*"
from datetime import datetime, timedelta
# Calculate the current time and the time one hour ago
current_time = datetime.utcnow()
one_hour_ago = current_time - timedelta(hours=1)
# Format times in ISO8601 format as expected by Elasticsearch
current_time_iso = current_time.strftime('%Y-%m-%dT%H:%M:%SZ')
one_hour_ago_iso = one_hour_ago.strftime('%Y-%m-%dT%H:%M:%SZ')
# SQL query with time filter
sql_query = f"""
SELECT "@timestamp", host.hostname, host.ip, log.level, winlog.event_id, winlog.task, message
FROM "winlogbeat-7.10.0-2024.06.23-*"
WHERE host.hostname = 'win10'
AND winlog.provider_name = 'Microsoft-Windows-Sysmon'
AND "@timestamp" >= '{one_hour_ago_iso}'
AND "@timestamp" <= '{current_time_iso}'
"""
# Initial search request to start scrolling
initial_response = requests.post(
f"{base_url}/_sql?format=json",
headers={"Content-Type": "application/json"},
json={
"query": sql_query,
"field_multi_value_leniency": True
}
).json()
# Extract the cursor for scrolling
cursor = initial_response.get('cursor')
rows = initial_response.get('rows')
columns = [col['name'] for col in initial_response['columns']]
# Initialize CSV file (assumes the first batch is not empty)
if rows:
df = pd.DataFrame(rows, columns=columns)
df = recursively_normalize(df.to_dict(orient='records'))
df.to_csv("lab_logs_blindtest_activity.csv", mode='w', index=False, header=True)
# Track total documents retrieved
total_documents_retrieved = len(rows)
print(f"Retrieved {total_documents_retrieved} documents.")
# Loop to fetch subsequent batches of documents until no more documents are left
while cursor:
# Fetch next batch of documents using cursor
response = fetch_next_batch(cursor)
# Update cursor for the next batch
cursor = response.get('cursor')
rows = response.get('rows')
# If no rows, break out of the loop
if not rows:
break
# Normalize data and append to CSV
df = pd.DataFrame(rows, columns=columns)
df = recursively_normalize(df.to_dict(orient='records'))
# Append to CSV file without headers
df.to_csv("lab_logs_blindtest_activity.csv", mode='a', index=False, header=False)
# Convert DataFrame to JSON, line by line
json_lines = df.to_json(orient='records', lines=True).splitlines()
# Append each line to an existing JSON file
with open("lab_logs_blindtest_activity.json", 'a') as file:
for line in json_lines:
file.write(line + '\n') # Append each line and add a newline
# Update total documents retrieved
total_documents_retrieved += len(rows)
print(f"Retrieved {total_documents_retrieved} documents.")
print("Files have been written.")In [ ]:
import polars as pl
# Define the path to your CSV file
csv_file_path = 'lab_logs_blindtest_activity.csv'
# Load the CSV file into a DataFrame
df = pl.read_csv(csv_file_path)
# Show the DataFrame to confirm it's loaded correctly
print(df)
In [ ]:
def remove_keyword_lines(batch, keywords):
def modify_line(line):
# Check each keyword; filter the line if the keyword is at the start followed by a colon
for keyword in keywords:
if line.startswith(f"{keyword}:"):
# Special handling for 'User' keyword
if keyword == 'User':
parts = line.split('\\')
if len(parts) > 1:
return f"User: {parts[1]}" # Only keep the part after the backslash
elif keyword == 'SourceHostname':
parts = line.split('.')
if len(parts) > 0:
return f"{keyword}: {parts[0].split(': ')[1]}" # Only keep the part before the first dot, remove keyword duplication
return None # For other keywords, remove the line altogether
return line # Return the line unchanged if no keyword conditions are met
# Use map_elements to apply a function to each message in the batch
return batch.map_elements(lambda message: '\n'.join(
filter(None, (modify_line(line) for line in message.split('\n')))),
return_dtype=pl.Utf8)
# keywords to filter or process
keywords_to_filter = ["UtcTime", "SourceProcessGUID","ProcessGuid", "TargetProcessGUID", "TargetObject", "FileVersion", "Hashes", "LogonGuid", "LogonId", "CreationUtcTime", "User", "ParentProcessGuid", "SourceHostname"]
# Load the DataFrame (assuming 'df' is already loaded)
# Apply the transformation to the 'message' column using map_batches
df_f = df.with_columns(
pl.col("message").map_batches(lambda batch: remove_keyword_lines(batch, keywords_to_filter), return_dtype=pl.Utf8).alias("filtered_message")
)
# Assuming df_f is your DataFrame with the 'filtered_message' column
# Fetch the first three rows from the 'filtered_message' column
first_messages = df_f["filtered_message"].head(200)
# Print each message completely
for i, message in enumerate(first_messages):
print(f"Message {i+1}:")
print(message)
print("-" * 50) # Separator for readability
In [ ]:
# Assuming df_f is your modified DataFrame with all necessary columns including 'filtered_message'
# Select specific columns from the DataFrame
selected_columns_df = df_f.select(["log.level", "winlog.event_id", "winlog.task","filtered_message"])
# Write the selected columns to a CSV file
selected_columns_df.write_csv('lab_logs_blindtest_activity_filtered.csv')
In [ ]:
selected_columns_df.head(5)In [ ]:
# Create an index series directly
index_series = pl.Series("index", range(selected_columns_df.height))
# Insert the index series as the first column using the recommended method
selected_columns_df = selected_columns_df.insert_column(0, index_series)
# Write the DataFrame to a CSV file, including the new index column
selected_columns_df.write_csv('lab_logs_blindtest_activity_filtered.csv')
In [ ]:
%conda install numpy scipy scikit-learn pandas joblib pytorchIn [ ]:
%pip install deap update_checker tqdm stopit xgboostIn [ ]:
%pip install tpotIn [ ]:
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
import polars as pl
import re
from transformers import BertTokenizer, BertModel
import torch
from tpot import TPOTClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoderIn [ ]:
# Extract relevant information using regular expressions
def extract_info(text):
image = re.search(r"Image: (.*?\.exe)", text, re.IGNORECASE)
target_filename = re.search(r"TargetFilename: (.*?\.exe)", text, re.IGNORECASE)
return {
"image": image.group(1) if image else "",
"target_filename": target_filename.group(1) if target_filename else "",
"text": text
}In [ ]:
# Apply extraction to the Polars DataFrame using map_elements
selected_columns_df = selected_columns_df.with_columns(
pl.col("filtered_message").map_elements(lambda x: extract_info(x), return_dtype=pl.Object).alias("extracted_info")
)In [ ]:
# Extract fields from the extracted_info column using map_elements with return_dtype
selected_columns_df = selected_columns_df.with_columns(
pl.col("extracted_info").map_elements(lambda x: x['image'], return_dtype=pl.Utf8).alias("image"),
pl.col("extracted_info").map_elements(lambda x: x['target_filename'], return_dtype=pl.Utf8).alias("target_filename"),
pl.col("extracted_info").map_elements(lambda x: x['text'], return_dtype=pl.Utf8).alias("text")
).drop("extracted_info")In [ ]:
print(selected_columns_df)In [ ]:
def define_label(row):
conditions = {
("EXCEL.EXE" in row['image'] and ".exe" in row['target_filename']): "bad",
(row['index'] == 874): "bad",
# Add more conditions here if needed
}
return conditions.get(True, "good")In [ ]:
# Apply the define_label function
selected_columns_df = selected_columns_df.with_columns(
pl.struct(["index", "image", "target_filename"]).map_elements(define_label, return_dtype=pl.Utf8).alias("label")
)In [ ]:
print(selected_columns_df)In [ ]:
bad_rows = selected_columns_df.filter(pl.col("label") == "bad")
print(bad_rows)In [ ]:
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
def vectorize_text(text):
inputs = tokenizer(text, return_tensors='pt', truncation=True, padding=True)
outputs = model(**inputs)
return outputs.last_hidden_state.mean(dim=1).detach().numpy()
# Apply vectorization to the Polars DataFrame using map_elements
selected_columns_df = selected_columns_df.with_columns(
pl.col("text").map_elements(lambda x: vectorize_text(x).flatten(), return_dtype=pl.Object).alias("text_vector")
)
print(selected_columns_df)In [ ]:
df = selected_columns_df.to_pandas()
# Save the Pandas DataFrame to a Parquet file
df.to_parquet("vectorized_texts.parquet")In [ ]:
import pandas as pd
# Load the DataFrame from the Parquet file
loaded_df = pd.read_parquet("vectorized_texts.parquet")
# Verify the loaded DataFrame
print(loaded_df)In [ ]:
import os
import pandas as pd
import torch
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from tpot import TPOTClassifier
# Load the DataFrame from the Parquet file
df = pd.read_parquet("vectorized_texts.parquet")
# Ensure to use only CPU for PyTorch
device = torch.device("cpu")
# Encode labels
le = LabelEncoder()
df['label_encoded'] = le.fit_transform(df['label'])
# Split data
X_train, X_test, y_train, y_test = train_test_split(df['text_vector'].tolist(), df['label_encoded'], test_size=0.2, random_state=42)
# Convert lists to numpy arrays
X_train = torch.tensor(X_train, device=device).numpy()
X_test = torch.tensor(X_test, device=device).numpy()
# TPOT classifier with higher verbosity
tpot = TPOTClassifier(verbosity=3, generations=5, population_size=20)
tpot.fit(X_train, y_train)
# Evaluate the model
print("TPOT Score:", tpot.score(X_test, y_test))
# Save the trained model
tpot.export('tpot_pipeline.py')
# Print the exported pipeline
with open('tpot_pipeline.py') as f:
print(f.read())
# Example of using the trained model
predictions = tpot.predict(X_test)
print("Predictions:", predictions)
In [ ]:
print("The accuracy of the best model is: ", tpot.score(X_test, y_test))
In [ ]:
%pip install matplotlibIn [ ]:
import os
import pandas as pd
import torch
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from tpot import TPOTClassifier
from collections import Counter
# Load the DataFrame from the Parquet file
df = pd.read_parquet("vectorized_texts.parquet")
# Ensure to use only CPU for PyTorch
device = torch.device("cpu")
# Encode labels
le = LabelEncoder()
df['label_encoded'] = le.fit_transform(df['label'])
# Split data
X_train, X_test, y_train, y_test = train_test_split(df['text_vector'].tolist(), df['label_encoded'], test_size=0.2, random_state=42)
# Convert lists to numpy arrays
X_train = torch.tensor(X_train, device=device).numpy()
X_test = torch.tensor(X_test, device=device).numpy()
# TPOT classifier with higher verbosity
tpot = TPOTClassifier(verbosity=3, generations=5, population_size=20)
tpot.fit(X_train, y_train)
# Evaluate the model
print("TPOT Score:", tpot.score(X_test, y_test))
# Save the trained model
tpot.export('tpot_pipeline.py')
# Print the exported pipeline
with open('tpot_pipeline.py') as f:
print(f.read())
# Example of using the trained model
predictions = tpot.predict(X_test)
print("Predictions:", predictions)
# Extract information about models tested
evaluated_pipelines = tpot.evaluated_individuals_
In [ ]:
# Count occurrences of each model type
model_counter = Counter()
for pipeline_str in evaluated_pipelines.keys():
models = re.findall(r'\w+\(.*?\)', pipeline_str)
for model in models:
model_name = model.split('(')[0]
model_counter[model_name] += 1
print("Models and their occurrences:")
for model, count in model_counter.items():
print(f"{model}: {count}")
# Visualize the count of different models
import matplotlib.pyplot as plt
model_names = list(model_counter.keys())
model_counts = list(model_counter.values())
plt.figure(figsize=(12, 6))
plt.barh(model_names, model_counts, color='skyblue')
plt.xlabel('Number of Occurrences')
plt.ylabel('Model')
plt.title('Frequency of Models Tested by TPOT')
plt.show()In [ ]: