From 258281ca5f6f931c02e89b432d9033d933854323 Mon Sep 17 00:00:00 2001 From: breadchris Date: Sun, 19 Dec 2021 00:56:38 -0500 Subject: [PATCH] testing the jar patcher by loading findings file and then looking at discovered files --- tools/log4shell/commands/patch.go | 113 ++++++++++++++++++++++++++ tools/log4shell/main.go | 44 ++-------- tools/log4shell/patch/archivepatch.go | 15 ++++ tools/log4shell/scan/scanfile.go | 12 ++- 4 files changed, 146 insertions(+), 38 deletions(-) create mode 100644 tools/log4shell/commands/patch.go create mode 100644 tools/log4shell/patch/archivepatch.go diff --git a/tools/log4shell/commands/patch.go b/tools/log4shell/commands/patch.go new file mode 100644 index 000000000..1a3721bc9 --- /dev/null +++ b/tools/log4shell/commands/patch.go @@ -0,0 +1,113 @@ +// Copyright 2021 by LunaSec (owned by Refinery Labs, Inc) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package commands + +import ( + "archive/zip" + "encoding/json" + "github.com/lunasec-io/lunasec/tools/log4shell/types" + "github.com/lunasec-io/lunasec/tools/log4shell/util" + "github.com/rs/zerolog/log" + "github.com/urfave/cli/v2" + "io/fs" + "io/ioutil" + "os" +) + +func JavaArchivePatchCommand(c *cli.Context, globalBoolFlags map[string]bool) error { + enableGlobalFlags(c, globalBoolFlags) + + findingsFile := c.String("findings") + + findingsContent, err := ioutil.ReadFile(findingsFile) + if err != nil { + log.Error(). + Err(err). + Str("findings", findingsFile). + Msg("Unable to open and read findings file") + return err + } + + var findings types.FindingsOutput + err = json.Unmarshal(findingsContent, &findings) + if err != nil { + log.Error(). + Err(err). + Str("findings", findingsFile). + Msg("Unable to unmarshal findings file") + return err + } + + for _, finding := range findings.VulnerableLibraries { + var file *os.File + + file, err = os.Open(finding.Path) + if err != nil { + log.Warn(). + Str("path", finding.Path). + Err(err). + Msg("unable to open findings archive") + return err + } + defer file.Close() + + info, _ := os.Stat(finding.Path) + + var zipReader *zip.Reader + + zipReader, err = zip.NewReader(file, info.Size()) + if err != nil { + log.Warn(). + Str("path", finding.Path). + Err(err). + Msg("unable to open archive for patching") + return err + } + + var zipFile fs.File + + zipFile, err = zipReader.Open(finding.FileName) + if err != nil { + log.Warn(). + Str("path", finding.Path). + Err(err). + Msg("unable to open file from zip") + return err + } + + var zipFileHash string + + zipFileHash, err = util.HexEncodedSha256FromReader(zipFile) + if err != nil { + log.Warn(). + Str("path", finding.Path). + Str("p", finding.Path). + Err(err). + Msg("unable to hash zip file") + return err + } + + if zipFileHash != finding.Hash { + log.Warn(). + Str("path", finding.Path). + Str("p", finding.Path). + Err(err). + Msg("hashes do not match, not deleting") + return nil + } + } + + return nil +} diff --git a/tools/log4shell/main.go b/tools/log4shell/main.go index e6d7d100e..c75de92af 100644 --- a/tools/log4shell/main.go +++ b/tools/log4shell/main.go @@ -43,38 +43,6 @@ func enableGlobalFlags(c *cli.Context) { } } -func jarPatchCommand(c *cli.Context) error { - enableGlobalFlags(c) - - fileName := c.String("file-name") - - if fileName == "" { - log.Info().Msg("Public IP not provided. Binding to the local network interface.") - panic("must specify a valid file name to patch") - } - - file, err := os.Open(path) - if err != nil { - log.Warn(). - Str("path", path). - Err(err). - Msg("unable to open archive") - panic("unable to open specified file") - } - - fileInfo, err := file.Stat() - - if err != nil { - panic("unable to read file info") - } - - findings := scan.SearchArchiveForVulnerableFiles(fileName, file, fileInfo.Size(), false) - - // TODO: Do something with these findings to actually patch them in-place. Either that or add the patching to `SearchArchiveForVulnerableFiles` above. - - return nil -} - func main() { zerolog.TimeFieldFormat = zerolog.TimeFormatUnix @@ -213,16 +181,18 @@ func main() { }, }, { - Name: "patch-local-jar", + Name: "patch", Aliases: []string{"s"}, - Usage: "Patches a specified JAR or WAR file against log4shell by injecting a fixed version of the vulnerable code into vulnerable log4j instances found within it.", + Usage: "Patches findings of libraries vulnerable toLog4Shell by removing the JndiLookup.class file from each.", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "file-name", - Usage: "Patches the specified file (must be a valid JAR or WAR file).", + Name: "findings", + Usage: "Patches all vulnerable Java archives which have been identified.", }, }, - Action: jarPatchCommand, + Action: func(c *cli.Context) error { + return commands.JavaArchivePatchCommand(c, globalBoolFlags) + }, }, }, } diff --git a/tools/log4shell/patch/archivepatch.go b/tools/log4shell/patch/archivepatch.go new file mode 100644 index 000000000..3e85df338 --- /dev/null +++ b/tools/log4shell/patch/archivepatch.go @@ -0,0 +1,15 @@ +// Copyright 2021 by LunaSec (owned by Refinery Labs, Inc) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package patch diff --git a/tools/log4shell/scan/scanfile.go b/tools/log4shell/scan/scanfile.go index 0843736f9..4fe056db8 100644 --- a/tools/log4shell/scan/scanfile.go +++ b/tools/log4shell/scan/scanfile.go @@ -20,6 +20,7 @@ import ( "github.com/lunasec-io/lunasec/tools/log4shell/util" "github.com/rs/zerolog/log" "io" + "path/filepath" "strings" ) @@ -66,8 +67,17 @@ func identifyPotentiallyVulnerableFile(reader io.Reader, path, fileName string, Str("cve", vulnerableFile.CVE). Msg("Identified vulnerable path") + absolutePath, err := filepath.Abs(path) + if err != nil { + log.Warn(). + Str("fileName", fileName). + Str("path", path). + Err(err). + Msg("Unable to resolve absolute path to file") + } + finding = &types.Finding{ - Path: path, + Path: absolutePath, FileName: fileName, Hash: fileHash, Version: vulnerableFile.Version,