📄 smb_andx_decode.c
字号:
/* * smb_andx_decode.c * * Copyright (C) 2004-2008 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;extern u_int8_t *dce_reassembly_buf;extern u_int16_t dce_reassembly_buf_size;extern SFSnortPacket *real_dce_mock_pkt;extern u_int8_t _debug_print;extern int _reassemble_increment;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 */void ReassembleSMBWriteX(u_int8_t *smb_hdr, u_int16_t smb_hdr_len){ SMB_WRITEX_REQ *write_andx; int pkt_len; int status; u_int16_t data_len = 0; DCERPC_Buffer *buf = &_dcerpc->smb_seg_buf; pkt_len = sizeof(NBT_HDR) + smb_hdr_len + buf->len; /* Make sure we have room to fit into reassembly buffer */ if (pkt_len > dce_reassembly_buf_size) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "Reassembled SMB packet greater " "than %d bytes, skipping.", dce_reassembly_buf_size);); /* just shorten it - don't want to lose all of * this information */ buf->len = dce_reassembly_buf_size - (pkt_len - buf->len); } /* Copy headers into buffer */ /* SMB Header */ status = SafeMemcpy(dce_reassembly_buf, _dcerpc_pkt->payload, sizeof(NBT_HDR) + smb_hdr_len, dce_reassembly_buf, dce_reassembly_buf + dce_reassembly_buf_size); if (status != SAFEMEM_SUCCESS) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "SMB header too big: %u, " "skipping SMB reassembly.", dce_reassembly_buf_size);); DCERPC_BufferFreeData(buf); return; } write_andx = (SMB_WRITEX_REQ *)((u_int8_t *)dce_reassembly_buf + sizeof(NBT_HDR) + sizeof(SMB_HDR)); write_andx->remaining = smb_htons(buf->len); write_andx->dataLength = smb_htons(buf->len); write_andx->dataOffset = smb_htons(smb_hdr_len); write_andx->andXCommand = 0xFF; write_andx->andXOffset = 0x0000; data_len = sizeof(NBT_HDR) + smb_hdr_len; status = SafeMemcpy(dce_reassembly_buf + data_len, buf->data, buf->len, dce_reassembly_buf + data_len, dce_reassembly_buf + dce_reassembly_buf_size); if (status != SAFEMEM_SUCCESS) { DEBUG_WRAP(DebugMessage(DEBUG_DCERPC, "SMB fragments too big: %u, " "skipping SMB reassembly.", dce_reassembly_buf_size);); DCERPC_BufferFreeData(buf); return; } data_len += buf->len; /* create pseudo packet */ real_dce_mock_pkt = DCERPC_SetPseudoPacket(_dcerpc_pkt, dce_reassembly_buf, data_len); if (real_dce_mock_pkt == NULL) { DCERPC_BufferFreeData(buf); return; } if (_debug_print) { PrintBuffer("SMB desegmented", (u_int8_t *)dce_reassembly_buf, data_len); }}/* 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); } printf("\n");}#endifint SkipBytes(u_int8_t *data, u_int16_t size){ u_int16_t i = 0; while ( i < size && *data != 0 ) { data++; i++; } return i;}int SkipBytesWide(u_int8_t *data, u_int16_t size){ u_int16_t i = 0; /* Check against size-1 in case someone is screwing with us and giving us an odd number of bytes for 2-byte Unicode. */ while ( i < (size - 1) && *data != 0 ) { data += 2; i += 2; } return i;}int ProcessSMBTreeConnXReq(SMB_HDR *smbHdr, u_int8_t *data, u_int16_t size, u_int16_t total_size){ SMB_TREE_CONNECTX_REQ *treeConnX; u_int16_t byteCount; u_int8_t *tree_data; u_int16_t tree_data_len; u_int8_t *passwd_ptr; u_int16_t passwd_len; u_int8_t *path_ptr; int path_len; u_int8_t *service_ptr; int service_len; int is_ipc; if ( size <= sizeof(SMB_TREE_CONNECTX_REQ) ) { return 0; } treeConnX = (SMB_TREE_CONNECTX_REQ *)data; size -= sizeof(SMB_TREE_CONNECTX_REQ); tree_data = data + sizeof(SMB_TREE_CONNECTX_REQ); byteCount = smb_ntohs(treeConnX->byteCount); tree_data_len = byteCount; passwd_len = smb_ntohs(treeConnX->passwdLen); /* Sanity check */ if ( byteCount > size || passwd_len >= byteCount) return 0; passwd_ptr = tree_data; tree_data += passwd_len; tree_data_len -= passwd_len; /* Get path */ path_len = GetSMBStringLength(tree_data, tree_data_len, HAS_UNICODE_STRINGS(smbHdr)); if (path_len == -1 || path_len == tree_data_len) return 0; path_ptr = tree_data; is_ipc = IsIPC(tree_data, path_len, HAS_UNICODE_STRINGS(smbHdr)); if (is_ipc && _dcerpc->smb_state == STATE_START) { _dcerpc->smb_state = STATE_GOT_TREE_CONNECT; } tree_data += path_len; tree_data_len -= path_len; /* Service field is ALWAYS ascii */ service_len = GetSMBStringLength(tree_data, tree_data_len, 0); if (service_len == -1) return 0; service_ptr = tree_data; /* there shouldn't be any more data */ if (tree_data + service_len != tree_data + tree_data_len) return 0;#ifdef DEBUG_DCERPC_PRINT /* Password data * it seems like the password length has to be an odd number * This passwd will always be ASCII -- equiv of * CaseInsensitivePasswd field from SessSetupAndX message */ if (passwd_len > 0) printf("Password: %02.*X\n", passwd_len, passwd_ptr); if (path_len > 0) PrintSMBString("Path: ", path_ptr, path_len, HAS_UNICODE_STRINGS(smbHdr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -