feat(Features): 🚧 Hidden Dragon Work
Many changes performed in development of Hidden Dragon hdragon command is broken for development
This commit is contained in:
parent
4418d3c65d
commit
f2c940ae37
19 changed files with 496 additions and 88 deletions
|
@ -18,4 +18,21 @@ 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.
|
||||
computing. In honor of this spirit of dedication to documentation, we all should struggle to make
|
||||
our own documentation worth it.
|
||||
|
||||
Well, that was a load of long winded bullshittery, let get to the good stuff.
|
||||
|
||||
### Acquiring Access Point Information
|
||||
|
||||
I do not claim to be any whiz at anything concerning network security, but what little I have
|
||||
learned proves that nothing happens like it does in the movies. There are are very intelligent and
|
||||
adept programmers out there, but it took them years if not a lifetime to obtain this knowledge, and
|
||||
more often than not, they had a hell of a lot of help to get there. The point of mentioning this is
|
||||
to stress the amount of effort real network security requires. You really have to invest time and
|
||||
effort into studying your target, and this will take a lot of time.
|
||||
|
||||
The Hidden Dragon feature takes an approach that has to have been exploited by several hundred chaps
|
||||
before us. It is to acquire the name of local access points in your target area. You can do this by
|
||||
performing wardriving on your own, or you can acquire a list of access points from publicly
|
||||
available sources, such as wigle.
|
||||
|
|
|
@ -182,6 +182,13 @@ options:
|
|||
A single or comma seperated list of channels.
|
||||
```
|
||||
|
||||
## Citations
|
||||
|
||||
```text
|
||||
Hansen, Y. (2018). Python Scapy Dot11. Createspace Independent Publishing Platform.
|
||||
|
||||
rpp0. (2024, January 23). rpp0/scapy-fakeap. GitHub. https://github.com/rpp0/scapy-fakeap
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
|
|
12
ap_db-rearrange.awk
Normal file
12
ap_db-rearrange.awk
Normal file
|
@ -0,0 +1,12 @@
|
|||
BEGIN {
|
||||
FS=OFS=",";
|
||||
RS="\n";
|
||||
outfile = "ap_db.csv";
|
||||
}
|
||||
|
||||
NR !=1 {
|
||||
!$1 and $1 !=0 {print "NULL"}
|
||||
srand() $0;
|
||||
}
|
||||
|
||||
print > outfile
|
|
@ -10,7 +10,30 @@
|
|||
# ---------------------------------------
|
||||
* Changelog
|
||||
** unreleased
|
||||
***
|
||||
*** 2024.03.11
|
||||
- Using standard csv to rearrange network database
|
||||
- Created bare knuckle dhcp server
|
||||
- Added function for dhcp to assign more than one IP address.
|
||||
- Added Eap file
|
||||
- Corrected reading of version file from __version__.py
|
||||
- for some reason still using semver to parse version
|
||||
- corrected parsing of configuration file when there is none.
|
||||
- renamed access point database csv to netdb_file
|
||||
- Renamed DataFrame class to CtigerDataFrame to avoid confusion
|
||||
- Corrected dual loading of ap network dataframe
|
||||
- added contents of rpy.py to mkintf
|
||||
*** 2024.02.24
|
||||
- Created awk script to rearrange ap_db file.
|
||||
- Further flushing out of args to pass to hidden dragon.
|
||||
- Polished up TapIF Class
|
||||
- Removed mon_type from list of arguments for Hidden Dragon.
|
||||
*** 2024.02.23
|
||||
- Added two additional dataclasses to the data module.
|
||||
- Log level selection no longer produces errors
|
||||
- Added new ascii art to crouching tiger.
|
||||
*** 2024.02.22
|
||||
**** feat(Features): 🚩 Begin development of Hidden Dragon
|
||||
- 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.
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
from ctiger.attack import Attack
|
||||
from ctiger.mac_purge import Purge
|
||||
from ctiger.proclog import ProcLog
|
||||
from ctiger.dataframe import DataFrame
|
||||
from ctiger.dataframe import CtigerDataFrame
|
||||
from ctiger.netdev import NetDev
|
||||
from ctiger.__version__ import version
|
||||
|
|
|
@ -50,9 +50,8 @@ 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')
|
||||
netdb_file = string(default='net_database.csv')
|
||||
dragon_results = string(default='dragon_results.csv')
|
||||
# -----------------------------------------------------------
|
||||
"""
|
||||
|
@ -97,9 +96,8 @@ class ProcArgs:
|
|||
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,
|
||||
dragon.hidden_dragon(ap_iface=args.ap_iface,
|
||||
netdb_file=args.netdb_file,
|
||||
results=args.results,
|
||||
log=log)
|
||||
case _:
|
||||
|
@ -149,7 +147,6 @@ class ProcArgs:
|
|||
config.write()
|
||||
print("configuration file written to ", config_path)
|
||||
sys.exit()
|
||||
else:
|
||||
config = ConfigObj(config_file, configspec=spec)
|
||||
validator = validate.Validator()
|
||||
test = config.validate(validator, preserve_errors=True)
|
||||
|
@ -157,14 +154,13 @@ class ProcArgs:
|
|||
print("Configuration file is invalid")
|
||||
sys.exit()
|
||||
# Versioning
|
||||
if os.path.exists('VERSION.md'):
|
||||
with open('VERSION.md', 'r') as f:
|
||||
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)
|
||||
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:
|
||||
|
@ -173,8 +169,7 @@ class ProcArgs:
|
|||
f.close()
|
||||
version = str(sem_vers)
|
||||
else:
|
||||
sem_vers = Version.parse(_version,
|
||||
optional_minor_and_patch=True)
|
||||
sem_vers = Version.parse(_version, optional_minor_and_patch=True)
|
||||
version = str(sem_vers)
|
||||
print("Crouching Tiger version: ", version)
|
||||
|
||||
|
@ -204,7 +199,7 @@ class ProcArgs:
|
|||
'\n')
|
||||
# options parser
|
||||
ap.add_argument('-v', '--version', action='version',
|
||||
version=f'%(prog)s {version}')
|
||||
version=f'Crouching Tiger version: {version}')
|
||||
ap.add_argument('-i', '--interface', dest='name',
|
||||
default=config['interface'],
|
||||
help='Interface(s) to scan on')
|
||||
|
@ -254,15 +249,11 @@ class ProcArgs:
|
|||
|
||||
# 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'],
|
||||
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'],
|
||||
|
|
|
@ -1 +1 @@
|
|||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
|
|
|
@ -11,7 +11,7 @@ from scapy.layers.eap import EAPOL
|
|||
from scapy.utils import PcapWriter
|
||||
from random import choice
|
||||
import pandas as pd
|
||||
from .dataframe import DataFrame
|
||||
from .dataframe import CtigerDataFrame
|
||||
from time import sleep
|
||||
import os
|
||||
import threading
|
||||
|
|
|
@ -5,9 +5,38 @@
|
|||
|
||||
import os
|
||||
import pandas as pd
|
||||
import csv
|
||||
from warnings import warn
|
||||
|
||||
|
||||
class DataFrame:
|
||||
class CtigerDataFrame:
|
||||
|
||||
def load_apnetworks(self, netdb_file, log) -> pd.DataFrame:
|
||||
self.netdb_file = netdb_file
|
||||
self.log = log
|
||||
log.debug('netdb_file type: {0}'.format(type(netdb_file)))
|
||||
if os.path.isfile(netdb_file):
|
||||
log.info('Loading networks from: {}'.format(netdb_file))
|
||||
network_df = pd.DataFrame(columns=['SSID', 'Mac', 'Crypto',
|
||||
'Channel', 'Last Update',
|
||||
'Latitude', 'Longitude'])
|
||||
network_df.set_index("SSID", inplace=True)
|
||||
netdict = csv.DictReader(open(netdb_file), delimiter=',')
|
||||
# SSID,NetID,Encryption,Channel,Last Update,Latitude,Longitude
|
||||
for entry in netdict:
|
||||
if entry.get('SSID') == '':
|
||||
BSSID = entry.get('NetID')
|
||||
entry['SSID'] = BSSID
|
||||
network_df.loc[entry['SSID']] = [entry['NetID'], entry['Encryption'], entry['Channel'], entry['Last Update'], entry['Latitude'], entry['Longitude']]
|
||||
return network_df
|
||||
else:
|
||||
warn(message='Could not load file', category=None, stacklevel=1)
|
||||
exit(1)
|
||||
|
||||
def gen_resdf(self, log):
|
||||
resdf = pd.DataFrame(columns=['BSSID', 'SSID', 'dBm_Signal', 'Channel', 'Crypto'])
|
||||
resdf.set_index("BSSID", inplace=True)
|
||||
return resdf
|
||||
|
||||
def load_df(self, valid_file, log):
|
||||
self.valid_file = valid_file
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
# from .hidden_dragon import __main__
|
||||
from .hidden_dragon.__main__ import HiddenDragon
|
||||
from ctiger.dataframe import CtigerDataFrame
|
||||
import os
|
||||
|
||||
|
||||
class Dragon:
|
||||
|
@ -20,7 +22,20 @@ class Dragon:
|
|||
\/_/\ \/ \ \ __ \ \ \ __\
|
||||
\ \_\ \ \_\ \_\ \ \_____\
|
||||
\/_/ \/_/\/_/ \/_____/
|
||||
|
||||
______________
|
||||
,===:'., `-._
|
||||
`:.`---.__ `-._
|
||||
`:. `--. `.
|
||||
\. `. `.
|
||||
(,,(, \. `. ____,-`.,
|
||||
(,' `/ \. ,--.___`.'
|
||||
, ,' ,--. `, \.;' `
|
||||
`{D, { \ : \;
|
||||
V,,' / / //
|
||||
j;; / ,' ,-//. ,---. ,
|
||||
\;' / ,' / _ \ / _ \ ,'/
|
||||
\ `' / \ `' / \ `.' /
|
||||
`.___,' `.__,' `.__,'
|
||||
) (
|
||||
( /( ( ( )\ )
|
||||
)\()) ( )\ ) )\ ) ( (()/( ( ) ( (
|
||||
|
@ -32,13 +47,19 @@ class Dragon:
|
|||
|___/
|
||||
""")
|
||||
|
||||
def hidden_dragon(self, mon_type, ap_iface, ap_db, results, log):
|
||||
def hidden_dragon(self, ap_iface, netdb_file, results, log):
|
||||
log.info('Starting Hidden Dragon')
|
||||
netdb_file = os.path.abspath(netdb_file)
|
||||
print("""
|
||||
You have configured Hidden Dragon to run with these options:
|
||||
mon_type: {0}
|
||||
ap_iface: {1}
|
||||
ap_db: {2}
|
||||
results: {3}
|
||||
ap_iface: {0}
|
||||
ap_db: {1}
|
||||
results: {2}
|
||||
Have a good day, and thanks for all the fish!
|
||||
""".format(mon_type, ap_iface, ap_db, results))
|
||||
""".format(ap_iface, netdb_file, results))
|
||||
dataframe = CtigerDataFrame()
|
||||
apnetwork_df = dataframe.load_apnetworks(netdb_file, log)
|
||||
results_df = dataframe.gen_resdf(log)
|
||||
HD = HiddenDragon()
|
||||
HD.start(ap_iface=ap_iface, net_db=apnetwork_df,
|
||||
results=results_df, log=log)
|
||||
|
|
|
@ -2,14 +2,18 @@
|
|||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
from threading import Thread
|
||||
from .data import apData
|
||||
from .mk_inf import TunIf
|
||||
from ctiger.dataframe import CtigerDataFrame
|
||||
|
||||
|
||||
def main(ap, log):
|
||||
iface = TunIf(ap=ap, apData=apData, log=log)
|
||||
class HiddenDragon(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
|
||||
def start(self, ap_iface, net_db, log):
|
||||
DF = CtigerDataFrame()
|
||||
resdf = DF.gen_resdf(log)
|
||||
iface = TunIf(ap=ap_iface, apData=apData, log=log)
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(ap, log)
|
||||
|
|
|
@ -10,3 +10,7 @@ from scapy.layers.dot11 import RadioTap, conf as scapyconf
|
|||
from scapy.layers.inet import TCP
|
||||
|
||||
|
||||
class wifiAP:
|
||||
|
||||
def pass_proxy(self, ip, port):
|
||||
pass
|
60
ctiger/hidden_dragon/arp.py
Normal file
60
ctiger/hidden_dragon/arp.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 threading
|
||||
from scapy.layers.inet import ARP
|
||||
from scapy.sendrecv import AsyncSniffer
|
||||
from scapy.sendrecv import sendp
|
||||
from scapy.utils import PcapWriter
|
||||
from ctiger.dataframe import CtigerDataFrame
|
||||
from ctiger.netdev import NetDev
|
||||
from ctiger.proclog import ProcLog
|
||||
|
||||
|
||||
class Arp(NetDev):
|
||||
def __init__(self, args):
|
||||
super().__init__(args)
|
||||
self.arp = ARP()
|
||||
self.arp.op = 2
|
||||
self.arp.hwdst = "ff:ff:ff:ff:ff:ff"
|
||||
|
||||
def send(self, pkt):
|
||||
sendp(pkt, iface=self.interface, verbose=False)
|
||||
|
||||
def arp_handler(self, pkt):
|
||||
self.arp_handler.handle_arp(pkt)
|
||||
|
||||
def sniff(self, stop_filter, iface):
|
||||
AsyncSniffer(
|
||||
stop_filter=stop_filter,
|
||||
filter="arp",
|
||||
iface=iface,
|
||||
prn=self.arp_handler,
|
||||
store=0,
|
||||
timeout=0.01)
|
||||
|
||||
|
||||
class ARPHandler():
|
||||
def __init__(self):
|
||||
self.mutex = threading.Lock()
|
||||
self.arp_table = {}
|
||||
|
||||
def add_entry(self, client_ip, client_mac):
|
||||
self.mutex.acquire()
|
||||
if client_ip not in self.arp_table:
|
||||
self.arp_table[client_ip] = client_mac
|
||||
self.mutex.release()
|
||||
|
||||
def get_entry(self, client_ip):
|
||||
self.mutex.acquire()
|
||||
try:
|
||||
temp = self.arp_table[client_ip]
|
||||
except KeyError:
|
||||
temp = None
|
||||
printd("Could not find IP %s in ARP table." %
|
||||
client_ip, Level.WARNING)
|
||||
self.mutex.release()
|
||||
|
||||
return temp
|
|
@ -3,16 +3,18 @@
|
|||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
from dataclasses import dataclass
|
||||
from random import choice
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List
|
||||
|
||||
DNS_SERVERS = ["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"]
|
||||
|
||||
|
||||
@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)
|
||||
DNS_SERVERS: List[str] = field(default_factory=lambda: 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
|
||||
|
@ -41,4 +43,41 @@ class apData:
|
|||
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"
|
||||
IP_ADDRESS: str = "10.0.2.1"
|
||||
NETMASK: str = "255.255.255.192"
|
||||
IP_NETWORK: str = "10.0.2"
|
||||
NET_BROADCAST: str = "10.0.2.63"
|
||||
DHCP_MIN: str = "10.0.2.2"
|
||||
DHCP_MAX: str = "10.0.2.62"
|
||||
DHCP_EXPIRY: int = 28800
|
||||
|
||||
@dataclass
|
||||
class EAPCode:
|
||||
REQUEST: int = 1
|
||||
RESPONSE: int = 2
|
||||
SUCCESS: int = 3
|
||||
FAILURE: int = 4
|
||||
|
||||
@dataclass
|
||||
class EAPType:
|
||||
IDENTITY: int = 1
|
||||
NOTIFICATION: int = 2
|
||||
NAK: int = 3
|
||||
MD5_CHALLENGE: int = 4
|
||||
OTP: int = 5
|
||||
GENERIC_TOKEN_CARD: int = 6
|
||||
EAP_TLS: int = 13
|
||||
EAP_LEAP: int = 17
|
||||
EAP_SIM: int = 18
|
||||
TTLS: int = 21
|
||||
PEAP: int = 25
|
||||
MSCHAP_V2: int = 29
|
||||
EAP_CISCO_FAST: int = 43
|
||||
EAP_MSCHAPV2: int = 44
|
||||
EAP_TLV: int = 45
|
||||
|
||||
@classmethod
|
||||
def convert_type(cls, type_value):
|
||||
for key, value in vars(cls).iteritems():
|
||||
if value == type_value:
|
||||
return str(key)
|
||||
|
|
89
ctiger/hidden_dragon/dhcp.py
Normal file
89
ctiger/hidden_dragon/dhcp.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
"""# DHCP Server specifically for wifi
|
||||
1. Craft DHCP Packets: Use Scapy to craft DHCP packets for the various stages of the DHCP process,
|
||||
including Discover, Offer, Request, Acknowledgement, and more as needed. Scapy provides a
|
||||
flexible way to build and manipulate network packets, including DHCP packets.
|
||||
|
||||
2. Bind a Socket: Create a raw socket to send and receive UDP packets using Python's socket module.
|
||||
This allows you to send and receive DHCP messages on the network.
|
||||
server_mac
|
||||
3. Listen for DHCP Requests: Listen for DHCP client requests (DHCP Discover) on the network using
|
||||
the raw socket. When a DHCP Discover packet is received, parse the packet using Scapy to extract
|
||||
relevant information such as the client's MAC address and requested parameters.
|
||||
|
||||
4. Craft DHCP Offer: Upon receiving a DHCP Discover, craft a DHCP Offer packet using Scapy to
|
||||
allocate an available IP address and other configuration parameters to the client. Send the DHCP
|
||||
Offer packet using the raw socket to the client's broadcast address.
|
||||
|
||||
5. Handle DHCP Request: If the client sends a DHCP Request for the offered parameters, process the
|
||||
request and send a DHCP Acknowledgement (ACK) packet to finalize the configuration.
|
||||
|
||||
6. Error Handling and Lease Management: Implement error handling for invalid requests and manage IP
|
||||
address lease allocation to ensure that IP addresses are properly assigned and reclaimed.
|
||||
"""
|
||||
# from scapy.all import *
|
||||
from scapy.layers.dhcp import DHCP
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.layers.dot11 import Dot11
|
||||
from scapy.layers.dhcp import BOOTP
|
||||
from scapy.sendrecv import sniff, sendp
|
||||
import subprocess
|
||||
from random import choice
|
||||
import time
|
||||
import socket
|
||||
import fcntl
|
||||
import struct
|
||||
from ctiger.hidden_dragon import ap
|
||||
from data import apData
|
||||
|
||||
# Define the DHCP server IP and the network ifname to listen on
|
||||
server_ip = apData.IP_ADDRESS # "10.0.2.1"
|
||||
ifname = "wlan0"
|
||||
|
||||
|
||||
class apDHCP:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.server_ip = apData.IP_ADDRESS
|
||||
self.netmask = apData.NETMASK
|
||||
self.broadcast = apData.NET_BROADCAST
|
||||
self.host_min = apData.DHCP_MIN
|
||||
self.host_max = apData.DHCP_MAX
|
||||
self.ip_net = apData.IP_NETWORK
|
||||
|
||||
def get_if_hwaddr(self, ifname):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
|
||||
return ''.join(['%02x' % ord(char) for char in info[18:24]])
|
||||
|
||||
# Create a DHCP packet handler
|
||||
def handle_dhcp_packet(self, packet):
|
||||
if DHCP in packet:
|
||||
# Check if the packet is a DHCP Discover
|
||||
if packet[DHCP].options[0][1] == 1:
|
||||
# Craft DHCP Offer
|
||||
min_host = self.host_min.split('.')[3]
|
||||
max_host = self.host_max.split('.')[3]
|
||||
cli_int = choice(range(int(min_host), int(max_host)))
|
||||
client_ip = self.ip_net + '.' + str(cli_int)
|
||||
dhcp_offer = Dot11(src=self.server_mac, dst="ff:ff:ff:ff:ff:ff") / IP(src=server_ip, dst="self.broadcast") / UDP(sport=67, dport=68) / BOOTP(op=2, yiaddr=client_ip, siaddr=server_ip, chaddr=packet[Dot11].src) / DHCP(options=[("message-type", "offer"), ("subnet_mask", self.netmask), "end"])
|
||||
sendp(dhcp_offer, iface=ifname, verbose=0)
|
||||
print("Sent DHCP Offer to", packet[Dot11].src)
|
||||
|
||||
# Wait for DHCP Request
|
||||
dhcp_request = sniff(iface=ifname, filter="udp and (port 67 or 68)", count=1)
|
||||
if DHCP in dhcp_request[0]:
|
||||
# Craft DHCP Acknowledgement
|
||||
dhcp_ack = Dot11(src=self.server_mac, dst=dhcp_request[0][Dot11].src) / IP(src=server_ip, dst="self.broadcast") / UDP(sport=67, dport=68) / BOOTP(op=2, yiaddr=client_ip, siaddr=server_ip, chaddr=dhcp_request[0][Dot11].src) / DHCP(options=[("message-type", "ack"), ("subnet_mask", self.netmask), "end"])
|
||||
sendp(dhcp_ack, iface=ifname, verbose=0)
|
||||
print("Sent DHCP Acknowledgement to", dhcp_request[0][Dot11].src)
|
||||
|
||||
def start_dhcp(self):
|
||||
self.server_mac = self.get_if_hwaddr(ifname)
|
||||
# Start sniffing DHCP traffic
|
||||
sniff(iface=ifname, filter="udp and (port 67 or 68)", prn=self.handle_dhcp_packet)
|
24
ctiger/hidden_dragon/eap.py
Normal file
24
ctiger/hidden_dragon/eap.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2024 Anoduck
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
import threading
|
||||
|
||||
|
||||
class EAPHandler():
|
||||
def __init__(self):
|
||||
self.id = 0
|
||||
self.mutex = threading.Lock()
|
||||
|
||||
def next_id(self):
|
||||
self.mutex.acquire()
|
||||
self.id = (self.id + 1)
|
||||
temp = self.id
|
||||
self.mutex.release()
|
||||
|
||||
return temp
|
||||
|
||||
def reset_id(self):
|
||||
self.mutex.acquire()
|
||||
self.id = 0
|
||||
self.mutex.release()
|
|
@ -7,21 +7,24 @@ import struct
|
|||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
from scapy.arch import str2mac, get_if_raw_hwaddr
|
||||
from scapy.layers.inet import IP
|
||||
from .data import apData
|
||||
from ctiger import NetDev
|
||||
from warnings import warn
|
||||
|
||||
|
||||
class TunIf(threading.Thread):
|
||||
def __init__(self, ap, apData, name="fakeap", log):
|
||||
def __init__(self, ap, apData, log, name="fakeap"):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self.apData = apData
|
||||
self.log = log
|
||||
self.dev = apData.dev
|
||||
|
||||
if len(name) > apData.IFNAMSIZ:
|
||||
raise Exception(
|
||||
"Tun interface name cannot be larger than " + str(apData.IFNAMSIZ))
|
||||
"Tun interface name cannot be larger than " + str(
|
||||
apData.IFNAMSIZ))
|
||||
|
||||
self.name = name
|
||||
self.setDaemon(True)
|
||||
|
@ -36,13 +39,13 @@ class TunIf(threading.Thread):
|
|||
# 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)
|
||||
if subprocess.call(['ip', 'addr', 'add', apData.ip, 'dev', self.dev]):
|
||||
warn("Failed to assign IP address {} to {}.".format(apData.ip,
|
||||
self.dev))
|
||||
if subprocess.call(['ip', 'link', 'set', 'dev', self.dev, 'up']):
|
||||
warn("Failed to bring device {} up.".format(self.dev))
|
||||
|
||||
print("Created TUN interface %s at %s. Bind it to your services as needed." % (
|
||||
name, self.ap.ip))
|
||||
log.info("Created TUN interface {} at {}".format(self.name, self.ap.ip))
|
||||
|
||||
def write(self, pkt):
|
||||
os.write(self.fd.fileno(), str(pkt[IP])) # Strip layer 2
|
||||
|
@ -58,3 +61,88 @@ class TunIf(threading.Thread):
|
|||
while True:
|
||||
raw_packet = self.read()
|
||||
self.ap.callbacks.cb_tint_read(raw_packet)
|
||||
|
||||
|
||||
class RouteTraffic(threading.Thread):
|
||||
|
||||
def __init__(self, apIface, apData, log) -> None:
|
||||
if subprocess.call(['iptables', '--table', 'nat', '--append',
|
||||
'POSTROUTING', '--out-interface', apIface, '-j',
|
||||
'MASQUERADE']):
|
||||
warn("Failed to setup postrouting for {}.".format(apIface))
|
||||
if subprocess.call(['iptables', '--append', 'FORWARD',
|
||||
'--in-interface', apData.dev, '-j', 'ACCEPT']):
|
||||
warn("Failed to setup forwarding for {}.".format(apData.dev))
|
||||
if subprocess.call(['sysctl', '-w', 'net.ipv4.ip_forward=1']):
|
||||
warn("Failed to enable IP forwarding.")
|
||||
log.info("Created route traffic for {}".format(apIface))
|
||||
pass
|
||||
|
||||
|
||||
def set_monitor_mode(wlan_dev, enable=True):
|
||||
monitor_dev = None
|
||||
if enable:
|
||||
result = subprocess.check_output(['airmon-ng', 'start', wlan_dev])
|
||||
if not "monitor mode enabled on" in result:
|
||||
printd(clr(Color.RED, "ERROR: Airmon could not enable monitor mode on device %s. Make sure you are root, and that"
|
||||
"your wlan card supports monitor mode." % wlan_dev), Level.CRITICAL)
|
||||
exit(1)
|
||||
monitor_dev = re.search(
|
||||
r"monitor mode enabled on (\w+)", result).group(1)
|
||||
|
||||
printd("Airmon set %s to monitor mode on %s" %
|
||||
(wlan_dev, monitor_dev), Level.INFO)
|
||||
else:
|
||||
subprocess.check_output(['airmon-ng', 'stop', wlan_dev])
|
||||
|
||||
return monitor_dev
|
||||
|
||||
|
||||
def set_ip_address(dev, ip):
|
||||
if subprocess.call(['ip', 'addr', 'add', ip, 'dev', dev]):
|
||||
printd("Failed to assign IP address %s to %s." %
|
||||
(ip, dev), Level.CRITICAL)
|
||||
|
||||
if subprocess.call(['ip', 'link', 'set', 'dev', dev, 'up']):
|
||||
printd("Failed to bring device %s up." % dev, Level.CRITICAL)
|
||||
|
||||
|
||||
def clear_ip_tables():
|
||||
if subprocess.call(['iptables', '--flush']):
|
||||
printd("Failed to flush iptables.", Level.CRITICAL)
|
||||
if subprocess.call(['iptables', '--table', 'nat', '--flush']):
|
||||
printd("Failed to flush iptables NAT.", Level.CRITICAL)
|
||||
if subprocess.call(['iptables', '--delete-chain']):
|
||||
printd("Failed to delete iptables chain.", Level.CRITICAL)
|
||||
if subprocess.call(['iptables', '--table', 'nat', '--delete-chain']):
|
||||
printd("Failed to delete iptables NAT chain.", Level.CRITICAL)
|
||||
|
||||
|
||||
def hex_offset_to_string(byte_array):
|
||||
temp = byte_array.replace("\n", "")
|
||||
temp = temp.replace(" ", "")
|
||||
return temp.decode("hex")
|
||||
|
||||
|
||||
def get_frequency(channel):
|
||||
if channel == 14:
|
||||
freq = 2484
|
||||
else:
|
||||
freq = 2407 + (channel * 5)
|
||||
|
||||
freq_string = struct.pack("<h", freq)
|
||||
|
||||
return freq_string
|
||||
|
||||
|
||||
def mac_to_bytes(mac):
|
||||
return ''.join(chr(int(x, 16)) for x in mac.split(':'))
|
||||
|
||||
|
||||
def bytes_to_mac(byte_array):
|
||||
return ':'.join("{:02x}".format(ord(byte)) for byte in byte_array)
|
||||
|
||||
|
||||
# Scapy sees mon0 interface as invalid address family, so we write our own
|
||||
def if_hwaddr(iff):
|
||||
return str2mac(get_if_raw_hwaddr(iff)[1])
|
||||
|
|
|
@ -11,7 +11,7 @@ import threading
|
|||
from random import choice
|
||||
from time import sleep
|
||||
import os
|
||||
from .dataframe import DataFrame
|
||||
from .dataframe import CtigerDataFrame
|
||||
from .netdev import NetDev
|
||||
|
||||
|
||||
|
@ -113,7 +113,7 @@ class Purge(object):
|
|||
self.valid_file = valid_file
|
||||
self.channels = channels
|
||||
self.log = log
|
||||
df = DataFrame()
|
||||
df = CtigerDataFrame()
|
||||
log.info('mac revealer started')
|
||||
log.info('setting up class attributes')
|
||||
self.scan_df = df.get_df()
|
||||
|
|
|
@ -13,17 +13,17 @@ class ProcLog:
|
|||
|
||||
def get_log(self, log_file, lev):
|
||||
self.log_file = log_file
|
||||
self.lev = 'debug'
|
||||
self.lev = lev
|
||||
if not os.path.exists(log_file):
|
||||
open(log_file, 'a').close()
|
||||
log = logging.getLogger(__name__)
|
||||
if log.hasHandlers():
|
||||
log.handlers.clear()
|
||||
log_levels = {'info': logging.INFO,
|
||||
'debug': logging.DEBUG,
|
||||
'error': logging.ERROR}
|
||||
if lev in log_levels.keys():
|
||||
set_level = log_levels[lev]
|
||||
log_levels = {'INFO': logging.INFO,
|
||||
'DEBUG': logging.DEBUG,
|
||||
'ERROR': logging.ERROR}
|
||||
if self.lev in log_levels.keys():
|
||||
set_level = log_levels[self.lev]
|
||||
log.setLevel(set_level)
|
||||
else:
|
||||
warn('Invalid level. Defaulting to debug')
|
||||
|
|
Loading…
Reference in a new issue