Skip to content

Commit

Permalink
cf changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
AlessandroZ committed Jun 11, 2015
1 parent b6bd676 commit c8d68fc
Show file tree
Hide file tree
Showing 15 changed files with 290 additions and 70 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
LaZagne 0.8 (11/06/2015)
- Only Linux
* /etc/shadow modules (dictionary attack on hash)

- For Windows / Linux
* management of the following options "-path" (for dictionary attack) and "-b" (for bruteforce attack) in a different way. Used as general options and not implemented by module. Using the same option, the file will be used by different modules; example: to find the mozilla masterpassword, the unix system password (from the hash), used by skype (for windows), etc.

LaZagne 0.71 (04/06/2015)
- Only Linux
* Wifi password module from WPA Supplicant implemented (by rpesche)
Expand Down
17 changes: 13 additions & 4 deletions Linux/src/LaZagne.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,29 @@ def launch_module(b):
b[i].run()

def manage_advanced_options():
if 'manually' in args:
constant.manually = args['manually']

# file used for dictionary attacks
if 'path' in args:
constant.path = args['path']
if 'bruteforce' in args:
constant.bruteforce = args['bruteforce']
if 'defaultpass' in args:
constant.defaultpass = args['defaultpass']

# mozilla advanced options
if 'manually' in args:
constant.manually = args['manually']
if 'specific_path' in args:
constant.specific_path = args['specific_path']

if 'mails' in args['auditType']:
constant.mozilla_software = 'Thunderbird'
elif 'browsers' in args['auditType']:
constant.mozilla_software = 'Firefox'

# jitsi advanced options
if 'master_pwd' in args:
constant.jitsi_masterpass = args['master_pwd']

# i.e advanced options
if 'historic' in args:
constant.ie_historic = args['historic']

Expand Down Expand Up @@ -124,6 +131,8 @@ def error(self, message):
PPoptional._optionals.title = 'optional arguments'
PPoptional.add_argument('-v', dest='verbose', action='count', default=0, help='increase verbosity level')
PPoptional.add_argument('--version', action='version', version='Version ' + str(constant.CURRENT_VERSION), help='laZagne version')
PPoptional.add_argument('-path', dest='path', action= 'store', help = 'path of a file used for dictionnary file')
PPoptional.add_argument('-b', dest='bruteforce', action= 'store', help = 'number of character to brute force')

# Output
PWrite = argparse.ArgumentParser(add_help=False,formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=constant.MAX_HELP_POSITION))
Expand Down
3 changes: 1 addition & 2 deletions Linux/src/config/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
class constant():
folder_name = 'results'
MAX_HELP_POSITION = 27
CURRENT_VERSION = 0.71
CURRENT_VERSION = 0.8
output = None
file_logger = None
verbose = False
Expand All @@ -14,7 +14,6 @@ class constant():
manually = None
path = None
bruteforce = None
defaultpass = None
specific_path = None
mozilla_software = ''

Expand Down
2 changes: 2 additions & 0 deletions Linux/src/config/manageModules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# sysadmin
from softwares.sysadmin.filezilla import Filezilla
from softwares.sysadmin.env_variable import Env_variable
from softwares.sysadmin.shadow import Shadow
# chats
from softwares.chats.pidgin import Pidgin
from softwares.chats.jitsi import Jitsi
Expand Down Expand Up @@ -40,6 +41,7 @@ def get_modules():
Mozilla(),
Opera(),
Pidgin(),
Shadow(),
SQLDeveloper(),
Squirrel(),
Wifi(),
Expand Down
23 changes: 16 additions & 7 deletions Linux/src/config/write_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,33 @@ def print_output(software_name, pwdFound):
Header().title(software_name)

toWrite = []
password_category = False
for pwd in pwdFound:
# detect which kinds of password has been found
lower_list = [s.lower() for s in pwd.keys()]
password = [s for s in lower_list if "password" in s]
key = [s for s in lower_list if "key" in s] # for the wifi
if password:
password_category = password
else:
key = [s for s in lower_list if "key" in s] # for the wifi
if key:
password_category = key
else:
hash = [s for s in lower_list if "hash" in s]
if hash:
password_category = hash

# No password found
if not password and not key:
if not password_category:
print_debug("FAILED", "Password not found !!!")
else:
print_debug("OK", "Password found !!!")
print_debug("OK", '%s found !!!' % password_category[0].title())
toWrite.append(pwd)

