| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
#include <unistd.h> |
|---|
| 22 |
#include <string.h> |
|---|
| 23 |
#include <errno.h> |
|---|
| 24 |
|
|---|
| 25 |
#include "sf_snort_plugin_api.h" |
|---|
| 26 |
#include "sf_snort_packet.h" |
|---|
| 27 |
#include "debug.h" |
|---|
| 28 |
|
|---|
| 29 |
#include "pehunter.h" |
|---|
| 30 |
#include "md5.h" |
|---|
| 31 |
|
|---|
| 32 |
#include "profiler.h" |
|---|
| 33 |
#ifdef PERF_PROFILING |
|---|
| 34 |
PreprocStats pehuntPerfStats; |
|---|
| 35 |
PreprocStats pehuntDetectPerfStats; |
|---|
| 36 |
int pehuntDetectCalled = 0; |
|---|
| 37 |
#endif |
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 |
extern DynamicPreprocessorData _dpd; |
|---|
| 41 |
|
|---|
| 42 |
SessionData *_pehunt; |
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
static void PEHunter_SessionFree(void * v) |
|---|
| 46 |
{ |
|---|
| 47 |
SessionData *sdata = (SessionData *) v; |
|---|
| 48 |
|
|---|
| 49 |
if (sdata) |
|---|
| 50 |
{ |
|---|
| 51 |
if ( sdata->data ) free(sdata->data); |
|---|
| 52 |
free(sdata); |
|---|
| 53 |
} |
|---|
| 54 |
return; |
|---|
| 55 |
} |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
SessionData *PEHunter_Setup(SFSnortPacket *p) |
|---|
| 60 |
{ |
|---|
| 61 |
SessionData *datap = NULL; |
|---|
| 62 |
|
|---|
| 63 |
if (( !p ) || ( !p->stream_session_ptr )) return(NULL); |
|---|
| 64 |
if ( !_dpd.streamAPI ) |
|---|
| 65 |
{ |
|---|
| 66 |
DEBUG_WRAP(_dpd.debugMsg(DEBUG_PEHUNTER, "Error: Failed to get Stream API - Stream not enabled?\n");); |
|---|
| 67 |
return(NULL); |
|---|
| 68 |
} |
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
if (( datap = _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_PEHUNTER)) == NULL) |
|---|
| 72 |
{ |
|---|
| 73 |
if ((datap = (SessionData *) malloc(sizeof(SessionData))) == NULL) |
|---|
| 74 |
{ |
|---|
| 75 |
_dpd.fatalMsg("%s(%d) => Failed to allocate memory for session data\n"); |
|---|
| 76 |
return(NULL); |
|---|
| 77 |
} |
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 |
bzero(datap, sizeof(SessionData)); |
|---|
| 81 |
_dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_PEHUNTER, datap, &PEHunter_SessionFree); |
|---|
| 82 |
} |
|---|
| 83 |
|
|---|
| 84 |
return(datap); |
|---|
| 85 |
} |
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 |
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
int Hunt(SFSnortPacket *p) |
|---|
| 99 |
{ |
|---|
| 100 |
int retval; |
|---|
| 101 |
u_int32_t parsedBytes, dosOffset, maxOffset, maxLen, i, parseStart, pos; |
|---|
| 102 |
IMAGE_DOS_HEADER *dosHeader; |
|---|
| 103 |
IMAGE_NT_HEADERS32 *peHeader; |
|---|
| 104 |
IMAGE_SECTION_HEADER *sectHeader; |
|---|
| 105 |
SessionData *session_data; |
|---|
| 106 |
const char *dh_sig = "MZ"; |
|---|
| 107 |
char *filename; |
|---|
| 108 |
FILE *dumpfile; |
|---|
| 109 |
PROFILE_VARS; |
|---|
| 110 |
|
|---|
| 111 |
dumpfile = NULL; |
|---|
| 112 |
filename = NULL; |
|---|
| 113 |
session_data = NULL; |
|---|
| 114 |
parsedBytes = 0; |
|---|
| 115 |
maxOffset = 0; |
|---|
| 116 |
maxLen = 0; |
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 |
if (( !p->payload ) || ( !p->payload_size )) |
|---|
| 120 |
{ |
|---|
| 121 |
return(0); |
|---|
| 122 |
} |
|---|
| 123 |
|
|---|
| 124 |
if ( (session_data = PEHunter_Setup(p)) == NULL) |
|---|
| 125 |
{ |
|---|
| 126 |
|
|---|
| 127 |
PREPROC_PROFILE_END(pehuntPerfStats); |
|---|
| 128 |
return(0); |
|---|
| 129 |
} |
|---|
| 130 |
|
|---|
| 131 |
if (session_data->dumped) |
|---|
| 132 |
{ |
|---|
| 133 |
|
|---|
| 134 |
return(1); |
|---|
| 135 |
} |
|---|
| 136 |
|
|---|
| 137 |
|
|---|
| 138 |
if ((session_data->data = (u_char *) realloc(session_data->data, session_data->len + p->payload_size)) == NULL) |
|---|
| 139 |
{ |
|---|
| 140 |
_dpd.fatalMsg("%s(%d) => Failed to allocate memory for session data\n"); |
|---|
| 141 |
return(0); |
|---|
| 142 |
} |
|---|
| 143 |
|
|---|
| 144 |
parseStart = (session_data->len ? (session_data->len-1) : 0); |
|---|
| 145 |
memcpy(session_data->data + session_data->len, p->payload, p->payload_size); |
|---|
| 146 |
session_data->len += p->payload_size; |
|---|
| 147 |
|
|---|
| 148 |
if (session_data->match && (session_data->len >= (session_data->matchpos + session_data->filelen))) |
|---|
| 149 |
{ |
|---|
| 150 |
|
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 |
|
|---|
| 156 |
if ((filename = strdup(_pehunterConfig.dumpDir)) == NULL) |
|---|
| 157 |
{ |
|---|
| 158 |
_dpd.fatalMsg("%s(): Unable to allocate memory: %s\n", __PRETTY_FUNCTION__, strerror(errno)); |
|---|
| 159 |
} |
|---|
| 160 |
if ((filename = realloc(filename, strlen(filename)+34)) == NULL) { |
|---|
| 161 |
_dpd.fatalMsg("%s(): Unable to allocate memory: %s\n", __PRETTY_FUNCTION__, strerror(errno)); |
|---|
| 162 |
} |
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 |
bzero(filename+strlen(filename), 34); |
|---|
| 166 |
strncat(filename, "/", 1); |
|---|
| 167 |
mem_md5sum(session_data->data+session_data->matchpos, session_data->filelen); |
|---|
| 168 |
strncat(filename, mem_md5sum(session_data->data+session_data->matchpos, session_data->filelen), 32); |
|---|
| 169 |
|
|---|
| 170 |
if ((dumpfile = fopen(filename, "w")) == NULL) |
|---|
| 171 |
{ |
|---|
| 172 |
_dpd.fatalMsg("%s(): Unable to open dumpfile %s: %s\n", __PRETTY_FUNCTION__, filename, strerror(errno)); |
|---|
| 173 |
} |
|---|
| 174 |
if ((retval = fwrite(session_data->data+session_data->matchpos, 1, session_data->filelen, dumpfile)) < session_data->filelen) |
|---|
| 175 |
{ |
|---|
| 176 |
_dpd.fatalMsg("%s(): Unable to write dumpfile %s (%u bytes written): %s\n", __PRETTY_FUNCTION__, filename, retval, strerror(errno)); |
|---|
| 177 |
} |
|---|
| 178 |
if (fclose(dumpfile) == EOF) |
|---|
| 179 |
{ |
|---|
| 180 |
_dpd.fatalMsg("%s(): Unable to close dumpfile %s: %s\n", __PRETTY_FUNCTION__, filename, strerror(errno)); |
|---|
| 181 |
} |
|---|
| 182 |
session_data->dumped = 1; |
|---|
| 183 |
_dpd.logMsg("PE file extracted: %u bytes dumped to %s.\n", session_data->filelen, filename); |
|---|
| 184 |
free(filename); |
|---|
| 185 |
|
|---|
| 186 |
return(1); |
|---|
| 187 |
} |
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
|
|---|
| 191 |
for (dosOffset=parseStart; (dosOffset + strlen(dh_sig)) < session_data->len; dosOffset++) |
|---|
| 192 |
{ |
|---|
| 193 |
if (memcmp(session_data->data + dosOffset, dh_sig, strlen(dh_sig)) == 0) break; |
|---|
| 194 |
} |
|---|
| 195 |
parsedBytes = dosOffset - parseStart; |
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 |
if (session_data->len < (sizeof(IMAGE_DOS_HEADER) + parsedBytes)) return(0); |
|---|
| 199 |
dosHeader = (IMAGE_DOS_HEADER *)(session_data->data + parsedBytes); |
|---|
| 200 |
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return(0); |
|---|
| 201 |
pos = parsedBytes; |
|---|
| 202 |
if (_pehunterConfig.debug) _dpd.logMsg("DOS header found at offset %lu.\n", pos); |
|---|
| 203 |
|
|---|
| 204 |
if (session_data->len < (sizeof(IMAGE_NT_HEADERS32) + parsedBytes + dosHeader->e_lfanew)) return(0); |
|---|
| 205 |
parsedBytes += dosHeader->e_lfanew; |
|---|
| 206 |
if (_pehunterConfig.debug) _dpd.logMsg("DOS header e_lfanew is %lu, parsedBytes is %lu.\n", dosHeader->e_lfanew, parsedBytes); |
|---|
| 207 |
|
|---|
| 208 |
|
|---|
| 209 |
if ((session_data->len) < (sizeof(IMAGE_NT_HEADERS32) + parsedBytes)) return(0); |
|---|
| 210 |
peHeader = (IMAGE_NT_HEADERS32*)(session_data->data + parsedBytes); |
|---|
| 211 |
if (peHeader->Signature == IMAGE_NT_SIGNATURE) |
|---|
| 212 |
{ |
|---|
| 213 |
if (_pehunterConfig.debug) _dpd.logMsg("NT header found at offset %lu.\n", parsedBytes); |
|---|
| 214 |
parsedBytes += sizeof(IMAGE_NT_HEADERS32); |
|---|
| 215 |
|
|---|
| 216 |
|
|---|
| 217 |
for (i=0; i<peHeader->FileHeader.NumberOfSections; i++) { |
|---|
| 218 |
if (session_data->len < (sizeof(IMAGE_SECTION_HEADER) + parsedBytes)) return(0); |
|---|
| 219 |
sectHeader = (IMAGE_SECTION_HEADER *)(session_data->data + parsedBytes); |
|---|
| 220 |
if (_pehunterConfig.debug) _dpd.logMsg("Section header found at offset %lu.\n", parsedBytes); |
|---|
| 221 |
parsedBytes += sizeof(IMAGE_SECTION_HEADER); |
|---|
| 222 |
if (_pehunterConfig.debug) _dpd.logMsg("Section %lu (%s): starts at offset %lu (%u bytes)\n", |
|---|
| 223 |
i, sectHeader->Name, sectHeader->PointerToRawData, sectHeader->SizeOfRawData); |
|---|
| 224 |
if (maxOffset < sectHeader->PointerToRawData) { |
|---|
| 225 |
maxOffset = sectHeader->PointerToRawData; |
|---|
| 226 |
maxLen = sectHeader->SizeOfRawData; |
|---|
| 227 |
} |
|---|
| 228 |
} |
|---|
| 229 |
} |
|---|
| 230 |
if (maxOffset + maxLen) |
|---|
| 231 |
{ |
|---|
| 232 |
session_data->match = 1; |
|---|
| 233 |
session_data->matchpos = pos; |
|---|
| 234 |
session_data->filelen = maxOffset + maxLen; |
|---|
| 235 |
} |
|---|
| 236 |
|
|---|
| 237 |
return(0); |
|---|
| 238 |
} |
|---|