diff --git a/doc/module_file.html b/doc/module_file.html index 16e0f836..d4e3e94c 100644 --- a/doc/module_file.html +++ b/doc/module_file.html @@ -263,7 +263,8 @@ label (key) and search parameters (value).

A search label is a string betw ], "options": { "matchall": true, - "maxdepth": 3 + "maxdepth": 3, + "decompress": true } } } @@ -341,7 +342,10 @@ single file search, you should probably consider breaking it down into smaller searches, or running the search locally instead of through MIG.

  • returnsha256 instructs the agent to return the SHA256 hash for any matched files. The client will display the hash with the file information in the result. As an example, this option can be used to do basic file -integrity monitoring across actions.

  • 2   Search algorithm

    FM traverse a directory tree starting from a root path and until no search are +integrity monitoring across actions.

  • decompress tells the agent to decompress gzipped files prior to +inspecting content or calculating hashes. Note that if the decompress flag +is set for one search, all searches will involve a test for file +decompression.

  • 2   Search algorithm

    FM traverse a directory tree starting from a root path and until no search are longer active. FM traverses a given path only once, regardless of the number of searches that are being performed. When FM enters a directory, it activates searches that apply to the directory, and deactivates the ones that don't. diff --git a/modules/file/doc.rst b/modules/file/doc.rst index 4027a821..71a90e1a 100644 --- a/modules/file/doc.rst +++ b/modules/file/doc.rst @@ -55,7 +55,8 @@ A search must have at least one search path. ], "options": { "matchall": true, - "maxdepth": 3 + "maxdepth": 3, + "decompress": true } } } @@ -214,6 +215,11 @@ Several options can be applied to a search: in the result. As an example, this option can be used to do basic file integrity monitoring across actions. +* **decompress** tells the agent to decompress gzipped files prior to + inspecting content or calculating hashes. Note that if the decompress flag + is set for one search, all searches will involve a test for file + decompression. + Search algorithm ---------------- diff --git a/modules/file/file.go b/modules/file/file.go index 0f0b0c4f..4598a508 100644 --- a/modules/file/file.go +++ b/modules/file/file.go @@ -7,7 +7,7 @@ /* The file module provides functions to scan a file system. It can look into files using regexes. It can search files by name. It can match hashes in md5, sha1, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384 and sha3_512. -The filesystem can be searches using pattern, as described in the Parameters +The filesystem can be searched using patterns, as described in the Parameters documentation at http://mig.mozilla.org/doc/module_file.html . */ package file /* import "mig.ninja/mig/modules/file" */ @@ -33,9 +33,12 @@ import ( "golang.org/x/crypto/sha3" "mig.ninja/mig/modules" + + "compress/gzip" ) var debug bool = false +var tryDecompress bool = false func debugprint(format string, a ...interface{}) { if debug { @@ -98,6 +101,7 @@ type options struct { MatchLimit float64 `json:"matchlimit"` Debug string `json:"debug,omitempty"` ReturnSHA256 bool `json:"returnsha256,omitempty"` + Decompress bool `json:"decompress,omitempty"` } type checkType uint64 @@ -514,6 +518,11 @@ func (r *run) ValidateParameters() (err error) { return } } + if s.Options.Decompress { + tryDecompress = true + } else { + tryDecompress = false + } } return } @@ -934,6 +943,57 @@ func followSymLink(link string) (mode os.FileMode, path string, err error) { return } +type fileEntry struct { + filename string + fd *os.File + compRdr io.Reader +} + +func (f *fileEntry) Close() { + f.fd.Close() +} + +// getReader returns an appropriate reader for the file being checked. +// This is done by checking whether the file is compressed or not +func (f *fileEntry) getReader() io.Reader { + var ( + err error + ) + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("getReader() -> %v", err) + } + }() + f.fd, err = os.Open(f.filename) + if err != nil { + stats.Openfailed++ + panic(err) + } + if tryDecompress != true { + return f.fd + } + magic := make([]byte, 2) + n, err := f.fd.Read(magic) + if err != nil { + panic(err) + } + if n != 2 { + return f.fd + } + _, err = f.fd.Seek(0, 0) + if err != nil { + panic(err) + } + if magic[0] == 0x1f && magic[1] == 0x8b { + f.compRdr, err = gzip.NewReader(f.fd) + if err != nil { + panic(err) + } + return f.compRdr + } + return f.fd +} + // evaluateFile takes a single file and applies searches to it func (r *run) evaluateFile(file string) (err error) { var activeSearches []string @@ -990,16 +1050,17 @@ func (r *run) evaluateFile(file string) (err error) { // Second pass: Enter all content & hash checks across all searches. // Only perform the searches that are active. // Optimize to only read a file once per check type - r.checkContent(file) - r.checkHash(file, checkMD5) - r.checkHash(file, checkSHA1) - r.checkHash(file, checkSHA256) - r.checkHash(file, checkSHA384) - r.checkHash(file, checkSHA512) - r.checkHash(file, checkSHA3_224) - r.checkHash(file, checkSHA3_256) - r.checkHash(file, checkSHA3_384) - r.checkHash(file, checkSHA3_512) + f := fileEntry{filename: file} + r.checkContent(f) + r.checkHash(f, checkMD5) + r.checkHash(f, checkSHA1) + r.checkHash(f, checkSHA256) + r.checkHash(f, checkSHA384) + r.checkHash(f, checkSHA512) + r.checkHash(f, checkSHA3_224) + r.checkHash(f, checkSHA3_256) + r.checkHash(f, checkSHA3_384) + r.checkHash(f, checkSHA3_512) return } @@ -1151,10 +1212,9 @@ func (s search) checkMtime(file string, fi os.FileInfo) (matchedall bool) { return } -func (r *run) checkContent(file string) { +func (r *run) checkContent(f fileEntry) { var ( err error - fd *os.File ) defer func() { if e := recover(); e != nil { @@ -1184,14 +1244,10 @@ func (r *run) checkContent(file string) { if !continuereadingfile { return } - fd, err = os.Open(file) - if err != nil { - stats.Openfailed++ - panic(err) - } - defer fd.Close() // iterate over the file content - scanner := bufio.NewScanner(fd) + reader := f.getReader() + defer f.Close() + scanner := bufio.NewScanner(reader) for scanner.Scan() { if err := scanner.Err(); err != nil { panic(err) @@ -1246,7 +1302,7 @@ func (r *run) checkContent(file string) { debugprint("checkContent: [pass] must match any line and current line matched. regex='%s', line='%s'\n", c.value, scanner.Text()) if c.wantThis(true) { - c.storeMatch(file) + c.storeMatch(f.filename) } } } else { @@ -1255,7 +1311,7 @@ func (r *run) checkContent(file string) { c.value, scanner.Text()) macroalstatus[label] = false if c.wantThis(true) { - c.storeMatch(file) + c.storeMatch(f.filename) } } else { debugprint("checkContent: [fail] must not match at least one line but current line matched. regex='%s', line='%s'\n", @@ -1280,7 +1336,7 @@ func (r *run) checkContent(file string) { c.value, scanner.Text()) macroalstatus[label] = false if c.wantThis(false) { - c.storeMatch(file) + c.storeMatch(f.filename) } } else { debugprint("checkContent: [fail] much match any line and current line didn't match. regex='%s', line='%s'\n", @@ -1309,7 +1365,7 @@ func (r *run) checkContent(file string) { // 1. if MACROAL is set and the search succeeded, store the file in each content check if search.Options.Macroal && macroalstatus[label] { debugprint("checkContent: macroal is set and search label '%s' passed on file '%s'\n", - label, file) + label, f.filename) // we match all content regexes on all lines of the file, // as requested via the Macroal flag // now store the filename in all checks @@ -1318,7 +1374,7 @@ func (r *run) checkContent(file string) { continue } if c.wantThis(checksstatus[label][i]) { - c.storeMatch(file) + c.storeMatch(f.filename) } search.checks[i] = c } @@ -1332,9 +1388,9 @@ func (r *run) checkContent(file string) { } if !checksstatus[label][i] && c.inversematch { debugprint("in search '%s' on file '%s', check '%s' has not matched and is set to inversematch, record this as a positive result\n", - label, file, c.value) + label, f.filename, c.value) if c.wantThis(checksstatus[label][i]) { - c.storeMatch(file) + c.storeMatch(f.filename) } // adjust check status to true because the check did in fact match as an inverse checksstatus[label][i] = true @@ -1350,7 +1406,7 @@ func (r *run) checkContent(file string) { // check hasn't matched, or has matched and we didn't want it to, deactivate the search if !checksstatus[label][i] || (checksstatus[label][i] && c.inversematch) { if c.wantThis(checksstatus[label][i]) { - c.storeMatch(file) + c.storeMatch(f.filename) search.checks[i] = c } search.deactivate() @@ -1362,7 +1418,7 @@ func (r *run) checkContent(file string) { return } -func (r *run) checkHash(file string, hashtype checkType) { +func (r *run) checkHash(f fileEntry, hashtype checkType) { var ( err error ) @@ -1382,7 +1438,7 @@ func (r *run) checkHash(file string, hashtype checkType) { if nothingToDo { return } - hash, err := getHash(file, hashtype) + hash, err := getHash(f, hashtype) if err != nil { panic(err) } @@ -1395,10 +1451,10 @@ func (r *run) checkHash(file string, hashtype checkType) { match := false if c.value == hash { match = true - debugprint("checkHash: file '%s' matches checksum '%s'\n", file, c.value) + debugprint("checkHash: file '%s' matches checksum '%s'\n", f.filename, c.value) } if c.wantThis(match) { - c.storeMatch(file) + c.storeMatch(f.filename) } else if search.Options.MatchAll { search.deactivate() } @@ -1411,19 +1467,15 @@ func (r *run) checkHash(file string, hashtype checkType) { } // getHash calculates the hash of a file. -func getHash(file string, hashType checkType) (hexhash string, err error) { +func getHash(f fileEntry, hashType checkType) (hexhash string, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("getHash() -> %v", e) } }() - fd, err := os.Open(file) - if err != nil { - stats.Openfailed++ - panic(err) - } - defer fd.Close() - debugprint("getHash: computing hash for '%s'\n", fd.Name()) + reader := f.getReader() + defer f.Close() + debugprint("getHash: computing hash for '%s'\n", f.fd.Name()) var h hash.Hash switch hashType { case checkMD5: @@ -1449,9 +1501,8 @@ func getHash(file string, hashType checkType) (hexhash string, err error) { panic(err) } buf := make([]byte, 4096) - var offset int64 = 0 for { - block, err := fd.ReadAt(buf, offset) + block, err := reader.Read(buf) if err != nil && err != io.EOF { panic(err) } @@ -1459,7 +1510,6 @@ func getHash(file string, hashType checkType) (hexhash string, err error) { break } h.Write(buf[:block]) - offset += int64(block) } hexhash = fmt.Sprintf("%X", h.Sum(nil)) return @@ -1554,7 +1604,8 @@ func (r *run) buildResults(t0 time.Time) (resStr string, err error) { mf.FileInfo.Mode = fi.Mode().String() mf.FileInfo.Mtime = fi.ModTime().UTC().String() if search.Options.ReturnSHA256 { - mf.FileInfo.SHA256, err = getHash(mf.File, checkSHA256) + f := fileEntry{filename: mf.File} + mf.FileInfo.SHA256, err = getHash(f, checkSHA256) if err != nil { panic(err) } diff --git a/modules/file/file_test.go b/modules/file/file_test.go index 60d41077..64037fb0 100644 --- a/modules/file/file_test.go +++ b/modules/file/file_test.go @@ -102,6 +102,48 @@ func TestContentSearch(t *testing.T) { } } +func TestDecompressedContentSearch(t *testing.T) { + for _, tp := range TESTDATA { + var ( + r run + s search + ) + var expectedfiles = []string{ + basedir + "/" + tp.name, + basedir + subdirs + tp.name, + } + // testfile8 is a corrupt gzip and should fail to decompress + if tp.name == "testfile8" { + expectedfiles = []string{""} + } + r.Parameters = *newParameters() + s.Paths = append(s.Paths, basedir) + if tp.decompressedcontent != "" { + s.Contents = append(s.Contents, tp.decompressedcontent) + } else { + s.Contents = append(s.Contents, tp.content) + } + s.Contents = append(s.Contents, "!^FOOBAR$") + s.Options.MatchAll = true + s.Options.Decompress = true + r.Parameters.Searches["s1"] = s + msg, err := modules.MakeMessage(modules.MsgClassParameters, r.Parameters) + if err != nil { + t.Fatal(err) + } + t.Logf("%s\n", msg) + out := r.Run(bytes.NewBuffer(msg)) + if len(out) == 0 { + t.Fatal("run failed") + } + t.Log(out) + err = evalResults([]byte(out), expectedfiles) + if err != nil { + t.Fatal(err) + } + } +} + func TestSize(t *testing.T) { for _, tp := range TESTDATA { var ( @@ -241,6 +283,46 @@ func TestHashes(t *testing.T) { } } +func TestDecompressedHash(t *testing.T) { + for _, tp := range TESTDATA { + var ( + r run + s search + ) + var expectedfiles = []string{ + basedir + "/" + tp.name, + basedir + subdirs + tp.name, + } + // testfile8 is a corrupt gzip and should fail to decompress + if tp.name == "testfile8" { + expectedfiles = []string{""} + } + r.Parameters = *newParameters() + s.Paths = append(s.Paths, basedir) + if tp.decompressedmd5 != "" { + s.MD5 = append(s.MD5, tp.decompressedmd5) + } else { + s.MD5 = append(s.MD5, tp.md5) + } + s.Options.Decompress = true + r.Parameters.Searches["s1"] = s + msg, err := modules.MakeMessage(modules.MsgClassParameters, r.Parameters) + if err != nil { + t.Fatal(err) + } + t.Logf("%s\n", msg) + out := r.Run(bytes.NewBuffer(msg)) + if len(out) == 0 { + t.Fatal("run failed") + } + t.Log(out) + err = evalResults([]byte(out), expectedfiles) + if err != nil { + t.Fatal(err) + } + } +} + func TestAllHashes(t *testing.T) { for _, tp := range TESTDATA { var ( @@ -387,7 +469,7 @@ type mismatchtest struct { func TestMismatch(t *testing.T) { var MismatchTestCases = []mismatchtest{ mismatchtest{ - desc: "want files that don't match name '^testfile0' with maxdepth=1, should find testfile1, 2, 3, 4 & 5", + desc: "want files that don't match name '^testfile0' with maxdepth=1, should find testfile1, 2, 3, 4, 5, 6, 7 & 8", search: search{ Paths: []string{basedir}, Names: []string{"^" + TESTDATA[0].name + "$"}, @@ -401,10 +483,13 @@ func TestMismatch(t *testing.T) { basedir + "/" + TESTDATA[2].name, basedir + "/" + TESTDATA[3].name, basedir + "/" + TESTDATA[4].name, - basedir + "/" + TESTDATA[5].name}, + basedir + "/" + TESTDATA[5].name, + basedir + "/" + TESTDATA[6].name, + basedir + "/" + TESTDATA[7].name, + basedir + "/" + TESTDATA[8].name}, }, mismatchtest{ - desc: "want files that don't have a size of 190 bytes or larger than 10{k,m,g,t} or smaller than 10 bytes, should find testfile1, 2 & 3", + desc: "want files that don't have a size of 190 bytes or larger than 10{k,m,g,t} or smaller than 10 bytes, should find testfile1, 2, 3, 4, 5, 6, 7 & 8", search: search{ Paths: []string{basedir}, Sizes: []string{"190", ">10k", ">10m", ">10g", ">10t", "<10"}, @@ -419,7 +504,10 @@ func TestMismatch(t *testing.T) { basedir + "/" + TESTDATA[2].name, basedir + "/" + TESTDATA[3].name, basedir + "/" + TESTDATA[4].name, - basedir + "/" + TESTDATA[5].name}, + basedir + "/" + TESTDATA[5].name, + basedir + "/" + TESTDATA[6].name, + basedir + "/" + TESTDATA[7].name, + basedir + "/" + TESTDATA[8].name}, }, mismatchtest{ desc: "want files that have not been modified in the last hour ago, should find nothing", @@ -473,7 +561,7 @@ func TestMismatch(t *testing.T) { basedir + subdirs + TESTDATA[1].name}, }, mismatchtest{ - desc: "want files that don't match the hashes of testfile2, should find testfile0, 1, 3, 4, & 5", + desc: "want files that don't match the hashes of testfile2, should find testfile0, 1, 3, 4, 5, 6, 7 & 8", search: search{ Paths: []string{basedir}, MD5: []string{TESTDATA[2].md5}, @@ -491,7 +579,10 @@ func TestMismatch(t *testing.T) { basedir + "/" + TESTDATA[1].name, basedir + "/" + TESTDATA[3].name, basedir + "/" + TESTDATA[4].name, - basedir + "/" + TESTDATA[5].name}, + basedir + "/" + TESTDATA[5].name, + basedir + "/" + TESTDATA[6].name, + basedir + "/" + TESTDATA[7].name, + basedir + "/" + TESTDATA[8].name}, }, } @@ -543,6 +634,7 @@ func TestParamsParser(t *testing.T) { args = append(args, "-matchlimit", "10") args = append(args, "-maxdepth", "2") args = append(args, "-verbose") + args = append(args, "-decompress") t.Logf("%s\n", args) _, err = r.ParamsParser(args) if err != nil { @@ -633,7 +725,8 @@ const subdirs string = `/a/b/c/d/e/f/g/h/i/j/k/l/m/n/` type testParams struct { data []byte name, size, mode, mtime, content, - md5, sha1, sha2, sha3 string + md5, sha1, sha2, sha3, + decompressedcontent, decompressedmd5 string } var TESTDATA = []testParams{ @@ -787,4 +880,77 @@ some other text`), sha2: `8871b2ff047be05571549398e54c1f36163ae171e05a89900468688ea3bac4f9f3d7c922f0bebc24fdac28d0b2d38fb2718209fb5976c9245e7c837170b79819`, sha3: `cb086f02b728d57e299651f89e1fb0f89c659db50c7c780ec2689a8143e55c8e5e63ab47fe20897be7155e409151c190`, }, + testParams{ + data: []byte("\x1f\x8b\x08\x08\xd9\xdc\x88\x56\x00\x03\x74\x65\x73\x74\x00\x8d" + + "\x8e\xcd\x0a\xc3\x30\x0c\x83\xef\x79\x0a\xc1\xae\xf3\x43\x65\xad" + + "\x4a\x0c\x49\x1c\x1a\xb3\xbf\xa7\x5f\x96\xb2\x4b\x4f\x33\x42\x18" + + "\xf3\x49\x58\x44\x90\x18\x57\xee\xd8\x6c\xc7\x5b\x5b\xe3\x8a\x4d" + + "\x33\x21\x22\xe1\x02\x4f\xda\x31\x14\xb1\x58\x29\xac\x1e\xf0\xdf" + + "\x8c\x6c\xbc\xd9\x9d\x33\x5c\x91\xb5\xf2\xdb\x9b\x47\xfd\x43\x3d" + + "\xa1\xb7\xb8\xb0\x87\x13\xc6\xd2\xfc\x35\xe1\x2b\xaa\xfd\xa0\x6e" + + "\x85\x70\x3e\xfd\xd8\xcc\xd3\xf8\xf7\xf0\x79\xfd\x00\x4c\x08\xa4" + + "\x7a\xc6\x00\x00\x00"), + name: `testfile6`, + size: `133`, + mode: `-rw-r--r--`, + mtime: `<1m`, + content: `KO3B`, + md5: `31d38eee231318166538e1569631aba9`, + sha1: `bd1f24d8cbb000bbf7bcd618c2aec73280388721`, + sha2: `bb4e449df74edae0292d60d2733a3b1801d90ae23560484b1e04fb52f111a14f`, + sha3: `433b84f162d1b00481e6da022c5738fb4d04c3bb4317f73266746dd1`, + decompressedcontent: `^--- header for zipped file ---$`, + decompressedmd5: `5bb23d3b1eaaddc6e108e3fb0ee80a61`, + }, + testParams{ + data: []byte("\x1f\x8b\x08\x00\xd9\xe3\x8f\x56\x00\x03\xed\xd4\xcb\x6a\x84\x30" + + "\x14\x06\x60\xd7\xf3\x14\x07\xba\xad\x60\xe2\xed\x09\xfa\x02\x5d" + + "\x14\xba\x4c\xf5\x0c\x86\x6a\x22\xe6\xf4\xfa\xf4\x8d\xce\x74\x28" + + "\x03\x65\xba\xb1\x45\xfa\x7f\x44\x22\x7a\x12\x43\xf0\x8f\x70\x90" + + "\xbd\xed\x59\x25\xeb\xc9\xa2\xaa\x2a\xe6\x5e\xd5\x65\xf6\xb5\x5f" + + "\xe4\xaa\x4c\x94\xae\x8a\xbc\xae\x54\xa1\x55\x92\x29\xad\xeb\x2c" + + "\xa1\x6c\xc5\x35\x9d\x3c\x05\x31\x13\x51\xf2\x68\x43\xe7\xa7\xef" + + "\xeb\x2e\xbd\xdf\xa8\x34\x4d\xa9\x63\xd3\xf2\x44\x7b\x1f\x2f\x3b" + + "\x05\xa1\x77\x3b\x8e\xdc\xd2\xfc\x5f\x50\x2c\xd8\x5d\x91\x74\x36" + + "\x50\x6c\x86\x1a\x3f\x0c\xec\x64\x47\x3f\x13\xc7\x9a\x07\xff\xcc" + + "\xcb\x60\x47\xbd\x75\x3c\xcf\xdb\xc7\xe9\x5f\xac\x74\x14\x46\xd3" + + "\x70\xd8\x9d\x95\xf1\x30\xca\xdb\x52\x7c\x4d\xce\x7f\x16\x05\x3f" + + "\x30\x09\xbf\xca\xe1\xce\x4b\x17\x57\x3d\x19\xd7\xfa\xe1\xf0\xf8" + + "\xaf\x37\x73\x83\xe4\x98\x7f\xbd\xe2\x37\x2e\xe6\x5f\xe7\xa7\xfc" + + "\x97\xc5\x31\xff\x39\xf2\xff\x1b\xce\xf2\x1f\xb8\xf1\xae\xdd\xd4" + + "\x01\x70\x77\x73\x7b\x8f\x53\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + "\x00\x00\x00\x00\x00\x00\x00\xfe\xaf\x0f\x60\x69\x1f\x15\x00\x28" + + "\x00\x00"), + name: `testfile7`, + size: `274`, + mode: `-rw-r--r--`, + mtime: `<1m`, + content: `t6Pl`, + md5: `52fa96013b5c6aa9302d39ee7fe2f6a5`, + sha1: `31952c0d2772c302ec94b303c2b80b67cf830060`, + sha2: `f6032dc9b4ba112397a6f8bcb778ab10708c1acd38e48f637ace15c3ae417ded`, + sha3: `3f4dacf0b2347d0a0ab6f09b7d7c98fd12cb2030d4af8baeacaf55a9`, + decompressedcontent: `ustar`, + decompressedmd5: `7f82b4c1613fd10208ad1f71de17ebb5`, + }, + testParams{ + data: []byte("\x1f\x8b\x08\x08\x2c\xe8\x8f\x56\x00\x03\x74\x65\x73\x74\x66\x69" + + "\x6c\x65\x33\x00\x8d\x8e\x4b\x0a\x03\x31\x0c\x43\xf7\x73\x0a\x41" + + "\xb7\xf5\xa1\xd2\x19\x0d\x09\x24\x71\x48\xdc\xef\xe9\xeb\xa6\xcc" + + "\xa6\xab\x1a\x81\x6c\x78\x12\x16\x11\x44\x86\x8d\x1d\xbb\x76\xac" + + "\xda\xfb\xb5\x19\x37\xbc\x52\x6b\x00\x00\xca\x84\x88\x2c\x27\x58" + + "\x4c\x03\xae\xe0\x54\x29\xac\xb6\xe0\xbf\xf1\x6c\xb8\xe8\x8d\x33" + + "\x5c\x91\x53\xe5\xa7\x37\x7b\xfd\x3d\x59\xc4\x68\x61\xe5\x58\x7e" + + "\x30\x96\x66\xcf\x09\x9f\x51\xf5\x80\x86\x16\xc2\xf8\xb0\xef\xa6" + + "\x16\xfd\xf3\x79\xbf\x01\x7b\xae\xde\x84\xca\x00\x00\x00"), + name: `testfile8`, + size: `142`, + mode: `-rw-r--r--`, + mtime: `<1m`, + content: `,'XL`, + md5: `df7b577ceb59f700d5b03db9d12d174e`, + sha1: `ea033d30e996ac443bc50e9c37eb25b37505302e`, + sha2: `2f4f81c0920501f178085032cd2784b8aa811b8c8e94da7ff85a43a361cd96cc`, + sha3: `d171566f8026a4ca6b4cdf8e6491a651625f98fbc15f9cb601833b64`, + }, } diff --git a/modules/file/paramscreator.go b/modules/file/paramscreator.go index 202bc71d..49c23025 100644 --- a/modules/file/paramscreator.go +++ b/modules/file/paramscreator.go @@ -76,6 +76,8 @@ Options is reached. %sreturnsha256 - include sha256 hash for matched files. ex: %sreturnsha256 +%sdecompress - decompress file before inspection + ex: %sdecompress Module documentation is at http://mig.mozilla.org/doc/module_file.html Cheatsheet and examples are at http://mig.mozilla.org/doc/cheatsheet.rst.html @@ -100,6 +102,7 @@ func (r *run) ParamsCreator() (interface{}, error) { search.Options.MatchAll = true search.Options.MaxDepth = 1000 search.Options.MatchLimit = 1000 + search.Options.Decompress = false for { fmt.Println("Give a name to this search, or 'done' to exit") fmt.Printf("label> ") @@ -347,6 +350,12 @@ func (r *run) ParamsCreator() (interface{}, error) { continue } search.Options.MatchLimit = v + case "decompress": + if checkValue != "" { + fmt.Println("This option doesn't take arguments, try again") + continue + } + search.Options.Decompress = true default: fmt.Printf("Invalid method!\n") continue @@ -369,9 +378,9 @@ func (r *run) ParamsParser(args []string) (interface{}, error) { err error paths, names, sizes, modes, mtimes, contents, md5s, sha1s, sha2s, sha3s, mismatch flagParam - maxdepth, matchlimit float64 - returnsha256, matchall, matchany, macroal, verbose bool - fs flag.FlagSet + maxdepth, matchlimit float64 + returnsha256, matchall, matchany, macroal, verbose, decompress bool + fs flag.FlagSet ) if len(args) < 1 || args[0] == "" || args[0] == "help" { printHelp(true) @@ -396,6 +405,7 @@ func (r *run) ParamsParser(args []string) (interface{}, error) { fs.BoolVar(¯oal, "macroal", false, "see help") fs.BoolVar(&debug, "verbose", false, "see help") fs.BoolVar(&returnsha256, "returnsha256", false, "see help") + fs.BoolVar(&decompress, "decompress", false, "see help") err = fs.Parse(args) if err != nil { return nil, err @@ -417,6 +427,7 @@ func (r *run) ParamsParser(args []string) (interface{}, error) { s.Options.Mismatch = mismatch s.Options.MatchAll = matchall s.Options.ReturnSHA256 = returnsha256 + s.Options.Decompress = decompress if matchany { s.Options.MatchAll = false }