# Store all passwords found on a table => for dictionary attack if master password set
constant.nbPasswordFound += 1
try:
if password:
constant.passwordFound.append(pwd['Password'].strip())
elif key:
constant.passwordFound.append(pwd['key'])
constant.passwordFound.append(pwd[password_category[0]])
except:
pass

Expand Down
41 changes: 17 additions & 24 deletions Linux/src/softwares/browsers/mozilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import json
import shutil
from config.dico import get_dico
import itertools
from itertools import product
#https://pypi.python.org/pypi/pyasn1/
from pyasn1.codec.der import decoder
from struct import unpack
Expand Down Expand Up @@ -91,16 +91,13 @@ def __init__(self, isThunderbird = False):
self.toCheck = []
self.manually_pass = None
self.dictionnary_path = None
self.number_toStop = None
self.number_toStop = 0

self.key3 = ''

# Manage options
suboptions = [
{'command': '-m', 'action': 'store', 'dest': 'manually', 'help': 'enter the master password manually', 'title': 'Advanced Mozilla master password options'},
{'command': '-p', 'action': 'store', 'dest': 'path', 'help': 'path of a dictionnary file', 'title': 'Advanced Mozilla master password options'},
{'command': '-b', 'type':int, 'action': 'store', 'dest': 'bruteforce', 'help': 'number of caracter to brute force', 'title': 'Advanced Mozilla master password options'},
{'command': '-d', 'action': 'store_true', 'dest': 'defaultpass', 'help': 'try 500 most common passwords', 'title': 'Advanced Mozilla master password options'},
{'command': '-s', 'action': 'store', 'dest': 'specific_path', 'help': 'enter the specific path to a profile you want to crack', 'title': 'Advanced Mozilla master password options'}
]

Expand Down Expand Up @@ -129,12 +126,9 @@ def manage_advanced_options(self):
self.toCheck.append('a')

if constant.bruteforce:
self.number_toStop = constant.bruteforce
self.number_toStop = int(constant.bruteforce) + 1
self.toCheck.append('b')

if constant.defaultpass:
self.toCheck.append('d')

# default attack
if self.toCheck == []:
self.toCheck = ['b', 'd']
Expand Down Expand Up @@ -395,29 +389,29 @@ def found_masterpassword(self):
print_debug('WARNING', 'No password has been found using the default list')

# brute force attack
if 'b' in self.toCheck:
if 'b' in self.toCheck or constant.bruteforce:
charset_list = 'abcdefghijklmnopqrstuvwxyz1234567890!?'
tab = [i for i in charset_list]

print_debug('ATTACK', 'Brute force attack !!! (%s characters)' % str(self.number_toStop))
current = 0
pass_found = False
print_debug('ATTACK', 'Brute force attack !!! (%s characters)' % str(constant.bruteforce))
print_debug('DEBUG', 'charset: %s' % charset_list)

try:
while current <= self.number_toStop and pass_found == False:
for i in itertools.product(tab, repeat=current):
word = ''.join(map(str,i))
if self.is_masterpassword_correct(word)[0]:
print_debug('FIND', 'Master password found: %s' % word.strip())
return word.strip()
current+= 1
for length in range(1, int(self.number_toStop)):
words = product(charset_list, repeat=length)
for word in words:
print_debug('DEBUG', '%s' % ''.join(word))
if self.is_masterpassword_correct(''.join(word))[0]:
w = ''.join(word)
print_debug('FIND', 'Master password found: %s' % w.strip())
return w.strip()
except (KeyboardInterrupt, SystemExit):
print 'INTERRUPTED!'
print_debug('INFO', 'Dictionnary attack interrupted')
except Exception,e:
print_debug('DEBUG', '{0}'.format(e))

print_debug('WARNING', 'No password has been found using the brute force attack')
return False

return False

# ------------------------------ End of Master Password Functions ------------------------------

Expand Down Expand Up @@ -529,4 +523,3 @@ def run(self):

# print the results
print_output(software_name, pwdFound)

135 changes: 135 additions & 0 deletions Linux/src/softwares/sysadmin/shadow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import os,sys
import crypt
from config.header import Header
from config.write_output import print_debug, print_output
from config.moduleInfo import ModuleInfo
from config.dico import get_dico
from config.constant import *
from itertools import product

class Shadow(ModuleInfo):

def __init__(self):
# Manage options
options = {'command': '-s', 'action': 'store_true', 'dest': 'shadow', 'help': '/etc/shadow - Need root Privileges'}
ModuleInfo.__init__(self, 'shadow', 'sysadmin', options)

