def exec(self, cmdline: str) -> str: '''在服务器上执行命令并获取结果 ''' fl = [self.method] if self.method in ('auto', None, ''): fl = [ 'exec', 'shell_exec', 'system', 'passthru', 'popen', 'proc_open', 'wscript' ] for f in fl: tmp = self.exp.evalfile(f'php/{f}', cmd=cmdline, pwd=self.exp.session.pwd) if not tmp.is_success(): return None r = json.loads(tmp.data) if r['code'] == 0: continue self.method = f result = base64.b64decode(r['result'].encode()).decode( self.exp.session.client.options.encoding, 'ignore') return result logger.warning( 'No way to exec command!Maybe all functions is disabled.') return None
def run(self, args: Cmdline) -> int: args = self.parse.parse_args(args.options) text = self.load_config(self._name) if text is None: logger.warning("There is currently no memo!Will create a new.") text = {'note': ''} text = text['note'] raw_text = base64.b64decode(text.encode()) with tempfile.TemporaryDirectory() as tmpdir: path = os.path.join(tmpdir, 'note') with open(path, 'wb') as f: f.write(raw_text) if os.system(f"{config.editor} {path}") != 0: logger.error( f"Run editor `{config.editor}` failed!The editor must edit file in console like `vim filename` or `notepad filename`" ) logger.info( f"You can change editor in config file `{os.path.join(config.root_path, 'config.py')}`" ) return self.STOP with open(path, 'rb') as f: text = f.read() if text == raw_text: logger.warning( 'The content has not been changed, so it has not been saved!' ) else: self.save_config(self._name, {'note': base64.b64encode(text).decode()}) logger.info("Content has been updated!", True) return self.SUCCESS
def put(self, kanban_id, issue_id): request.get_json(force=True) if api.payload is None or api.payload == {}: return {"response": "Unable to decode payload"}, 400 if (api.payload["stage"].replace(" ", "") == "" or api.payload["stage"] == "string"): return { "response": "Stage cannot be null or whitespaces only" }, 400 elif api.payload["stage"] not in [stage.value for stage in Stages]: return { "response": "Stage cannot be anything other than todo, done or doing" }, 400 issue_stage_hand = IssueStageHandler() logger.info(f"Changing issue with id {issue_id} current stage") try: issue_stage_hand.change_stage( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id, issue_id=issue_id, stage_to_assign=api.payload["stage"], ) return {}, 204 except AttributeError: logger.error( f"Issue is not set to any stage! Check issue config xml") return {"response": "Issue is not set to any stage"}, 500 except FileNotFoundError: logger.warning("Issue couldn't be found") return {"response": "Issue id not found"}, 400 except Exception as e: logger.error("Couldn't update issue stage!") logger.exception(e) return {"response": "Unable to update issue stage"}, 500
def get(self, kanban_id): """ Return all issues info for given kanban board """ kanban_finder = KanbanFinder() logger.info(f"Fetching kanban directory with id {kanban_id}") kanban_directory, kanban_check = kanban_finder.find_kanban_dir_with_id( kanban_id=kanban_id, kanbans_directory=config.kanbans_directory) logger.info(f"Kanban directory {kanban_directory}") if kanban_check: issue_finder = IssueFinder() try: logger.info( f"Fetching all issues for kanban with id {kanban_id}") all_issues_info_list = issue_finder.return_all_issues_info_for_kanban( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id) response = jsonify(all_issues_info_list) response.headers.add("Access-Control-Allow-Origin", "*") return response except Exception as e: logger.error("Unable to fetch issues!") logger.exception(e) return {"response": "Unable to fetch issues"}, 500 else: logger.warning( f"Unable to fetch issues! Kanban with id {kanban_id} not found" ) return {"response": "Kanban id not found"}, 400
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 run(self, args: Cmdline)-> int: args = self.parse.parse_args(args.options) ret = self.SUCCESS if args.add: lhost = args.lhost if args.lhost else None lport = args.lport if args.lport else None rhost = args.rhost if args.rhost else None rport = args.rport if args.rport else None lf = True if args.L else (False if args.R else None) uploadsize = args.uploadsize info = (lhost, lport, rhost, rport, lf, uploadsize) if None in info: logger.error("Some options are not set.Check you input.") return self.STOP ret = self._add(*info) elif args.flush: for ID in args.flush: rule = self._forward_list.get(ID) if rule: self._flush(ID) else: logger.warning(f"No specified rules `{ID}`!") elif args.delete: self._delete(args.delete) else: ret = self._list() return ret
def delete(self, kanban_id, issue_id): """ Deletes issue for given kanban """ kanban_finder = KanbanFinder() logger.info(f"Fetching kanban directory with id {kanban_id}") kanban_directory, kanban_check = kanban_finder.find_kanban_dir_with_id( kanban_id=kanban_id, kanbans_directory=config.kanbans_directory) logger.info(f"Kanban directory {kanban_directory}") if kanban_check: try: issue_deleter = IssueDeleter() issue_deleter.delete_issue_for_kanban( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id, issue_id=issue_id, ) except FileNotFoundError as fe: logger.warning( f"Unable to update issues! Issue with id {issue_id} not found" ) logger.exception(fe) return {"response": "Issue id not found"}, 400 except Exception as e: logger.error("Couldn't update issue") logger.exception(e) return {"response": "Couldn't update issue"}, 500 return 204 else: logger.warning( f"Unable to fetch issues! Kanban with id {kanban_id} not found" ) return {"response": "Kanban id not found"}, 400
def _forward(self, sessionid: str): '''执行前需要把webshell超时时间设置为无限 ''' self.exp.session.client.options.set_temp_option('timeout', 0) self.exp.session.client.options.set_temp_option('verbose', 1) ret = self.exp.evalfile('forward/forward', rhost=self.rhost, rport=self.rport, sessionid=sessionid) ret = ret.data if ret is None: logger.warning( "Forward request has exit!If forwarding is still working, please ignore this warning." ) return ret = json.loads(ret) if ret['code'] == -1: # connect failed error = base64.b64decode(ret['msg'].encode()).decode( self.exp.session.client.options.encoding, 'ignore') logger.error(error) elif ret['code'] == 1: logger.info( f"Connection has closed successfully for id `{sessionid}`!", False) self._close(sessionid)
def post(self, kanban_id): request.get_json(force=True) if api.payload is None or api.payload == {}: return {"response": "Unable to decode payload"}, 400 try: if (api.payload["name"].replace(" ", "") == "" or api.payload["creator"].replace(" ", "") == ""): return { "response": "Name/creator cannot be null or whitespaces only" }, 400 except KeyError as ke: logger.exception(ke) return {"response": "Name/description is missing"}, 400 logger.info("Creating issue xml config") issue_creator = IssueCreator() try: logger.info("Creating issue directory if needed") issue_creator.create_issue_folder( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id) except FileNotFoundError as fe: logger.error(f"Unable to create issue directory! " f"Kanban with id {kanban_id} doesn't exist") logger.exception(fe) return {"response": "Kanban id not found"}, 400 except Exception as e: logger.error("Unable to create issues directory!") logger.exception(e) return {"response": "Unable to create issues directory!"}, 500 try: logger.info("Creating new issue") issue_creator.create_new_issue_config( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id, issue_description=api.payload["description"], issue_name=api.payload["name"], creator=api.payload["creator"], ) return { "response": f"Issue with name {api.payload['name']} for kanban with id {kanban_id} created!" }, 201 except FileExistsError as fe: logger.warning("Issue already exists!") return { "response": "Unable to create new issue!", "exception": str(fe), }, 500 except Exception as e: logger.error("Unable to create issue!") logger.exception(e) return {"response": "Unable to create new issue!"}, 500
def _upload(self, remote: str, data: bytes, force: bool, uploadsize: int) -> int: '''将数据写入到远程文件 ''' sign = 1 if force else 0 total = math.ceil(len(data) / uploadsize) if uploadsize > 0 else 1 progress = 0 while data: block = data[:uploadsize] if uploadsize > 0 else data data = data[uploadsize:] if uploadsize > 0 else b'' ret = self.evalfile('upload', pwd=self.session.pwd, path=remote, data=block, sign=sign) sign = 2 ret = ret.data while ret is None: if total > 1: # 如果分片上传时失败,则重传一次该分片 ret = self.evalfile('upload', pwd=self.session.pwd, path=remote, data=block, sign=sign) if ret.is_success(): ret = ret.data break logger.error("upload file error!") return self.STOP if ret == '0': logger.warning(f"Remote file `{remote}` is exist.") if utils.input("Are you sure to overwrite the file? (y/n) " ).lower() == 'y': return self._upload(remote, block + data, True, uploadsize) elif ret == '-1': logger.error("Remote file open failed!") logger.error( 'Check if the path is correct or if you have write permission.' ) return self.STOP elif ret == '1': if total > 1: progress += 1 per = str(int(progress / total * 100)) + '%' per = per.rjust(4, ' ') print(f"Upload progress {per} ({progress}/{total}).", end='\r', flush=True) continue else: logger.error("Unknow error!") return self.STOP logger.info(f"Upload file `{remote}` successfully!") return self.SUCCESS
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 _delete(self, id_list: list): if not id_list: return logger.info("Deleting the specified forwarding rules...") for ID in id_list: rule = self._forward_list.get(ID) if rule: if rule['forwd']: rule['forwd'].close() self._forward_list.pop(ID) logger.info(f"Delete a forward rule `{ID}`", False) else: logger.warning(f"No specified rules `{ID}`!")
def _close(self, sessionid: str): self.lock.acquire() if sessionid in self.connections: sock = self.connections.pop(sessionid) if sock: try: sock.shutdown(socket.SHUT_RDWR) except OSError: pass sock.close() self.exp.evalfile('reverse/close', sessionid=sessionid) logger.warning('Connection is closed!') self.lock.release()
def _close(self, sessionid: str): self.lock.acquire() if sessionid in self.connections: client = self.connections.pop(sessionid) if client: try: client.shutdown(socket.SHUT_RDWR) except OSError: pass client.close() self.exp.evalfile('forward/close', sessionid=sessionid) logger.warning('Connection is closed!') self.lock.release()
def _error_handler(self, error: dict, result: EvalResult)-> bool: '''处理webshell返回的错误信息 ''' if error['code'] != 1: for msg in error['msg']: err = self.EvalError(msg[0], base64.b64decode(msg[1].encode()).decode(self.options.encoding, 'ignore'), True if error['code'] == 0 or msg[2] else False, True) result.add_error_info(err) if err.iswarning and self.options.verbose > 1: logger.warning(err) elif not err.iswarning and self.options.verbose > 0: logger.error(err) if error['code'] == -1: return False return True
def run(self, args: Cmdline) -> int: args = self.parse.parse_args(args.options) if args.interactive: self.interactive(args.interactive, args.type) elif args.show_methods: self.show_methods() elif args.executor_method: self.executor.method = args.executor_method self.show_methods() elif args.command == '': logger.warning("You entered an empty command!") else: self.exec(args.command, args.raw_executor) return self.SUCCESS
def get(self, kanban_id): """Returns kanban board with given id""" kanban_finder = KanbanFinder() logger.info(f"Fetching kanban with id {kanban_id} info") kanban_directory, kanban_found = kanban_finder.find_kanban_dir_with_id( kanban_id=kanban_id, kanbans_directory=config.kanbans_directory) if kanban_found: kanban_info_list = kanban_finder.return_kanban_info( kanban_directory=kanban_directory) response = jsonify(kanban_info_list) response.headers.add("Access-Control-Allow-Origin", "*") return response else: logger.warning(f"Kanban with id {kanban_id} not found!") return {"response": "Kanban id not found"}, 400
def _create_from_client(self, session: Session, nosave: bool, save_id: int) -> int: '''从指定session中的webshell client建立连接 ''' webshell = session.client if webshell is None: logger.error('You must use a webshell client first.') return self.STOP if len(webshell.options.unset_list()) > 0: # 检测选项设置 logger.error("There are some unset options!") return self.STOP # explot 当前目标 if webshell.connect(): ID = 1 if len(self.manager.session_map) == 0 else max( self.manager.session_map) + 1 s = WebshellSession(webshell, ID) self.manager.session_map[ID] = s if save_id: s.state['save_id'] = save_id # 表示该session是从保存的连接建立的 if isinstance(session, MainSession): session.client = None session[ 'Prompt'] = lambda: f"{colour.colorize(config.app_name, 'underline')} {colour.colorize(config.prompt, fore='blue')} " logger.info(f'A session is created, id is `{ID}`', True) if not nosave: # 存储建立的连接 self._save(s) else: s.state['nosave'] = True # 给session增加一个不保存的标志 webshell.hook_start(s) s['Prompt'] = lambda :colour.colorize(s.server_info.domain+'\\'+s.server_info.user, 'bold', 'cyan')+'@'+\ colour.colorize(s.state['name'], fore='purple')+\ ':'+f"({colour.colorize(s.pwd, fore='red')})"+' \n'+colour.colorize(config.prompt, 'bold', 'blue')+' ' self.manager.loadexploit_to_session( self.manager.modules.get('exploit', {}), 'exploit', s) # 载入命令 # 全部命令加载成功后调用命令回调 s._hook_loaded() webshell.hook_loaded() self.manager.exec(["sessions", '-i', str(ID)]) return self.SUCCESS logger.warning("Session create failed!") return self.STOP
def delete(self, kanban_id): """ Delete kanban board with given id """ logger.info(f"Deleting kanban with id {kanban_id}") try: kanban_deleter = KanbanDeleter() kanban_deleter.delete_kanban( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id) return {"response": "Kanban deleted"}, 204 except FileNotFoundError: logger.warning(f"Kanban with id {kanban_id} not found") return {"response": "Kanban id not found"}, 400 except Exception as e: logger.error("Unable to delte kanban") logger.exception(e) return { "response": "Unable to delte kanban", "exception": str(e) }, 500
def run(self, args: Cmdline) -> int: args = self.parse.parse_args(args.options) local = args.local if local is None: local = utils.pathsplit(args.source)[1] local = local.replace('/', os.sep) local = os.path.join(config.work_path, local) d, fname = utils.pathsplit(args.source) if os.path.exists(local): if os.path.isfile(local): logger.warning(f"Local file `{local}` is exist.") if utils.input( colour.colorize("Are you sure to overwrite it?(y/n) ", 'bold')).lower() != 'y': return self.STOP elif os.path.isdir(local): # 如果指定的本地路径为目录,那么会把下载的文件或目录放在该目录下 for f in os.listdir(local): if f.lower() == fname.lower(): if os.path.isdir(f): # 不准有同名目录 logger.error( f"Local folder `{local}` contain a same name directory `{f}`!" ) return self.STOP logger.warning( f"Local folder `{local}` contain a same name file `{fname}`." ) if utils.input( colour.colorize( "Are you sure to overwrite it?(y/n) ", 'bold')).lower() != 'y': return self.STOP break else: dirname = os.path.dirname(local.rstrip(os.sep)) if not os.path.exists(dirname): logger.error(f"Local directory `{dirname}` is not exist!") return self.STOP logger.info("Downloading...") ret = self.download(args.source, local, args.recursive) if ret == self.SUCCESS: logger.info("All items downloaded!") return ret
def _list(self) -> int: table = [['ID', 'Webshell Type', 'Target']] try: tree = ET.parse(config.webshell_save_path) root = tree.getroot() for c in root: l = [] l.append(c.attrib.get('id', 1)) l.append(c.find("./webshell").attrib.get("value")) l.append( c.find("./options/option[@name='target']").attrib.get( 'value')) table.append(l) except (FileNotFoundError, ET.ParseError): logger.warning( f"Load or parse file `{config.webshell_save_path}` failed!") return self.STOP print(tablor(table, border=False, title="Saved Webshell Connections")) return self.SUCCESS
def _kill(self, ID: int, force=False) -> int: if ID not in self.manager.session_map: logger.error(f"No session id is `{ID}`.") return self.STOP if isinstance(self.session, WebshellSession) and ID == self.session.id: logger.warning('You will kill the session you live on!') if force or utils.input( f"Are you sure to kill the session with id `{ID}` (y/n)" ).lower() == 'y': s = self.manager.session_map[ID] # 执行销毁时的回调函数 s._hook_destroy() del self.manager.session_map[ID] logger.info(f"A session `{ID}` has been killed.", False) if isinstance(self.session, WebshellSession) and ID == self.session.id: return self._switch(0) return self.SUCCESS
def put(self, kanban_id): """Updates kanban board with given id""" kanban_finder = KanbanFinder() logger.info(f"Updating kanban with id {kanban_id}") kanban_directory, kanban_found = kanban_finder.find_kanban_dir_with_id( kanban_id=kanban_id, kanbans_directory=config.kanbans_directory) response = dict() if kanban_found: config_file_dir = os.path.join(kanban_directory, "config.xml") logger.info(config_file_dir) request.get_json(force=True) if api.payload is None or api.payload == {}: return {"response": "Unable to decode payload"}, 400 try: if api.payload["name"].replace(" ", "") == "": return { "response": "Name cannot be null or whitespaces only" }, 400 elif api.payload["name"] != "string": update_xml_attribute(config_file_dir, "name", api.payload["name"]) response[ "response_name"] = f"Updated with {api.payload['name']}" if api.payload["description"] != "string": update_xml_attribute(config_file_dir, "description", api.payload["description"]) response[ "response_desc"] = f"Updated with {api.payload['description']}" except KeyError as ke: logger.error("Key not matching model used!") logger.exception(ke) return {"response": "Wrong key! Use given model"}, 400 return response, 204 else: logger.warning(f"Kanban with id {kanban_id} not found!") return {"response": "Kanban id not found"}, 404
def get(self, kanban_id, issue_id): kanban_finder = KanbanFinder() logger.info(f"Fetching kanban directory with id {kanban_id}") kanban_directory, kanban_check = kanban_finder.find_kanban_dir_with_id( kanban_id=kanban_id, kanbans_directory=config.kanbans_directory) logger.info(f"Kanban directory {kanban_directory}") if kanban_check: issue_finder = IssueFinder() issues_directory = issue_finder.return_issues_directory_for_kanban( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id) issue_check = issue_finder.check_if_issue_extists( issues_directory=issues_directory, issue_id=issue_id) if issue_check: try: logger.info( f"Fetching issues with id {issue_id} for kanban with id {kanban_id}" ) issue_info_list = issue_finder.return_issue_info_for_kanban( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id, issue_id=issue_id, ) response = jsonify(issue_info_list) response.headers.add("Access-Control-Allow-Origin", "*") return response except Exception as e: logger.error("Unable to fetch issues!") logger.exception(e) return {"response": "Unable to fetch issues"}, 500 else: logger.warning( f"Unable to fetch issues! Issue with id {issue_id} not found" ) return {"response": "Issue id not found"}, 400 else: logger.warning( f"Unable to fetch issues! Kanban with id {kanban_id} not found" ) return {"response": "Kanban id not found"}, 400
def run(self, args: Cmdline) -> int: args = self.parse.parse_args(args.options) if args.force or utils.input( "Are you sure to delete these files? (y/n) ").lower() == 'y': flist = "\n".join(args.dest) ret = self.evalfile('payload', flist=flist, pwd=self.session.pwd) ret = ret.data if ret is None: logger.error("Remove file error!") return self.STOP ret = json.loads(ret) for msg in ret['msg']: msg = base64.b64decode(msg).decode( self.session.client.options.encoding, 'ignore') if 'failed' in msg or 'exist' in msg: logger.warning(msg) else: logger.info(msg) if ret['code'] == -1: return self.STOP return self.SUCCESS
def _parse_hosts(self, hosts: list) -> list: '''解析ip范围,返回ip字符串的列表 ''' ret = [] if not hosts: # 若未指定hosts,则使用上传扫描结果中存活的主机 logger.warning( "No host specified, use the host that alive the last scan.") for ip in self._scan_result: ret.append(ip) logger.info(f"Using alive host {ip}") return ret for h in hosts: h = h.strip() min_ip = 0 max_ip = 0 try: if '/' in h: ip, mask = h.split('/') ip = struct.unpack("!L", socket.inet_aton(ip))[0] mask = int(mask) if mask <= 0 or mask >= 32: raise ValueError('mask is error!') min_ip = ip & (2**32 - 2**(32 - mask)) + 1 max_ip = min_ip + 2**(32 - mask) - 3 elif '-' in h: ip0, ip1 = h.split('-') min_ip = struct.unpack("!L", socket.inet_aton(ip0))[0] max_ip = struct.unpack("!L", socket.inet_aton(ip1))[0] if min_ip > max_ip: raise ValueError('IP range is error!') else: min_ip = max_ip = struct.unpack("!L", socket.inet_aton(h))[0] for ip in range(min_ip, max_ip + 1): ret.append(socket.inet_ntoa(struct.pack('!L', ip))) except: logger.error(f"Host `{h}` format error!") return ret
def start_shell(self): self.exp.session.client.options.set_temp_option("timeout", 0) self.exp.session.client.options.set_temp_option( "verbose", self._verbose) ret = self.exp.evalfile("interact_normal/shell", shell=self.shell, pwd=self.exp.session.pwd, infile=self.in_file, outfile=self.out_file) ret = ret.data if ret is None: logger.warning( "Request `start_shell` has exit, if the shell is running normally please ignore the warning" ) return if ret == "-1": logger.error( "Cannot run interactive shell!The remote server is missing a necessary component!" ) elif ret == "-2": logger.error("The interactive shell process failed to start!") self.close()
def interactive(self, shell: str, type: str): if shell == "ok": if self.session.server_info.isWindows(): shell = "cmd 2>&1" else: shell = "sh -i 2>&1" interact_shell = BaseShell(self) if type is None: type = "base" if type == "normal": interact_shell = NormalShell(self, shell) elif type == "namedpipe": if self.session.server_info.isWindows(): logger.warning( "Windows system has not yet implemented interactive shell execution through named pipes!" ) logger.info( "The same effect can be achieved by using `normal` type") return else: interact_shell = NamedpipeUnixShell(self, shell) interact_shell.cmdloop()
def cmdloop(self): logger.info( "Simply execute commands without maintaining any state.Type `exit` or `Ctrl-C` to exit." ) logger.warning( "This shell is just a loop to execute the input commands, not a real interactive shell!" ) self.running = True try: while self.running: cmd = utils.input(">> ") if cmd: if cmd.lower() == 'exit': self.running = False break msg = self.exp.exec_command(cmd + " 2>&1") if msg is None: logger.error(f"Exec `{cmd}` failed!") continue print( msg.decode(self.exp.session.client.options.encoding, 'ignore')) except KeyboardInterrupt: pass
def get(self, kanban_id, issue_id): """ Check on which stage issue is """ issue_stage_hand = IssueStageHandler() logger.info(f"Checking issue with id {issue_id} current stage") try: stage = issue_stage_hand.check_stage( kanbans_directory=config.kanbans_directory, kanban_id=kanban_id, issue_id=issue_id, ) response = jsonify(stage) response.headers.add("Access-Control-Allow-Origin", "*") return response except AttributeError: logger.error( f"Issue is not set to any stage! Check issue config xml") return {"response": "Issue is not set to any stage"}, 500 except FileNotFoundError: logger.warning("Issue couldn't be found") return {"response": "Issue id not found"}, 400 except Exception as e: logger.error("Couldn't check issue stage!") logger.exception(e) return {"response": "Couldn't check issue stage"}, 500