detect-filemagic.c detect-filemagic.h \
detect-filemd5.c detect-filemd5.h \
detect-filesha1.c detect-filesha1.h \
+detect-filesha256.c detect-filesha256.h \
detect-filename.c detect-filename.h \
detect-filesize.c detect-filesize.h \
detect-filestore.c detect-filestore.h \
flags |= FILE_NOSHA1;
}
+ if (s->f->flags & FLOW_FILE_NO_SHA256_TC) {
+ SCLogDebug("no sha256 for this flow in toclient direction, so none for this file");
+ flags |= FILE_NOSHA256;
+ }
+
if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) {
flags |= FILE_NOSTORE;
}
flags |= FILE_NOSHA1;
}
+ if (s->f->flags & FLOW_FILE_NO_SHA256_TS) {
+ SCLogDebug("no sha256 for this flow in toserver direction, so none for this file");
+ flags |= FILE_NOSHA256;
+ }
+
if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) {
flags |= FILE_NOSTORE;
}
flags |= FILE_NOSHA1;
}
+ if (flow->flags & FLOW_FILE_NO_SHA256_TS) {
+ flags |= FILE_NOSHA256;
+ }
+
/* Find file */
if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
break;
}
+ if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) {
+ SCLogDebug("sig needs file sha256, but we don't have any");
+ r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+ break;
+ }
+
if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) {
SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED");
r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
SCLogDebug("sgh %p has filesha1", sgh);
break;
}
+
+ if (SignatureIsFileSha256Inspecting(s)) {
+ sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA256;
+ SCLogDebug("sgh %p has filesha256", sgh);
+ break;
+ }
}
return;
#include "suricata-common.h"
#include "util-detect-file-hash.h"
-
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "suricata-common.h"
#include "util-detect-file-hash.h"
-
#include "util-unittest.h"
#include "util-unittest-helper.h"
--- /dev/null
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ * \author Duarte Silva <duarte.silva@serializing.me>
+ *
+ */
+
+#include "suricata-common.h"
+
+#include "util-detect-file-hash.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+#include "detect-filesha256.h"
+
+#ifndef HAVE_NSS
+
+static int DetectFileSha256SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c)
+{
+ SCLogError(SC_ERR_NO_SHA256_SUPPORT, "no SHA-256 calculation support built in, needed for filesha256 keyword");
+ return -1;
+}
+
+/**
+ * \brief Registration function for keyword: filesha256
+ */
+void DetectFileSha256Register(void)
+{
+ sigmatch_table[DETECT_FILESHA256].name = "filesha256";
+ sigmatch_table[DETECT_FILESHA256].FileMatch = NULL;
+ sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256SetupNoSupport;
+ sigmatch_table[DETECT_FILESHA256].Free = NULL;
+ sigmatch_table[DETECT_FILESHA256].RegisterTests = NULL;
+ sigmatch_table[DETECT_FILESHA256].flags = SIGMATCH_NOT_BUILT;
+
+ SCLogDebug("registering filesha256 rule option");
+ return;
+}
+
+#else /* HAVE_NSS */
+
+static int DetectFileSha256Setup (DetectEngineCtx *, Signature *, char *);
+static void DetectFileSha256RegisterTests(void);
+
+/**
+ * \brief Registration function for keyword: filesha256
+ */
+void DetectFileSha256Register(void)
+{
+ sigmatch_table[DETECT_FILESHA256].name = "filesha256";
+ sigmatch_table[DETECT_FILESHA256].desc = "match file SHA-256 against list of SHA-256 checksums";
+ sigmatch_table[DETECT_FILESHA256].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesha256";
+ sigmatch_table[DETECT_FILESHA256].FileMatch = DetectFileHashMatch;
+ sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256Setup;
+ sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree;
+ sigmatch_table[DETECT_FILESHA256].RegisterTests = DetectFileSha256RegisterTests;
+
+ SCLogDebug("registering filesha256 rule option");
+ return;
+}
+
+/**
+ * \brief this function is used to parse filesha256 options
+ * \brief into the current signature
+ *
+ * \param de_ctx pointer to the Detection Engine Context
+ * \param s pointer to the Current Signature
+ * \param str pointer to the user provided "filesha256" option
+ *
+ * \retval 0 on Success
+ * \retval -1 on Failure
+ */
+static int DetectFileSha256Setup (DetectEngineCtx *de_ctx, Signature *s, char *str)
+{
+ return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256);
+}
+
+#ifdef UNITTESTS
+static int SHA256MatchLookupString(ROHashTable *hash, char *string)
+{
+ uint8_t sha256[32];
+ if (ReadHashString(sha256, string, "file", 88, 64) == 1) {
+ void *ptr = ROHashLookup(hash, &sha256, (uint16_t)sizeof(sha256));
+ if (ptr == NULL)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int SHA256MatchTest01(void)
+{
+ ROHashTable *hash = ROHashInit(4, 32);
+ if (hash == NULL) {
+ return 0;
+ }
+ if (LoadHashTable(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8", "file", 1, DETECT_FILESHA256) != 1)
+ return 0;
+ if (LoadHashTable(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3", "file", 2, DETECT_FILESHA256) != 1)
+ return 0;
+ if (LoadHashTable(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047", "file", 3, DETECT_FILESHA256) != 1)
+ return 0;
+ if (LoadHashTable(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b", "file", 4, DETECT_FILESHA256) != 1)
+ return 0;
+ if (LoadHashTable(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f", "file", 5, DETECT_FILESHA256) != 1)
+ return 0;
+ if (LoadHashTable(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9", "file", 6, DETECT_FILESHA256) != 1)
+ return 0;
+
+ if (ROHashInitFinalize(hash) != 1) {
+ return 0;
+ }
+
+ if (SHA256MatchLookupString(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8") != 1)
+ return 0;
+ if (SHA256MatchLookupString(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3") != 1)
+ return 0;
+ if (SHA256MatchLookupString(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047") != 1)
+ return 0;
+ if (SHA256MatchLookupString(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b") != 1)
+ return 0;
+ if (SHA256MatchLookupString(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f") != 1)
+ return 0;
+ if (SHA256MatchLookupString(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9") != 1)
+ return 0;
+ /* Shouldn't match */
+ if (SHA256MatchLookupString(hash, "3333333333333333333333333333333333333333333333333333333333333333") == 1)
+ return 0;
+
+ ROHashFree(hash);
+ return 1;
+}
+#endif
+
+void DetectFileSha256RegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("SHA256MatchTest01", SHA256MatchTest01);
+#endif
+}
+
+#endif /* HAVE_NSS */
--- /dev/null
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ * \author Duarte Silva <duarte.silva@serializing.me>
+ */
+
+#ifndef __DETECT_FILESHA256_H__
+#define __DETECT_FILESHA256_H__
+
+/* prototypes */
+void DetectFileSha256Register (void);
+
+#endif /* __DETECT_FILESHA256_H__ */
#include "detect-filemagic.h"
#include "detect-filemd5.h"
#include "detect-filesha1.h"
+#include "detect-filesha256.h"
#include "detect-filesize.h"
#include "detect-dsize.h"
#include "detect-flowvar.h"
FileDisableSha1(pflow, STREAM_TOSERVER);
}
+ /* see if this sgh requires us to consider file sha256 */
+ if (!FileForceSha256() && (pflow->sgh_toserver == NULL ||
+ !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESHA256)))
+ {
+ SCLogDebug("disabling sha256 for flow");
+ FileDisableSha256(pflow, STREAM_TOSERVER);
+ }
+
/* see if this sgh requires us to consider filesize */
if (pflow->sgh_toserver == NULL ||
!(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE))
FileDisableSha1(pflow, STREAM_TOCLIENT);
}
+ /* check if this flow needs sha256, if not disable it */
+ if (!FileForceSha256() && (pflow->sgh_toclient == NULL ||
+ !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESHA256)))
+ {
+ SCLogDebug("disabling sha256 for flow");
+ FileDisableSha256(pflow, STREAM_TOCLIENT);
+ }
+
/* see if this sgh requires us to consider filesize */
if (pflow->sgh_toclient == NULL ||
!(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE))
return 0;
}
+/**
+ * \brief Check if a signature contains the filesha256 keyword.
+ *
+ * \param s signature
+ *
+ * \retval 0 no
+ * \retval 1 yes
+ */
+int SignatureIsFileSha256Inspecting(Signature *s)
+{
+ if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA256))
+ return 1;
+
+ return 0;
+}
+
/**
* \brief Check if a signature contains the filesize keyword.
*
DetectFilemagicRegister();
DetectFileMd5Register();
DetectFileSha1Register();
+ DetectFileSha256Register();
DetectFilesizeRegister();
DetectAppLayerEventRegister();
DetectHttpUARegister();
#define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21)
#define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22)
#define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23)
+#define SIG_GROUP_HEAD_HAVEFILESHA256 (1 << 24)
-#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 24)
-#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 25)
-#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 26)
-#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 27)
-#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 28)
+#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 25)
+#define SIG_GROUP_HEAD_MPM_TLSSNI (1 << 26)
+#define SIG_GROUP_HEAD_MPM_TLSISSUER (1 << 27)
+#define SIG_GROUP_HEAD_MPM_TLSSUBJECT (1 << 28)
+#define SIG_GROUP_HEAD_MPM_FD_SMTP (1 << 29)
#define APP_MPMS_MAX 21
int SignatureIsFilemagicInspecting(Signature *);
int SignatureIsFileMd5Inspecting(Signature *);
int SignatureIsFileSha1Inspecting(Signature *s);
+int SignatureIsFileSha256Inspecting(Signature *s);
int SignatureIsFilesizeInspecting(Signature *);
int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int);
#define FLOW_FILE_NO_SHA1_TS 0x04000000
#define FLOW_FILE_NO_SHA1_TC 0x08000000
+/** no sha256 on files in this flow */
+#define FLOW_FILE_NO_SHA256_TS 0x10000000
+#define FLOW_FILE_NO_SHA256_TC 0x20000000
+
/** no size tracking of files in this flow */
#define FLOW_FILE_NO_SIZE_TS 0x40000000
#define FLOW_FILE_NO_SIZE_TC 0x80000000
}
fprintf(fp, "\", ");
}
+ if (ff->flags & FILE_SHA256) {
+ fprintf(fp, "\"sha256\": \"");
+ size_t x;
+ for (x = 0; x < sizeof(ff->sha256); x++) {
+ fprintf(fp, "%02x", ff->sha256[x]);
+ }
+ fprintf(fp, "\", ");
+ }
#endif
break;
case FILE_STATE_TRUNCATED:
}
fprintf(fp, "\n");
}
+ if (ff->flags & FILE_SHA256) {
+ fprintf(fp, "SHA256: ");
+ size_t x;
+ for (x = 0; x < sizeof(ff->sha256); x++) {
+ fprintf(fp, "%02x", ff->sha256[x]);
+ }
+ fprintf(fp, "\n");
+ }
#endif
break;
case FILE_STATE_TRUNCATED:
}
json_object_set_new(fjs, "sha1", json_string(s));
}
+ if (ff->flags & FILE_SHA256) {
+ size_t x;
+ int i;
+ char s[256];
+ for (i = 0, x = 0; x < sizeof(ff->sha256); x++) {
+ i += snprintf(&s[i], 255-i, "%02x", ff->sha256[x]);
+ }
+ json_object_set_new(fjs, "sha256", json_string(s));
+ }
#endif
break;
case FILE_STATE_TRUNCATED:
CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL);
CASE_CODE (SC_ERR_INVALID_HASH);
CASE_CODE (SC_ERR_NO_SHA1_SUPPORT);
+ CASE_CODE (SC_ERR_NO_SHA256_SUPPORT);
}
return "UNKNOWN_ERROR";
SC_ERR_NO_FILES_FOR_PROTOCOL,
SC_ERR_INVALID_HASH,
SC_ERR_NO_SHA1_SUPPORT,
+ SC_ERR_NO_SHA256_SUPPORT,
} SCError;
const char *SCErrorToString(SCError);
*/
static int g_file_force_sha1 = 0;
+/** \brief switch to force sha256 calculation on all files
+ * regardless of the rules.
+ */
+static int g_file_force_sha256 = 0;
+
/** \brief switch to force tracking off all files
* regardless of the rules.
*/
g_file_force_sha1 = 1;
}
+void FileForceSha256Enable(void)
+{
+ g_file_force_sha256 = 1;
+}
+
int FileForceFilestore(void)
{
return g_file_force_filestore;
return g_file_force_sha1;
}
+int FileForceSha256(void)
+{
+ return g_file_force_sha256;
+}
+
void FileForceTrackingEnable(void)
{
g_file_force_tracking = 1;
HASH_Destroy(ff->md5_ctx);
if (ff->sha1_ctx)
HASH_Destroy(ff->sha1_ctx);
+ if (ff->sha256_ctx)
+ HASH_Destroy(ff->sha256_ctx);
#endif
SCFree(ff);
}
if (file->sha1_ctx) {
HASH_Update(file->sha1_ctx, data, data_len);
}
+ if (file->sha256_ctx) {
+ HASH_Update(file->sha256_ctx, data, data_len);
+ }
#endif
SCReturnInt(0);
}
HASH_Update(ffc->tail->sha1_ctx, data, data_len);
SCReturnInt(0);
}
+ if (ffc->tail->sha256_ctx) {
+ HASH_Update(ffc->tail->sha256_ctx, data, data_len);
+ SCReturnInt(0);
+ }
#endif
if (g_file_force_tracking || (!(ffc->tail->flags & FILE_NOTRACK)))
SCReturnInt(0);
SCLogDebug("not doing sha1 for this file");
ff->flags |= FILE_NOSHA1;
}
+ if (flags & FILE_NOSHA256) {
+ SCLogDebug("not doing sha256 for this file");
+ ff->flags |= FILE_NOSHA256;
+ }
if (flags & FILE_USE_DETECT) {
SCLogDebug("considering content_inspect tracker when pruning");
ff->flags |= FILE_USE_DETECT;
HASH_Begin(ff->sha1_ctx);
}
}
+ if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) {
+ ff->sha256_ctx = HASH_Create(HASH_AlgSHA256);
+ if (ff->sha256_ctx != NULL) {
+ HASH_Begin(ff->sha256_ctx);
+ }
+ }
#endif
ff->state = FILE_STATE_OPENED;
HASH_Update(ff->md5_ctx, data, data_len);
if (ff->sha1_ctx)
HASH_Update(ff->sha1_ctx, data, data_len);
+ if (ff->sha256_ctx)
+ HASH_Update(ff->sha256_ctx, data, data_len);
#endif
} else {
if (AppendData(ff, data, data_len) != 0) {
HASH_End(ff->sha1_ctx, ff->sha1, &len, sizeof(ff->sha1));
ff->flags |= FILE_SHA1;
}
+ if (ff->sha256_ctx) {
+ unsigned int len = 0;
+ HASH_End(ff->sha256_ctx, ff->sha256, &len, sizeof(ff->sha256));
+ ff->flags |= FILE_SHA256;
+ }
#endif
}
SCReturn;
}
+/**
+ * \brief disable file sha256 calc for this flow
+ *
+ * \param f *LOCKED* flow
+ * \param direction flow direction
+ */
+void FileDisableSha256(Flow *f, uint8_t direction)
+{
+ File *ptr = NULL;
+
+ SCEnter();
+
+ DEBUG_ASSERT_FLOW_LOCKED(f);
+
+ if (direction == STREAM_TOSERVER)
+ f->flags |= FLOW_FILE_NO_SHA256_TS;
+ else
+ f->flags |= FLOW_FILE_NO_SHA256_TC;
+
+ FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction);
+ if (ffc != NULL) {
+ for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) {
+ SCLogDebug("disabling sha256 for file %p from direction %s",
+ ptr, direction == STREAM_TOSERVER ? "toserver":"toclient");
+ ptr->flags |= FILE_NOSHA256;
+
+#ifdef HAVE_NSS
+ /* destroy any ctx we may have so far */
+ if (ptr->sha256_ctx != NULL) {
+ HASH_Destroy(ptr->sha256_ctx);
+ ptr->sha256_ctx = NULL;
+ }
+#endif
+ }
+ }
+
+ SCReturn;
+}
+
/**
* \brief disable file size tracking for this flow
*
ff->flags |= FILE_NOSTORE;
if (ff->state == FILE_STATE_OPENED && FileSize(ff) >= (uint64_t)FileMagicSize()) {
- if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_tracking == 0) {
+ if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_sha256 == 0
+ && g_file_force_tracking == 0) {
(void)FileCloseFilePtr(ff, NULL, 0,
(FILE_TRUNCATED|FILE_NOSTORE));
}
void FileForceSha1Enable(void);
int FileForceSha1(void);
+void FileDisableSha256(Flow *f, uint8_t);
+void FileForceSha256Enable(void);
+int FileForceSha256(void);
+
void FileForceTrackingEnable(void);
void FileStoreAllFiles(FileContainer *);
strlcat(sha1, one, sizeof(sha1));
}
}
+ char sha256[65] = "";
+ char *sha256ptr = sha256;
+ if (file->flags & FILE_SHA256) {
+ size_t x;
+ for (x = 0; x < sizeof(file->sha256); x++) {
+ char one[3] = "";
+ snprintf(one, sizeof(one), "%02x", file->sha256[x]);
+ strlcat(sha256, one, sizeof(sha256));
+ }
+ }
#else
char *md5ptr = NULL;
char *sha1ptr = NULL;
+ char *sha256ptr = NULL;
#endif
lua_pushnumber(luastate, file->file_id);
lua_pushstring (luastate, file->magic);
lua_pushstring(luastate, md5ptr);
lua_pushstring(luastate, sha1ptr);
+ lua_pushstring(luastate, sha256ptr);
return 6;
}