feat(Features): 🚩 Begin development of Hidden Dragon
corrected parsing of log level (sort of), beginning work on implementing Hidden Dragon.
This commit is contained in:
parent
a79cd2e5e9
commit
4418d3c65d
12 changed files with 294 additions and 28 deletions
21
Docs/User_Docs.md
Normal file
21
Docs/User_Docs.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!--
|
||||
Copyright (c) 2024 Anoduck
|
||||
This software is released under the MIT License.
|
||||
https://opensource.org/licenses/MIT
|
||||
-->
|
||||
|
||||
# Crouching Tiger User Documentation
|
||||
|
||||
**Hazaa! You made it to the docs!**
|
||||
|
||||
## Forward
|
||||
|
||||
Out dear little program finally grew to the point where it was felt that more thorough documentation
|
||||
was a neccessity. Personally, yours truly, has always been frustrated with projects where the
|
||||
doccumentation is lacking in substance. Thankfully, I am rather long winded, literorically speaking.
|
||||
So, if my attention span holds up, this should be something worth while.
|
||||
|
||||
What set aside the original AT&T Unix from other operating systems of the time was Dennis Ritchie's
|
||||
unwavering dedication to thoroughly well-written documentation, and project transparency. As also
|
||||
the creator of the "C" programming language, Ritchie created most of the codebase for modern
|
||||
computing. We should all keep the importance of documentation in mind in our endeavours.
|
1
__version__.py
Normal file
1
__version__.py
Normal file
|
@ -0,0 +1 @@
|
|||
__version__ = '0.4.3'
|
|
@ -9,6 +9,20 @@
|
|||
#+EXPORT_EXCLUDE_TAGS: noexport
|
||||
# ---------------------------------------
|
||||
* Changelog
|
||||
** unreleased
|
||||
*** 2024.02.22
|
||||
- Reconfigured logging to allow dynamic level setting
|
||||
- Setup log to Rotate using logging.handlers.RotateLogging (or something like that.)
|
||||
- Created HDragon class in preparation for creation of hidden_dragon module.
|
||||
- Created apData class in hidden_dragon module.
|
||||
- added scapy-fakeap to project workspace for reference.
|
||||
- Created TapIf for hidden_dragon
|
||||
- Created __main__ for hdragon.
|
||||
- Began to add hdragon parameters to config file.
|
||||
- Created native banner for ctiger, art no longer needed.
|
||||
- Created banner for hdragon, art still no longer needed.
|
||||
- added argparse condiguration for hdragon.
|
||||
- ctiger passes args to hdragon class and displays cute message.
|
||||
** 0.4.3
|
||||
*** 2024.02.13
|
||||
- Setup own awkward Semver solution, not too pleased
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../scapy-fakeap"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"conventionalCommits.scopes": [
|
||||
"Structure"
|
||||
"Structure",
|
||||
"Features"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from art.art import tprint
|
||||
from configobj import ConfigObj, validate
|
||||
from .proclog import ProcLog
|
||||
from .mac_purge import Purge
|
||||
from .attack import Attack
|
||||
from .hdragon import Dragon
|
||||
from semver import Version
|
||||
from .__version__ import version as _version
|
||||
|
||||
|
@ -38,12 +38,23 @@ use_daemon = boolean(default=False)
|
|||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# Mac Purge Setings
|
||||
# Mac Purge Settings
|
||||
# -----------------
|
||||
[MAC_PURGE]
|
||||
if_type = option('create', 'switch', default='switch')
|
||||
valid_results = string(default='ct_valid.csv')
|
||||
channel_list = list(default=list(1, 6, 11))
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# Hidden Dragon Settings
|
||||
# -----------------------
|
||||
[DRAGON]
|
||||
if_type = option('create', 'switch', default='switch')
|
||||
ap_iface = string(default='mon0')
|
||||
ap_db = string(default='ap_database.csv')
|
||||
dragon_results = string(default='dragon_results.csv')
|
||||
# -----------------------------------------------------------
|
||||
"""
|
||||
|
||||
|
||||
|
@ -60,7 +71,7 @@ class ProcArgs:
|
|||
None
|
||||
"""
|
||||
alog = ProcLog()
|
||||
log = alog.get_log(args.log_file)
|
||||
log = alog.get_log(args.log_file, args.log_level)
|
||||
log.info('Started crouching tiger')
|
||||
log.info('Started logger...')
|
||||
match args.module:
|
||||
|
@ -73,8 +84,6 @@ class ProcArgs:
|
|||
log=log)
|
||||
case "mac":
|
||||
log.info('Beginning Mac Purge')
|
||||
#mon_dev, mon_type, valid_file, channels
|
||||
#mon_dev, mon_type, valid_file, channels
|
||||
log.debug('args: {0}'.format(args))
|
||||
global valid_file
|
||||
valid_file = args.valid_file
|
||||
|
@ -84,6 +93,15 @@ class ProcArgs:
|
|||
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(mon_type=args.mon_type,
|
||||
ap_iface=args.ap_iface,
|
||||
ap_db=args.ap_db,
|
||||
results=args.results,
|
||||
log=log)
|
||||
case _:
|
||||
ap.print_help()
|
||||
|
||||
|
@ -106,7 +124,11 @@ class ProcArgs:
|
|||
- None
|
||||
"""
|
||||
|
||||
tprint('Crouching Tiger', font='tarty3')
|
||||
print("""
|
||||
░█▀▀█ █▀▀█ █▀▀█ █──█ █▀▀ █──█ ─▀─ █▀▀▄ █▀▀▀ ▀▀█▀▀ ─▀─ █▀▀▀ █▀▀ █▀▀█
|
||||
░█─── █▄▄▀ █──█ █──█ █── █▀▀█ ▀█▀ █──█ █─▀█ ─░█── ▀█▀ █─▀█ █▀▀ █▄▄▀
|
||||
░█▄▄█ ▀─▀▀ ▀▀▀▀ ─▀▀▀ ▀▀▀ ▀──▀ ▀▀▀ ▀──▀ ▀▀▀▀ ─░█── ▀▀▀ ▀▀▀▀ ▀▀▀ ▀─▀▀
|
||||
""")
|
||||
|
||||
# This script must be run as root!
|
||||
if not os.geteuid() == 0:
|
||||
|
@ -171,11 +193,14 @@ class ProcArgs:
|
|||
'\n'
|
||||
'There are three types of actions that can be performed:\n'
|
||||
'\n'
|
||||
'2. ATTACK [att] = Will run a scan in the background looking for aps in target list.\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'
|
||||
'3. 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'
|
||||
'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',
|
||||
|
@ -213,6 +238,7 @@ class ProcArgs:
|
|||
# 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'],
|
||||
|
@ -226,6 +252,22 @@ class ProcArgs:
|
|||
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('-t', '--type', dest='mon_type',
|
||||
choices=['create', 'switch'],
|
||||
default=config['DRAGON']['if_type'],
|
||||
help='Create new monitor inf or switch mode.')
|
||||
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', '--ap_db', dest='ap_db',
|
||||
default=config['DRAGON']['ap_db'],
|
||||
help='Database file of APs')
|
||||
hd_parse.add_argument('-r', '--results', dest='results',
|
||||
default=config['DRAGON']['dragon_results'],
|
||||
help='File to write results too.')
|
||||
|
||||
##################
|
||||
# parse the args #
|
||||
##################
|
||||
|
|
44
ctiger/hdragon.py
Normal file
44
ctiger/hdragon.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
# from .hidden_dragon import __main__
|
||||
|
||||
|
||||
class Dragon:
|
||||
|
||||
def __init__(self):
|
||||
print("""
|
||||
______ __ __ ______ ______ ______
|
||||
/\ ___\ /\ "-.\ \ /\__ _\ /\ ___\ /\ == \
|
||||
\ \ __\ \ \ \-. \ \/_/\ \/ \ \ __\ \ \ __<
|
||||
\ \_____\ \ \_\\"\_\ \ \_\ \ \_____\ \ \_\ \_\
|
||||
\/_____/ \/_/ \/_/ \/_/ \/_____/ \/_/ /_/
|
||||
|
||||
______ __ __ ______
|
||||
/\__ _\ /\ \_\ \ /\ ___\
|
||||
\/_/\ \/ \ \ __ \ \ \ __\
|
||||
\ \_\ \ \_\ \_\ \ \_____\
|
||||
\/_/ \/_/\/_/ \/_____/
|
||||
|
||||
) (
|
||||
( /( ( ( )\ )
|
||||
)\()) ( )\ ) )\ ) ( (()/( ( ) ( (
|
||||
((_)\ )\ (()/( (()/( ))\ ( /(_)) )( ( /( )\))( ( (
|
||||
_((_)((_) ((_)) ((_))/((_) )\ ) (_))_ (()\ )(_))((_))\ )\ )\ )
|
||||
| || | (_) _| | _| |(_)) _(_/( | \ ((_)((_)_ (()(_)((_) _(_/(
|
||||
| __ | | |/ _` |/ _` |/ -_)| ' \)) | |) || '_|/ _` |/ _` |/ _ \| ' \))
|
||||
|_||_| |_|\__,_|\__,_|\___||_||_| |___/ |_| \__,_|\__, |\___/|_||_|
|
||||
|___/
|
||||
""")
|
||||
|
||||
def hidden_dragon(self, mon_type, ap_iface, ap_db, results, log):
|
||||
log.info('Starting Hidden Dragon')
|
||||
print("""
|
||||
You have configured Hidden Dragon to run with these options:
|
||||
mon_type: {0}
|
||||
ap_iface: {1}
|
||||
ap_db: {2}
|
||||
results: {3}
|
||||
Have a good day, and thanks for all the fish!
|
||||
""".format(mon_type, ap_iface, ap_db, results))
|
5
ctiger/hidden_dragon/__init__.py
Normal file
5
ctiger/hidden_dragon/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
15
ctiger/hidden_dragon/__main__.py
Normal file
15
ctiger/hidden_dragon/__main__.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
from .data import apData
|
||||
from .mk_inf import TunIf
|
||||
|
||||
|
||||
def main(ap, log):
|
||||
iface = TunIf(ap=ap, apData=apData, log=log)
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(ap, log)
|
12
ctiger/hidden_dragon/ap.py
Normal file
12
ctiger/hidden_dragon/ap.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
import subprocess
|
||||
from scapy.all import sniff
|
||||
from time import time, sleep
|
||||
from scapy.layers.dot11 import RadioTap, conf as scapyconf
|
||||
from scapy.layers.inet import TCP
|
||||
|
||||
|
44
ctiger/hidden_dragon/data.py
Normal file
44
ctiger/hidden_dragon/data.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
from dataclasses import dataclass
|
||||
from random import choice
|
||||
|
||||
|
||||
@dataclass
|
||||
class apData:
|
||||
dns_servers: list = ["8.8.8.8", "9.9.9.9", "1.1.1.1",
|
||||
"208.67.222.222", "208.67.220.220",
|
||||
"8.26.56.26", "8.20.247.20", "89.0.142.86"]
|
||||
DEFAULT_DNS_SERVER: str = choice(dns_servers)
|
||||
RSN: str = "\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x28\x00"
|
||||
|
||||
AP_WLAN_TYPE_OPEN: int = 0
|
||||
AP_WLAN_TYPE_WPA: int = 1
|
||||
AP_WLAN_TYPE_WPA2: int = 2
|
||||
AP_WLAN_TYPE_WPA_WPA2: int = 3
|
||||
AP_AUTH_TYPE_OPEN: int = 0
|
||||
AP_AUTH_TYPE_SHARED: int = 1
|
||||
AP_RATES: str = "\x0c\x12\x18\x24\x30\x48\x60\x6c"
|
||||
|
||||
DOT11_MTU: int = 4096
|
||||
|
||||
DOT11_TYPE_MANAGEMENT: int = 0
|
||||
DOT11_TYPE_CONTROL: int = 1
|
||||
DOT11_TYPE_DATA: int = 2
|
||||
|
||||
DOT11_SUBTYPE_DATA: int = 0x00
|
||||
DOT11_SUBTYPE_PROBE_REQ: int = 0x04
|
||||
DOT11_SUBTYPE_AUTH_REQ: int = 0x0B
|
||||
DOT11_SUBTYPE_ASSOC_REQ: int = 0x00
|
||||
DOT11_SUBTYPE_REASSOC_REQ: int = 0x02
|
||||
DOT11_SUBTYPE_QOS_DATA: int = 0x28
|
||||
|
||||
IFNAMSIZ: int = 16
|
||||
IFF_TUN: int = 0x0001
|
||||
IFF_TAP: int = 0x0002 # Should we want to tunnel layer 2...
|
||||
IFF_NO_PI: int = 0x1000
|
||||
TUNSETIFF: int = 0x400454ca
|
||||
IP_ADDRESS: str = "10.0.0.2"
|
60
ctiger/hidden_dragon/mk_inf.py
Normal file
60
ctiger/hidden_dragon/mk_inf.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
import fcntl
|
||||
import struct
|
||||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
from scapy.layers.inet import IP
|
||||
from .data import apData
|
||||
from ctiger import NetDev
|
||||
|
||||
|
||||
class TunIf(threading.Thread):
|
||||
def __init__(self, ap, apData, name="fakeap", log):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self.apData = apData
|
||||
self.log = log
|
||||
|
||||
if len(name) > apData.IFNAMSIZ:
|
||||
raise Exception(
|
||||
"Tun interface name cannot be larger than " + str(apData.IFNAMSIZ))
|
||||
|
||||
self.name = name
|
||||
self.setDaemon(True)
|
||||
self.ap = ap
|
||||
|
||||
# Virtual interface
|
||||
self.fd = open('/dev/net/tun', 'r+b')
|
||||
ifr_flags = apData.IFF_TUN | apData.IFF_NO_PI # Tun device without packet information
|
||||
ifreq = struct.pack('16sH', name, ifr_flags)
|
||||
fcntl.ioctl(self.fd, apData.TUNSETIFF, ifreq) # Syscall to create interface
|
||||
|
||||
# Assign IP and bring interface up
|
||||
# set_ip_address(name, self.ap.ip)
|
||||
# def set_ip_address(dev, ip):
|
||||
if subprocess.call(['ip', 'addr', 'add', apData.ip, 'dev', apData.dev]):
|
||||
print("Failed to assign IP address {} to {}.".format(apData.ip, apData.dev))
|
||||
if subprocess.call(['ip', 'link', 'set', 'dev', apData.dev, 'up']):
|
||||
print("Failed to bring device %s up." % dev, Level.CRITICAL)
|
||||
|
||||
print("Created TUN interface %s at %s. Bind it to your services as needed." % (
|
||||
name, self.ap.ip))
|
||||
|
||||
def write(self, pkt):
|
||||
os.write(self.fd.fileno(), str(pkt[IP])) # Strip layer 2
|
||||
|
||||
def read(self):
|
||||
raw_packet = os.read(self.fd.fileno(), apData.DOT11_MTU)
|
||||
return raw_packet
|
||||
|
||||
def close(self):
|
||||
os.close(self.fd.fileno())
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
raw_packet = self.read()
|
||||
self.ap.callbacks.cb_tint_read(raw_packet)
|
|
@ -4,34 +4,38 @@
|
|||
# https://opensource.org/licenses/MIT
|
||||
|
||||
import logging
|
||||
from logging import handlers
|
||||
from warnings import warn
|
||||
import os
|
||||
|
||||
|
||||
class ProcLog:
|
||||
|
||||
def get_log(self, log_file,):
|
||||
def get_log(self, log_file, lev):
|
||||
self.log_file = log_file
|
||||
lev = 'debug'
|
||||
rot = True
|
||||
self.lev = 'debug'
|
||||
if not os.path.exists(log_file):
|
||||
open(log_file, 'a').close()
|
||||
if rot:
|
||||
log_size = os.path.getsize(log_file)
|
||||
smart_size = log_size % 1024
|
||||
if smart_size >= 1024:
|
||||
os.remove(log_file)
|
||||
log = logging.getLogger(__name__)
|
||||
log = logging.getLogger(__name__)
|
||||
if log.hasHandlers():
|
||||
log.handlers.clear()
|
||||
if lev == 'info':
|
||||
log.setLevel(logging.INFO)
|
||||
elif lev == 'debug':
|
||||
log_levels = {'info': logging.INFO,
|
||||
'debug': logging.DEBUG,
|
||||
'error': logging.ERROR}
|
||||
if lev in log_levels.keys():
|
||||
set_level = log_levels[lev]
|
||||
log.setLevel(set_level)
|
||||
else:
|
||||
warn('Invalid level. Defaulting to debug')
|
||||
log.setLevel(logging.DEBUG)
|
||||
handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
log.addHandler(handler)
|
||||
log.info('started motion detection')
|
||||
log.info('Acquired Logger')
|
||||
handler = handlers.RotatingFileHandler(filename=log_file,
|
||||
mode='a', maxBytes=1024,
|
||||
backupCount=2, encoding='utf-8',
|
||||
delay=False)
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
log.addHandler(handler)
|
||||
log.info('started motion detection')
|
||||
log.info('Acquired Logger')
|
||||
return log
|
||||
|
|
Loading…
Reference in a new issue