int SMB_Fragmentation(u_int8_t *smb_hdr, SMB_WRITEX_REQ *writeX, u_int8_t *smb_data, u_int16_t data_size) { u_char fragmented = 0; u_int16_t writeX_length; u_char success = 0; /* Check for fragmentation */ if ( _disable_smb_fragmentation ) return 0; /* If not yet reassembling, attempt to parse as full DCE/RPC packet */ if ( !(_dcerpc->fragmentation & SMB_FRAGMENTATION) ) { success = ProcessDCERPCMessage(smb_hdr, smb_data, data_size); if ( success ) return 0; } /* Set up writeX buffer to save SMB data. Ignore dataLengthHigh, since we won't handle fragments that big. */ writeX_length = writeX->dataLength; /* Allocate space for buffer For now, ignore offset, since servers seem to */ if ( !(_dcerpc->fragmentation & SUSPEND_FRAGMENTATION) ) { if ( _dcerpc->write_andx_buf == NULL ) { if ( writeX_length > _max_frag_size ) writeX_length = _max_frag_size; _dcerpc->write_andx_buf = (u_int8_t *) DCERPC_FragAlloc(NULL, 0, &writeX_length); if ( !_dcerpc->write_andx_buf ) _dpd.fatalMsg("Failed to allocate space for SMB Write AndX\n"); if ( writeX_length == 0 ) { DEBUG_WRAP(_dpd.debugMsg(DEBUG_DCERPC, "Memcap reached, ignoring SMB fragmentation reassembly.\n");); DCERPC_FragFree(_dcerpc->write_andx_buf, 0); _dcerpc->write_andx_buf = NULL; _dcerpc->fragmentation |= SUSPEND_FRAGMENTATION; return 0; } _dcerpc->write_andx_buf_size = writeX_length; _dcerpc->write_andx_buf_len = 0; }
static void ReassembleSMBWriteX(SMB_WRITEX_REQ *writeX, u_int8_t *smb_data) { SMB_WRITEX_REQ temp_writeX; unsigned int smb_hdr_len = (u_int8_t *)writeX - _dcerpc_pkt->payload; unsigned int writeX_len = smb_data - (u_int8_t *)writeX; /* Make sure we have room to fit into alternate buffer */ if ( (smb_hdr_len + writeX_len + _dcerpc->write_andx_buf_len) > _dpd.altBufferLen ) { _dpd.logMsg("Reassembled SMB packet greater than %d bytes, skipping.", _dpd.altBufferLen); return; } /* Mock up header */ memcpy(&temp_writeX, writeX, writeX_len); temp_writeX.remaining = _dcerpc->write_andx_buf_len; temp_writeX.dataLength = _dcerpc->write_andx_buf_len; /* Copy headers into buffer */ /* SMB Header */ memcpy(_dpd.altBuffer, _dcerpc_pkt->payload, smb_hdr_len); _dcerpc_pkt->normalized_payload_size = smb_hdr_len; /* Write AndX header */ memcpy(_dpd.altBuffer + _dcerpc_pkt->normalized_payload_size, &temp_writeX, writeX_len); _dcerpc_pkt->normalized_payload_size += writeX_len; /* Copy data into buffer */ memcpy(_dpd.altBuffer + _dcerpc_pkt->normalized_payload_size, _dcerpc->write_andx_buf, _dcerpc->write_andx_buf_len); _dcerpc_pkt->normalized_payload_size += _dcerpc->write_andx_buf_len; _dcerpc_pkt->flags |= FLAG_ALT_DECODE; ProcessDCERPCMessage(_dcerpc_pkt->payload, _dcerpc->write_andx_buf, _dcerpc->write_andx_buf_len); /* Get ready for next write */ DCERPC_FragFree(_dcerpc->write_andx_buf, _dcerpc->write_andx_buf_size); _dcerpc->write_andx_buf = NULL; _dcerpc->write_andx_buf_len = 0; _dcerpc->write_andx_buf_size = 0; _dcerpc->fragmentation &= ~SMB_FRAGMENTATION; _dcerpc->fragmentation &= ~SUSPEND_FRAGMENTATION; }
void *DCERPC_FragAlloc(void *p, u_int16_t old_size, u_int16_t *new_size) { u_int16_t add_size; void *new_buf = NULL; if (old_size >= *new_size) { *new_size = old_size; return p; } add_size = *new_size - old_size; if ( (((u_int32_t) add_size) + _total_memory) > _memcap ) { /* Raise alert */ if ( _alert_memcap ) { DCERPC_GenerateAlert(DCERPC_EVENT_MEMORY_OVERFLOW, DCERPC_EVENT_MEMORY_OVERFLOW_STR); } add_size = (u_int16_t) (_memcap - _total_memory); } *new_size = old_size + add_size; if (*new_size == old_size) return p; new_buf = calloc(*new_size, 1); if (new_buf == NULL) { if (p != NULL) { DCERPC_FragFree(p, old_size); } return NULL; } if (p != NULL) { int ret; ret = SafeMemcpy(new_buf, p, old_size, new_buf, (u_int8_t *)new_buf + *new_size); if (ret == 0) { *new_size = old_size; free(new_buf); return p; } DCERPC_FragFree(p, old_size); } /* DCERPC_FragFree will decrement old_size from _total_memory so * we add the *new_size */ _total_memory += *new_size; return new_buf; }