Skip to content

Commit adc1b19

Browse files
committed
code refactoring + bug fix
1 parent 15c8d09 commit adc1b19

File tree

18 files changed

+379
-839
lines changed

18 files changed

+379
-839
lines changed

Windows/laZagne.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def clean_args(arg):
111111
PPoptional = argparse.ArgumentParser(
112112
add_help=False,
113113
formatter_class=lambda prog: argparse.HelpFormatter(prog,
114-
max_help_position=constant.MAX_HELP_POSITION)
114+
max_help_position=constant.max_help)
115115
)
116116
PPoptional._optionals.title = 'optional arguments'
117117
PPoptional.add_argument('-v', dest='verbose', action='count', default=0, help='increase verbosity level')
@@ -122,7 +122,7 @@ def clean_args(arg):
122122
PWrite = argparse.ArgumentParser(
123123
add_help=False,
124124
formatter_class=lambda prog: argparse.HelpFormatter(prog,
125-
max_help_position=constant.MAX_HELP_POSITION)
125+
max_help_position=constant.max_help)
126126
)
127127
PWrite._optionals.title = 'Output'
128128
PWrite.add_argument('-oN', dest='write_normal', action='store_true', default=None,
@@ -138,7 +138,7 @@ def clean_args(arg):
138138
add_help=False,
139139
formatter_class=lambda prog: argparse.HelpFormatter(
140140
prog,
141-
max_help_position=constant.MAX_HELP_POSITION)
141+
max_help_position=constant.max_help)
142142
)
143143
PPwd._optionals.title = 'Windows User Password'
144144
PPwd.add_argument('-password', dest='password', action='store',
@@ -151,7 +151,7 @@ def clean_args(arg):
151151
all_categories[c]['parser'] = argparse.ArgumentParser(
152152
add_help=False,
153153
formatter_class=lambda prog: argparse.HelpFormatter(prog,
154-
max_help_position=constant.MAX_HELP_POSITION)
154+
max_help_position=constant.max_help)
155155
)
156156
all_categories[c]['parser']._optionals.title = all_categories[c]['help']
157157

@@ -170,7 +170,7 @@ def clean_args(arg):
170170
add_help=False,
171171
formatter_class=lambda prog: argparse.HelpFormatter(
172172
prog,
173-
max_help_position=constant.MAX_HELP_POSITION)
173+
max_help_position=constant.max_help)
174174
)
175175
tmp_subparser._optionals.title = sub['title']
176176
if 'type' in sub:

Windows/lazagne/config/DPAPI/masterkey.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .eater import DataStruct, Eater
1414
from collections import defaultdict
1515

16+
import codecs
1617
import hashlib
1718
import struct
1819
import os
@@ -414,10 +415,9 @@ def try_credential_hash(self, sid, pwdhash=None):
414415
if mk.decrypted:
415416
mkf.decrypted = True
416417
self.nb_mkf_decrypted += 1
417-
418-
yield True, u'{hash} ok for masterkey {masterkey}'.format(hash=pwdhash, masterkey=mk.guid)
418+
yield True, u'{hash} ok for masterkey {masterkey}'.format(hash=codecs.encode(pwdhash, 'hex'), masterkey=mkf.guid)
419419
else:
420-
yield False, u'{hash} not ok for masterkey {masterkey}'.format(hash=pwdhash, masterkey=mk.guid)
420+
yield False, u'{hash} not ok for masterkey {masterkey}'.format(hash=codecs.encode(pwdhash, 'hex'), masterkey=mkf.guid)
421421

