?? smb_andx_decode.c
字號:
/* * smb_andx_decode.c * * Copyright (C) 2004-2006 Sourcefire,Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Description: * * This performs the decoding of SMB AndX commands. * * NOTES: * - 08.12.04: Initial Development. SAS * */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#ifdef HAVE_WCHAR_H#include <wchar.h>#endif#include <string.h>#include "debug.h"#include "bounds.h"#include "snort_dcerpc.h"#include "smb_structs.h"#include "smb_andx_structs.h"#include "smb_andx_decode.h"#include "dcerpc_util.h"#include "dcerpc.h"#define FIELD_ACCT_NAME 0#define FIELD_PRIM_DOMAIN 1#define SESS_AUTH_FIELD(i) ((i == FIELD_ACCT_NAME) ? "AccountName" : ((i == FIELD_PRIM_DOMAIN) ? "PrimaryDomain" : "Unknown"))#define FIELD_NATIVE_OS 0#define FIELD_NATIVE_LANMAN 1#define SESS_NATIVE_FIELD(i) ((i == FIELD_NATIVE_OS) ? "NativeOS" : ((i == FIELD_NATIVE_LANMAN) ? "NativeLanMan" : "Unknown"))/* Externs */extern DCERPC *_dcerpc;extern SFSnortPacket *_dcerpc_pkt;extern u_int8_t _disable_smb_fragmentation;extern u_int16_t _max_frag_size;static void ReassembleSMBWriteX(SMB_WRITEX_REQ *writeX, u_int8_t *smb_data);static int SMB_Fragmentation(u_int8_t *smb_hdr, SMB_WRITEX_REQ *writeX, u_int8_t *smb_data, u_int16_t data_size);static int GetSMBStringLength(u_int8_t *data, u_int16_t data_size, int unicode);#ifdef DEBUG_DCERPC_PRINTstatic void PrintSMBString(char *pre, u_int8_t *str, u_int16_t str_len, int unicode);#endif/* smb_data is guaranteed to be at least an SMB_WRITEX_REQ length away from writeX * if it's farther it's because there was padding */static void ReassembleSMBWriteX(SMB_WRITEX_REQ *writeX, u_int8_t *smb_data){ SMB_WRITEX_REQ temp_writeX; u_int16_t smb_hdr_len = sizeof(SMB_HDR) + sizeof(NBT_HDR); u_int16_t writeX_len = (u_int16_t)(smb_data - (u_int8_t *)writeX); u_int32_t check_len; int ret; int padding = writeX_len - sizeof(SMB_WRITEX_REQ); check_len = (u_int32_t)smb_hdr_len + (u_int32_t)writeX_len + (u_int32_t)_dcerpc->write_andx_buf_len; /* Make sure we have room to fit into alternate buffer */ if ( check_len > _dpd.altBufferLen ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "Reassembled SMB packet greater than %d bytes, skipping.", _dpd.altBufferLen)); goto dcerpc_fragfree; } /* Mock up header */ ret = SafeMemcpy(&temp_writeX, writeX, sizeof(SMB_WRITEX_REQ), &temp_writeX, (u_int8_t *)&temp_writeX + sizeof(SMB_WRITEX_REQ)); if (ret == 0) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "WriteAndX header too big: %u, skipping SMB reassembly.", _dpd.altBufferLen)); goto dcerpc_fragfree; } temp_writeX.remaining = smb_htons(_dcerpc->write_andx_buf_len); temp_writeX.dataLength = smb_htons(_dcerpc->write_andx_buf_len); temp_writeX.dataOffset = smb_htons(sizeof(SMB_HDR) + sizeof(SMB_WRITEX_REQ) + padding); temp_writeX.andXCommand = 0xFF; temp_writeX.andXOffset = 0x0000; /* Copy headers into buffer */ /* SMB Header */ ret = SafeMemcpy(_dpd.altBuffer, _dcerpc_pkt->payload, smb_hdr_len, _dpd.altBuffer, _dpd.altBuffer + _dpd.altBufferLen); if ( ret == 0 ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "WriteAndX header too big: %u, skipping SMB reassembly.", _dpd.altBufferLen)); goto dcerpc_fragfree; } _dcerpc_pkt->normalized_payload_size = smb_hdr_len; /* Write AndX header */ ret = SafeMemcpy(_dpd.altBuffer + _dcerpc_pkt->normalized_payload_size, &temp_writeX, sizeof(SMB_WRITEX_REQ), _dpd.altBuffer, _dpd.altBuffer + _dpd.altBufferLen); if ( ret == 0 ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "WriteAndX header too big: %u, skipping SMB reassembly.", _dpd.altBufferLen)); goto dcerpc_fragfree; } _dcerpc_pkt->normalized_payload_size += sizeof(SMB_WRITEX_REQ); /* Account for optional padding byte in WriteAndX header. It is never used so we don't write it. */ _dcerpc_pkt->normalized_payload_size += padding; /* Copy data into buffer */ ret = SafeMemcpy(_dpd.altBuffer + _dcerpc_pkt->normalized_payload_size, _dcerpc->write_andx_buf, _dcerpc->write_andx_buf_len, _dpd.altBuffer, _dpd.altBuffer + _dpd.altBufferLen); if ( ret == 0 ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "WriteAndX header too big: %u, skipping SMB reassembly.", _dpd.altBufferLen)); goto dcerpc_fragfree; } _dcerpc_pkt->normalized_payload_size += _dcerpc->write_andx_buf_len; _dcerpc_pkt->flags |= FLAG_ALT_DECODE; if (_dcerpc->write_andx_buf_len > 0) ProcessDCERPCMessage(_dcerpc_pkt->payload + sizeof(NBT_HDR), sizeof(SMB_HDR) + writeX_len, _dcerpc->write_andx_buf, _dcerpc->write_andx_buf_len);dcerpc_fragfree: /* 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;}int SMB_Fragmentation(u_int8_t *smb_hdr, SMB_WRITEX_REQ *writeX, u_int8_t *smb_data, u_int16_t data_size){ u_int16_t writeX_length, temp_len; int success = 0; int ret = 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 - 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 = data_size; /* Allocate space for buffer For now, ignore offset, since servers seem to */ if ( _dcerpc->fragmentation & SUSPEND_FRAGMENTATION ) return 0; 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 ( writeX_length == 0 ) { DEBUG_WRAP(DebugMessage(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; } if ( !_dcerpc->write_andx_buf ) DynamicPreprocessorFatalMessage("Failed to allocate space for first SMB Write AndX\n"); _dcerpc->write_andx_buf_size = writeX_length; _dcerpc->write_andx_buf_len = 0; } else { u_int16_t new_size; if ( writeX_length > _max_frag_size ) writeX_length = _max_frag_size; if ( _dcerpc->write_andx_buf_size >= (0xFFFF - writeX_length) ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "SMB fragmentation overflow.\n");); _dcerpc->fragmentation |= SUSPEND_FRAGMENTATION; 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; return 0; } new_size = _dcerpc->write_andx_buf_size + writeX_length; _dcerpc->write_andx_buf = (u_int8_t *) DCERPC_FragAlloc(_dcerpc->write_andx_buf, _dcerpc->write_andx_buf_size, &new_size); if ( new_size == _dcerpc->write_andx_buf_size ) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "Memcap reached, suspending SMB fragmentation reassembly.\n");); _dcerpc->fragmentation |= SUSPEND_FRAGMENTATION; 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; return 0; } if ( !_dcerpc->write_andx_buf ) DynamicPreprocessorFatalMessage("Failed to reallocate space for SMB Write AndX\n"); _dcerpc->write_andx_buf_size = new_size; } /* SMB frag */ if ( writeX_length > (_dcerpc->write_andx_buf_size - _dcerpc->write_andx_buf_len) ) { writeX_length = _dcerpc->write_andx_buf_size - _dcerpc->write_andx_buf_len; } /* Make sure data to be copied is within source buffer */ if ( (smb_data + writeX_length) > (_dcerpc_pkt->payload + _dcerpc_pkt->payload_size) ) { temp_len = _dcerpc_pkt->payload + _dcerpc_pkt->payload_size - smb_data; if ( writeX_length > temp_len ) { writeX_length = temp_len; } } ret = SafeMemcpy(_dcerpc->write_andx_buf + _dcerpc->write_andx_buf_len, smb_data, writeX_length, _dcerpc->write_andx_buf, _dcerpc->write_andx_buf + _dcerpc->write_andx_buf_size); if (ret == 0) { 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 |= SUSPEND_FRAGMENTATION; return 0; } _dcerpc->write_andx_buf_len += writeX_length; _dcerpc->fragmentation |= SMB_FRAGMENTATION; if ( IsCompleteDCERPCMessage(_dcerpc->write_andx_buf, _dcerpc->write_andx_buf_len) ) { ReassembleSMBWriteX(writeX, smb_data); _dcerpc->fragmentation &= ~SMB_FRAGMENTATION; } return 0;}/* IPC$ has to occur at the end of this path - path_len should include null termination */static int IsIPC(u_int8_t *path, int path_len, u_int32_t isUnicode){ const u_int8_t ipc[] = {'I', 'P', 'C', '$', '\0'}; const u_int16_t ipc_len = 5; const u_int8_t unicode_ipc[] = {'I', '\0', 'P', '\0', 'C', '\0', '$', '\0', '\0', '\0'}; const u_int16_t unicode_ipc_len = 10; if (isUnicode) { if (path_len < unicode_ipc_len) return 0; /* go to end of path then back up the length of the * unicode_ipc string */ path = (path + path_len) - unicode_ipc_len; if (memcmp(path, unicode_ipc, unicode_ipc_len) == 0) return 1; } else { if (path_len < ipc_len) return 0; /* go to end of path and back up the length of the * ipc string */ path = (path + path_len) - ipc_len; if (memcmp(path, ipc, ipc_len) == 0) return 1; } return 0;}/* returns -1 if not null terminated * returns -2 for other error * otherwise returns length of null terminated string * including null terminating bytes */static int GetSMBStringLength(u_int8_t *data, u_int16_t data_size, int unicode){ u_int16_t size_left; if (data == NULL) return -2; size_left = data_size; if (unicode) { while (size_left >= sizeof(uni_char_t)) { size_left -= sizeof(uni_char_t); if (*((uni_char_t *)data) == 0x0000) { return (int)(data_size - size_left); } data += sizeof(uni_char_t); } } else { while (size_left >= sizeof(char)) { size_left -= sizeof(char); if (*((char *)data) == 0x00) { return (int)(data_size - size_left); } data += sizeof(char); } } return -1;}#ifdef DEBUG_DCERPC_PRINTstatic void PrintSMBString(char *pre, u_int8_t *str, u_int16_t str_len, int unicode){ if (pre == NULL || str == NULL || str_len == 0) return; printf("%s", pre); if (unicode) { int i = 0; while (i < str_len) { printf("%c", str[i]); i += sizeof(uni_char_t); } } else { printf("%.*s", str_len, str); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -