diff options
Diffstat (limited to '')
-rw-r--r-- | python/samba/emulate/traffic_packets.py | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/python/samba/emulate/traffic_packets.py b/python/samba/emulate/traffic_packets.py new file mode 100644 index 0000000..95c7465 --- /dev/null +++ b/python/samba/emulate/traffic_packets.py @@ -0,0 +1,973 @@ +# Dispatch for various request types. +# +# Copyright (C) Catalyst IT Ltd. 2017 +# +# This program 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. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +# +import os +import ctypes +import random + +from samba.net import Net +from samba.dcerpc import security, drsuapi, nbt, lsa, netlogon, ntlmssp +from samba.dcerpc.netlogon import netr_WorkstationInformation +from samba.dcerpc.security import dom_sid +from samba.netbios import Node +from samba.ndr import ndr_pack +from samba.credentials import ( + CLI_CRED_NTLMv2_AUTH, + MUST_USE_KERBEROS, + DONT_USE_KERBEROS +) +from samba import NTSTATUSError +from samba.ntstatus import ( + NT_STATUS_OBJECT_NAME_NOT_FOUND, + NT_STATUS_NO_SUCH_DOMAIN +) +import samba +import dns.resolver +from ldb import SCOPE_BASE + +def uint32(v): + return ctypes.c_uint32(v).value + + +def check_runtime_error(runtime, val): + if runtime is None: + return False + + err32 = uint32(runtime.args[0]) + if err32 == val: + return True + + return False + + +name_formats = [ + drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779, + drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, + drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY, + drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID, + drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL, + drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, + drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX, + drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL, + drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY, + drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN, + drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID, + drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS, + drsuapi.DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE, + drsuapi.DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME, + drsuapi.DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_NCS, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS, + drsuapi.DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID, + drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_ROLES, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE, + drsuapi.DRSUAPI_DS_NAME_FORMAT_LIST_SITES, +] + + +def warning(message): + print("\033[37;41;1m" "Warning: %s" "\033[00m" % (message)) + +############################################################################### +# +# Packet generation functions: +# +# All the packet generation functions have the following form: +# packet_${protocol}_${opcode}(packet, conversation, context) +# +# The functions return true, if statistics should be collected for the packet +# false, the packet has been ignored. +# +# Where: +# protocol is the protocol, i.e. cldap, dcerpc, ... +# opcode is the protocol op code i.e. type of the packet to be +# generated. +# +# packet contains data about the captured/generated packet +# provides any extra data needed to generate the packet +# +# conversation Details of the current client/server interaction +# +# context state data for the current interaction +# +# +# +# The following protocols are not currently handled: +# smb +# smb2 +# browser +# smb_netlogon +# +# The following drsuapi replication packets are currently ignored: +# DsReplicaSync +# DsGetNCChanges +# DsReplicaUpdateRefs + + +# Packet generators that do NOTHING are assigned to the null_packet +# function which allows the conversation generators to notice this and +# avoid a whole lot of pointless work. +def null_packet(packet, conversation, context): + return False + + +def packet_cldap_3(packet, conversation, context): + # searchRequest + net = Net(creds=context.creds, lp=context.lp) + net.finddc(domain=context.lp.get('realm'), + flags=(nbt.NBT_SERVER_LDAP | + nbt.NBT_SERVER_DS | + nbt.NBT_SERVER_WRITABLE)) + return True + + +packet_cldap_5 = null_packet +# searchResDone + +packet_dcerpc_0 = null_packet +# Request +# Can be ignored, it's the continuation of an existing conversation + +packet_dcerpc_2 = null_packet +# Request +# Server response, so should be ignored + +packet_dcerpc_3 = null_packet + +packet_dcerpc_11 = null_packet +# Bind +# creation of the rpc dcerpc connection is managed by the higher level +# protocol drivers. So we ignore it when generating traffic + + +packet_dcerpc_12 = null_packet +# Bind_ack +# Server response, so should be ignored + + +packet_dcerpc_13 = null_packet +# Bind_nak +# Server response, so should be ignored + + +packet_dcerpc_14 = null_packet +# Alter_context +# Generated as part of the connect process + + +def packet_dcerpc_15(packet, conversation, context): + # Alter_context_resp + # This means it was GSSAPI/krb5 (probably) + # Check the kerberos_state and issue a diagnostic if kerberos not enabled + if context.user_creds.get_kerberos_state() == DONT_USE_KERBEROS: + warning("Kerberos disabled but have dcerpc Alter_context_resp " + "indicating Kerberos was used") + return False + + +def packet_dcerpc_16(packet, conversation, context): + # AUTH3 + # This means it was NTLMSSP + # Check the kerberos_state and issue a diagnostic if kerberos enabled + if context.user_creds.get_kerberos_state() == MUST_USE_KERBEROS: + warning("Kerberos enabled but have dcerpc AUTH3 " + "indicating NTLMSSP was used") + return False + + +def packet_dns_0(packet, conversation, context): + # query + name, rtype = context.guess_a_dns_lookup() + dns.resolver.query(name, rtype) + return True + + +packet_dns_1 = null_packet +# response +# Server response, so should be ignored + + +def packet_drsuapi_0(packet, conversation, context): + # DsBind + context.get_drsuapi_connection_pair(True) + return True + + +NAME_FORMATS = [getattr(drsuapi, _x) for _x in dir(drsuapi) + if 'NAME_FORMAT' in _x] + + +def packet_drsuapi_12(packet, conversation, context): + # DsCrackNames + drs, handle = context.get_drsuapi_connection_pair() + + names = drsuapi.DsNameString() + names.str = context.server + + req = drsuapi.DsNameRequest1() + req.format_flags = 0 + req.format_offered = 7 + req.format_desired = random.choice(name_formats) + req.codepage = 1252 + req.language = 1033 # German, I think + req.format_flags = 0 + req.count = 1 + req.names = [names] + + (result, ctr) = drs.DsCrackNames(handle, 1, req) + return True + + +def packet_drsuapi_13(packet, conversation, context): + # DsWriteAccountSpn + req = drsuapi.DsWriteAccountSpnRequest1() + req.operation = drsuapi.DRSUAPI_DS_SPN_OPERATION_REPLACE + req.unknown1 = 0 # Unused, must be 0 + req.object_dn = context.user_dn + req.count = 1 # only 1 name + spn_name = drsuapi.DsNameString() + spn_name.str = 'foo/{}'.format(context.username) + req.spn_names = [spn_name] + (drs, handle) = context.get_drsuapi_connection_pair() + (level, res) = drs.DsWriteAccountSpn(handle, 1, req) + return True + + +def packet_drsuapi_1(packet, conversation, context): + # DsUnbind + (drs, handle) = context.get_drsuapi_connection_pair() + drs.DsUnbind(handle) + del context.drsuapi_connections[-1] + return True + + +packet_drsuapi_2 = null_packet +# DsReplicaSync +# This is between DCs, triggered on a DB change +# Ignoring for now + + +packet_drsuapi_3 = null_packet +# DsGetNCChanges +# This is between DCs, trigger with DB operation, +# or DsReplicaSync between DCs. +# Ignoring for now + + +packet_drsuapi_4 = null_packet +# DsReplicaUpdateRefs +# Ignoring for now + + +packet_epm_3 = null_packet +# Map +# Will be generated by higher level protocol calls + + +def packet_kerberos_(packet, conversation, context): + # Use the presence of kerberos packets as a hint to enable kerberos + # for the rest of the conversation. + # i.e. kerberos packets are not explicitly generated. + context.user_creds.set_kerberos_state(MUST_USE_KERBEROS) + context.user_creds_bad.set_kerberos_state(MUST_USE_KERBEROS) + context.machine_creds.set_kerberos_state(MUST_USE_KERBEROS) + context.machine_creds_bad.set_kerberos_state(MUST_USE_KERBEROS) + context.creds.set_kerberos_state(MUST_USE_KERBEROS) + return False + + +packet_ldap_ = null_packet +# Unknown +# The ldap payload was probably encrypted so just ignore it. + + +def packet_ldap_0(packet, conversation, context): + # bindRequest + if packet.extra[5] == "simple": + # Perform a simple bind. + context.get_ldap_connection(new=True, simple=True) + else: + # Perform a sasl bind. + context.get_ldap_connection(new=True, simple=False) + return True + + +packet_ldap_1 = null_packet +# bindResponse +# Server response ignored for traffic generation + + +def packet_ldap_2(packet, conversation, context): + # unbindRequest + # pop the last one off -- most likely we're in a bind/unbind ping. + del context.ldap_connections[-1:] + return False + + +def packet_ldap_3(packet, conversation, context): + # searchRequest + + (scope, dn_sig, filter, attrs, extra, desc, oid) = packet.extra + if not scope: + scope = SCOPE_BASE + + samdb = context.get_ldap_connection() + dn = context.get_matching_dn(dn_sig) + + # try to guess the search expression (don't bother for base searches, as + # they're only looking up a single object) + if (filter is None or filter == '') and scope != SCOPE_BASE: + filter = context.guess_search_filter(attrs, dn_sig, dn) + + samdb.search(dn, + expression=filter, + scope=int(scope), + attrs=attrs.split(','), + controls=["paged_results:1:1000"]) + return True + + +packet_ldap_4 = null_packet +# searchResEntry +# Server response ignored for traffic generation + + +packet_ldap_5 = null_packet +# Server response ignored for traffic generation + +packet_ldap_6 = null_packet + +packet_ldap_7 = null_packet + +packet_ldap_8 = null_packet + +packet_ldap_9 = null_packet + +packet_ldap_16 = null_packet + +packet_lsarpc_0 = null_packet +# lsarClose + +packet_lsarpc_1 = null_packet +# lsarDelete + +packet_lsarpc_2 = null_packet +# lsarEnumeratePrivileges + +packet_lsarpc_3 = null_packet +# LsarQuerySecurityObject + +packet_lsarpc_4 = null_packet +# LsarSetSecurityObject + +packet_lsarpc_5 = null_packet +# LsarChangePassword + +packet_lsarpc_6 = null_packet +# lsa_OpenPolicy +# We ignore this, but take it as a hint that the lsarpc handle should +# be over a named pipe. +# + + +def packet_lsarpc_14(packet, conversation, context): + # lsa_LookupNames + c = context.get_lsarpc_named_pipe_connection() + + objectAttr = lsa.ObjectAttribute() + pol_handle = c.OpenPolicy2(u'', objectAttr, + security.SEC_FLAG_MAXIMUM_ALLOWED) + + sids = lsa.TransSidArray() + names = [lsa.String("This Organization"), + lsa.String("Digest Authentication")] + level = lsa.LSA_LOOKUP_NAMES_ALL + count = 0 + c.LookupNames(pol_handle, names, sids, level, count) + return True + + +def packet_lsarpc_15(packet, conversation, context): + # lsa_LookupSids + c = context.get_lsarpc_named_pipe_connection() + + objectAttr = lsa.ObjectAttribute() + pol_handle = c.OpenPolicy2(u'', objectAttr, + security.SEC_FLAG_MAXIMUM_ALLOWED) + + sids = lsa.SidArray() + sid = lsa.SidPtr() + + x = dom_sid("S-1-5-7") + sid.sid = x + sids.sids = [sid] + sids.num_sids = 1 + names = lsa.TransNameArray() + level = lsa.LSA_LOOKUP_NAMES_ALL + count = 0 + + c.LookupSids(pol_handle, sids, names, level, count) + return True + + +def packet_lsarpc_39(packet, conversation, context): + # lsa_QueryTrustedDomainInfoBySid + # Samba does not support trusted domains, so this call is expected to fail + # + c = context.get_lsarpc_named_pipe_connection() + + objectAttr = lsa.ObjectAttribute() + + pol_handle = c.OpenPolicy2(u'', objectAttr, + security.SEC_FLAG_MAXIMUM_ALLOWED) + + domsid = security.dom_sid(context.domain_sid) + level = 1 + try: + c.QueryTrustedDomainInfoBySid(pol_handle, domsid, level) + except NTSTATUSError as error: + # Object Not found is the expected result from samba, + # while No Such Domain is the expected result from windows, + # anything else is a failure. + if not check_runtime_error(error, NT_STATUS_OBJECT_NAME_NOT_FOUND) \ + and not check_runtime_error(error, NT_STATUS_NO_SUCH_DOMAIN): + raise + return True + + +packet_lsarpc_40 = null_packet +# lsa_SetTrustedDomainInfo +# Not currently supported + + +packet_lsarpc_43 = null_packet +# LsaStorePrivateData + + +packet_lsarpc_44 = null_packet +# LsaRetrievePrivateData + + +packet_lsarpc_68 = null_packet +# LsarLookupNames3 + + +def packet_lsarpc_76(packet, conversation, context): + # lsa_LookupSids3 + c = context.get_lsarpc_connection() + sids = lsa.SidArray() + sid = lsa.SidPtr() + # Need a set + x = dom_sid("S-1-5-7") + sid.sid = x + sids.sids = [sid] + sids.num_sids = 1 + names = lsa.TransNameArray2() + level = lsa.LSA_LOOKUP_NAMES_ALL + count = 0 + lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES + client_revision = lsa.LSA_CLIENT_REVISION_2 + c.LookupSids3(sids, names, level, count, lookup_options, client_revision) + return True + + +def packet_lsarpc_77(packet, conversation, context): + # lsa_LookupNames4 + c = context.get_lsarpc_connection() + sids = lsa.TransSidArray3() + names = [lsa.String("This Organization"), + lsa.String("Digest Authentication")] + level = lsa.LSA_LOOKUP_NAMES_ALL + count = 0 + lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES + client_revision = lsa.LSA_CLIENT_REVISION_2 + c.LookupNames4(names, sids, level, count, lookup_options, client_revision) + return True + + +def packet_nbns_0(packet, conversation, context): + # query + n = Node() + try: + n.query_name("ANAME", context.server, timeout=4, broadcast=False) + except: + pass + return True + + +packet_nbns_1 = null_packet +# response +# Server response, not generated by the client + + +packet_rpc_netlogon_0 = null_packet + +packet_rpc_netlogon_1 = null_packet + +packet_rpc_netlogon_4 = null_packet +# NetrServerReqChallenge +# generated by higher level protocol drivers +# ignored for traffic generation + +packet_rpc_netlogon_14 = null_packet + +packet_rpc_netlogon_15 = null_packet + +packet_rpc_netlogon_21 = null_packet +# NetrLogonDummyRoutine1 +# Used to determine security settings. Triggered from schannel setup +# So no need for an explicit generator + + +packet_rpc_netlogon_26 = null_packet +# NetrServerAuthenticate3 +# Triggered from schannel set up, no need for an explicit generator + + +def packet_rpc_netlogon_29(packet, conversation, context): + # NetrLogonGetDomainInfo [531] + c = context.get_netlogon_connection() + (auth, succ) = context.get_authenticator() + query = netr_WorkstationInformation() + + c.netr_LogonGetDomainInfo(context.server, + context.netbios_name, + auth, + succ, + 2, # TODO are there other values? + query) + return True + + +def packet_rpc_netlogon_30(packet, conversation, context): + # NetrServerPasswordSet2 + c = context.get_netlogon_connection() + (auth, succ) = context.get_authenticator() + DATA_LEN = 512 + # Set the new password to the existing password, this generates the same + # work load as a new value, and leaves the account password intact for + # subsequent runs + newpass = context.machine_creds.get_password().encode('utf-16-le') + pwd_len = len(newpass) + filler = [x if isinstance(x, int) else ord(x) for x in os.urandom(DATA_LEN - pwd_len)] + pwd = netlogon.netr_CryptPassword() + pwd.length = pwd_len + pwd.data = filler + [x if isinstance(x, int) else ord(x) for x in newpass] + context.machine_creds.encrypt_netr_crypt_password(pwd) + c.netr_ServerPasswordSet2(context.server, + # must ends with $, so use get_username instead + # of get_workstation here + context.machine_creds.get_username(), + context.machine_creds.get_secure_channel_type(), + context.netbios_name, + auth, + pwd) + return True + + +packet_rpc_netlogon_34 = null_packet + + +def packet_rpc_netlogon_39(packet, conversation, context): + # NetrLogonSamLogonEx [4331] + def connect(creds): + c = context.get_netlogon_connection() + + # Disable Kerberos in cli creds to extract NTLM response + old_state = creds.get_kerberos_state() + creds.set_kerberos_state(DONT_USE_KERBEROS) + + logon = samlogon_logon_info(context.domain, + context.netbios_name, + creds) + logon_level = netlogon.NetlogonNetworkTransitiveInformation + validation_level = netlogon.NetlogonValidationSamInfo4 + netr_flags = 0 + c.netr_LogonSamLogonEx(context.server, + context.machine_creds.get_workstation(), + logon_level, + logon, + validation_level, + netr_flags) + + creds.set_kerberos_state(old_state) + + context.last_samlogon_bad =\ + context.with_random_bad_credentials(connect, + context.user_creds, + context.user_creds_bad, + context.last_samlogon_bad) + return True + + +def samlogon_target(domain_name, computer_name): + target_info = ntlmssp.AV_PAIR_LIST() + target_info.count = 3 + computername = ntlmssp.AV_PAIR() + computername.AvId = ntlmssp.MsvAvNbComputerName + computername.Value = computer_name + + domainname = ntlmssp.AV_PAIR() + domainname.AvId = ntlmssp.MsvAvNbDomainName + domainname.Value = domain_name + + eol = ntlmssp.AV_PAIR() + eol.AvId = ntlmssp.MsvAvEOL + target_info.pair = [domainname, computername, eol] + + return ndr_pack(target_info) + + +def samlogon_logon_info(domain_name, computer_name, creds): + + target_info_blob = samlogon_target(domain_name, computer_name) + + challenge = b"abcdefgh" + # User account under test + response = creds.get_ntlm_response(flags=CLI_CRED_NTLMv2_AUTH, + challenge=challenge, + target_info=target_info_blob) + + logon = netlogon.netr_NetworkInfo() + + logon.challenge = [x if isinstance(x, int) else ord(x) for x in challenge] + logon.nt = netlogon.netr_ChallengeResponse() + logon.nt.length = len(response["nt_response"]) + logon.nt.data = [x if isinstance(x, int) else ord(x) for x in response["nt_response"]] + + logon.identity_info = netlogon.netr_IdentityInfo() + + (username, domain) = creds.get_ntlm_username_domain() + logon.identity_info.domain_name.string = domain + logon.identity_info.account_name.string = username + logon.identity_info.workstation.string = creds.get_workstation() + + return logon + + +def packet_rpc_netlogon_40(packet, conversation, context): + # DsrEnumerateDomainTrusts + c = context.get_netlogon_connection() + c.netr_DsrEnumerateDomainTrusts( + context.server, + netlogon.NETR_TRUST_FLAG_IN_FOREST | + netlogon.NETR_TRUST_FLAG_OUTBOUND | + netlogon.NETR_TRUST_FLAG_INBOUND) + return True + + +def packet_rpc_netlogon_45(packet, conversation, context): + # NetrLogonSamLogonWithFlags [7] + def connect(creds): + c = context.get_netlogon_connection() + (auth, succ) = context.get_authenticator() + + # Disable Kerberos in cli creds to extract NTLM response + old_state = creds.get_kerberos_state() + creds.set_kerberos_state(DONT_USE_KERBEROS) + + logon = samlogon_logon_info(context.domain, + context.netbios_name, + creds) + logon_level = netlogon.NetlogonNetworkTransitiveInformation + validation_level = netlogon.NetlogonValidationSamInfo4 + netr_flags = 0 + c.netr_LogonSamLogonWithFlags(context.server, + context.machine_creds.get_workstation(), + auth, + succ, + logon_level, + logon, + validation_level, + netr_flags) + + creds.set_kerberos_state(old_state) + + context.last_samlogon_bad =\ + context.with_random_bad_credentials(connect, + context.user_creds, + context.user_creds_bad, + context.last_samlogon_bad) + return True + + +def packet_samr_0(packet, conversation, context): + # Open + c = context.get_samr_context() + c.get_handle() + return True + + +def packet_samr_1(packet, conversation, context): + # Close + c = context.get_samr_context() + s = c.get_connection() + # close the last opened handle, may not always be accurate + # but will do for load simulation + if c.user_handle is not None: + s.Close(c.user_handle) + c.user_handle = None + elif c.group_handle is not None: + s.Close(c.group_handle) + c.group_handle = None + elif c.domain_handle is not None: + s.Close(c.domain_handle) + c.domain_handle = None + c.rids = None + elif c.handle is not None: + s.Close(c.handle) + c.handle = None + c.domain_sid = None + return True + + +def packet_samr_3(packet, conversation, context): + # QuerySecurity + c = context.get_samr_context() + s = c.get_connection() + if c.user_handle is None: + packet_samr_34(packet, conversation, context) + s.QuerySecurity(c.user_handle, 1) + return True + + +def packet_samr_5(packet, conversation, context): + # LookupDomain + c = context.get_samr_context() + s = c.get_connection() + h = c.get_handle() + d = lsa.String() + d.string = context.domain + c.domain_sid = s.LookupDomain(h, d) + return True + + +def packet_samr_6(packet, conversation, context): + # EnumDomains + c = context.get_samr_context() + s = c.get_connection() + h = c.get_handle() + s.EnumDomains(h, 0, 0) + return True + + +def packet_samr_7(packet, conversation, context): + # OpenDomain + c = context.get_samr_context() + s = c.get_connection() + h = c.get_handle() + if c.domain_sid is None: + packet_samr_5(packet, conversation, context) + + c.domain_handle = s.OpenDomain(h, + security.SEC_FLAG_MAXIMUM_ALLOWED, + c.domain_sid) + return True + + +SAMR_QUERY_DOMAIN_INFO_LEVELS = [8, 12] + + +def packet_samr_8(packet, conversation, context): + # QueryDomainInfo [228] + c = context.get_samr_context() + s = c.get_connection() + if c.domain_handle is None: + packet_samr_7(packet, conversation, context) + level = random.choice(SAMR_QUERY_DOMAIN_INFO_LEVELS) + s.QueryDomainInfo(c.domain_handle, level) + return True + + +packet_samr_14 = null_packet +# CreateDomainAlias +# Ignore these for now. + + +def packet_samr_15(packet, conversation, context): + # EnumDomainAliases + c = context.get_samr_context() + s = c.get_connection() + if c.domain_handle is None: + packet_samr_7(packet, conversation, context) + + s.EnumDomainAliases(c.domain_handle, 100, 0) + return True + + +def packet_samr_16(packet, conversation, context): + # GetAliasMembership + c = context.get_samr_context() + s = c.get_connection() + if c.domain_handle is None: + packet_samr_7(packet, conversation, context) + + sids = lsa.SidArray() + sid = lsa.SidPtr() + sid.sid = c.domain_sid + sids.sids = [sid] + s.GetAliasMembership(c.domain_handle, sids) + return True + + +def packet_samr_17(packet, conversation, context): + # LookupNames + c = context.get_samr_context() + s = c.get_connection() + if c.domain_handle is None: + packet_samr_7(packet, conversation, context) + + name = lsa.String(context.username) + c.rids = s.LookupNames(c.domain_handle, [name]) + return True + + +def packet_samr_18(packet, conversation, context): + # LookupRids + c = context.get_samr_context() + s = c.get_connection() + if c.rids is None: + packet_samr_17(packet, conversation, context) + rids = [] + for r in c.rids: + for i in r.ids: + rids.append(i) + s.LookupRids(c.domain_handle, rids) + return True + + +def packet_samr_19(packet, conversation, context): + # OpenGroup + c = context.get_samr_context() + s = c.get_connection() + if c.domain_handle is None: + packet_samr_7(packet, conversation, context) + + rid = 0x202 # Users I think. + c.group_handle = s.OpenGroup(c.domain_handle, + security.SEC_FLAG_MAXIMUM_ALLOWED, + rid) + return True + + +def packet_samr_25(packet, conversation, context): + # QueryGroupMember + c = context.get_samr_context() + s = c.get_connection() + if c.group_handle is None: + packet_samr_19(packet, conversation, context) + s.QueryGroupMember(c.group_handle) + return True + + +def packet_samr_34(packet, conversation, context): + # OpenUser + c = context.get_samr_context() + s = c.get_connection() + if c.rids is None: + packet_samr_17(packet, conversation, context) + c.user_handle = s.OpenUser(c.domain_handle, + security.SEC_FLAG_MAXIMUM_ALLOWED, + c.rids[0].ids[0]) + return True + + +def packet_samr_36(packet, conversation, context): + # QueryUserInfo + c = context.get_samr_context() + s = c.get_connection() + if c.user_handle is None: + packet_samr_34(packet, conversation, context) + level = 1 + s.QueryUserInfo(c.user_handle, level) + return True + + +packet_samr_37 = null_packet + + +def packet_samr_39(packet, conversation, context): + # GetGroupsForUser + c = context.get_samr_context() + s = c.get_connection() + if c.user_handle is None: + packet_samr_34(packet, conversation, context) + s.GetGroupsForUser(c.user_handle) + return True + + +packet_samr_40 = null_packet + +packet_samr_44 = null_packet + + +def packet_samr_57(packet, conversation, context): + # Connect2 + c = context.get_samr_context() + c.get_handle() + return True + + +def packet_samr_64(packet, conversation, context): + # Connect5 + c = context.get_samr_context() + c.get_handle() + return True + + +packet_samr_68 = null_packet + + +def packet_srvsvc_16(packet, conversation, context): + # NetShareGetInfo + s = context.get_srvsvc_connection() + server_unc = "\\\\" + context.server + share_name = "IPC$" + level = 1 + s.NetShareGetInfo(server_unc, share_name, level) + return True + + +def packet_srvsvc_21(packet, conversation, context): + """NetSrvGetInfo + + FIXME: Level changed from 102 to 101 here, to bypass Windows error. + + Level 102 will cause WERR_ACCESS_DENIED error against Windows, because: + + > If the level is 102 or 502, the Windows implementation checks whether + > the caller is a member of one of the groups previously mentioned or + > is a member of the Power Users local group. + + It passed against Samba since this check is not implemented by Samba yet. + + refer to: + + https://msdn.microsoft.com/en-us/library/cc247297.aspx#Appendix_A_80 + + """ + srvsvc = context.get_srvsvc_connection() + server_unc = "\\\\" + context.server + level = 101 + srvsvc.NetSrvGetInfo(server_unc, level) + return True |