Пример #1
0
    def _invoke(self, function_name, opnum, data):
        req = RequestPDU()
        req['pfx_flags'].set_flag(PFlags.PFC_FIRST_FRAG)
        req['pfx_flags'].set_flag(PFlags.PFC_LAST_FRAG)
        req['packed_drep'] = DataRepresentationFormat()
        req['call_id'] = self.call_id
        self.call_id += 1

        req['opnum'] = opnum
        req['stub_data'] = data

        ioctl_request = SMB2IOCTLRequest()
        ioctl_request['ctl_code'] = CtlCode.FSCTL_PIPE_TRANSCEIVE
        ioctl_request['file_id'] = self.handle.file_id
        ioctl_request['max_output_response'] = 1024
        ioctl_request['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
        ioctl_request['buffer'] = req

        session_id = self.tree.session.session_id
        tree_id = self.tree.tree_connect_id
        log.info("Sending svcctl RPC request for %s" % function_name)
        log.debug(str(req))
        request = self.tree.session.connection.send(ioctl_request,
                                                    sid=session_id,
                                                    tid=tree_id)
        log.info("Receiving svcctl RPC response for %s" % function_name)
        resp = self.tree.session.connection.receive(request)
        ioctl_resp = SMB2IOCTLResponse()
        ioctl_resp.unpack(resp['data'].get_value())
        log.debug(str(ioctl_resp))

        pdu_resp = self._parse_pdu(ioctl_resp['buffer'].get_value(), opnum)
        return pdu_resp
Пример #2
0
 def test_parse_message(self):
     actual = SMB2IOCTLResponse()
     data = b"\x31\x00\x00\x00" \
            b"\x04\x02\x14\x00" \
            b"\xff\xff\xff\xff\xff\xff\xff\xff" \
            b"\xff\xff\xff\xff\xff\xff\xff\xff" \
            b"\x00\x00\x00\x00" \
            b"\x00\x00\x00\x00" \
            b"\x70\x00\x00\x00" \
            b"\x04\x00\x00\x00" \
            b"\x01\x00\x00\x00" \
            b"\x00\x00\x00\x00" \
            b"\x20\x21\x22\x23"
     actual.unpack(data)
     assert len(actual) == 52
     assert actual['structure_size'].get_value() == 49
     assert actual['reserved'].get_value() == 0
     assert actual['ctl_code'].get_value() == \
         CtlCode.FSCTL_VALIDATE_NEGOTIATE_INFO
     assert actual['file_id'].pack() == b"\xff" * 16
     assert actual['input_offset'].get_value() == 0
     assert actual['input_count'].get_value() == 0
     assert actual['output_offset'].get_value() == 112
     assert actual['output_count'].get_value() == 4
     assert actual['flags'].get_value() == IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
     assert actual['reserved2'].get_value() == 0
     assert actual['buffer'].get_value() == b"\x20\x21\x22\x23"
Пример #3
0
    def _verify_dialect_negotiate(self):
        log_header = "Session: %s, Tree: %s" \
                     % (self.session.username, self.share_name)
        log.info("%s - Running secure negotiate process" % log_header)
        ioctl_request = SMB2IOCTLRequest()
        ioctl_request['ctl_code'] = \
            CtlCode.FSCTL_VALIDATE_NEGOTIATE_INFO
        ioctl_request['file_id'] = b"\xff" * 16

        val_neg = SMB2ValidateNegotiateInfoRequest()
        val_neg['capabilities'] = \
            self.session.connection.client_capabilities
        val_neg['guid'] = self.session.connection.client_guid
        val_neg['security_mode'] = \
            self.session.connection.client_security_mode
        val_neg['dialects'] = \
            self.session.connection.negotiated_dialects

        ioctl_request['buffer'] = val_neg
        ioctl_request['max_output_response'] = len(val_neg)
        ioctl_request['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
        log.info("%s - Sending Secure Negotiate Validation message"
                 % log_header)
        log.debug(ioctl_request)
        request = self.session.connection.send(ioctl_request,
                                               sid=self.session.session_id,
                                               tid=self.tree_connect_id)

        log.info("%s - Receiving secure negotiation response" % log_header)
        response = self.session.connection.receive(request)
        ioctl_resp = SMB2IOCTLResponse()
        ioctl_resp.unpack(response['data'].get_value())
        log.debug(ioctl_resp)

        log.info("%s - Unpacking secure negotiate response info" % log_header)
        val_resp = SMB2ValidateNegotiateInfoResponse()
        val_resp.unpack(ioctl_resp['buffer'].get_value())
        log.debug(val_resp)

        self._verify("server capabilities",
                     val_resp['capabilities'].get_value(),
                     self.session.connection.server_capabilities.get_value())
        self._verify("server guid",
                     val_resp['guid'].get_value(),
                     self.session.connection.server_guid)
        self._verify("server security mode",
                     val_resp['security_mode'].get_value(),
                     self.session.connection.server_security_mode)
        self._verify("server dialect",
                     val_resp['dialect'].get_value(),
                     self.session.connection.dialect)
        log.info("Session: %d, Tree: %d - Secure negotiate complete"
                 % (self.session.session_id, self.tree_connect_id))
Пример #4
0
def dfs_request(tree, path):  # type: (TreeConnect, str) -> DFSReferralResponse
    """ Send a DFS Referral request to the IPC tree and return the referrals. """
    dfs_referral = DFSReferralRequest()
    dfs_referral['request_file_name'] = to_text(path)

    ioctl_req = SMB2IOCTLRequest()
    ioctl_req['ctl_code'] = CtlCode.FSCTL_DFS_GET_REFERRALS
    ioctl_req['file_id'] = b"\xFF" * 16
    ioctl_req['max_output_response'] = 56 * 1024
    ioctl_req['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
    ioctl_req['buffer'] = dfs_referral

    request = tree.session.connection.send(ioctl_req, sid=tree.session.session_id, tid=tree.tree_connect_id)
    response = tree.session.connection.receive(request)

    ioctl_resp = SMB2IOCTLResponse()
    ioctl_resp.unpack(response['data'].get_value())

    dfs_response = DFSReferralResponse()
    dfs_response.unpack(ioctl_resp['buffer'].get_value())

    return dfs_response
Пример #5
0
 def test_create_message(self):
     message = SMB2IOCTLResponse()
     message['ctl_code'] = CtlCode.FSCTL_VALIDATE_NEGOTIATE_INFO
     message['file_id'] = b"\xff" * 16
     message['input_offset'] = 0
     message['input_count'] = 0
     message['output_offset'] = 112
     message['output_count'] = 4
     message['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
     message['buffer'] = b"\x20\x21\x22\x23"
     expected = b"\x31\x00\x00\x00" \
                b"\x04\x02\x14\x00" \
                b"\xff\xff\xff\xff\xff\xff\xff\xff" \
                b"\xff\xff\xff\xff\xff\xff\xff\xff" \
                b"\x00\x00\x00\x00" \
                b"\x00\x00\x00\x00" \
                b"\x70\x00\x00\x00" \
                b"\x04\x00\x00\x00" \
                b"\x01\x00\x00\x00" \
                b"\x00\x00\x00\x00" \
                b"\x20\x21\x22\x23"
     actual = message.pack()
     assert len(message) == 52
     assert actual == expected
Пример #6
0
 def _receive_resp(request):
     response = transaction.raw.fd.connection.receive(request)
     query_resp = SMB2IOCTLResponse()
     query_resp.unpack(response['data'].get_value())
     return query_resp['buffer'].get_value()
Пример #7
0
    def enum_services_status_w(self, server_handle, service_type,
                               service_state):
        """
        Enumerates the services based on the criteria selected

        :param server_handle: A handle to SCMR
        :param service_type: ServiceType flags to filter by service type
        :param service_state: EnumServiceState enum value
        :return: List dictionaries with the following entries
            service_name: The service name of the service
            display_name: The display name of the service
            service_status: ServiceStatus structure of the service
        """
        # https://msdn.microsoft.com/en-us/library/cc245933.aspx
        opnum = 14

        # sent 0 bytes on the buffer size for the 1st request to get the
        # buffer size that is required
        req_data = server_handle
        req_data += struct.pack("<i", service_type)
        req_data += struct.pack("<i", service_state)
        req_data += struct.pack("<i", 0)
        req_data += b"\x00\x00\x00\x00"
        res = self._invoke("REnumServicesStatusW", opnum, req_data)

        # now send another request with the total buffer size sent
        buffer_size = struct.unpack("<i", res[4:8])[0]
        req_data = server_handle
        req_data += struct.pack("<i", service_type)
        req_data += struct.pack("<i", service_state)
        req_data += res[4:8]
        req_data += b"\x00\x00\x00\x00"

        try:
            res = self._invoke("REnumServicesStatusW", opnum, req_data)
            data = res
        except SMBResponseException as exc:
            if exc.status != NtStatus.STATUS_BUFFER_OVERFLOW:
                raise exc

            ioctl_resp = SMB2IOCTLResponse()
            ioctl_resp.unpack(exc.header['data'].get_value())
            pdu_resp = self._parse_pdu(ioctl_resp['buffer'].get_value(), opnum)
            read_data = self.handle.read(0, 3256)  # 4280 - 1024
            data = pdu_resp + read_data

        while len(data) < buffer_size:
            read_data = self.handle.read(0, 4280)
            data += self._parse_pdu(read_data, opnum)

        return_code = struct.unpack("<i", data[-4:])[0]
        self._parse_error(return_code, "REnumServicesStatusW")

        # now we have all the data, let's unpack it
        services = []
        services_returned = struct.unpack("<i", data[-12:-8])[0]
        offset = 4
        for i in range(0, services_returned):
            name_offset = struct.unpack("<i", data[offset:4 + offset])[0]
            disp_offset = struct.unpack("<i", data[4 + offset:8 + offset])[0]
            service_status = ServiceStatus()
            service_name = data[name_offset + 4:].split(b"\x00\x00")[0]
            display_name = data[disp_offset + 4:].split(b"\x00\x00")[0]
            service_status.unpack(data[offset + 8:])

            service_info = {
                "display_name": (display_name + b"\x00").decode('utf-16-le'),
                "service_name": (service_name + b"\x00").decode('utf-16-le'),
                "service_status": service_status
            }
            services.append(service_info)
            offset += 8 + len(service_status)

        return services
Пример #8
0
    def _verify_dialect_negotiate(self):
        log_header = "Session: %s, Tree: %s" \
                     % (self.session.username, self.share_name)
        log.info("%s - Running secure negotiate process" % log_header)

        if not self.session.signing_key:
            # This will only happen if we authenticated with the guest or anonymous user.
            raise SMBException(
                'Cannot verify negotiate information without a session signing key. Authenticate with '
                'a non-guest or anonymous account or set require_secure_negotiate=False to disable the '
                'negotiation info verification checks.')

        dialect = self.session.connection.dialect
        if dialect >= Dialects.SMB_3_1_1:
            # SMB 3.1.1+ uses the negotiation info to generate the signing key so doesn't need this extra exchange.
            return

        ioctl_request = SMB2IOCTLRequest()
        ioctl_request['ctl_code'] = \
            CtlCode.FSCTL_VALIDATE_NEGOTIATE_INFO
        ioctl_request['file_id'] = b"\xff" * 16

        val_neg = SMB2ValidateNegotiateInfoRequest()
        val_neg['capabilities'] = \
            self.session.connection.client_capabilities
        val_neg['guid'] = self.session.connection.client_guid
        val_neg['security_mode'] = \
            self.session.connection.client_security_mode
        val_neg['dialects'] = \
            self.session.connection.negotiated_dialects

        ioctl_request['buffer'] = val_neg
        ioctl_request['max_output_response'] = len(val_neg)
        ioctl_request['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL
        log.info("%s - Sending Secure Negotiate Validation message" %
                 log_header)
        log.debug(ioctl_request)
        request = self.session.connection.send(ioctl_request,
                                               sid=self.session.session_id,
                                               tid=self.tree_connect_id,
                                               force_signature=True)

        log.info("%s - Receiving secure negotiation response" % log_header)
        try:
            response = self.session.connection.receive(request)

        except (FileClosed, InvalidDeviceRequest, NotSupported) as e:
            # https://docs.microsoft.com/en-us/archive/blogs/openspecification/smb3-secure-dialect-negotiation
            # Older dialects may respond with these exceptions, this is expected and we only want to fail if
            # they are not signed. Check that header signature was signed, fail if it wasn't. The signature, if
            # present, would have been verified when the connection received the data.
            if e.header['signature'].get_value() == b'\x00' * 16:
                raise

            return

        # If we received an actual response we want to validate the info provided matches with what was negotiated.
        ioctl_resp = SMB2IOCTLResponse()
        ioctl_resp.unpack(response['data'].get_value())
        log.debug(ioctl_resp)

        log.info("%s - Unpacking secure negotiate response info" % log_header)
        val_resp = SMB2ValidateNegotiateInfoResponse()
        val_resp.unpack(ioctl_resp['buffer'].get_value())
        log.debug(val_resp)

        self._verify("server capabilities",
                     val_resp['capabilities'].get_value(),
                     self.session.connection.server_capabilities.get_value())
        self._verify("server guid", val_resp['guid'].get_value(),
                     self.session.connection.server_guid)
        self._verify("server security mode",
                     val_resp['security_mode'].get_value(),
                     self.session.connection.server_security_mode)
        self._verify("server dialect", val_resp['dialect'].get_value(),
                     self.session.connection.dialect)
        log.info("Session: %d, Tree: %d - Secure negotiate complete" %
                 (self.session.session_id, self.tree_connect_id))