Files
CoM-covert_sd_card_tool/covert_sd_card_tool.py
T
2024-11-09 12:18:36 -05:00

587 lines
22 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import subprocess
import sys
import os
import shutil
from datetime import datetime
import time
import json
# Global variables
DEBUG = False
FAST_MODE = False
TIMESTAMP = datetime.now().strftime('%Y%m%d_%H%M%S')
LOG_FILE = f"covert_sd_setup_{TIMESTAMP}.log"
CREATE_KALI = False
CREATE_DOCS = False
CREATE_TAILS = False
KALI_ISO = ""
TAILS_ISO = ""
DRIVE = ""
def log(message):
with open(LOG_FILE, "a") as log_file:
log_file.write(message + "\n")
print(message)
def run_command(command, shell=False, interactive=False):
if DEBUG:
log(f"Running command: {command}")
try:
if interactive:
subprocess.run(command, shell=shell, check=True)
else:
result = subprocess.run(
command,
shell=shell,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
if result.stdout:
log(result.stdout.strip())
if result.stderr:
log(result.stderr.strip())
except subprocess.CalledProcessError as e:
log(f"Command failed: {e}\nOutput: {e.stdout}\nError: {e.stderr}")
sys.exit(1)
def check_dependencies():
dependencies = ["parted", "cryptsetup", "lsblk", "dd", "sgdisk", "wipefs", "bc", "fdisk", "veracrypt", "lsof", "fuser", "mountpoint", "udevadm"]
missing = []
for dep in dependencies:
if not shutil.which(dep):
missing.append(dep)
if missing:
log(f"Missing dependencies: {', '.join(missing)}")
install = input(f"Do you want to install the missing dependencies? (y/n) [Default: y]: ") or "y"
if install.lower() == "y":
run_command(["sudo", "apt", "update"])
run_command(["sudo", "apt", "install", "-y"] + missing)
else:
log("Cannot proceed without installing dependencies. Exiting.")
sys.exit(1)
def list_drives():
log("Available drives:")
result = subprocess.run(["lsblk", "-J", "-o", "NAME,SIZE,TYPE"], capture_output=True, text=True)
lsblk_output = json.loads(result.stdout)
for device in lsblk_output['blockdevices']:
if device['type'] == 'disk':
name = device['name']
size = device['size']
drive = f"/dev/{name} {size}"
log(drive)
def get_partition_name(drive, partition_number):
if 'nvme' in drive or 'mmcblk' in drive:
return f"{drive}p{partition_number}"
else:
return f"{drive}{partition_number}"
def prepare_drive(drive):
result = subprocess.run(["lsblk", "-lnp", drive], capture_output=True, text=True)
for line in result.stdout.strip().splitlines():
parts = line.strip().split()
if len(parts) >= 7 and parts[6]: # If mountpoint is not empty
part = parts[0]
log(f"Unmounting {part}...")
run_command(["sudo", "umount", "-l", part])
with open("/proc/swaps") as swaps_file:
for line in swaps_file:
if drive in line:
swap_part = line.strip().split()[0]
log(f"Disabling swap on {swap_part}...")
run_command(["sudo", "swapoff", swap_part])
log(f"Checking for processes using {drive}...")
result = subprocess.run(["sudo", "lsof", drive], capture_output=True, text=True)
if result.stdout.strip():
log(f"Processes using {drive}:\n{result.stdout}")
kill = input(f"Do you want to kill these processes? (y/n) [Default: y]: ") or "y"
if kill.lower() == "y":
run_command(["sudo", "fuser", "-k", drive])
log(f"Killed processes using {drive}.")
else:
log("Cannot proceed while processes are using the drive. Exiting.")
sys.exit(1)
else:
log(f"No processes are using {drive}.")
def setup_usb():
global DRIVE
log("Setting up bootable USB or preparing partitions...")
list_drives()
DRIVE = input("Enter the drive to use for USB (e.g., /dev/sda) [Default: /dev/sda]: ") or "/dev/sda"
confirm = input(f"You have selected {DRIVE}. Is this correct? (y/n) [Default: y]: ") or "y"
if confirm.lower() != "y":
log("Drive selection canceled. Exiting.")
sys.exit(1)
prepare_drive(DRIVE)
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
wipe = input(f"Do you want to wipe the drive {DRIVE} before starting? (y/n) [Default: n]: ") or "n"
if wipe.lower() == "y":
log(f"Wiping {DRIVE} and clearing any existing file system or encryption signatures...")
run_command(["sudo", "wipefs", "--all", DRIVE])
run_command(["sudo", "sgdisk", "--zap-all", DRIVE])
run_command(["sudo", "dd", "if=/dev/zero", f"of={DRIVE}", "bs=1M", "count=10"])
log(f"{DRIVE} wiped successfully.")
# Initialize variables to track if ISO has been written
iso_written = False
if CREATE_KALI or CREATE_TAILS:
global KALI_ISO, TAILS_ISO
if CREATE_KALI:
if not KALI_ISO:
KALI_ISO = input("Enter the path to the Kali ISO file: ")
if not os.path.isfile(KALI_ISO):
log(f"Error: Kali ISO file not found at {KALI_ISO}")
sys.exit(1)
ISO_PATH = KALI_ISO
elif CREATE_TAILS:
if not TAILS_ISO:
TAILS_ISO = input("Enter the path to the Tails ISO file: ")
if not os.path.isfile(TAILS_ISO):
log(f"Error: Tails ISO file not found at {TAILS_ISO}")
sys.exit(1)
ISO_PATH = TAILS_ISO
log(f"Writing ISO to {DRIVE}...")
run_command(f"sudo dd if='{ISO_PATH}' of='{DRIVE}' bs=64M status=progress", shell=True, interactive=True)
log(f"ISO written to {DRIVE} successfully.")
iso_written = True
# After writing ISO, set up partitions accordingly
if iso_written:
if CREATE_KALI:
fix_partition_table()
if CREATE_TAILS:
fix_partition_table_tails()
# If documents partition is requested, set it up
if CREATE_DOCS and not (CREATE_KALI or CREATE_TAILS):
# If not setting up OS bootable USB, proceed directly
fix_partition_table_docs_only()
elif CREATE_DOCS and (CREATE_KALI or CREATE_TAILS):
# If setting up OS bootable USB, documents partition is handled in fix_partition_table() or fix_partition_table_tails()
# Depending on the specific needs, you might want to call fix_partition_table_docs_only() here
# Let's call it to ensure documents partition is created
fix_partition_table_docs_only()
def fix_partition_table_docs_only():
log("Setting up partitions for documents only...")
# Clear existing partitions if any
run_command(f"sudo parted -a optimal -s {DRIVE} mklabel gpt", shell=True)
run_command(f"sudo partprobe {DRIVE}", shell=True)
run_command("sudo udevadm settle", shell=True)
time.sleep(5) # Increased sleep to ensure partitions are recognized
# Get the total size of the drive in bytes
result = subprocess.run(["lsblk", "-b", "-n", "-o", "SIZE", DRIVE], capture_output=True, text=True)
try:
total_size_bytes = int(result.stdout.strip())
except ValueError:
log("Error: Unable to determine drive size.")
sys.exit(1)
total_size_mib = total_size_bytes / (1024 * 1024) # Convert to MiB
# Ask for document partition size
size_docs = input("Enter size for documents partition in GB (leave blank to use remaining space minus 1GB): ")
start_docs_mib = 1 # Starting immediately after the first MiB
if size_docs:
try:
size_docs_gb = float(size_docs)
end_docs_mib = start_docs_mib + (size_docs_gb * 1024)
if end_docs_mib > (total_size_mib - 1024):
log("Error: Documents partition size exceeds available space when reserving 1GB for unencrypted partition.")
sys.exit(1)
except ValueError:
log("Invalid size entered for documents partition. Exiting.")
sys.exit(1)
else:
end_docs_mib = total_size_mib - 1024 # Reserve 1GB for unencrypted partition
# Create documents partition
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_docs_mib}MiB {end_docs_mib}MiB", shell=True)
log("Created documents partition.")
# Create unencrypted partition
start_unencrypted_mib = end_docs_mib
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_unencrypted_mib}MiB 100%", shell=True)
log("Created unencrypted partition for scripts/instructions.")
# Refresh partition table to recognize new partitions
run_command(f"sudo partprobe {DRIVE}", shell=True)
run_command("sudo udevadm settle", shell=True)
time.sleep(5) # Increased sleep to ensure partitions are recognized
setup_unencrypted_partition()
setup_docs_partition()
def fix_partition_table():
log("Fixing partition table to reclaim remaining space...")
# Attempt to delete partition 2 if it exists
try:
run_command(f"sudo parted -a optimal -s {DRIVE} rm 2", shell=True)
log("Deleted partition 2.")
except SystemExit:
log("No partition 2 to delete.")
# Get the end of partition 1
result = subprocess.run(["sudo", "parted", "-s", DRIVE, "unit", "MiB", "print"], capture_output=True, text=True)
end_of_p1 = None
for line in result.stdout.strip().splitlines():
if line.strip().startswith("1"):
parts = line.strip().split()
if len(parts) >= 3:
end_of_p1 = parts[2].replace('MiB', '')
break
if end_of_p1 is None:
log("Error: Could not find end of partition 1.")
sys.exit(1)
log(f"End of partition 1: {end_of_p1}MiB")
# Get the total size of the drive in bytes
result = subprocess.run(["lsblk", "-b", "-n", "-o", "SIZE", DRIVE], capture_output=True, text=True)
try:
total_size_bytes = int(result.stdout.strip())
except ValueError:
log("Error: Unable to determine drive size.")
sys.exit(1)
total_size_mib = total_size_bytes / (1024 * 1024) # Convert to MiB
# Ask for persistence partition size
size_persistence = input("Enter size for persistence partition in GB (e.g., 4): ") or "4"
try:
size_persistence_gb = float(size_persistence)
except ValueError:
log("Invalid size entered for persistence partition. Exiting.")
sys.exit(1)
start_persistence_mib = float(end_of_p1)
end_persistence_mib = start_persistence_mib + (size_persistence_gb * 1024)
if end_persistence_mib > total_size_mib:
log("Error: Persistence partition size exceeds available space.")
sys.exit(1)
# Create persistence partition
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_persistence_mib}MiB {end_persistence_mib}MiB", shell=True)
log("Created persistence partition.")
# Set up documents partition
start_docs_mib = end_persistence_mib
size_docs = input("Enter size for documents partition in GB (leave blank to use remaining space minus 1GB): ")
if size_docs:
try:
size_docs_gb = float(size_docs)
end_docs_mib = start_docs_mib + (size_docs_gb * 1024)
if end_docs_mib > (total_size_mib - 1024):
log("Error: Documents partition size exceeds available space when reserving 1GB for unencrypted partition.")
sys.exit(1)
except ValueError:
log("Invalid size entered for documents partition. Exiting.")
sys.exit(1)
else:
end_docs_mib = total_size_mib - 1024 # Reserve 1GB for unencrypted partition
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_docs_mib}MiB {end_docs_mib}MiB", shell=True)
log("Created documents partition.")
# Create unencrypted partition
start_unencrypted_mib = end_docs_mib
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary {start_unencrypted_mib}MiB 100%", shell=True)
log("Created unencrypted partition for scripts/instructions.")
# Refresh partition table to recognize new partitions
run_command(f"sudo partprobe {DRIVE}", shell=True)
run_command("sudo udevadm settle", shell=True)
time.sleep(5) # Increased sleep to ensure partitions are recognized
setup_kali_partition()
if CREATE_DOCS:
setup_docs_partition()
setup_unencrypted_partition()
def fix_partition_table_tails():
log("Setting up partition table for Tails...")
# Clear existing partitions if any
run_command(f"sudo parted -a optimal -s {DRIVE} mklabel gpt", shell=True)
run_command(f"sudo partprobe {DRIVE}", shell=True)
run_command("sudo udevadm settle", shell=True)
time.sleep(5) # Increased sleep to ensure partitions are recognized
# Tails typically does not require a persistence partition, but we'll create an unencrypted partition for scripts/instructions
run_command(f"sudo parted -a optimal -s {DRIVE} mkpart primary 1MiB 100%", shell=True)
log("Created unencrypted partition for scripts/instructions.")
# Refresh partition table to recognize new partitions
run_command(f"sudo partprobe {DRIVE}", shell=True)
run_command("sudo udevadm settle", shell=True)
time.sleep(5)
setup_unencrypted_partition()
def setup_kali_partition():
global DRIVE
PERSIST_PART = get_partition_name(DRIVE, 2)
# Check if partition exists
if not os.path.exists(PERSIST_PART):
log(f"Error: Partition {PERSIST_PART} does not exist.")
sys.exit(1)
run_command(["sudo", "wipefs", "--all", PERSIST_PART])
log("Configuring encrypted persistence partition...")
if FAST_MODE:
luks_format_cmd = (
f"sudo cryptsetup luksFormat '{PERSIST_PART}' "
f"--type luks1 "
f"--cipher aes-cbc-essiv:sha256 "
f"--key-size 256 "
f"--hash sha256 "
f"--iter-time 1000"
)
mkfs_cmd = f"sudo mkfs.ext3 -L persistence /dev/mapper/kali_USB"
else:
luks_format_cmd = (
f"sudo cryptsetup luksFormat '{PERSIST_PART}' "
f"--cipher aes-xts-plain64 "
f"--key-size 512 "
f"--hash sha512 "
f"--iter-time 5000"
)
mkfs_cmd = f"sudo mkfs.ext4 -L persistence /dev/mapper/kali_USB"
run_command(luks_format_cmd, shell=True, interactive=True)
time.sleep(2)
run_command(f"sudo cryptsetup luksOpen '{PERSIST_PART}' kali_USB", shell=True, interactive=True)
run_command(mkfs_cmd, shell=True)
run_command("sudo mkdir -p /mnt/kali_USB", shell=True)
run_command("sudo mount /dev/mapper/kali_USB /mnt/kali_USB", shell=True)
run_command('echo "/ union" | sudo tee /mnt/kali_USB/persistence.conf', shell=True)
run_command("sudo umount /mnt/kali_USB", shell=True)
run_command("sudo cryptsetup luksClose kali_USB", shell=True)
log("Kali persistence setup complete.")
def setup_docs_partition():
global DRIVE
DOCS_PART = get_partition_name(DRIVE, get_last_partition_number() - 1)
# Check if the partition exists
if not os.path.exists(DOCS_PART):
log(f"Error: Partition {DOCS_PART} does not exist.")
sys.exit(1)
run_command(["sudo", "wipefs", "--all", DOCS_PART])
log("Configuring VeraCrypt encryption for documents partition...")
if FAST_MODE:
veracrypt_create_cmd = (
f"veracrypt --text --create '{DOCS_PART}' "
f"--encryption AES "
f"--hash SHA-256 "
f"--filesystem exfat "
f"--volume-type normal "
f"--quick "
)
else:
veracrypt_create_cmd = (
f"veracrypt --text --create '{DOCS_PART}' "
f"--encryption AES-Twofish-Serpent "
f"--hash whirlpool "
f"--filesystem exfat "
f"--volume-type normal "
)
run_command(veracrypt_create_cmd, shell=True, interactive=True)
log("Encrypted documents partition setup complete.")
def setup_unencrypted_partition():
global DRIVE
UNENCRYPTED_PART = get_partition_name(DRIVE, get_last_partition_number())
# Check if the partition exists
if not os.path.exists(UNENCRYPTED_PART):
log(f"Error: Partition {UNENCRYPTED_PART} does not exist.")
sys.exit(1)
log(f"Attempting to format partition {UNENCRYPTED_PART} with FAT32 filesystem.")
run_command(f"sudo mkfs.vfat -n 'TOOLS' {UNENCRYPTED_PART}", shell=True)
log("Formatted unencrypted partition with FAT32 filesystem.")
run_command("sudo mkdir -p /mnt/unencrypted", shell=True)
run_command(f"sudo mount {UNENCRYPTED_PART} /mnt/unencrypted", shell=True)
instructions = f"""
To mount the encrypted documents partition, use the provided 'mount_encrypted_partitions.sh' script.
To unmount and lock it, use the 'cleanup_encrypted_partitions.sh' script.
**Automount Script:**
Run: sudo ./mount_encrypted_partitions.sh
**Cleanup Script:**
Run: sudo ./cleanup_encrypted_partitions.sh
"""
with open("/tmp/README.txt", "w") as readme_file:
readme_file.write(instructions)
run_command("sudo cp /tmp/README.txt /mnt/unencrypted/README.txt", shell=True)
run_command("sudo rm /tmp/README.txt", shell=True)
log("Created README.txt with mounting instructions.")
mount_script = """#!/bin/bash
# Script to mount encrypted documents partition
echo "Available drives:"
lsblk -o NAME,SIZE,TYPE | grep disk
read -p "Enter the drive path for the documents partition (default: /dev/sdc1): " DRIVE_PATH
DRIVE_PATH=${DRIVE_PATH:-/dev/sdc1}
if [ -b "$DRIVE_PATH" ]; then
echo "Mounting VeraCrypt documents partition at $DRIVE_PATH..."
sudo mkdir -p /mnt/veracrypt_docs
sudo veracrypt --text --mount "$DRIVE_PATH" /mnt/veracrypt_docs
echo "Documents partition mounted at /mnt/veracrypt_docs."
else
echo "Error: Partition $DRIVE_PATH not found."
fi
"""
with open("/tmp/mount_encrypted_partitions.sh", "w") as script_file:
script_file.write(mount_script)
run_command("sudo cp /tmp/mount_encrypted_partitions.sh /mnt/unencrypted/mount_encrypted_partitions.sh", shell=True)
run_command("sudo chmod +x /mnt/unencrypted/mount_encrypted_partitions.sh", shell=True)
run_command("sudo rm /tmp/mount_encrypted_partitions.sh", shell=True)
log("Created mount_encrypted_partitions.sh script.")
cleanup_script = """#!/bin/bash
# Script to unmount and lock encrypted documents partition
echo "Available drives:"
lsblk -o NAME,SIZE,TYPE | grep disk
read -p "Enter the drive path for the documents partition (default: /dev/sdc1): " DRIVE_PATH
DRIVE_PATH=${DRIVE_PATH:-/dev/sdc1}
echo "Unmounting and locking encrypted documents partition at $DRIVE_PATH..."
if mountpoint -q /mnt/veracrypt_docs; then
sudo veracrypt --text --dismount /mnt/veracrypt_docs
echo "VeraCrypt documents partition unmounted."
else
echo "Documents partition is not currently mounted."
fi
"""
with open("/tmp/cleanup_encrypted_partitions.sh", "w") as script_file:
script_file.write(cleanup_script)
run_command("sudo cp /tmp/cleanup_encrypted_partitions.sh /mnt/unencrypted/cleanup_encrypted_partitions.sh", shell=True)
run_command("sudo chmod +x /mnt/unencrypted/cleanup_encrypted_partitions.sh", shell=True)
run_command("sudo rm /tmp/cleanup_encrypted_partitions.sh", shell=True)
log("Created cleanup_encrypted_partitions.sh script.")
run_command("sudo umount /mnt/unencrypted", shell=True)
log("Unencrypted partition setup complete.")
def get_last_partition_number():
"""Returns the highest partition number on the DRIVE."""
result = subprocess.run(["lsblk", "-ln", "-o", "NAME", DRIVE], capture_output=True, text=True)
partitions = [line.strip() for line in result.stdout.strip().splitlines() if line.strip()]
partition_numbers = []
for part in partitions:
if 'p' in part:
# Handle /dev/nvme0n1p1 format
if part.startswith(os.path.basename(DRIVE)):
num = part.replace(os.path.basename(DRIVE), '').replace('p', '')
if num.isdigit():
partition_numbers.append(int(num))
else:
# Handle /dev/sda1 format
if part.startswith(os.path.basename(DRIVE)):
num = part.replace(os.path.basename(DRIVE), '')
if num.isdigit():
partition_numbers.append(int(num))
if not partition_numbers:
log(f"No partitions found on {DRIVE}.")
sys.exit(1)
return max(partition_numbers)
def main():
global DEBUG, FAST_MODE, CREATE_KALI, CREATE_DOCS, CREATE_TAILS, KALI_ISO, TAILS_ISO, DRIVE
parser = argparse.ArgumentParser(description="Covert SD Card Tool")
parser.add_argument("-a", "--all", action="store_true", help="Set up both OS bootable USB and documents partition")
parser.add_argument("-k", "--kali", action="store_true", help="Create Kali bootable USB and persistence partition")
parser.add_argument("-d", "--docs", action="store_true", help="Create encrypted documents partition")
parser.add_argument("-t", "--tails", action="store_true", help="Create Tails bootable USB (no persistence)")
parser.add_argument("-i", "--iso", help="Path to the Kali or Tails ISO file")
parser.add_argument("--fast", action="store_true", help="Enable fast setup with less secure encryption")
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
args = parser.parse_args()
if not any([args.all, args.kali, args.docs, args.tails]):
parser.print_help()
sys.exit(1)
DEBUG = args.debug
if DEBUG:
log("Debug mode enabled")
FAST_MODE = args.fast
if FAST_MODE:
log("Fast mode enabled: Using less secure encryption for quicker setup.")
if args.all:
CREATE_DOCS = True
if args.tails:
CREATE_TAILS = True
else:
CREATE_KALI = True
else:
CREATE_KALI = args.kali
CREATE_DOCS = args.docs
CREATE_TAILS = args.tails
if args.iso:
if CREATE_KALI:
KALI_ISO = args.iso
elif CREATE_TAILS:
TAILS_ISO = args.iso
check_dependencies()
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
setup_usb()
else:
list_drives()
DRIVE = input("Enter the drive to use (e.g., /dev/sda) [Default: /dev/sda]: ") or "/dev/sda"
prepare_drive(DRIVE)
if CREATE_DOCS:
fix_partition_table_docs_only()
else:
setup_unencrypted_partition()
log("Partition setup complete.")
if __name__ == "__main__":
main()