422422
def try_system_credential(self):
423423
"""

Windows/lazagne/config/change_privileges.py

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22
# Original code from https://github.com/joren485/PyWinPrivEsc/blob/master/RunAsSystem.py
33

44
import sys
5-
import psutil
5+
import traceback
6+
67
from lazagne.config.write_output import print_debug
78
from lazagne.config.winstructure import *
89

910
import os
1011

1112

12-
def get_token_sid(hToken):
13+
def get_token_info(hToken):
1314
"""
14-
Retrieve SID from Token
15+
Retrieve SID and user owner from Token
1516
"""
1617
dwSize = DWORD(0)
17-
pStringSid = LPSTR()
18+
pStringSid = LPWSTR()
1819
TokenUser = 1
1920

2021
if GetTokenInformation(hToken, TokenUser, byref(TOKEN_USER()), 0, byref(dwSize)) == 0:
@@ -23,11 +24,12 @@ def get_token_sid(hToken):
2324
GetTokenInformation(hToken, TokenUser, address, dwSize, byref(dwSize))
2425
pToken_User = cast(address, POINTER(TOKEN_USER))
2526
if pToken_User.contents.User.Sid:
26-
ConvertSidToStringSidA(pToken_User.contents.User.Sid, byref(pStringSid))
27+
ConvertSidToStringSid(pToken_User.contents.User.Sid, byref(pStringSid))
28+
owner, domaine, _ = LookupAccountSidW(None, pToken_User.contents.User.Sid)
2729
if pStringSid:
2830
sid = pStringSid.value
2931
LocalFree(address)
30-
return sid
32+
return sid, owner
3133
return False
3234

3335

@@ -69,55 +71,37 @@ def enable_privilege(privilegeStr, hToken=None):
6971

7072
def get_debug_privilege():
7173
"""
72-
Enable Debug privilege on token
74+
Enable SE Debug privilege on token
7375
"""
74-
if enable_privilege("SeDebugPrivilege"):
75-
return True
76-
else:
77-
return False
76+
return RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE)
7877

7978

8079
def list_sids():
8180
"""
8281
List all SID by process
8382
"""
8483
sids = []
85-
86-
for proc in psutil.process_iter():
87-
try:
88-
pinfo = proc.as_dict(attrs=['pid', 'username', 'name'])
89-
except psutil.NoSuchProcess:
84+
for pid in EnumProcesses():
85+
if pid <= 4:
9086
continue
91-
except WindowsError as e:
92-
if e.winerror == 1722: # WindowsError: [Error 1722] The RPC server is unavailable
93-
continue
9487

95-
if pinfo['pid'] <= 4:
96-
continue
97-
if pinfo['username'] is None:
98-
continue
9988
try:
100-
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pinfo['pid']))
101-
if not hProcess:
102-
continue
103-
104-
hToken = HANDLE(INVALID_HANDLE_VALUE)
105-
if not hToken:
106-
continue
107-
108-
OpenProcessToken(hProcess, tokenprivs, byref(hToken))
109-
if not hToken:
110-
continue
111-
112-
token_sid = get_token_sid(hToken)
113-
if not token_sid:
114-
continue
115-
sids.append((pinfo['pid'], pinfo['name'], token_sid, pinfo['username'].decode(sys.getfilesystemencoding())))
89+
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, pid)
90+
if hProcess:
91+
hToken = HANDLE(INVALID_HANDLE_VALUE)
92+
if hToken:
93+
OpenProcessToken(hProcess, tokenprivs, byref(hToken))
94+
if hToken:
95+
token_sid, owner = get_token_info(hToken)
96+
if token_sid and owner:
97+
pname = ''
98+
sids.append((pid, pname, token_sid, owner.decode(sys.getfilesystemencoding())))
99+
CloseHandle(hToken)
100+
CloseHandle(hProcess)
116101

117-
CloseHandle(hToken)
118-
CloseHandle(hProcess)
119102
except Exception as e:
120-
print_debug('ERROR', u'{error}'.format(error=e))
103+
print_debug('DEBUG', traceback.format_exc())
104+
continue
121105

122106
return list(sids)
123107

@@ -145,18 +129,20 @@ def get_sid_token(token_sid):
145129
break
146130
return False
147131

148-
pids = [int(x) for x in psutil.pids() if int(x) > 4]
149-
for pid in pids:
132+
for pid in EnumProcesses():
133+
if pid <= 4:
134+
continue
135+
150136
try:
151137
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pid))
152138
if hProcess:
153139
hToken = HANDLE(INVALID_HANDLE_VALUE)
154140
if hToken:
155141
OpenProcessToken(hProcess, tokenprivs, byref(hToken))
156142
if hToken:
157-
if get_token_sid(hToken) == token_sid:
158-
print
159-
print_debug('INFO', u'Using PID: ' + str(pid))
143+
sid, owner = get_token_info(hToken)
144+
if sid == token_sid:
145+
print_debug('INFO', u'Impersonate token from pid: ' + str(pid))
160146
CloseHandle(hProcess)
161147
return hToken
162148
CloseHandle(hToken)
@@ -213,6 +199,8 @@ def impersonate_token(hToken):
213199
CloseHandle(hToken)
214200
if ImpersonateLoggedOnUser(hTokendupe):
215201
return hTokendupe
202+
else:
203+
print_debug('DEBUG', 'Get debug privilege failed')
216204
return False
217205

218206

Windows/lazagne/config/constant.py

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,56 @@
55
import time
66
import os
77

8-
date = time.strftime("%d%m%Y_%H%M%S")
9-
tmp = tempfile.gettempdir()
8+
date = time.strftime("%d%m%Y_%H%M%S")
9+
tmp = tempfile.gettempdir()
1010

1111

1212
class constant():
13-
folder_name = '.'
14-
file_name_results = 'credentials_{current_time}'.format(current_time=date) # The extention is added depending on the user output choice
15-
MAX_HELP_POSITION = 27
16-
CURRENT_VERSION = '2.3.2'
17-
output = None
18-
file_logger = None
19-
modules_dic = {}
20-
nb_password_found = 0 # Total password found
21-
password_found = [] # Tab containing all passwords used for dictionary attack
22-
stdout_result = [] # Tab containing all results by user
23-
24-
finalResults = {}
25-
profile = {
26-
'APPDATA' : u'{drive}:\\Users\\{user}\\AppData\\Roaming\\',
27-
'USERPROFILE' : u'{drive}:\\Users\\{user}\\',
28-
'HOMEDRIVE' : u'{drive}:',
29-
'HOMEPATH' : u'{drive}:\\Users\\{user}',
30-
'ALLUSERSPROFILE' : u'{drive}:\\ProgramData',
31-
'COMPOSER_HOME' : u'{drive}:\\Users\\{user}\\AppData\\Roaming\\Composer\\',
32-
'LOCALAPPDATA' : u'{drive}:\\Users\\{user}\\AppData\\Local',
33-
}
34-
username = u''
35-
keepass = {}
36-
hives = {
37-
'sam' : os.path.join(tmp, ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])),
38-
'security' : os.path.join(tmp, ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))])),
39-
'system' : os.path.join(tmp, ''.join([random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12))]))
40-
}
41-
quiet_mode = False
42-
st = None # Standard output
43-
drive = u'C'
44-
user_dpapi = None
45-
system_dpapi = None
46-
lsa_secrets = None
47-
is_current_user = False # If True, Windows API are used otherwise dpapi is used
48-
user_password = None
49-
wifi_password = False # Check if the module as already be done
50-
module_to_exec_at_end = {
51-
"winapi": [],
52-
"dpapi" : [],
53-
}
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'
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+
}

Windows/lazagne/config/dpapi_structure.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,33 @@
1010
from lazagne.config.constant import constant
1111
from lazagne.softwares.windows.lsa_secrets import LSASecrets
1212

13+
import getpass
1314
import os
15+
import sys
16+
17+
18+
def are_masterkeys_retrieved():
19+
"""
20+
Before running modules using DPAPI, we have to retrieve masterkeys
21+
otherwise, we do not realize these checks
22+
"""
23+
current_user = constant.username
24+
if constant.pypykatz_result.get(current_user, None):
25+
password = constant.pypykatz_result[current_user].get('Password', None)
26+
pwdhash = constant.pypykatz_result[current_user].get('Shahash', None)
27+
28+
# Create one DPAPI object by user
29+
constant.user_dpapi = UserDpapi(password=password, pwdhash=pwdhash)
30+
31+
if not constant.user_dpapi or not constant.user_dpapi.unlocked:
32+
# constant.user_password represents the password entered manually by the user
33+
constant.user_dpapi = UserDpapi(password=constant.user_password)
34+
35+
# Add username to check username equals passwords
36+
constant.user_dpapi.check_credentials([constant.username] + constant.password_found)
37+
38+
# Return True if at least one masterkey has been decrypted
39+
return constant.user_dpapi.unlocked
1440

1541

1642
def manage_response(ok, msg):

Windows/lazagne/config/execute_cmd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def save_hives():
7676
info = subprocess.STARTUPINFO()
7777
info.dwFlags = STARTF_USESHOWWINDOW
7878
info.wShowWindow = SW_HIDE
79-
p = subprocess.Popen(command, startupinfo=info, stderr=subprocess.STDOUT,
79+
p = subprocess.Popen(command, startupinfo=info, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,
8080
stdout=subprocess.PIPE, universal_newlines=True)
8181
results, _ = p.communicate()
8282
except Exception as e:

0 commit comments

Comments
 (0)