private byte[] ProtectPDU(byte[] header, ref byte[] stub_data, int auth_padding_length) { List <SecurityBuffer> buffers = new List <SecurityBuffer>(); if (_negotiated_auth_type != RpcAuthenticationType.Kerberos) { buffers.Add(new SecurityBufferInOut(SecurityBufferType.Data | SecurityBufferType.ReadOnlyWithChecksum, header)); } var stub_data_buffer = new SecurityBufferInOut(SecurityBufferType.Data, stub_data); buffers.Add(stub_data_buffer); if (_negotiated_auth_type != RpcAuthenticationType.Kerberos) { buffers.Add(new SecurityBufferInOut(SecurityBufferType.Data | SecurityBufferType.ReadOnlyWithChecksum, AuthData.ToArray(_transport_security, auth_padding_length, 0, new byte[0]))); } byte[] signature; if (_transport_security.AuthenticationLevel == RpcAuthenticationLevel.PacketIntegrity) { signature = _auth_context.MakeSignature(buffers, _send_sequence_no); } else { signature = _auth_context.EncryptMessage(buffers, SecurityQualityOfProtectionFlags.None, _send_sequence_no); stub_data = stub_data_buffer.ToArray(); RpcUtils.DumpBuffer(true, "Send Encrypted Data", stub_data); } RpcUtils.DumpBuffer(true, "Send Signature Data", signature); return(AuthData.ToArray(_transport_security, auth_padding_length, 0, signature)); }
private RpcClientResponse SendAndReceiveImmediate(int proc_num, Guid objuuid, byte[] ndr_buffer, IReadOnlyCollection <NtObject> handles) { LRPC_IMMEDIATE_REQUEST_MESSAGE req_msg = new LRPC_IMMEDIATE_REQUEST_MESSAGE() { Header = new LRPC_HEADER(LRPC_MESSAGE_TYPE.lmtRequest), BindingId = 0, CallId = CallId++, ProcNum = proc_num, }; if (objuuid != Guid.Empty) { req_msg.ObjectUuid = objuuid; req_msg.Flags |= LRPC_REQUEST_MESSAGE_FLAGS.ObjectUuid; } AlpcMessageType <LRPC_IMMEDIATE_REQUEST_MESSAGE> send_msg = new AlpcMessageType <LRPC_IMMEDIATE_REQUEST_MESSAGE>(req_msg, ndr_buffer); AlpcMessageRaw resp_msg = new AlpcMessageRaw(0x1000); AlpcSendMessageAttributes send_attr = new AlpcSendMessageAttributes(); if (handles.Count > 0) { send_attr.AddHandles(handles); } using (AlpcReceiveMessageAttributes recv_attr = new AlpcReceiveMessageAttributes()) { RpcUtils.DumpBuffer(true, "ALPC Request Immediate", send_msg); _client.SendReceive(AlpcMessageFlags.SyncRequest, send_msg, send_attr, resp_msg, recv_attr, NtWaitTimeout.Infinite); RpcUtils.DumpBuffer(true, "ALPC Response Immediate", resp_msg); RpcClientResponse response = HandleResponse(resp_msg, recv_attr, req_msg.CallId); ClearAttributes(resp_msg, recv_attr); return(response); } }
internal byte[] ProtectPDU(byte[] header, ref byte[] stub_data, int auth_padding_length, int send_sequence_no) { List <SecurityBuffer> buffers = new List <SecurityBuffer>(); buffers.Add(new SecurityBufferInOut(SecurityBufferType.Data | SecurityBufferType.ReadOnly, header)); var stub_data_buffer = new SecurityBufferInOut(SecurityBufferType.Data, stub_data); buffers.Add(stub_data_buffer); buffers.Add(new SecurityBufferInOut(SecurityBufferType.Data | SecurityBufferType.ReadOnly, AuthData.ToArray(TransportSecurity, auth_padding_length, ContextId, new byte[0]))); byte[] signature = new byte[0]; if (TransportSecurity.AuthenticationLevel == RpcAuthenticationLevel.PacketIntegrity) { signature = AuthContext.MakeSignature(buffers, send_sequence_no); } else if (TransportSecurity.AuthenticationLevel == RpcAuthenticationLevel.PacketPrivacy) { signature = AuthContext.EncryptMessage(buffers, SecurityQualityOfProtectionFlags.None, send_sequence_no); stub_data = stub_data_buffer.ToArray(); RpcUtils.DumpBuffer(true, "Send Encrypted Data", stub_data); } if (signature.Length > 0) { RpcUtils.DumpBuffer(true, "Send Signature Data", signature); } return(AuthData.ToArray(TransportSecurity, auth_padding_length, ContextId, signature)); }
private Tuple <PDUHeader, byte[]> ReadPDU(int frag_count) { byte[] buffer = _pipe.Read(_max_recv_fragment); RpcUtils.DumpBuffer(true, $"RPC Named Pipe Receive Buffer - Fragment {frag_count}", buffer); MemoryStream stm = new MemoryStream(buffer); BinaryReader reader = new BinaryReader(stm); PDUHeader header = PDUHeader.Read(reader); NdrUnmarshalBuffer.CheckDataRepresentation(header.DataRep); if (header.AuthLength != 0) { throw new NotSupportedException("Named pipe transport doesn't support authentication data."); } return(Tuple.Create(header, reader.ReadAllBytes(header.FragmentLength - PDUHeader.PDU_HEADER_SIZE))); }
private RpcClientResponse SendAndReceiveLarge(int proc_num, Guid objuuid, byte[] ndr_buffer, IReadOnlyCollection <NtObject> handles) { LRPC_LARGE_REQUEST_MESSAGE req_msg = new LRPC_LARGE_REQUEST_MESSAGE() { Header = new LRPC_HEADER(LRPC_MESSAGE_TYPE.lmtRequest), BindingId = 0, CallId = CallId++, ProcNum = proc_num, LargeDataSize = ndr_buffer.Length, Flags = LRPC_REQUEST_MESSAGE_FLAGS.ViewPresent }; if (objuuid != Guid.Empty) { req_msg.ObjectUuid = objuuid; req_msg.Flags |= LRPC_REQUEST_MESSAGE_FLAGS.ObjectUuid; } var send_msg = new AlpcMessageType <LRPC_LARGE_REQUEST_MESSAGE>(req_msg); var recv_msg = new AlpcMessageRaw(0x1000); var send_attr = new AlpcSendMessageAttributes(); if (handles.Count > 0) { send_attr.AddHandles(handles); } using (var port_section = _client.CreatePortSection(AlpcCreatePortSectionFlags.Secure, ndr_buffer.Length)) { using (var data_view = port_section.CreateSectionView(AlpcDataViewAttrFlags.Secure | AlpcDataViewAttrFlags.AutoRelease, ndr_buffer.Length)) { data_view.WriteBytes(ndr_buffer); send_attr.Add(data_view.ToMessageAttribute()); using (var recv_attr = new AlpcReceiveMessageAttributes()) { RpcUtils.DumpBuffer(true, "ALPC Request Large", send_msg); _client.SendReceive(AlpcMessageFlags.SyncRequest, send_msg, send_attr, recv_msg, recv_attr, NtWaitTimeout.Infinite); RpcUtils.DumpBuffer(true, "ALPC Response Large", recv_msg); RpcClientResponse response = HandleResponse(recv_msg, recv_attr, req_msg.CallId); ClearAttributes(recv_msg, recv_attr); return(response); } } } }
private Tuple <PDUHeader, byte[], AuthData> ReadPDU(int frag_count) { byte[] buffer = ReadFragment(_max_recv_fragment); RpcUtils.DumpBuffer(true, $"{GetType().Name} Receive Buffer - Fragment {frag_count}", buffer); MemoryStream stm = new MemoryStream(buffer); BinaryReader reader = new BinaryReader(stm); PDUHeader header = PDUHeader.Read(reader); NdrUnmarshalBuffer.CheckDataRepresentation(header.DataRep); AuthData auth_data = new AuthData(); int auth_trailing_length = header.AuthLength > 0 ? header.AuthLength + AuthData.PDU_AUTH_DATA_HEADER_SIZE : 0; byte[] data = reader.ReadAllBytes(header.FragmentLength - PDUHeader.PDU_HEADER_SIZE - auth_trailing_length); if (auth_trailing_length > 0) { stm.Seek(header.FragmentLength - auth_trailing_length, SeekOrigin.Begin); auth_data = AuthData.Read(reader, header.AuthLength); } return(Tuple.Create(header, data, auth_data)); }
private void BindInterface(Guid interface_id, Version interface_version) { var bind_msg = new AlpcMessageType <LRPC_BIND_MESSAGE>(new LRPC_BIND_MESSAGE(interface_id, interface_version)); RpcUtils.DumpBuffer(true, "ALPC BindInterface Send", bind_msg); var recv_msg = new AlpcMessageRaw(0x1000); using (var recv_attr = new AlpcReceiveMessageAttributes()) { _client.SendReceive(AlpcMessageFlags.SyncRequest, bind_msg, null, recv_msg, recv_attr, NtWaitTimeout.Infinite); RpcUtils.DumpBuffer(true, "ALPC BindInterface Receive", recv_msg); using (var buffer = recv_msg.Data.ToBuffer()) { CheckForFault(buffer, LRPC_MESSAGE_TYPE.lmtBind); var value = buffer.Read <LRPC_BIND_MESSAGE>(0); if (value.RpcStatus != 0) { throw new NtException(NtObjectUtils.MapDosErrorToStatus(value.RpcStatus)); } } } }
private PDUBase SendReceivePDU(PDUBase send_pdu) { try { CallId++; PDUHeader pdu_header = new PDUHeader() { MajorVersion = PDUHeader.RPC_VERSION_MAJOR, MinorVersion = PDUHeader.RPC_VERSION_MINOR, DataRep = _data_rep, CallId = CallId, Type = send_pdu.PDUType }; List <byte[]> fragments = send_pdu.DoFragment(_max_send_fragment - PDUHeader.PDU_HEADER_SIZE); for (int i = 0; i < fragments.Count; ++i) { pdu_header.Flags = send_pdu.GetFlags(); if (i == 0) { pdu_header.Flags |= PDUFlags.FirstFrag; } if (i == fragments.Count - 1) { pdu_header.Flags |= PDUFlags.LastFrag; } pdu_header.FragmentLength = (ushort)(fragments[i].Length + PDUHeader.PDU_HEADER_SIZE); MemoryStream send_stm = new MemoryStream(); BinaryWriter writer = new BinaryWriter(send_stm); pdu_header.Write(writer); writer.Write(fragments[i]); byte[] fragment = send_stm.ToArray(); string name = fragments.Count == 1 ? "RPC Named Pipe Send Buffer" : $"RPC Named Pipe Send Buffer - Fragment {i}"; RpcUtils.DumpBuffer(true, name, fragment); if (_pipe.Write(fragment) != fragment.Length) { throw new RpcTransportException("Failed to write out PDU buffer."); } } MemoryStream recv_stm = new MemoryStream(); PDUHeader curr_header = new PDUHeader(); int frag_count = 0; while ((curr_header.Flags & PDUFlags.LastFrag) == 0) { var pdu = ReadPDU(frag_count++); curr_header = pdu.Item1; if (curr_header.CallId != CallId) { throw new RpcTransportException("Mismatching call ID."); } recv_stm.Write(pdu.Item2, 0, pdu.Item2.Length); } return(CheckFault(curr_header.ToPDU(recv_stm.ToArray()))); } catch (EndOfStreamException) { throw new RpcTransportException("End of stream."); } }
private byte[] SendReceiveRequestPDU(int proc_num, Guid objuuid, byte[] stub_data, RpcTransportSecurityContext security_context) { try { CallId++; PDURequest request_pdu = new PDURequest() { OpNum = (short)proc_num, ObjectUUID = objuuid }; int max_fragment = _max_send_fragment - request_pdu.HeaderLength; int auth_data_length = 0; if (_auth_data_required) { auth_data_length = security_context.AuthDataLength; max_fragment -= (auth_data_length + AuthData.PDU_AUTH_DATA_HEADER_SIZE); max_fragment &= ~0xF; } List <byte[]> fragments = PDURequest.DoFragment(stub_data, max_fragment); for (int i = 0; i < fragments.Count; ++i) { PDUHeader pdu_header = new PDUHeader() { MajorVersion = PDUHeader.RPC_VERSION_MAJOR, MinorVersion = PDUHeader.RPC_VERSION_MINOR, DataRep = _data_rep, CallId = CallId, Type = PDUType.Request }; if (i == 0) { pdu_header.Flags |= PDUFlags.FirstFrag; } if (i == fragments.Count - 1) { pdu_header.Flags |= PDUFlags.LastFrag; } byte[] stub_fragment = fragments[i]; byte[] auth_data = new byte[0]; byte[] header = request_pdu.ToArray(pdu_header, stub_fragment.Length, 0); if (_auth_data_required) { int auth_data_padding = 0; int auth_trailing_size = (header.Length + stub_fragment.Length + AuthData.PDU_AUTH_DATA_HEADER_SIZE) & 0xF; if (auth_trailing_size != 0) { auth_data_padding = 16 - auth_trailing_size; Array.Resize(ref stub_fragment, stub_fragment.Length + auth_data_padding); } header = request_pdu.ToArray(pdu_header, stub_fragment.Length + AuthData.PDU_AUTH_DATA_HEADER_SIZE, auth_data_length); auth_data = security_context.ProtectPDU(header, ref stub_fragment, auth_data_padding, _send_sequence_no); } MemoryStream send_stm = new MemoryStream(); BinaryWriter writer = new BinaryWriter(send_stm); writer.Write(header); writer.Write(stub_fragment); writer.Write(auth_data); byte[] fragment = send_stm.ToArray(); string name = fragments.Count == 1 ? $"{GetType().Name} Send Buffer" : $"{GetType().Name} Send Buffer - Fragment {i}"; RpcUtils.DumpBuffer(true, name, fragment); if (!WriteFragment(fragment)) { throw new RpcTransportException("Failed to write out PDU buffer."); } _send_sequence_no++; } MemoryStream recv_stm = new MemoryStream(); PDUHeader curr_header = new PDUHeader(); int frag_count = 0; while ((curr_header.Flags & PDUFlags.LastFrag) == 0) { var pdu = ReadPDU(frag_count++); curr_header = pdu.Item1; AuthData auth_data = pdu.Item3; if (curr_header.CallId != CallId) { throw new RpcTransportException($"Mismatching call ID - {curr_header.CallId} should be {CallId}."); } if (auth_data.ContextId != security_context.ContextId) { security_context = GetContext(auth_data.ContextId); } var recv_pdu = CheckFault(curr_header.ToPDU(pdu.Item2)); if (recv_pdu is PDUResponse resp_pdu) { byte[] resp_stub_data = _auth_data_required ? security_context.UnprotectPDU(resp_pdu.ToArray(curr_header), resp_pdu.StubData, auth_data, _recv_sequence_no) : resp_pdu.StubData; _recv_sequence_no++; recv_stm.Write(resp_stub_data, 0, resp_stub_data.Length); } else { throw new RpcTransportException($"Unexpected {recv_pdu.PDUType} PDU from server."); } } return(recv_stm.ToArray()); } catch (EndOfStreamException) { throw new RpcTransportException("End of stream."); } }
private Tuple <PDUBase, AuthData> SendReceivePDU(int call_id, PDUBase send_pdu, byte[] auth_data, bool receive_pdu, RpcTransportSecurityContext security_context) { try { int trailing_auth_length = auth_data.Length > 0 ? auth_data.Length + AuthData.PDU_AUTH_DATA_HEADER_SIZE : 0; PDUHeader pdu_header = new PDUHeader() { MajorVersion = PDUHeader.RPC_VERSION_MAJOR, MinorVersion = PDUHeader.RPC_VERSION_MINOR, DataRep = _data_rep, CallId = CallId, Type = send_pdu.PDUType, Flags = PDUFlags.LastFrag | PDUFlags.FirstFrag, AuthLength = checked ((ushort)auth_data.Length) }; byte[] pdu_data = send_pdu.ToArray(); int pdu_data_length = pdu_data.Length + PDUHeader.PDU_HEADER_SIZE; int auth_padding = 0; if (auth_data.Length > 0 && (pdu_data_length & 15) != 0 && send_pdu.PDUType != PDUType.Auth3) { auth_padding = 16 - (pdu_data_length & 15); } pdu_header.FragmentLength = checked ((ushort)(pdu_data.Length + PDUHeader.PDU_HEADER_SIZE + trailing_auth_length + auth_padding)); MemoryStream send_stm = new MemoryStream(); BinaryWriter writer = new BinaryWriter(send_stm); pdu_header.Write(writer); writer.Write(pdu_data); if (auth_data.Length > 0) { writer.Write(new byte[auth_padding]); new AuthData(security_context.TransportSecurity.AuthenticationType, security_context.TransportSecurity.AuthenticationLevel, auth_padding, security_context.ContextId, auth_data).Write(writer, auth_padding); } byte[] fragment = send_stm.ToArray(); RpcUtils.DumpBuffer(true, $"{GetType().Name} Send Buffer", fragment); if (!WriteFragment(fragment)) { throw new RpcTransportException("Failed to write out PDU buffer."); } _send_sequence_no++; if (!receive_pdu) { return(null); } var pdu = ReadPDU(0); var curr_header = pdu.Item1; if (!curr_header.Flags.HasFlagAllSet(PDUFlags.LastFrag | PDUFlags.FirstFrag)) { throw new RpcTransportException($"Invalid PDU flags {curr_header.Flags}."); } if (curr_header.CallId != call_id) { throw new RpcTransportException($"Mismatching call ID - {curr_header.CallId} should be {call_id}."); } if (pdu.Item3.ContextId != security_context.ContextId) { throw new RpcTransportException($"Mismatching context ID - {pdu.Item3.ContextId} should be {security_context.ContextId}."); } _recv_sequence_no++; return(Tuple.Create(CheckFault(curr_header.ToPDU(pdu.Item2)), pdu.Item3)); } catch (EndOfStreamException) { throw new RpcTransportException("End of stream."); } }