def port_scan(self, ip: str, connect_timeout: int, ports: list, isudp: bool, threads: int): logger.info(f"Start {'UDP' if isudp else 'TCP'} port scan on {ip}...") block_ports = [] for i in range(0, len(ports), 10): #每次检测10个端口 block_ports.append(ports[i:i + 10]) job = Worker(self._port_scan_handler, block_ports, threads) job.set_param(ip, connect_timeout, isudp) job.start() try: while job.is_running(): workdone_count = 0 opened_count = 0 for v in job.current_vlist: if v.solved: opened_count += len(v.ret[0]) workdone_count += v.ret[1] per = int(workdone_count / len(ports) * 100) print( f"Progress {per}% ({workdone_count}/{len(ports)}), {opened_count} opened ports on {ip}.", end='\r', flush=True) utils.sleep(0.3) except: job.stop() logger.warning("Work is over!") for v in job.current_vlist: # 线程结束后统计 if self._scan_result.get(ip) is None: self._scan_result[ip] = [] self._scan_result[ip].extend(v.ret[0]) logger.info( f"All {'UDP' if isudp else 'TCP'} ports have been detected, total `{len(self._scan_result[ip])}` opened on {ip}." + ' ' * 20)
def cmdloop(self): self.running = True thread_list = [] keepthread = threading.Thread(target=self._keep_shell_alive, name="keep shell alive") shellthread = threading.Thread(target=self._shell, name="shell") readerthread = threading.Thread(target=self._reader, name="reader") keepthread.setDaemon(True) shellthread.setDaemon(True) readerthread.setDaemon(True) thread_list.append(keepthread) keepthread.start() utils.sleep(1) if self.running: thread_list.append(shellthread) thread_list.append(readerthread) shellthread.start() else: return utils.sleep(1) readerthread.start() try: if self.exp.session.server_info.isUnix( ) and self._is_supported_shell(): logger.info( 'You can type `:getfshell` to upgrade to a fully interactive shell(The premise is that Pty has been obtained.)' ) logger.info( "Type `Ctrl + c` three times in a row to exit the fully interactive shell" ) while self.running: cmd = utils.input() if not cmd: continue if self.exp.session.server_info.isUnix( ) and cmd == ':getfshell' and self._is_supported_shell(): if not self.enter_fully_shell(): logger.error( "Unable to get a fully interactive shell!") continue break self._writer(cmd + '\n') except KeyboardInterrupt: pass self.close() logger.info("Wait for thread exit...") for t in thread_list: t.join(5) if t.is_alive() and not utils.kill_thread(t.ident): logger.error( f"Exit thread `{t.name}` failed, thread id is `{t.ident}`!" ) logger.info("All have been cleaned up!")
def enter_fully_shell(self) -> bool: '''获取完全交互式shell,仅支持Unix(服务器和本机),需要首先获取一个tty ''' self.writer('tty && echo -e "ok\\tok" || echo -e "not\\ta\\ttty"\n') msg = '' sign = False while True: self._lock.acquire() msg = self.last_recv self._lock.release() if msg is not None: if "not\ta\ttty" in msg: logger.error("There is no Pty at present!") break elif "ok\tok" in msg: sign = True break if not self.running: return False utils.sleep(0.1) if sign: rows = os.get_terminal_size().lines columns = os.get_terminal_size().columns term = os.environ.get('TERM', 'linux') self.writer( f'export TERM={term};export SHELL=bash;stty rows {rows} columns {columns}\n' ) # 设置当前terminal termios = importlib.import_module('termios') tty = importlib.import_module('tty') fd = ioconfig.stdin.fileno() old = termios.tcgetattr(fd) new = old[:] new[3] &= ~termios.ECHO termios.tcsetattr(fd, termios.TCSANOW, new) tty.setraw(fd, termios.TCSANOW) logger.info("Now you have acquired a fully interactive shell!", True) # 进入完全交互式shell exit_code = b'' while self.running: cmd = ioconfig.stdin.getbytes() if cmd == b"\x03": exit_code += b'\x03' else: exit_code = b'' if exit_code == b'\x03\x03\x03': break self.writer(cmd) # 还原终端设置 termios.tcsetattr(fd, termios.TCSANOW, old) return True return False
def host_survival_scan(self, hosts: str, timeout: int, threads: int, host_detect_udp: bool): '''测试主机是否存活,timeout超时时间,单位毫秒 ''' logger.info("Start host survival detection...") if not host_detect_udp: # 若使用ping扫描,则检查是否有ping命令使用权限 ret = None if self.session.server_info.isWindows(): ret = self.exec_command( f'cmd /c "ping -n 1 -w {timeout} 127.0.0.1 && echo pingok"' ) else: ret = self.exec_command( f'ping -c 1 -W {timeout//1000} 127.0.0.1 && echo pingok') if ret is not None and 'pingok' in ret: logger.info("Ping scan is currently available!") else: logger.error( "Currently, there is no permission to use ping command, or ping command does not exist!" ) return block_hosts = [] for i in range(0, len(hosts), 10): #每次检测10个主机 block_hosts.append(hosts[i:i + 10]) job = Worker( self._host_survival_scan_handler_by_ping if not host_detect_udp else self._host_survival_scan_handler_by_udp, block_hosts, threads) job.set_param(timeout) job.start() try: while job.is_running(): workdone_count = 0 alive_count = 0 for v in job.current_vlist: if v.solved: alive_count += len(v.ret[0]) workdone_count += v.ret[1] per = int(workdone_count / len(hosts) * 100) print( f"Progress {per}% ({workdone_count}/{len(hosts)}), {alive_count} alive hosts.", end='\r', flush=True) utils.sleep(0.3) except: job.stop() logger.warning("Work is over!") for v in job.current_vlist: # 线程结束后统计 for ip in v.ret[0]: self._scan_result[ip] = [] logger.info( f"All hosts have been detected, total `{len(self._scan_result)}` alive." + ' ' * 20)
def run(self): try: self.sock.bind((self.lhost, self.lport)) self.sock.listen(self.max_listen_count) except OSError as e: logger.error(e) return thread_list = [] while True: try: sock, addr = self.sock.accept() except OSError: break logger.info(f"A connection created!From {addr}") sock.setblocking(False) sessionid = utils.randomstr(16) self.connections[sessionid] = sock forwardwork = threading.Thread( target=self._forward, args=(sessionid, ), name=f"{sessionid}-forward on rule `{self._rule_name}`") readerthread = threading.Thread( target=self._reader, args=(sessionid, ), name=f"{sessionid}-reader on rule `{self._rule_name}`") writerthread = threading.Thread( target=self._writer, args=(sessionid, ), name=f"{sessionid}-writer on rule `{self._rule_name}`") thread_list.append(forwardwork) thread_list.append(readerthread) thread_list.append(writerthread) forwardwork.setDaemon(True) readerthread.setDaemon(True) writerthread.setDaemon(True) forwardwork.start() utils.sleep(1) readerthread.start() writerthread.start() for t in thread_list: t.join()
def run(self): thread_list = [] sessionid = utils.randomstr(16) self.connections[sessionid] = None forwardwork = threading.Thread(target=self._forward, args=(sessionid, )) forwardwork.setDaemon(True) thread_list.append(forwardwork) forwardwork.start() utils.sleep(1) if self._test_connect(sessionid): sock = socket.socket() self.connections[sessionid] = sock sock.settimeout(5) try: sock.connect((self.lhost, self.lport)) except OSError as e: logger.error( f"Connect to `{self.lhost}:{self.lport}` on rule `{self._rule_name}` failed!" ) logger.error(e.strerror) self._close(sessionid) for t in thread_list: t.join() return sock.setblocking(False) readerthread = threading.Thread(target=self._reader, args=(sessionid, ), name=f"{self._rule_name}-reader") writerthread = threading.Thread(target=self._writer, args=(sessionid, ), name=f"{self._rule_name}-writer") readerthread.setDaemon(True) writerthread.setDaemon(True) thread_list.append(readerthread) thread_list.append(writerthread) readerthread.start() writerthread.start() for t in thread_list: t.join()
def cmdloop(self): self.running = True start_thread = threading.Thread(target=self.start_shell) reader_thread = threading.Thread(target=self.reader) thread_list = [start_thread, reader_thread] start_thread.setDaemon(True) reader_thread.setDaemon(True) start_thread.start() utils.sleep(1) reader_thread.start() try: if self.exp.session.server_info.isUnix( ) and self._is_supported_shell(): logger.info( 'You can type `:getfshell` to upgrade to a fully interactive shell(The premise is that Pty has been obtained.)' ) logger.info( "Type `Ctrl + c` three times in a row to exit the fully interactive shell" ) while self.running: cmd = utils.input() if not cmd: continue if self.exp.session.server_info.isUnix( ) and cmd == ':getfshell' and self._is_supported_shell(): if not self.enter_fully_shell(): logger.error( "Unable to get a fully interactive shell!") continue break self.writer(cmd + '\n') except KeyboardInterrupt: pass except BaseException as e: logger.error(e) self.close() for t in thread_list: t.join(5) if t.is_alive(): utils.kill_thread(t.ident)