From 22c9c9755f0f23ddc00cb0c27d1170f7ef5f25a9 Mon Sep 17 00:00:00 2001 From: Daniel Uroz Date: Tue, 14 Apr 2020 16:15:14 +0200 Subject: [PATCH] Projecto moved to https://github.com/reversea-me/winesap --- README.md | 24 +----- lab/active_setup.py | 6 -- lab/appinit_dlls.py | 13 --- lab/image_file_exec_options.py | 6 -- lab/installed_components.py | 7 -- lab/run_keys.py | 36 -------- lab/runall.py | 11 --- lab/scheduled_task.py | 6 -- lab/service.py | 7 -- lab/shortcuts.py | 16 ---- lab/startup.py | 14 ---- lab/winlogon.py | 6 -- lab/winutils.py | 89 -------------------- plugin/winesap.py | 148 --------------------------------- 14 files changed, 1 insertion(+), 388 deletions(-) delete mode 100644 lab/active_setup.py delete mode 100644 lab/appinit_dlls.py delete mode 100644 lab/image_file_exec_options.py delete mode 100644 lab/installed_components.py delete mode 100644 lab/run_keys.py delete mode 100644 lab/runall.py delete mode 100644 lab/scheduled_task.py delete mode 100644 lab/service.py delete mode 100644 lab/shortcuts.py delete mode 100644 lab/startup.py delete mode 100644 lab/winlogon.py delete mode 100644 lab/winutils.py delete mode 100644 plugin/winesap.py diff --git a/README.md b/README.md index b1e912e..1e0bcb7 100644 --- a/README.md +++ b/README.md @@ -1,23 +1 @@ -##Usage -Command: - -```vol.py --plugins=AutoRuns/plugin --profile=Win7SP1x64 -f dump.vmem autoruns``` - -Help: - -``` -Search for all Autostart Extensibility Points (AESPs) - -Options: - --match: only shows suspicious entries -``` - -##Help scripts - -Under ```lab``` folder there are some scripts to simulate an infection on a Windows system. You can run them one by one or use ```runall.py``` to run them all (needs a privileged command line). - -Anyway, there is available an [infected memory dump](https://drive.google.com/file/d/1f6E3mCQMu86UDk3j2PkHSbF63YJOctND/) with all scripts executed. - -###Dependencies - -```pip install pywin32``` in order to work with Windows registers. +Project moved to https://github.com/reversea-me/winesap diff --git a/lab/active_setup.py b/lab/active_setup.py deleted file mode 100644 index 9ac76cc..0000000 --- a/lab/active_setup.py +++ /dev/null @@ -1,6 +0,0 @@ -import winutils - -binary = winutils.infect_system_exe() - -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{0}'.format(winutils.random_guid()), 'StubPath', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) -winutils.set_registry_value('HKCU\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{0}'.format(winutils.random_guid()), 'StubPath', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) \ No newline at end of file diff --git a/lab/appinit_dlls.py b/lab/appinit_dlls.py deleted file mode 100644 index 9c8d6b0..0000000 --- a/lab/appinit_dlls.py +++ /dev/null @@ -1,13 +0,0 @@ -import winutils - -binary = winutils.infect_system_dll() - -# System32 -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'LoadAppInit_DLLs', 0x1) -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'RequireSignedAppInit_DLLs', 0x0) -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'AppInit_DLLs', binary) - -# SysWow64 -winutils.set_registry_value('HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'LoadAppInit_DLLs', 0x1) -winutils.set_registry_value('HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'RequireSignedAppInit_DLLs', 0x0) -winutils.set_registry_value('HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows', 'AppInit_DLLs', binary) diff --git a/lab/image_file_exec_options.py b/lab/image_file_exec_options.py deleted file mode 100644 index d34f2c9..0000000 --- a/lab/image_file_exec_options.py +++ /dev/null @@ -1,6 +0,0 @@ -import winutils - -binary = winutils.infect_system_exe() - -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\firefox.exe', 'Debugger', binary) -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\chrome.exe', 'Debugger', binary) diff --git a/lab/installed_components.py b/lab/installed_components.py deleted file mode 100644 index a2d977b..0000000 --- a/lab/installed_components.py +++ /dev/null @@ -1,7 +0,0 @@ -import winutils - -binary = winutils.infect_system_exe() -guid = winutils.random_guid() - -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Active Setup\\Installed Components\\{0}'.format(guid), 'StubPath', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Active Setup\\Installed Components\\{0}'.format(guid), None, winutils.random_name()) \ No newline at end of file diff --git a/lab/run_keys.py b/lab/run_keys.py deleted file mode 100644 index 8cc9e62..0000000 --- a/lab/run_keys.py +++ /dev/null @@ -1,36 +0,0 @@ -import winutils - -binary = winutils.infect_system_exe() - -# HKCU Run -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', winutils.random_name(), binary) - -# HKCU RunOnce -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce', winutils.random_name(), 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) - -# HKCU RunOnceEx -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Title', winutils.random_name()) -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Flags', 0x00000002) -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\0001', 'RunMyApp', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) - -# Terminal Run -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', winutils.random_name(), binary) - -# Terminal RunOnce -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce', winutils.random_name(), 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) - -# Terminal RunOnceEx -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Title', winutils.random_name()) -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Flags', 0x00000002) -winutils.set_registry_value('HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'RunMyApp', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary)) - -# HKLM Run -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', 'Test', binary) - -# HKLM RunOnce -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce', 'Test', 'C:\\Windows\\System32\\rundll32.exe C:\\Windows\\System32\\shell32.dll,ShellExec_RunDLL C:\\Windows\\System32\\calc.exe') - -# HKLM RunOnceEx -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Title', winutils.random_name()) -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx', 'Flags', 0x00000002) -winutils.set_registry_value('HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\0001', 'RunMyApp', 'C:\\Windows\\System32\\rundll32.exe C:\\Windows\\System32\\shell32.dll,ShellExec_RunDLL C:\\Windows\\System32\\calc.exe') \ No newline at end of file diff --git a/lab/runall.py b/lab/runall.py deleted file mode 100644 index 9c4731d..0000000 --- a/lab/runall.py +++ /dev/null @@ -1,11 +0,0 @@ -import os -import sys -import glob -import ctypes -import subprocess - -files = [x for x in glob.glob('*.py') if x not in ['winutils.py', os.path.basename(__file__)]] - -for f in sorted(files): - print('Running {0}...'.format(f)) - subprocess.call([sys.executable, f]) diff --git a/lab/scheduled_task.py b/lab/scheduled_task.py deleted file mode 100644 index 7377a62..0000000 --- a/lab/scheduled_task.py +++ /dev/null @@ -1,6 +0,0 @@ -import winutils -import subprocess - -binary = winutils.infect_system_exe() - -subprocess.call(['schtasks', '/create', '/tn', winutils.random_name(), '/tr', binary, '/sc', 'onstart']) \ No newline at end of file diff --git a/lab/service.py b/lab/service.py deleted file mode 100644 index e3ddd98..0000000 --- a/lab/service.py +++ /dev/null @@ -1,7 +0,0 @@ -import winutils -import subprocess - -binary = winutils.infect_system_exe() -name = winutils.random_name() - -subprocess.call(['sc', 'create', name, 'Displayname=', name, 'binpath=', 'rundll32.exe shell32.dll,ShellExec_RunDLL {0}'.format(binary), 'start=', 'auto']) diff --git a/lab/shortcuts.py b/lab/shortcuts.py deleted file mode 100644 index 01797a3..0000000 --- a/lab/shortcuts.py +++ /dev/null @@ -1,16 +0,0 @@ -import os -import glob -import winutils - -from win32com.client import Dispatch - -binary = winutils.infect_system_exe() -desktop = os.path.join(os.getenv('userprofile'), 'Desktop') -shorcuts = glob.glob(os.path.join(desktop, '*.lnk')) - -for sc in shorcuts: - shortcut = winutils.read_shorcut(sc) - winutils.create_shortcut(sc, binary, - arguments=shortcut.Targetpath, - working_dir=os.path.dirname(shortcut.Targetpath), - icon=shortcut.Targetpath) diff --git a/lab/startup.py b/lab/startup.py deleted file mode 100644 index 567a8a9..0000000 --- a/lab/startup.py +++ /dev/null @@ -1,14 +0,0 @@ -import os -import winutils - -lnk_path = 'Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{0}.lnk'.format(winutils.random_name()) -target = winutils.infect_system_exe() -working_dir = os.getenv('userprofile') - -# User -shortcut_path = os.path.join(os.getenv('appdata'), lnk_path) -winutils.create_shortcut(shortcut_path, target, working_dir=working_dir) - -# All Users -shortcut_path = os.path.join(os.getenv('allusersprofile'), lnk_path) -winutils.create_shortcut(shortcut_path, target, working_dir=working_dir) diff --git a/lab/winlogon.py b/lab/winlogon.py deleted file mode 100644 index 3321522..0000000 --- a/lab/winlogon.py +++ /dev/null @@ -1,6 +0,0 @@ -import winutils - -binary = winutils.infect_system_exe() - -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'Shell', 'explorer.exe,{0}'.format(binary)) -winutils.set_registry_value('HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon', 'Userinit', 'C:\\Windows\\System32\\userinit.exe,{0}'.format(binary)) diff --git a/lab/winutils.py b/lab/winutils.py deleted file mode 100644 index 5b86da9..0000000 --- a/lab/winutils.py +++ /dev/null @@ -1,89 +0,0 @@ -import os -import re -import random -import winreg - -from win32com.client import Dispatch -from shutil import copyfile - -HEX_ALPH = '0123456789ABCDEF' -MIN_ALPH = 'abcdefghijklmnopqrstuvwxyz' -MAX_APLH = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' -ALPH = '{0}{1}'.format(MIN_ALPH, MAX_APLH) - -def set_registry_value(reg_path, name, data): - root, path = _get_root(reg_path) - winreg.CreateKey(root, path) - registry_key = winreg.OpenKey(root, path, 0, winreg.KEY_WRITE) - data_type = _get_data_type(data) - winreg.SetValueEx(registry_key, name, 0, data_type, data) - winreg.CloseKey(registry_key) - -def create_shortcut(shortcut_path, target, arguments=None, working_dir=None, icon=None): - shortcut = read_shorcut(shortcut_path) - shortcut.Targetpath = target - - if arguments: shortcut.Arguments = arguments - if working_dir: shortcut.WorkingDirectory = working_dir - if icon: shortcut.IconLocation = icon - - shortcut.save() - -def read_shorcut(shortcut_path): - shell = Dispatch('WScript.Shell') - - return shell.CreateShortCut(shortcut_path) - -def random_guid(): - return '{{{0}-{1}-{2}-{3}-{4}}}'.format(_random_hex(8), _random_hex(4), _random_hex(4), _random_hex(4), _random_hex(12)) - -def random_name(n_words=1): - ret = random.choice(MAX_APLH) - for _ in range(n_words): - length = random.randint(6, 10) - name = ''.join(random.choice(MIN_ALPH) for _ in range(length)) - ret = '{0}{1} '.format(ret, name) - return ret[:-1] - -def infect_system(file_path): - newpath = os.path.join(os.getenv('appdata'), random_name()) - if not os.path.exists(newpath): - os.makedirs(newpath) - newbinary = os.path.join(newpath, os.path.basename(file_path)) - copyfile(file_path, newbinary) - - return newbinary - -def infect_system_exe(): - return infect_system('C:\\Windows\\System32\\cmd.exe') - -def infect_system_dll(): - return infect_system('C:\\Windows\\System32\\autoplay.dll') - -def _get_root(reg_path): - match = re.search(r'([a-zA-Z_]{3,19})\\(.+)', reg_path) - if match: - if re.search(r'(HKLM|HKEY_LOCAL_MACHINE)', match.group(1), flags=re.IGNORECASE): - return winreg.HKEY_LOCAL_MACHINE, match.group(2) - elif re.search(r'(HKCU|HKEY_CURRENT_USER)', match.group(1), flags=re.IGNORECASE): - return winreg.HKEY_CURRENT_USER, match.group(2) - - raise winreg.WindowsError('Malformed Windows registry path: {0}'.format(reg_path)) - -def _get_data_type(data): - if type(data) == str: - return winreg.REG_SZ - elif type(data) == int: - return winreg.REG_DWORD - - return winreg.REG_NONE - -def _get_absolute_path(path): - match = re.search(r'(%.+%)\\(.+)', path) - if match: - return os.path.join(os.getenv(match.group(1)), match.group(2)) - - return path - -def _random_hex(lenght): - return ''.join(random.choice(HEX_ALPH) for _ in range(lenght)) diff --git a/plugin/winesap.py b/plugin/winesap.py deleted file mode 100644 index 9bab53e..0000000 --- a/plugin/winesap.py +++ /dev/null @@ -1,148 +0,0 @@ -import re -import itertools - -import volatility.utils as utils -import volatility.debug as debug -import volatility.win32.rawreg as rawreg -from volatility.plugins.common import AbstractWindowsCommand -import volatility.plugins.registry.registryapi as registryapi - - -class AutoRuns(AbstractWindowsCommand): - """ - Search for all Autostart Extensibility Points (AESPs) - - Options: - --match: only shows suspicious entries - """ - def __init__(self, config, *args, **kwargs): - AbstractWindowsCommand.__init__(self, config, *args, **kwargs) - self._config.add_option('MATCH', help='Only shows suspicious entries', action='store_true') - self.addr_space = utils.load_as(self._config) - self.regapi = registryapi.RegistryApi(self._config) - - def calculate(self): - yield self.get_run() - yield self.get_installed_components() - yield self.get_services() - yield self.get_image_file_execution_options() - yield self.get_winlogon() - yield self.get_appinit_dlls() - - def get_run(self): - self.regapi.set_current('ntuser.dat') - yield {'root': 'HKCU\\', 'key': self.regapi.reg_get_key('ntuser.dat', 'Software\\Microsoft\\Windows\\CurrentVersion\\Run'), 'value': []} - yield {'root': 'HKCU\\', 'key': self.regapi.reg_get_key('ntuser.dat', 'Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce'), 'value': []} - for k in self.regapi.reg_get_all_subkeys('ntuser.dat', 'Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx'): - yield {'root': 'HKCU\\', 'key': k, 'value': []} - - yield {'root': 'HKCU\\', 'key': self.regapi.reg_get_key('ntuser.dat', 'Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'), 'value': []} - yield {'root': 'HKCU\\', 'key': self.regapi.reg_get_key('ntuser.dat', 'Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce'), 'value': []} - for k in self.regapi.reg_get_all_subkeys('ntuser.dat', 'Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx'): - yield {'root': 'HKCU\\', 'key': k, 'value': ['RunMyApp']} - - self.regapi.set_current('software') - yield {'root': 'HKLM\\Software\\', 'key': self.regapi.reg_get_key('software', 'Microsoft\\Windows\\CurrentVersion\\Run'), 'value': []} - yield {'root': 'HKLM\\Software\\', 'key': self.regapi.reg_get_key('software', 'Microsoft\\Windows\\CurrentVersion\\RunOnce'), 'value': []} - for k in self.regapi.reg_get_all_subkeys('software', 'Microsoft\\Windows\\CurrentVersion\\RunOnceEx'): - yield {'root': 'HKLM\\Software\\', 'key': k, 'value': ['RunMyApp']} - - def get_installed_components(self): - self.regapi.set_current('software') - for k in self.regapi.reg_get_all_subkeys('software', 'Microsoft\\Active Setup\\Installed Components'): - yield {'root': 'HKLM\\Software\\', 'key': k, 'value': ['StubPath']} - - def get_services(self): - self.regapi.set_current('system') - currentcontrolset = self.regapi.reg_get_currentcontrolset(fullname=True) - if currentcontrolset is None: - currentcontrolset = 'ControlSet001' - - for k in self.regapi.reg_get_all_subkeys('system', '{0}\\Services'.format(currentcontrolset)): - yield {'root': 'HKLM\\System\\', 'key': k, 'value': ['ImagePath']} - - def get_image_file_execution_options(self): - self.regapi.set_current('software') - for k in self.regapi.reg_get_all_subkeys('software', 'Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options'): - yield {'root': 'HKLM\\Software\\', 'key': k, 'value': ['Debugger']} - - def get_winlogon(self): - self.regapi.set_current('software') - yield {'root': 'HKLM\\Software\\', 'key': self.regapi.reg_get_key('software', 'Microsoft\\Windows NT\\CurrentVersion\\Winlogon'), 'value': ['Shell', 'Userinit']} - - def get_appinit_dlls(self): - self.regapi.set_current('software') - yield {'root': 'HKLM\\Software\\', 'key': self.regapi.reg_get_key('software', 'Microsoft\\Windows NT\\CurrentVersion\\Windows'), 'value': ['AppInit_DLLs']} - yield {'root': 'HKLM\\Software\\', 'key': self.regapi.reg_get_key('software', 'Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows'), 'value': ['AppInit_DLLs']} - - def render_text(self, outfd, data): - for gen in data: - for key in gen: - root = key['root'] - filtered_keys = self.filter_key(key['key'], key['value']) - for filtered_key in filtered_keys: - if not self._config.MATCH or (self._config.MATCH and filtered_key['reason']): - outfd.write('-' * 30) - if filtered_key['reason']: - outfd.write('\nWARNING: {0}'.format(warning_message(', '.join(filtered_key['reason'])))) - outfd.write('\n{0}{1}\n'.format(root, self.regapi.reg_get_key_path(filtered_key['key']))) - - tp, dt = rawreg.value_data(filtered_key['value']) - if tp == 'REG_BINARY' or tp == 'REG_NONE': - dt = "\n" + "\n".join(["{0:#010x} {1:<48} {2}".format(o, h, ''.join(c)) for o, h, c in utils.Hexdump(dt[:0x40])]) - outfd.write('{0}: {1}: {2}\n'.format(self.get_value_name(filtered_key['value']), tp, dt)) - - def filter_key(self, key, value): - ret = [] - if key: - for v in rawreg.values(key): - if not value or (value and self.get_value_name(v) in value): - tp, dat = rawreg.value_data(v) - if tp == 'REG_BINARY' or tp == 'REG_NONE': - reason = self.is_bin_suspicious(dat) - ret += [{'key': key, 'value': v, 'reason': reason}] - elif tp in ['REG_SZ', 'REG_EXPAND_SZ', 'REG_LINK']: - reason = self.is_string_suspicious(dat) - ret += [{'key': key, 'value': v, 'reason': reason}] - return ret - - def is_string_suspicious(self, string): - ret = [] - PATHS = ['AppData', 'Roaming', 'Temp', 'Application Data'] - - if re.search(r'.+\\({0}).+\..+'.format('|'.join(PATHS)), string, flags=re.IGNORECASE): - ret += ['Suspicious path file'] - - if re.search(r'.*regsvr32\.exe /s (?!(\\/:*?"<>|)).+:.+', string, flags=re.IGNORECASE): - ret += ['Suspicious Alternate Data Stream (ADS)'] - - if re.search(r'.*rundll32\.exe (?!(\\/:*?"<>|)).+:.+', string, flags=re.IGNORECASE): - ret += ['Suspicious Alternate Data Stream (ADS)'] - - if re.search(r'.*rundll32\.exe.+shell32\.dll.*', string, flags=re.IGNORECASE): - ret += ['Suspicious shell execution'] - - return ret - - def is_bin_suspicious(self, data): - if self.is_pe(dat): - return 'Suspicious PE file' - - return '' - - def is_pe(self, data): - try: - if data[:0x2] == b'\x4d\x5a': # MZ - pe_offset = ord(data[0x3c]) - if data[pe_offset:pe_offset+0x2] == b'\x50\x45': # PE - return True - except IndexError: - pass - - return False - - def get_value_name(self, value): - return str(value.dereference().Name) - -def warning_message(message): - return '{0}{1}{2}'.format('\033[93m', message, '\033[0m') -- 2.18.0