Initial RPCScope release
This commit is contained in:
commit
9dc7289652
40 files changed
+6688
No files matched your search
@@ -0,0 +1,188 @@
|
||||
import unittest
|
||||
|
||||
from rpcscope.parsers import parse_enum4linux, parse_nxc, parse_rpcdump
|
||||
|
||||
|
||||
class ParserTests(unittest.TestCase):
|
||||
def test_nxc_alive_evidence_requires_a_banner_or_positive_response(self):
|
||||
hosts = parse_nxc("\n".join([
|
||||
"SMB 192.0.2.1 445 NONE [-] Error connecting to host: timed out",
|
||||
"SMB 192.0.2.2 445 HOST [*] Windows 11 (name:HOST)",
|
||||
"SMB 192.0.2.3 445 HOST [+] LAB\\auditor:password",
|
||||
]))
|
||||
self.assertEqual(hosts["192.0.2.1"].services, {})
|
||||
self.assertEqual(hosts["192.0.2.2"].services, {"445": "open"})
|
||||
self.assertEqual(hosts["192.0.2.3"].services, {"445": "open"})
|
||||
|
||||
def test_parse_nxc_host_and_share(self):
|
||||
text = """
|
||||
SMB 10.10.10.25 445 FILE01 [*] Windows 7 Build 7601 (name:FILE01) (domain:LAB) (signing:False) (SMBv1:True)
|
||||
SMB 10.10.10.25 445 FILE01 [+] LAB\\guest
|
||||
SMB 10.10.10.25 445 FILE01 Public READ,WRITE Team share
|
||||
"""
|
||||
host = parse_nxc(text)["10.10.10.25"]
|
||||
self.assertEqual(host.hostname, "FILE01")
|
||||
self.assertIs(host.smb1, True)
|
||||
self.assertIs(host.signing, False)
|
||||
self.assertIs(host.guest_session, True)
|
||||
self.assertEqual(host.shares[0].name, "Public")
|
||||
self.assertEqual(host.shares[0].access, ["READ", "WRITE"])
|
||||
|
||||
|
||||
def test_parse_rpcdump_block(self):
|
||||
text = """
|
||||
Protocol: [MS-RPRN]: Print System Remote Protocol
|
||||
Provider: spoolsv.exe
|
||||
UUID : 12345678-1234-ABCD-EF00-0123456789AB v1.0
|
||||
Bindings:
|
||||
ncacn_np:10.10.10.25[\\pipe\\spoolss]
|
||||
"""
|
||||
host = parse_rpcdump(text, "10.10.10.25")
|
||||
self.assertEqual(host.rpc_interfaces[0].uuid, "12345678-1234-abcd-ef00-0123456789ab")
|
||||
self.assertIn("spoolss", host.rpc_interfaces[0].endpoint)
|
||||
|
||||
|
||||
def test_parse_enum4linux_core_fields(self):
|
||||
data = {
|
||||
"target": {"host": "10.10.10.25"},
|
||||
"sessions": {"sessions_possible": True, "null": True, "guest": False},
|
||||
"smb": {"smb1_supported": True, "signing_required": False},
|
||||
"shares": {"Public": {"access": {"mapping": "OK", "listing": "OK"}}},
|
||||
}
|
||||
host = parse_enum4linux(data, "fixture.json")
|
||||
self.assertEqual(host.address, "10.10.10.25")
|
||||
self.assertIs(host.null_session, True)
|
||||
self.assertIs(host.smb1, True)
|
||||
self.assertIs(host.signing, False)
|
||||
self.assertEqual(host.shares[0].access, ["READ"])
|
||||
|
||||
def test_enum4linux_current_schema_and_server_facts(self):
|
||||
data = {
|
||||
"target": {"host": "10.10.10.25"},
|
||||
"credentials": {"domain": "LOGIN-DOMAIN", "password": "WRITE"},
|
||||
"smb_dialects": {
|
||||
"Supported dialects": {"SMB 1.0": False, "SMB 3.1.1": True},
|
||||
"SMB1 only": False,
|
||||
"SMB signing required": True,
|
||||
},
|
||||
"smb_domain_info": {"NetBIOS computer name": "FILE01",
|
||||
"NetBIOS domain name": "LAB"},
|
||||
"rpc_domain_info": {"Domain": "RPC-LAB"},
|
||||
"os_info": {"OS": "Windows Server 2019", "Native OS": "Windows 10.0"},
|
||||
}
|
||||
host = parse_enum4linux(data, "fixture.json")
|
||||
self.assertIs(host.smb1, False)
|
||||
self.assertIs(host.signing, True)
|
||||
self.assertEqual(host.hostname, "FILE01")
|
||||
self.assertEqual(host.domain, "RPC-LAB")
|
||||
self.assertEqual(host.os, "Windows Server 2019")
|
||||
|
||||
def test_enum_share_requires_successful_listing(self):
|
||||
data = {
|
||||
"target": {"host": "10.10.10.25"},
|
||||
"shares": {
|
||||
"Denied": {"access": {"mapping": "ok", "listing": "denied"}},
|
||||
"WrongPassword": {"access": {"mapping": "ok", "listing": "wrong password"}},
|
||||
"IPC$": {"access": {"mapping": "ok", "listing": "not supported"}},
|
||||
"NoProbe": {"comment": "READ WRITE backup share"},
|
||||
"FalseFlags": {"access": {"read": False, "write": False}},
|
||||
"Readable": {"access": {"mapping": "ok", "listing": "ok"}},
|
||||
},
|
||||
}
|
||||
host = parse_enum4linux(data, "fixture.json")
|
||||
permissions = {share.name: share.access for share in host.shares}
|
||||
self.assertEqual(permissions.pop("Readable"), ["READ"])
|
||||
self.assertTrue(all(access == [] for access in permissions.values()))
|
||||
|
||||
def test_enum_ignores_client_settings_and_credentials(self):
|
||||
host = parse_enum4linux({"target": {"host": "10.10.10.25"},
|
||||
"credentials": {"domain": "ATTACKER"},
|
||||
"smb": {"ipc_signing": False},
|
||||
"errors": {"os": "failed"}}, "fixture.json")
|
||||
self.assertIsNone(host.signing)
|
||||
self.assertEqual(host.domain, "")
|
||||
self.assertEqual(host.os, "")
|
||||
|
||||
def test_nxc_does_not_infer_null_or_guest_from_partial_names(self):
|
||||
text = """
|
||||
SMB 10.10.10.25 445 FILE01 [+] LAB\\annulled:anonymous
|
||||
SMB 10.10.10.25 445 FILE01 [+] LAB\\guestadmin:password
|
||||
SMB 10.10.10.25 445 FILE01 [-] guest session failed
|
||||
"""
|
||||
host = parse_nxc(text)["10.10.10.25"]
|
||||
self.assertIsNone(host.null_session)
|
||||
self.assertIsNone(host.guest_session)
|
||||
|
||||
def test_nxc_explicit_null_and_guest_flags(self):
|
||||
text = """
|
||||
SMB 10.10.10.25 445 FILE01 [*] Windows Server 2019 (name:FILE01) (domain:LAB) (Null Auth:True) (Guest Auth:True)
|
||||
"""
|
||||
host = parse_nxc(text)["10.10.10.25"]
|
||||
self.assertIs(host.null_session, True)
|
||||
self.assertIs(host.guest_session, True)
|
||||
|
||||
def test_nxc_handles_ipv6_and_repeated_share_permissions(self):
|
||||
text = """
|
||||
SMB 2001:db8::25 445 FILE01 [*] Windows Server 2019 (name:FILE01) (domain:LAB)
|
||||
SMB 2001:db8::25 445 FILE01 Data READ first pass
|
||||
SMB 2001:db8::25 445 FILE01 data READ,WRITE second pass
|
||||
SMB 2001:db8::25 445 FILE01 Team Files READ Shared files
|
||||
"""
|
||||
host = parse_nxc(text)["2001:db8::25"]
|
||||
self.assertEqual(len(host.shares), 2)
|
||||
self.assertEqual(host.shares[0].access, ["READ", "WRITE"])
|
||||
self.assertEqual(host.shares[1].name, "Team Files")
|
||||
|
||||
def test_nxc_does_not_parse_credential_or_comment_as_share(self):
|
||||
text = """
|
||||
SMB 10.10.10.25 445 FILE01 [+] LAB\\user:READ WRITE
|
||||
SMB 10.10.10.25 445 FILE01 Public READONLY This is a comment
|
||||
"""
|
||||
self.assertEqual(parse_nxc(text)["10.10.10.25"].shares, [])
|
||||
|
||||
def test_nxc_share_table_keeps_acl_labels_and_ignores_denied_remarks(self):
|
||||
prefix = "SMB 10.10.10.25 445 FILE01 "
|
||||
rows = [f"{'Share':<15} {'Permissions':<22} Remark",
|
||||
f"{'Denied':<15} {'':<22} READ WRITE access is denied",
|
||||
f"{'AclOnly':<15} {'READ,WRITE (ACL)':<22} Permission changes allowed",
|
||||
f"{'SubdirOnly':<15} {'WRITE (SUBDIR)':<22} Directory creation allowed",
|
||||
f"{'A very long share name':<15} {'READ':<22} Long name"]
|
||||
host = parse_nxc("\n".join(prefix + row for row in rows))["10.10.10.25"]
|
||||
self.assertEqual([share.name for share in host.shares],
|
||||
["AclOnly", "SubdirOnly", "A very long share name"])
|
||||
self.assertEqual(host.shares[0].access, ["READ", "WRITE (ACL)"])
|
||||
self.assertEqual(host.shares[1].access, ["WRITE (SUBDIR)"])
|
||||
|
||||
def test_rpcdump_preserves_all_bindings_and_inline_annotation(self):
|
||||
text = """
|
||||
Protocol: [MS-RPRN]: Print System Remote Protocol
|
||||
Provider: spoolsv.exe
|
||||
UUID : 12345678-1234-ABCD-EF00-0123456789AB v1.0 Print annotation
|
||||
Bindings:
|
||||
ncalrpc:[local-spooler]
|
||||
ncacn_ip_tcp:10.10.10.25[49665]
|
||||
ncacn_np:10.10.10.25[\\pipe\\spoolss]
|
||||
ncacn_np:10.10.10.25[\\pipe\\spoolss]
|
||||
"""
|
||||
interface = parse_rpcdump(text, "10.10.10.25").rpc_interfaces[0]
|
||||
self.assertEqual(len(interface.bindings), 3)
|
||||
self.assertEqual(interface.endpoint, "ncalrpc:[local-spooler]")
|
||||
self.assertEqual(interface.annotation, "Print annotation")
|
||||
|
||||
def test_rpcdump_unlabelled_uuid_in_mixed_output(self):
|
||||
text = """
|
||||
UUID: 12345678-1234-abcd-ef00-0123456789ab v1.0
|
||||
Bindings: ncacn_ip_tcp:10.10.10.25[49665]
|
||||
367abb81-9844-35f1-ad32-98f038001003 2.0 Service manager
|
||||
Bindings:
|
||||
ncacn_np:10.10.10.25[\\pipe\\svcctl]
|
||||
"""
|
||||
interfaces = parse_rpcdump(text, "10.10.10.25").rpc_interfaces
|
||||
self.assertEqual(len(interfaces), 2)
|
||||
self.assertEqual(interfaces[1].version, "2.0")
|
||||
self.assertEqual(interfaces[1].annotation, "Service manager")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in new issue
Block a user