#include "dce_smb_module.h"
#include "dce_list.h"
#include "dce_utils.h"
+#include "dce_smb_utils.h"
#include "log/messages.h"
#include "main/snort_debug.h"
#include "utils/util.h"
********************************************************************/
static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData* sd, DCE2_CoTracker* cot, uint16_t ctx_id)
{
-
/* This should be set if we've gotten a Bind */
if (cot->ctx_ids == nullptr)
return DCE2_RET__ERROR;
dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
int co_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__CO_CLI :
DCE2_MOCK_HDR_LEN__CO_SRV;
+ int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+ DCE2_MOCK_HDR_LEN__SMB_SRV;
if (sd->trans == DCE2_TRANS_TYPE__TCP)
{
{
case DCE2_RPKT_TYPE__SMB_CO_FRAG:
case DCE2_RPKT_TYPE__SMB_CO_SEG:
- // FIXIT-M add this when SMB is ported
- return nullptr;
+ DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, (uint8_t*)rpkt->data,
+ (uint16_t)(rpkt->dsize - smb_hdr_len));
+
+ if (rpkt_type == DCE2_RPKT_TYPE__SMB_CO_FRAG)
+ {
+ DCE2_CoSetRdata(sd, cot, (uint8_t*)rpkt->data + smb_hdr_len,
+ (uint16_t)(rpkt->dsize - (smb_hdr_len + co_hdr_len)));
+
+ if (DCE2_SsnFromClient(sd->wire_pkt))
+ dce_common_stats->co_cli_frag_reassembled++;
+ else
+ dce_common_stats->co_srv_frag_reassembled++;
+ }
+ else
+ {
+ if (DCE2_SsnFromClient(sd->wire_pkt))
+ dce_common_stats->co_cli_seg_reassembled++;
+ else
+ dce_common_stats->co_srv_seg_reassembled++;
+ }
+
+ *co_hdr = (DceRpcCoHdr*)(rpkt->data + smb_hdr_len);
+ cot->stub_data = rpkt->data + smb_hdr_len + co_hdr_len;
+ return rpkt;
case DCE2_RPKT_TYPE__TCP_CO_FRAG:
case DCE2_RPKT_TYPE__TCP_CO_SEG:
DCE2_Buffer* frag_buf = DCE2_CoGetFragBuf(sd, &cot->frag_tracker);
uint16_t max_frag_data;
- // FIXIT-M add SMB max_frag_data when SMB is ported
-
- max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__TCP_CO_FRAG);
+ /* Check for potential overflow */
+ if (sd->trans == DCE2_TRANS_TYPE__SMB)
+ max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__SMB_CO_FRAG);
+ else
+ max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__TCP_CO_FRAG);
ret_val = dce_co_handle_frag(sd, cot,co_hdr, frag_ptr, frag_len,frag_buf,max_frag_data);
if (ret_val == DCE2_RET__SUCCESS)
const uint8_t* data_ptr, uint32_t data_len)
{
Packet* rpkt = nullptr;
- // FIXIT-M add smb_hdr_len when SMB is ported
+ int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+ DCE2_MOCK_HDR_LEN__SMB_SRV;
if (sd->trans == DCE2_TRANS_TYPE__TCP)
{
switch (sd->trans)
{
case DCE2_TRANS_TYPE__SMB:
- // FIXIT-M add when SMB is ported
+ rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__SMB_CO_SEG,
+ data_ptr, data_len);
+ if (rpkt == nullptr)
+ {
+ DebugMessage(DEBUG_DCE_COMMON, "Failed to create reassembly packet.\n");
+ return nullptr;
+ }
+ DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, (uint8_t*)rpkt->data,
+ (uint16_t)(rpkt->dsize - smb_hdr_len));
break;
case DCE2_TRANS_TYPE__TCP:
const uint8_t* frag_ptr = nullptr;
uint16_t frag_len = 0;
dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
- // FIXIT-M add smb_hdr_len when SMB is ported
+ int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+ DCE2_MOCK_HDR_LEN__SMB_SRV;
if (DCE2_SsnFromClient(sd->wire_pkt))
dce_common_stats->co_cli_seg_reassembled++;
switch (sd->trans)
{
case DCE2_TRANS_TYPE__SMB:
- // FIXIT-M add when SMB is ported
+ frag_ptr = rpkt->data + smb_hdr_len;
+ frag_len = rpkt->dsize - smb_hdr_len;
break;
case DCE2_TRANS_TYPE__TCP:
return;
}
- // FIXIT-L PORT_IF_NEEDED
- //Push packet on stack and call detect
+ if (DCE2_PushPkt(rpkt,sd) != DCE2_RET__SUCCESS)
+ {
+ DebugMessage(DEBUG_DCE_COMMON, "Failed to push packet onto packet stack.\n");
+ return;
+ }
/* All is good. Decode the pdu */
DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
DebugMessage(DEBUG_DCE_COMMON, "Reassembled CO segmented packet\n");
DCE2_PrintPktData(rpkt->data, rpkt->dsize);
+
+ /* Call detect since this is a reassembled packet that the
+ * detection engine hasn't seen yet */
+ if (!co_reassembled)
+ DCE2_Detect(sd);
+
+ DCE2_PopPkt(sd);
}
static DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer* seg_buf, const uint8_t* data_ptr,
{
DCE2_CoSeg* seg = DCE2_CoGetSegPtr(sd, cot);
dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+ uint32_t num_frags = 0;
dce_common_stats->co_pdus++;
-
co_reassembled = 0;
- // FIXIT-L PORT_IF_NEEDED
- //Loop to walk through multiple fragments in a packet
-
- /* Fast track full fragments */
- if (DCE2_BufferIsEmpty(seg->buf))
+ while (data_len > 0)
{
- const uint8_t* frag_ptr = data_ptr;
- uint16_t frag_len;
+ num_frags++;
- // FIXIT-L PORT_IF_NEEDED
- //Not enough data left for a headerr
+ DebugFormat(DEBUG_DCE_COMMON, "DCE/RPC message number: %u\n", num_frags);
- if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS)
- return;
+ /* Fast track full fragments */
+ if (DCE2_BufferIsEmpty(seg->buf))
+ {
+ const uint8_t* frag_ptr = data_ptr;
+ uint16_t frag_len;
- frag_len = DceRpcCoFragLen((DceRpcCoHdr*)data_ptr);
+ // FIXIT-L PORT_IF_NEEDED
+ //Not enough data left for a headerr
- /* Not enough data left for the pdu. */
- if (data_len < frag_len)
- {
- DebugFormat(DEBUG_DCE_COMMON,
- "Not enough data in packet for fragment length: %hu\n", frag_len);
+ if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS)
+ return;
- /* Set frag length so we don't have to check it again in seg code */
- seg->frag_len = frag_len;
+ frag_len = DceRpcCoFragLen((DceRpcCoHdr*)data_ptr);
- DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len);
- goto dce2_coprocess_exit;
- }
+ /* Not enough data left for the pdu. */
+ if (data_len < frag_len)
+ {
+ DebugFormat(DEBUG_DCE_COMMON,
+ "Not enough data in packet for fragment length: %hu\n", frag_len);
- /* Got a full DCE/RPC pdu */
- DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
+ /* Set frag length so we don't have to check it again in seg code */
+ seg->frag_len = frag_len;
- // FIXIT-L PORT_IF_NEEDED
- //Detect first frag and reset frag count, DCE_MOVE
- }
- else /* We've already buffered data */
- {
- DebugFormat(DEBUG_DCE_COMMON, "Segmentation buffer has %u bytes\n",
- DCE2_BufferLength(seg->buf));
+ DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len);
+ goto dce2_coprocess_exit;
+ }
- // FIXIT-L PORT_IF_NEEDED
- //Need more data to get header
+ DCE2_MOVE(data_ptr, data_len, frag_len);
- /* Need more data for full pdu */
- if (DCE2_BufferLength(seg->buf) < seg->frag_len)
- {
- DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len,
- seg->frag_len);
+ /* Got a full DCE/RPC pdu */
+ DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
- /* Still not enough */
- if (status != DCE2_RET__SUCCESS)
- goto dce2_coprocess_exit;
+ /* If we're configured to do defragmentation only detect on first frag
+ * since we'll detect on reassembled */
+ if (!DCE2_GcDceDefrag((dce2CommonProtoConf*)sd->config) || ((num_frags == 1) &&
+ !co_reassembled))
+ DCE2_Detect(sd);
+
+ /* Reset if this is a last frag */
+ if (DceRpcCoLastFrag((DceRpcCoHdr*)frag_ptr))
+ num_frags = 0;
}
+ else /* We've already buffered data */
+ {
+ DebugFormat(DEBUG_DCE_COMMON, "Segmentation buffer has %u bytes\n",
+ DCE2_BufferLength(seg->buf));
- // FIXIT-L PORT_IF_NEEDED
- //Reset frag count, DCE_MOVE, data_used
+ // FIXIT-L PORT_IF_NEEDED
+ //Need more data to get header
- /* Got the full DCE/RPC pdu. Need to create new packet before decoding */
- DCE2_CoSegDecode(sd, cot, seg);
+ /* Need more data for full pdu */
+ if (DCE2_BufferLength(seg->buf) < seg->frag_len)
+ {
+ DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len,
+ seg->frag_len);
+
+ /* Still not enough */
+ if (status != DCE2_RET__SUCCESS)
+ goto dce2_coprocess_exit;
+ }
+
+ // FIXIT-L PORT_IF_NEEDED
+ // DCE_MOVE, data_used
+
+ /* Do this before calling DCE2_CoSegDecode since it will empty
+ * seg buffer */
+ if (DceRpcCoLastFrag((DceRpcCoHdr*)seg->buf->data))
+ num_frags = 0;
+
+ /* Got the full DCE/RPC pdu. Need to create new packet before decoding */
+ DCE2_CoSegDecode(sd, cot, seg);
+ }
}
dce2_coprocess_exit:
#include "dce_tcp.h"
#include "dce_smb.h"
#include "dce_co.h"
+#include "dce_smb_utils.h"
#include "framework/base_api.h"
#include "framework/module.h"
#include "flow/flow.h"
{
case DCE2_RPKT_TYPE__SMB_SEG:
case DCE2_RPKT_TYPE__SMB_TRANS:
+ break;
+
case DCE2_RPKT_TYPE__SMB_CO_SEG:
+ if (DCE2_SsnFromClient(p))
+ overhead += DCE2_MOCK_HDR_LEN__SMB_CLI;
+ else
+ overhead += DCE2_MOCK_HDR_LEN__SMB_SRV;
+ break;
+
case DCE2_RPKT_TYPE__SMB_CO_FRAG:
- // FIXIT-M add support for these when SMB is ported
+ if (DCE2_SsnFromClient(p))
+ overhead += DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
+ else
+ overhead += DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
break;
case DCE2_RPKT_TYPE__TCP_CO_SEG:
return (DCE2_REASSEMBLY_BUF_SIZE - overhead);
}
+static void dce2_fill_rpkt_info(Packet* rpkt, Packet* p)
+{
+ DceEndianness* endianness = (DceEndianness*)rpkt->endianness;
+ rpkt->reset();
+ rpkt->endianness = (Endianness*)endianness;
+ ((DceEndianness*)rpkt->endianness)->reset();
+ rpkt->pkth = p->pkth;
+ rpkt->ptrs = p->ptrs;
+ rpkt->flow = p->flow;
+ rpkt->proto_bits = p->proto_bits;
+ rpkt->packet_flags = p->packet_flags;
+ rpkt->packet_flags |= PKT_PSEUDO;
+ rpkt->user_policy_id = p->user_policy_id;
+}
+
Packet* DCE2_GetRpkt(Packet* p,DCE2_RpktType rpkt_type,
const uint8_t* data, uint32_t data_len)
{
Packet* rpkt = nullptr;
uint16_t data_overhead = 0;
- DceEndianness* endianness;
switch (rpkt_type)
{
case DCE2_RPKT_TYPE__SMB_SEG:
+ rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+ dce2_fill_rpkt_info(rpkt, p);
+ rpkt->pseudo_type = PSEUDO_PKT_SMB_SEG;
+ break;
+
case DCE2_RPKT_TYPE__SMB_TRANS:
+ rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+ dce2_fill_rpkt_info(rpkt, p);
+ rpkt->pseudo_type = PSEUDO_PKT_SMB_TRANS;
+ if (DCE2_SsnFromClient(p))
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+ }
+ else
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+ }
+ break;
+
case DCE2_RPKT_TYPE__SMB_CO_SEG:
+ rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+ dce2_fill_rpkt_info(rpkt, p);
+ rpkt->pseudo_type = PSEUDO_PKT_DCE_SEG;
+ if (DCE2_SsnFromClient(p))
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+ }
+ else
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+ }
+ break;
+
case DCE2_RPKT_TYPE__SMB_CO_FRAG:
+ rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+ dce2_fill_rpkt_info(rpkt, p);
+ rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
+ if (DCE2_SsnFromClient(p))
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+ DCE2_CoInitRdata((uint8_t*)rpkt->data +
+ DCE2_MOCK_HDR_LEN__SMB_CLI, PKT_FROM_CLIENT);
+ }
+ else
+ {
+ data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
+ memset((void*)rpkt->data, 0, data_overhead);
+ DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+ DCE2_CoInitRdata((uint8_t*)rpkt->data +
+ DCE2_MOCK_HDR_LEN__SMB_SRV, PKT_FROM_SERVER);
+ }
+ break;
+
case DCE2_RPKT_TYPE__UDP_CL_FRAG:
- // FIXIT-M add support when SMB, UDP are ported
+ // FIXIT-M add support when UDP is ported
return nullptr;
case DCE2_RPKT_TYPE__TCP_CO_SEG:
case DCE2_RPKT_TYPE__TCP_CO_FRAG:
rpkt = dce2_tcp_rpkt[rpkt_type - DCE2_TCP_RPKT_TYPE_START];
- endianness = (DceEndianness*)rpkt->endianness;
- rpkt->reset();
- rpkt->endianness = (Endianness*)endianness;
- ((DceEndianness*)rpkt->endianness)->reset();
- rpkt->pkth = p->pkth;
- rpkt->ptrs = p->ptrs;
- rpkt->flow = p->flow;
- rpkt->proto_bits = p->proto_bits;
- rpkt->packet_flags = p->packet_flags;
- rpkt->packet_flags |= PKT_PSEUDO;
- rpkt->user_policy_id = p->user_policy_id;
+ dce2_fill_rpkt_info(rpkt, p);
if (rpkt_type == DCE2_RPKT_TYPE__TCP_CO_FRAG)
{
rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
{
Packet* p = (Packet*)snort_calloc(sizeof(Packet));
p->data = (uint8_t*)snort_calloc(DCE2_REASSEMBLY_BUF_SIZE);
+ p->endianness = (Endianness*)new DceEndianness();
p->dsize = DCE2_REASSEMBLY_BUF_SIZE;
dce2_smb_rpkt[i] = p;
}
{
snort_free((void*)p->data);
}
+ delete p->endianness;
snort_free(p);
dce2_smb_rpkt[i] = nullptr;
}
#define DCE2_SMB_NAME "dce_smb"
#define DCE2_SMB_HELP "dce over smb inspection"
#define DCE2_SMB_RPKT_TYPE_MAX 4
+#define DCE2_SMB_RPKT_TYPE_START 1
#define DCE2_SMB_BAD_NBSS_TYPE 2
#define DCE2_SMB_BAD_TYPE 3
#include "utils/util.h"
#include "detection/detect.h"
-
#define SERVICE_0 (0) // IPC start
#define SERVICE_1 (SERVICE_0+4) // DISK start
#define SERVICE_FS (SERVICE_1+3) // Failure
if (ftracker->fp_writex_raw->remaining == 0)
{
- //FIXIT-M - port Create reassembled packet
-/*
- const uint8_t *data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
- uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
- SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd,
- &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
+ const uint8_t* data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
+ uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
+ Packet* rpkt = DCE2_SmbGetRpkt(ssd,
+ &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
- if (rpkt == nullptr)
- {
- DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
- return DCE2_RET__ERROR;
- }
+ if (rpkt == nullptr)
+ {
+ DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+ return DCE2_RET__ERROR;
+ }
- DebugMessage(DEBUG_DCE_SMB,
- "Reassembled WriteAndX raw mode request\n"));
- DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
+ DebugMessage(DEBUG_DCE_SMB,
+ "Reassembled WriteAndX raw mode request\n");
+ DCE2_PrintPktData(rpkt->data, rpkt->dsize);
- (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
+ (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
- DCE2_SmbReturnRpkt();
- DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
-*/
+ DCE2_SmbReturnRpkt(ssd);
+ DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
}
}
else
{
DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
- if ((dcnt != 0)
- && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
- != DCE2_RET__SUCCESS))
+ if ((ttracker->dsent < ttracker->tdcnt)
+ || (ttracker->psent < ttracker->tpcnt)
+ || !DCE2_BufferIsEmpty(ttracker->dbuf))
{
- return DCE2_RET__ERROR;
- }
+ if ((dcnt != 0)
+ && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
+ != DCE2_RET__SUCCESS))
+ {
+ return DCE2_RET__ERROR;
+ }
+ }
}
if (data_params & DCE2_SMB_TRANS__PARAMS)
{
DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + poff) - nb_ptr);
-
- if ((pcnt != 0)
- && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
- != DCE2_RET__SUCCESS))
+
+ if ((ttracker->dsent < ttracker->tdcnt)
+ || (ttracker->psent < ttracker->tpcnt)
+ || !DCE2_BufferIsEmpty(ttracker->dbuf))
{
- return DCE2_RET__ERROR;
- }
+ if ((pcnt != 0)
+ && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
+ != DCE2_RET__SUCCESS))
+ {
+ return DCE2_RET__ERROR;
+ }
+ }
}
if ((ttracker->dsent == ttracker->tdcnt)
switch (ttracker->subcom)
{
case TRANS_TRANSACT_NMPIPE:
- case TRANS_READ_NMPIPE:
- {
- // FIXIT-M port reassembly case
+ case TRANS_READ_NMPIPE:
+ if (!DCE2_BufferIsEmpty(ttracker->dbuf))
+ {
+ const uint8_t* data_ptr = DCE2_BufferData(ttracker->dbuf);
+ uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
+ Packet* rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr,
+ &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
- uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
- uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+ if (rpkt == nullptr)
+ return DCE2_RET__ERROR;
- DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+ DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction response\n");
+ DCE2_PrintPktData(rpkt->data, rpkt->dsize);
- if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
- return DCE2_RET__ERROR;
+ status = DCE2_SmbProcessResponseData(ssd, data_ptr, data_len);
+
+ DCE2_SmbReturnRpkt(ssd);
+
+ if (status != DCE2_RET__SUCCESS)
+ return status;
+ }
+ else
+ {
+ uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
+ uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+
+ DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+ if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
+ return DCE2_RET__ERROR;
+ }
break;
- }
+
case TRANS_SET_NMPIPE_STATE:
DebugFormat(DEBUG_DCE_SMB, "Setting pipe "
"to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message");
case TRANS_TRANSACT_NMPIPE:
case TRANS_WRITE_NMPIPE:
{
-// FIXIT-M uncomment after porting packet reassembly code
-/*
- const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf);
- uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
- rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
+ const uint8_t* data_ptr = DCE2_BufferData(ttracker->dbuf);
+ uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
+ Packet* rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
- if (rpkt == nullptr)
- return DCE2_RET__ERROR;
+ if (rpkt == nullptr)
+ return DCE2_RET__ERROR;
- DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction request\n"));
- DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
+ DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction request\n");
+ DCE2_PrintPktData(rpkt->data, rpkt->dsize);
- status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len,
- DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
+ status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len,
+ DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
- DCE2_SmbReturnRpkt();
-*/
+ DCE2_SmbReturnRpkt(ssd);
}
break;
return DCE2_RET__SUCCESS;
}
+
{
DCE2_SmbFileTracker* ftracker = DCE2_SmbGetFileTracker(ssd, fid);
- DebugFormat(DEBUG_DCE_SMB,
- "Entering Processing request data with Fid: 0x%04X, ftracker ? %s ~~~~~~~~~~~~~~~~~\n",
- fid,ftracker ? "TRUE" : "FALSE");
if (ftracker == nullptr)
return DCE2_RET__ERROR;
DebugFormat(DEBUG_DCE_SMB,
- "Processing request data with Fid: 0x%04X, is_ipc ? %s ~~~~~~~~~~~~~~~~~\n", ftracker->fid,
- ftracker->is_ipc ? "TRUE" : "FALSE");
+ "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid);
// Set this in case of chained commands or reassembled packet
ssd->cur_rtracker->ftracker = ftracker;
return DCE2_RET__SUCCESS;
}
+static inline uint16_t SmbHtons(const uint16_t* ptr)
+{
+ return alignedNtohs(ptr);
+}
+
+/********************************************************************
+ * Function: DCE2_SmbInitRdata()
+ *
+ * Purpose:
+ * Initializes the reassembled packet structure for an SMB
+ * reassembled packet. Uses WriteAndX and ReadAndX.
+ * TODO Use command that was used when reassembly occurred.
+ * One issue with this is that multiple different write/read
+ * commands can be used to write/read the full DCE/RPC
+ * request/response.
+ *
+ * Arguments:
+ * uint8_t * - pointer to the start of the NetBIOS header where
+ * data initialization should start.
+ * int dir - FLAG_FROM_CLIENT or FLAG_FROM_SERVER
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbInitRdata(uint8_t* nb_ptr, int dir)
+{
+ NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+ SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+
+ nb_hdr->type = NBSS_SESSION_TYPE__MESSAGE;
+ memcpy((void*)smb_hdr->smb_idf, (void*)"\xffSMB", sizeof(smb_hdr->smb_idf));
+
+ if (dir == PKT_FROM_CLIENT)
+ {
+ SmbWriteAndXReq* writex =
+ (SmbWriteAndXReq*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq);
+
+ smb_hdr->smb_com = SMB_COM_WRITE_ANDX;
+ smb_hdr->smb_flg = 0x00;
+
+ writex->smb_wct = 12;
+ writex->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
+ writex->smb_doff = SmbHtons(&offset);
+ }
+ else
+ {
+ SmbReadAndXResp* readx =
+ (SmbReadAndXResp*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp);
+
+ smb_hdr->smb_com = SMB_COM_READ_ANDX;
+ smb_hdr->smb_flg = 0x80;
+
+ readx->smb_wct = 12;
+ readx->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
+ readx->smb_doff = SmbHtons(&offset);
+ }
+}
+
+/********************************************************************
+ * Function: DCE2_SmbSetRdata()
+ *
+ * Purpose:
+ * When a reassembled packet is needed this function is called to
+ * fill in appropriate fields to make the reassembled packet look
+ * correct from an SMB standpoint.
+ *
+ * Arguments:
+ * DCE2_SmbSsnData * - the session data structure.
+ * uint8_t * - pointer to the start of the NetBIOS header where
+ * data initialization should start.
+ * uint16_t - the length of the connection-oriented DCE/RPC data.
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbSetRdata(DCE2_SmbSsnData* ssd, uint8_t* nb_ptr, uint16_t co_len)
+{
+ NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+ SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+ uint16_t uid = (ssd->cur_rtracker == nullptr) ? 0 : ssd->cur_rtracker->uid;
+ uint16_t tid = (ssd->cur_rtracker == nullptr) ? 0 : ssd->cur_rtracker->tid;
+ DCE2_SmbFileTracker* ftracker = (ssd->cur_rtracker == nullptr) ? nullptr :
+ ssd->cur_rtracker->ftracker;
+
+ smb_hdr->smb_uid = SmbHtons((const uint16_t*)&uid);
+ smb_hdr->smb_tid = SmbHtons((const uint16_t*)&tid);
+
+ if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
+ {
+ SmbWriteAndXReq* writex =
+ (SmbWriteAndXReq*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq) + co_len;
+
+ /* The data will get truncated anyway since we can only fit
+ * 64K in the reassembly buffer */
+ if (nb_len > UINT16_MAX)
+ nb_len = UINT16_MAX;
+
+ nb_hdr->length = htons((uint16_t)nb_len);
+
+ if ((ftracker != nullptr) && (ftracker->fid > 0))
+ {
+ uint16_t fid = (uint16_t)ftracker->fid;
+ writex->smb_fid = SmbHtons(&fid);
+ }
+ else
+ {
+ writex->smb_fid = 0;
+ }
+
+ writex->smb_countleft = SmbHtons(&co_len);
+ writex->smb_dsize = SmbHtons(&co_len);
+ writex->smb_bcc = SmbHtons(&co_len);
+ }
+ else
+ {
+ SmbReadAndXResp* readx =
+ (SmbReadAndXResp*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp) + co_len;
+
+ /* The data will get truncated anyway since we can only fit
+ * 64K in the reassembly buffer */
+ if (nb_len > UINT16_MAX)
+ nb_len = UINT16_MAX;
+
+ nb_hdr->length = htons((uint16_t)nb_len);
+
+ readx->smb_remaining = SmbHtons(&co_len);
+ readx->smb_dsize = SmbHtons(&co_len);
+ readx->smb_bcc = SmbHtons(&co_len);
+ }
+}
+
+Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData* ssd,
+ const uint8_t** data, uint32_t* data_len, DCE2_RpktType rtype)
+{
+ if ((ssd == nullptr) || (data == nullptr) || (*data == nullptr)
+ || (data_len == nullptr) || (*data_len == 0))
+ return nullptr;
+
+ Packet* rpkt = DCE2_GetRpkt(ssd->sd.wire_pkt, rtype, *data, *data_len);
+
+ if (rpkt == nullptr)
+ {
+ DebugFormat(DEBUG_DCE_SMB,
+ "%s(%d) Failed to create reassembly packet.",
+ __FILE__, __LINE__);
+
+ return nullptr;
+ }
+
+ if (DCE2_PushPkt(rpkt, &ssd->sd) != DCE2_RET__SUCCESS)
+ {
+ DebugFormat(DEBUG_DCE_SMB,
+ "%s(%d) Failed to push packet onto packet stack.",
+ __FILE__, __LINE__);
+ return nullptr;
+ }
+
+ *data = rpkt->data;
+ *data_len = rpkt->dsize;
+
+ uint16_t header_len;
+ switch (rtype)
+ {
+ case DCE2_RPKT_TYPE__SMB_TRANS:
+ if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
+ header_len = DCE2_MOCK_HDR_LEN__SMB_CLI;
+ else
+ header_len = DCE2_MOCK_HDR_LEN__SMB_SRV;
+ DCE2_SmbSetRdata(ssd, (uint8_t*)rpkt->data,
+ (uint16_t)(rpkt->dsize - header_len));
+ DCE2_MOVE(*data, *data_len, header_len);
+ break;
+ case DCE2_RPKT_TYPE__SMB_SEG:
+ default:
+ break;
+ }
+
+ return rpkt;
+}
+
const uint8_t*, uint32_t, uint64_t);
DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData*,
const uint8_t*, uint32_t);
+void DCE2_SmbInitRdata(uint8_t*, int);
+void DCE2_SmbSetRdata(DCE2_SmbSsnData*, uint8_t*, uint16_t);
+Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData*, const uint8_t **,
+ uint32_t*, DCE2_RpktType);
/********************************************************************
* Inline functions
return false;
}
+inline void DCE2_SmbReturnRpkt(DCE2_SmbSsnData* ssd)
+{
+ DCE2_PopPkt(&ssd->sd);
+}
+
#endif