832e46bf1d
polishing signal reception, creation of ap class, added time class,further work on logging and features. Hidden Dragon is unfinished, do not use.
235 lines
10 KiB
Python
235 lines
10 KiB
Python
# Copyright (c) 2024 Anoduck
|
|
#
|
|
# This software is released under the MIT License.
|
|
# https://opensource.org/licenses/MIT
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from configobj import ConfigObj, validate
|
|
from proclog import ProcLog
|
|
from parse_config import ParseConfig
|
|
from mac_purge import Purge
|
|
from attack import Attack
|
|
from hdragon import Dragon
|
|
from semver import Version
|
|
from .__version__ import version as _version
|
|
|
|
config_file = os.path.abspath("/etc/ctiger/config.ini")
|
|
|
|
|
|
class ProcArgs:
|
|
|
|
def process_args(self, args: argparse.Namespace, ap) -> None:
|
|
"""
|
|
Processes the command line arguments.
|
|
|
|
Args:
|
|
args (argparse.Namespace): The parsed command line arguments.
|
|
|
|
Returns:
|
|
None
|
|
"""
|
|
alog = ProcLog()
|
|
log = alog.get_log(args.log_file, args.log_level)
|
|
log.info('Started crouching tiger')
|
|
log.info('Started logger...')
|
|
match args.module:
|
|
case "att":
|
|
log.info('Starting attack formation...')
|
|
att = Attack()
|
|
att.attack(mondev=args.interface,
|
|
scan_file=args.scan_file,
|
|
net_file=args.net_file,
|
|
log=log)
|
|
case "mac":
|
|
log.info('Beginning Mac Purge')
|
|
log.debug('args: {0}'.format(args))
|
|
global valid_file
|
|
valid_file = args.valid_file
|
|
purge = Purge()
|
|
purge.mac_revealer(interface=args.name,
|
|
mon_type=args.mon_type,
|
|
valid_file=args.valid_file,
|
|
channels=args.channels,
|
|
log=log)
|
|
case "dragon":
|
|
log.info('Beginning Hidden Dragon')
|
|
log.debug('args: {0}'.format(args))
|
|
dragon = Dragon()
|
|
dragon.hidden_dragon(ap_iface=args.ap_iface,
|
|
netdb_file=args.netdb_file,
|
|
results=args.results,
|
|
config=args.config, log=log)
|
|
case _:
|
|
ap.print_help()
|
|
|
|
def main(self):
|
|
"""
|
|
Main function that executes the script.
|
|
|
|
This function performs the following tasks:
|
|
- Prints a stylized message using the `tprint` function.
|
|
- Checks if the script is being run as root.
|
|
- Sets up the `config` object.
|
|
- Sets up the `ap` argument parser.
|
|
- Parses the command line arguments.
|
|
- Calls the appropriate function based on the chosen action.
|
|
|
|
Parameters:
|
|
- None
|
|
|
|
Returns:
|
|
- None
|
|
"""
|
|
|
|
print("""
|
|
░█▀▀█ █▀▀█ █▀▀█ █──█ █▀▀ █──█ ─▀─ █▀▀▄ █▀▀▀ ▀▀█▀▀ ─▀─ █▀▀▀ █▀▀ █▀▀█
|
|
░█─── █▄▄▀ █──█ █──█ █── █▀▀█ ▀█▀ █──█ █─▀█ ─░█── ▀█▀ █─▀█ █▀▀ █▄▄▀
|
|
░█▄▄█ ▀─▀▀ ▀▀▀▀ ─▀▀▀ ▀▀▀ ▀──▀ ▀▀▀ ▀──▀ ▀▀▀▀ ─░█── ▀▀▀ ▀▀▀▀ ▀▀▀ ▀─▀▀
|
|
""")
|
|
|
|
# This script must be run as root!
|
|
if not os.geteuid() == 0:
|
|
sys.exit('Must be root! Damn, Shawty!')
|
|
|
|
#############
|
|
# configObj #
|
|
############
|
|
config_path = os.path.realpath(config_file)
|
|
spec = cfg.split("\n")
|
|
if not os.path.isfile(config_file):
|
|
if not os.path.exists(os.path.dirname(config_file)):
|
|
os.mkdir(os.path.dirname(config_file))
|
|
config = ConfigObj(config_file, configspec=spec)
|
|
config.filename = config_file
|
|
validator = validate.Validator()
|
|
config.validate(validator, copy=True)
|
|
config.write()
|
|
print("configuration file written to ", config_path)
|
|
sys.exit()
|
|
config = ConfigObj(config_file, configspec=spec)
|
|
validator = validate.Validator()
|
|
test = config.validate(validator, preserve_errors=True)
|
|
if not test:
|
|
print("Configuration file is invalid")
|
|
sys.exit()
|
|
# Versioning
|
|
global version
|
|
if os.path.exists('../VERSION.md'):
|
|
with open('../VERSION.md', 'r') as f:
|
|
raw_vers = f.read()
|
|
versionMd = str(raw_vers)
|
|
pyver = Version.parse(_version, optional_minor_and_patch=True)
|
|
txtver = Version.parse(versionMd, optional_minor_and_patch=True)
|
|
sem_vers = max(pyver, txtver)
|
|
if sem_vers != pyver:
|
|
with open('__version__.py', 'w') as wrt:
|
|
wrt.write("__version__ = '{}'\n".format(str(sem_vers)))
|
|
wrt.close()
|
|
f.close()
|
|
version = str(sem_vers)
|
|
else:
|
|
sem_vers = Version.parse(_version, optional_minor_and_patch=True)
|
|
version = str(sem_vers)
|
|
print("Crouching Tiger version: ", version)
|
|
|
|
##################
|
|
# ArgParse Setup #
|
|
##################
|
|
ap = argparse.ArgumentParser(
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
conflict_handler='resolve',
|
|
usage='%(prog)s -i $IFACE (-t $TARGET or -f $TARGET_FILE)\n',
|
|
description='Performs various actions on wifi targets.\n'
|
|
'\n'
|
|
'This program was created with the intent to allow users to attack\n'
|
|
'wifi targets that are only available some of the time, and extract\n'
|
|
'information from them.\n'
|
|
'\n'
|
|
'There are three types of actions that can be performed:\n'
|
|
'\n'
|
|
'1. ATTACK [att] = Will run a scan in the background looking for aps in target list.\n'
|
|
' If found will begin capturing a pcap file and deauth attack.\n'
|
|
'\n'
|
|
'2. Mac_Purge [mac] = Experimental: Scans for wireless devices and acquires their MAC\n' ' addresses. Then transmits a Clear to Send Frame. If the device responds with \n'
|
|
' data frame, then information on the device will be stored and written to file.\n'
|
|
'\n'
|
|
'3. Hidden_Dragon [dragon] = Experimental: Creates a "evil twin" access point\n'
|
|
'from which various attack vectors can be leverages.\n'
|
|
'\n')
|
|
# options parser
|
|
ap.add_argument('-v', '--version', action='version',
|
|
version=f'Crouching Tiger version: {version}')
|
|
ap.add_argument('-i', '--interface', dest='name',
|
|
default=config['interface'],
|
|
help='Interface(s) to scan on')
|
|
ap.add_argument('-f', '--file', dest='config_file', default='config_path',
|
|
help='configuration file')
|
|
ap.add_argument('-l', '--log_level', dest='log_level', default=config['logging_level'],
|
|
choices=['INFO', 'DEBUG'], help='Log level')
|
|
ap.add_argument('-z', '--log_file', dest='log_file', default=config['log_file'],
|
|
help='Log file')
|
|
|
|
# Subparser
|
|
subparse = ap.add_subparsers(title='actions',
|
|
description='Use "ctiger.py $(action) --help" for more info',
|
|
required=True, dest='module',
|
|
help='You must use one.')
|
|
|
|
# attack Subcommands
|
|
dest='config'
|
|
att_parse = subparse.add_parser('att', help='Attack target')
|
|
att_parse.add_argument('-s', '--scan_file', dest='scan_file',
|
|
default=config['ATTACK']['scan_file'],
|
|
required=False,)
|
|
att_parse.add_argument('-t', '--type', choices=['create', 'switch'],
|
|
dest='mon_type',
|
|
default=config['ATTACK']['mon_type'],
|
|
help='Create new monitor inf or switch mode.')
|
|
att_parse.add_argument('-n', '--netfile', dest='net_file',
|
|
default=config['ATTACK']['network_file'],
|
|
help='File containing names of local networks.')
|
|
# att_parse.add_argument('-d', '--use_daemon', action='store_true',
|
|
# dest='use_daemon', required=False,
|
|
# help='Run in daemon mode.')
|
|
att_parse.set_defaults(fun=Attack.attack)
|
|
|
|
# mac parse subcommands
|
|
mac_parse = subparse.add_parser('mac', help='Grab Valid addresses')
|
|
mac_parse.add_argument('-t', '--type', dest='mon_type',
|
|
choices=['create', 'switch'],
|
|
default=config['MAC_PURGE']['if_type'],
|
|
help='Create new monitor inf or switch mode.')
|
|
mac_parse.add_argument('-f', '--file', dest='valid_file',
|
|
default=config['MAC_PURGE']['valid_results'],
|
|
help='File to write results too.')
|
|
mac_parse.add_argument('-c', '--channels', dest='channels',
|
|
default=config['MAC_PURGE']['channel_list'],
|
|
help='A single or comma seperated list of channels.')
|
|
mac_parse.set_defaults(fun=Purge.mac_revealer)
|
|
|
|
# Dragon Subcommands
|
|
hd_parse = subparse.add_parser('dragon', help='Perform Dragon')
|
|
hd_parse.add_argument('-a', '--ap_iface', dest='ap_iface',
|
|
default=config['DRAGON']['ap_iface'],
|
|
help='Interface to use for AP')
|
|
hd_parse.add_argument('-d', '--netdb_file', dest='netdb_file',
|
|
default=config['DRAGON']['netdb_file'],
|
|
help='Database file of APs')
|
|
hd_parse.add_argument('-r', '--results', dest='results',
|
|
default=config['DRAGON']['dragon_results'],
|
|
help='File to write results too.')
|
|
hd_parse.add_argument('-c', '--config' , dest='config',
|
|
default=config_path, help='Config file')
|
|
|
|
##################
|
|
# parse the args #
|
|
##################
|
|
ap.set_defaults(fun=self.process_args)
|
|
args = ap.parse_args(args=None if sys.argv[1:] else ['--help'])
|
|
self.process_args(args, ap)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parse = ProcArgs()
|
|
parse.main()
|