PacketTracer::log("File: Type-%s found\n",
file_type_name(get_file_type()).c_str());
config_file_type(false);
+
+ if (PacketTracer::is_active() and (!(is_file_signature_enabled())))
+ PacketTracer::log("File: signature config is disabled\n");
+
file_stats->files_processed[get_file_type()][get_file_direction()]++;
//Check file type based on file policy
FileVerdict v = policy->type_lookup(p, this);
}
// Update the segment list based on new data
-void FileSegments::add(const uint8_t* file_data, uint64_t data_size, uint64_t offset)
+void FileSegments::add(const uint8_t* file_data, int64_t data_size, uint64_t offset)
{
- FileSegment* new_segment = new FileSegment();
- new_segment->offset = offset;
- new_segment->data = new std::string((const char*)file_data, data_size);
-
if (!head)
{
+ FileSegment* new_segment = new FileSegment();
+ new_segment->offset = offset;
+ new_segment->data = new std::string((const char*)file_data, data_size);
head = new_segment;
return;
}
FileSegment* left = nullptr;
FileSegment* previous = nullptr;
bool find_left = false;
- bool is_overlap = false;
// Find left boundary, left points to segment that needs update
while (current_segment)
// New segment should be at the end of link list
if (!find_left)
{
- previous->next = new_segment;
+ left = previous;
+ if (left->offset +left->data->size() >start)
+ {
+ offset = left->offset + left->data->size();
+ data_size = end -offset;
+ file_data = file_data + offset - start;
+ }
}
// New segment should be at the start of link list
else if (!left)
{
- if (end <= head->offset)
+ if (end > head->offset)
{
- new_segment->next = head;
- head = new_segment;
- }
- else
- {
- is_overlap = true;
+ /* Overlap, trim off extra data from end */
+ data_size = head->offset - offset;
}
}
else
{
- if ((left->offset + left->data->size() > start) ||
- (left->next->offset < end))
+ //Left Overlap
+ if ( (left->offset + left->data->size() > start) )
{
- is_overlap = true;
+ offset = left->offset + left->data->size();
+ data_size = end - offset;
+ file_data = file_data + offset - start;
}
- else
+ //Right Overlap
+ if ( (left->next->offset < end) )
{
- new_segment->next = left->next;
- left->next = new_segment;
+ data_size = left->next->offset - offset;
}
+
}
// ignore overlap case
- if (is_overlap)
+ if (data_size <= 0)
{
- delete new_segment;
return;
}
+
+ FileSegment* new_segment = new FileSegment();
+ new_segment->offset = offset;
+ new_segment->data = new std::string((const char*)file_data, data_size);
+
+ if (!find_left)
+ {
+ previous->next = new_segment;
+
+ }
+ else if (!left)
+ {
+ new_segment->next = head;
+ head = new_segment;
+ }
+ else
+ {
+ new_segment->next = left->next;
+ left->next = new_segment;
+ }
}
FilePosition FileSegments::get_file_position(uint64_t data_size, uint64_t file_size)
uint64_t current_offset;
snort::FileContext* context = nullptr;
- void add(const uint8_t* file_data, uint64_t data_size, uint64_t offset);
+ void add(const uint8_t* file_data, int64_t data_size, uint64_t offset);
FilePosition get_file_position(uint64_t data_size, uint64_t file_size);
int process_one(snort::Packet*, const uint8_t* file_data, int data_size, snort::FilePolicyBase*,
FilePosition position=SNORT_FILE_POSITION_UNKNOWN);
const Smb2NegotiateResponseHdr* neg_resp_hdr = (const Smb2NegotiateResponseHdr*)smb_data;
if (neg_resp_hdr->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)
{
- Packet *p = DetectionEngine::get_current_packet();
+ Packet* p = DetectionEngine::get_current_packet();
Dce2SmbFlowData* fd =
create_expected_smb_flow_data(p, (dce2SmbProtoConf *)sd.config);
if (fd)
session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end, flow_key);
}
else
+ {
SMB2_HANDLE_INVALID_STRUC_SIZE(ioctl)
+ }
}
break;
default:
else
{
tcp_file_tracker_mutex.lock();
- if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data())
+ if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data_from(flow_key))
{
debug_logf(dce_smb_trace, p, "processing raw data for file id %" PRIu64 "\n",
tcp_file_tracker->get_file_id());
tcp_file_tracker->process_data(flow_key, data_ptr, data_len);
+ tcp_file_tracker->stop_accepting_raw_data_from(flow_key);
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, p, "not processing raw data\n");
}
tcp_file_tracker_mutex.unlock();
}
#define UNKNOWN_FILE_SIZE (~0)
-void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow)
+void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset)
{
if (flow)
{
- smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+ uint32_t current_flow_key = flow->get_flow_key();
+ std::lock_guard<std::mutex> guard(flow_state_mutex);
+ tcp_flow_state& current_flow_state = flow_state[current_flow_key];
+ if ( (current_flow_state.pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA) and
+ (current_flow_state.file_offset == current_flow_state.max_offset))
+ {
+ current_flow_state.file_offset = offset;
+ }
+
+ current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
flow->set_tcp_file_tracker(this);
}
}
+void Dce2Smb2FileTracker::stop_accepting_raw_data_from(uint32_t current_flow_key)
+{
+ std::lock_guard<std::mutex> guard(flow_state_mutex);
+ tcp_flow_state& current_flow_state = flow_state[current_flow_key];
+ if(current_flow_state.file_offset == current_flow_state.max_offset)
+ current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+}
inline void Dce2Smb2FileTracker::file_detect()
{
bool Dce2Smb2FileTracker::close(const uint32_t current_flow_key)
{
- uint64_t file_offset = file_offsets[current_flow_key];
+ flow_state_mutex.lock();
+ uint64_t file_offset = flow_state[current_flow_key].file_offset;
+ flow_state_mutex.unlock();
if (!ignore and !file_size and file_offset)
{
file_size = file_offset;
}
bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const uint8_t* file_data,
- uint32_t data_size, const uint64_t offset)
+ uint32_t data_size, const uint64_t offset, uint64_t max_offset)
{
- file_offsets[current_flow_key] = offset;
+ flow_state_mutex.lock();
+ tcp_flow_state& current_flow_state = flow_state[current_flow_key];
+ current_flow_state.file_offset = offset;
+ current_flow_state.max_offset = offset + max_offset;
+ flow_state_mutex.unlock();
return process_data(current_flow_key, file_data, data_size);
}
int64_t file_detection_depth = current_flow->get_smb_file_depth();
int64_t detection_size = 0;
- uint64_t file_offset = file_offsets[current_flow_key];
+ Packet* p = DetectionEngine::get_current_packet();
+ flow_state_mutex.lock();
+ uint64_t file_offset = flow_state[current_flow_key].file_offset;
+ flow_state_mutex.unlock();
if (file_detection_depth == 0)
detection_size = data_size;
if (ignore)
return true;
- Packet* p = DetectionEngine::get_current_packet();
-
if (file_size and file_offset > file_size)
{
debug_logf(dce_smb_trace, p, "file_process: bad offset\n");
}
file_offset += data_size;
- file_offsets[current_flow_key] = file_offset;
+ flow_state_mutex.lock();
+ flow_state[current_flow_key].file_offset = file_offset;
+ flow_state_mutex.unlock();
return true;
}
class Dce2Smb2TreeTracker;
+typedef struct _tcp_flow_state
+{
+ Dce2SmbPduState pdu_state;
+ uint64_t file_offset;
+ uint64_t max_offset;
+} tcp_flow_state;
+
class Dce2Smb2FileTracker
{
public:
Dce2Smb2FileTracker(uint64_t file_idv, const uint32_t flow_key, Dce2Smb2TreeTracker* p_tree) :
ignore(true), file_name_len(0), file_flow_key(flow_key),
file_id(file_idv), file_size(0), file_name_hash(0), file_name(nullptr),
- direction(FILE_DOWNLOAD), smb2_pdu_state(DCE2_SMB_PDU_STATE__COMMAND), parent_tree(p_tree)
+ direction(FILE_DOWNLOAD), parent_tree(p_tree)
{
debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
"file tracker %" PRIu64 " created\n", file_id);
}
~Dce2Smb2FileTracker();
- bool process_data(const uint32_t, const uint8_t*, uint32_t, const uint64_t);
+ bool process_data(const uint32_t, const uint8_t*, uint32_t, const uint64_t, uint64_t);
bool process_data(const uint32_t, const uint8_t*, uint32_t);
bool close(const uint32_t);
void set_info(char*, uint16_t, uint64_t);
- void accept_raw_data_from(Dce2Smb2SessionData*);
- bool accepting_raw_data()
- { return (smb2_pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); }
+ void accept_raw_data_from(Dce2Smb2SessionData*, uint64_t = 0);
+ bool accepting_raw_data_from(uint32_t current_flow_key)
+ {
+ std::lock_guard<std::mutex> guard(flow_state_mutex);
+ return (flow_state[current_flow_key].pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA);
+ }
+ void stop_accepting_raw_data_from(uint32_t);
void set_direction(FileDirection dir) { direction = dir; }
Dce2Smb2TreeTracker* get_parent() { return parent_tree; }
uint64_t file_name_hash;
char* file_name;
FileDirection direction;
- std::atomic<Dce2SmbPduState> smb2_pdu_state;
Dce2Smb2TreeTracker* parent_tree;
- std::unordered_map<uint32_t, uint64_t,std::hash<uint32_t> > file_offsets;
+ std::unordered_map<uint32_t, tcp_flow_state, std::hash<uint32_t> > flow_state;
std::mutex process_file_mutex;
+ std::mutex flow_state_mutex;
};
using Dce2Smb2FileTrackerMap =
{
const uint8_t* file_data = (const uint8_t*)read_resp_hdr +
SMB2_READ_RESPONSE_STRUC_SIZE - 1;
- int data_size = end - file_data;
- if (file_tracker->process_data(current_flow_key, file_data, data_size, read_request->get_offset()))
+ // we may not have enough data in some case, use best effort to process file for whatever
+ // data we have till now.
+ int data_size = (read_resp_hdr->length > (end - file_data)) ?
+ (end - file_data) : read_resp_hdr->length;
+ if (file_tracker->process_data(current_flow_key, file_data, data_size,
+ read_request->get_offset(), read_resp_hdr->length))
{
if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(read_resp_hdr->length)))
{
debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: store failed\n");
delete read_request;
}
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key);
+ if (file_tracker)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "SMB2_COM_READ_REQ: start accepting Raw Data\n");
+ file_tracker->accept_raw_data_from(current_flow,offset);
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "SMB2_COM_READ_REQ: file tracker missing\n");
+ }
}
void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id,
if (file_tracker)
{
file_tracker->set_direction(FILE_UPLOAD);
- int data_size = end - file_data;
+ // we may not have enough data in some case, use best effort to process file for whatever
+ // data we have till now.
+ int data_size = (write_req_hdr->length > (end - file_data)) ?
+ (end - file_data) : write_req_hdr->length;
uint64_t offset = alignedNtohq((const uint64_t*)(&(write_req_hdr->offset)));
- if (file_tracker->process_data(current_flow_key, file_data, data_size, offset))
+ if (file_tracker->process_data(current_flow_key, file_data, data_size, offset,
+ write_req_hdr->length))
{
if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(write_req_hdr->length)))
{