self.filestr = '/etc/shadow'
self.hash = '\n'
self.pwdFound = []

# used for dictionary attack, if user specify a specific file
def get_dic(self, dictionnary_path):
words = []
if dictionnary_path:
try:
dicFile = open (dictionnary_path,'r')
except Exception,e:
print_debug('DEBUG', '{0}'.format(e))
print_debug('ERROR', 'Unable to open passwords file: %s' % str(self.dictionnary_path))
return []

for word in dicFile.readlines():
words.append(word.strip('\n'))
dicFile.close()
return words

def attack(self, user, cryptPwd):
# By default 500 most famous passwords are used for the dictionary attack
dic = get_dico()
# add the user on the list to found weak password (login equal password)
dic.insert(0, user)

# file for dictionnary attack entered
if constant.path:
if os.path.exists(constant.path):
dic = self.get_dic(constant.path)
else:
print_debug('WARNING', 'The file does not exist: %s' % str(constant.path))

# Different possible hash type
# ID | Method
# --------------------------------------------------------------------------
# 1 | MD5
# 2 | Blowfish (not in mainline glibc; added in some Linux distributions)
# 5 | SHA-256 (since glibc 2.7)
# 6 | SHA-512 (since glibc 2.7)

hashType = cryptPwd.split("$")[1]
values = {'Category': 'System Account'}

if hashType == '1': # MD5
print_debug('INFO', '[+] Hash type MD5 detected ...')
elif hashType == '2':
print_debug('INFO', '[+] Hash type Blowfish detected ...')
elif hashType == '5':
print_debug('INFO', '[+] Hash type SHA-256 detected ...')
elif hashType == '6': # ShA-512 => used by all modern computers
print_debug('INFO', '[+] Hash type SHA-512 detected ...')

salt = cryptPwd.split("$")[2]
realSalt = "$" + hashType + "$" + salt + "$"

# -------------------------- Dictionary attack --------------------------
print_debug('INFO', 'Dictionnary Attack on the hash !!! ')
try:
for word in dic:
try:
cryptWord = crypt.crypt(word, realSalt)
except Exception,e:
print_debug('DEBUG', '{0}'.format(e))
cryptWord = ''

if cryptWord == cryptPwd:
values['User'] = user
values['password'] = word
self.pwdFound.append(values)
return
except (KeyboardInterrupt, SystemExit):
print 'INTERRUPTED!'
print_debug('DEBUG', 'Dictionnary attack interrupted')
except Exception,e:
print_debug('DEBUG', '{0}'.format(e))

print_debug('INFO', 'No password found using this attack !!! ')

def root_access(self):
if os.getuid() != 0:
print_debug('INFO', 'You need more privileges (run it with sudo)\n')
return False
return True

def check_file_access(self):
if not os.path.exists(self.filestr):
print_debug('WARNING', 'The path "%s" does not exist' % s(self.filestr))
return False
return True

def run(self):
Header().title_info('System account (from /etc/shadow)')

# check root access
if self.root_access():
if self.check_file_access():
shadowFile = open (self.filestr,'r')
for line in shadowFile.readlines():
_hash = line.replace('\n', '')

line = _hash.split(':')

# check if a password is defined
if not line[1] in [ 'x', '*','!' ]:
user = line[0]
cryptPwd = line[1]

# save each hash non empty
self.hash += _hash + '\n'

# try dictionary and bruteforce attack
self.attack(user, cryptPwd)

values = {'Category' : 'Hash', 'Hash' : self.hash }
self.pwdFound.append(values)

# print the results
print_output('System account (from /etc/shadow)', self.pwdFound)
Binary file modified Linux/standalone/32bits/LaZagne-32bits
Binary file not shown.
Binary file modified Linux/standalone/64bits/LaZagne-64bits
Binary file not shown.
4 changes: 1 addition & 3 deletions Windows/src/LaZagne/config/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
class constant():
folder_name = 'results'
MAX_HELP_POSITION = 27
CURRENT_VERSION = 0.7
CURRENT_VERSION = 0.8
output = None
file_logger = None

# jitsi options
jitsi_masterpass = None

# mozilla options
isInteractive = False
manually = None
path = None
bruteforce = None
defaultpass = None
specific_path = None
mozilla_software = ''

Expand Down
Loading

0 comments on commit c8d68fc

Please sign in to comment.