Skip to content

Instantly share code, notes, and snippets.

@adiroiban
Last active August 9, 2024 15:59
Show Gist options
  • Save adiroiban/e5774682fd74f5d14f65f1e1a99083b2 to your computer and use it in GitHub Desktop.
Save adiroiban/e5774682fd74f5d14f65f1e1a99083b2 to your computer and use it in GitHub Desktop.
List all shares on remote Windows server using smbprotocol
# Conversion of pysmb code to smbprotocol
# Original code at
# https://github.com/miketeo/pysmb/blob/76dc1708007fdcdd9d96a3703910938b84691704/python3/smb/base.py#L413-L548
#
import binascii
import uuid
import pprint
import struct
from smbprotocol.connection import Connection
from smbprotocol.open import (
CreateDisposition,
CreateOptions,
FilePipePrinterAccessMask,
ImpersonationLevel,
Open,
RequestedOplockLevel,
ShareAccess,
)
from smbprotocol.session import Session
from smbprotocol.tree import TreeConnect
# Replace these with your values.
server = '10.10.10.10'
user = 'test-user'
password = 'test-pass'
########################
conn = Connection(
uuid.uuid4(),
server,
445,
require_signing=True,
)
conn.connect()
session = Session(
conn,
user,
password,
require_encryption=True,
)
session.connect()
tree = TreeConnect(session, f'\\\\{server}\\IPC$')
tree.connect(require_secure_negotiate=True)
handler = Open(tree, 'srvsvc')
handler.create(
file_attributes=0,
desired_access=(
FilePipePrinterAccessMask.FILE_READ_DATA |
FilePipePrinterAccessMask.FILE_WRITE_DATA
),
share_access=(
ShareAccess.FILE_SHARE_READ |
ShareAccess.FILE_SHARE_WRITE
),
impersonation_level=ImpersonationLevel.Impersonation,
create_options=CreateOptions.FILE_NON_DIRECTORY_FILE,
create_disposition=CreateDisposition.FILE_OPEN,
)
call_id = 1
list_shares_init = data_bytes = \
binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \
struct.pack('<I', call_id) + \
binascii.unhexlify(b"""
b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00
c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88
03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00
2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b
70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00
2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00
01 00 00 00
""".replace(b' ', b'').replace(b'\n', b''))
handler.write(list_shares_init)
list_share_response = handler.read(0, 1000)
call_id = 2
remote_name = f'\\\\{server}'
server_len = len(remote_name) + 1
server_bytes_len = server_len * 2
if server_len % 2 != 0:
padding = b'\0\0'
server_bytes_len += 2
list_shares_request = binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \
struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \
binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \
struct.pack('<III', server_len, 0, server_len) + \
(remote_name + '\0').encode('UTF-16LE') + padding + \
binascii.unhexlify(b"""
01 00 00 00 01 00 00 00 04 00 02 00 00 00 00 00
00 00 00 00 ff ff ff ff 08 00 02 00 00 00 00 00
""".replace(b' ', b'').replace(b'\n', b''))
handler.write(list_shares_request)
data_bytes = handler.read(0, 1000)
shares_count = struct.unpack('<I', data_bytes[36:40])[0]
results = [] # A list of SharedDevice instances
offset = 36 + 12 # You need to study the byte stream to understand the meaning of these constants
for i in range(0, shares_count):
results.append({
'type': struct.unpack('<I', data_bytes[offset+4:offset+8])[0]})
offset += 12
for i in range(0, shares_count):
max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
offset += 12
results[i]['name'] = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')
if length % 2 != 0:
offset += (length * 2 + 2)
else:
offset += (length * 2)
max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12])
offset += 12
results[i]['comments'] = data_bytes[offset:offset+length*2-2].decode('UTF-16LE')
if length % 2 != 0:
offset += (length * 2 + 2)
else:
offset += (length * 2)
pprint.pp(results)
handler.close()
[{'type': 2147483648, 'name': 'ADMIN$', 'comments': 'Remote Admin'},
{'type': 2147483648, 'name': 'C$', 'comments': 'Default share'},
{'type': 2147483651, 'name': 'IPC$', 'comments': 'Remote IPC'},
{'type': 0, 'name': 'testMyNewShare', 'comments': ''},
{'type': 0, 'name': 'NETLOGON', 'comments': 'Logon server share '},
{'type': 0, 'name': 'SYSVOL', 'comments': 'Logon server share '}]
@creddie
Copy link

creddie commented Aug 8, 2024

I am getting the following error in line 101

data_bytes = handler.read(0, 1000)

Error:

ValueError: Enum value 16 does not exist in enum type <class 'smbprotocol.exceptions.ErrorContextId'>

Any sugestion on how to make this work?

Regards
-ed

@adiroiban
Copy link
Author

sorry. I don't know what it going on there.

It worked for me while tested with a Windows 2019 Server.

I have not tested in with any other server

@adiroiban
Copy link
Author

I guess that you are using the AWS SMB server.
I have no idea what software is used by AWS ... it might not be a Windows server and it might not implement the RPC over SMB protocol , or it might not implement the srvsvc named pipe.

@adiroiban
Copy link
Author

There is a much better version here https://gist.github.com/jborean93/13dbfbd94e83ff810afc55e178371eb9


Note that this will not work with cloud provides as they don't implement this function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment