Skip to content

Commit

Permalink
fix patch detection
Browse files Browse the repository at this point in the history
  • Loading branch information
1lann committed Dec 11, 2021
1 parent 7476eb2 commit ae6491d
Showing 1 changed file with 116 additions and 16 deletions.
132 changes: 116 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package main

import (
"archive/zip"
"bytes"
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"path"
"path/filepath"
"strings"
"sync"
Expand Down Expand Up @@ -40,7 +44,7 @@ func main() {
}

if !f.IsDir() {
checkJar(target)
checkJar(target, nil, 0, 0)
return
}

Expand All @@ -51,7 +55,8 @@ func main() {
if filepath.Ext(osPathname) == ".jar" {
pool <- struct{}{}
go func() {
checkJar(osPathname)
status, desc := checkJar(osPathname, nil, 0, 0)
printStatus(osPathname, status, desc)
<-pool
}()
}
Expand All @@ -73,18 +78,42 @@ func main() {
}
}

func checkJar(pathToFile string) {
func checkJar(pathToFile string, rd io.ReaderAt, size int64, depth int) (status Status, desc string) {
if depth > 100 {
status = StatusUnknown
desc = "reached recursion limit of 100 (why do you have so many jars in jars???)"
return
}

err := func() error {
rd, err := zip.OpenReader(pathToFile)
if rd == nil {
f, err := os.Open(pathToFile)
if err != nil {
return err
}
defer f.Close()

stat, err := f.Stat()
if err != nil {
return err
}

size = stat.Size()
rd = f
}

zipRd, err := zip.NewReader(rd, size)
if err != nil {
return err
}

var vulnClassFound = false
var patchedClassFound = false
var maybeClassFound = ""
var worstSubStatus Status = StatusOK
var worstDesc string

for _, file := range rd.File {
for _, file := range zipRd.File {
if strings.HasSuffix(file.Name, "log4j/core/lookup/JndiLookup.class") {
vulnClassFound = true
}
Expand All @@ -93,42 +122,113 @@ func checkJar(pathToFile string) {
maybeClassFound = file.Name
}

if strings.HasSuffix(file.Name, "log4j/core/lookup/JndiRestrictedLookup.class") {
patchedClassFound = true
if strings.HasSuffix(file.Name, "log4j/core/appender/mom/JmsAppender$Builder.class") {
err := func() error {
if file.UncompressedSize64 > 1024*1024 {
return errors.New("JmsAppender is too big??")
}

subRd, err := file.Open()
if err != nil {
return err
}
defer subRd.Close()

data, err := io.ReadAll(subRd)
if err != nil {
return err
}

if bytes.Contains(data, []byte("allowedLdapHosts")) {
patchedClassFound = true
}

return nil
}()
if err != nil {
log.Printf("error reading %q: %v", file.Name, err)
}
}

if path.Ext(file.Name) == ".jar" {
var subStatus Status
var subDesc string
if file.UncompressedSize64 > 500*1024*1024 {
subStatus = StatusUnknown
subDesc = fmt.Sprintf("embedded jar file %q is too large (> 500 MB)", file.Name)
} else {
err := func() error {
subRd, err := file.Open()
if err != nil {
return err
}

defer subRd.Close()

buf := bytes.NewBuffer(make([]byte, 0, file.UncompressedSize64))
_, err = buf.ReadFrom(subRd)
if err != nil {
return err
}

subStatus, subDesc = checkJar(pathToFile, bytes.NewReader(buf.Bytes()), int64(buf.Len()), depth+1)
return nil
}()
if err != nil {
subStatus = StatusUnknown
subDesc = fmt.Sprintf("error while checking embedded jar file %q: %v", file.Name, err)
}
}

if subStatus > worstSubStatus {
worstSubStatus = subStatus
worstDesc = subDesc
}
}
}

if !vulnClassFound {
if maybeClassFound != "" {
printStatus(pathToFile, StatusMaybe, maybeClassFound)
status = StatusMaybe
desc = maybeClassFound
} else {
printStatus(pathToFile, StatusOK, "")
status = StatusOK
desc = ""
}
} else if patchedClassFound {
printStatus(pathToFile, StatusPatched, "")
status = StatusPatched
desc = ""
} else {
printStatus(pathToFile, StatusVulnerable, "")
status = StatusVulnerable
desc = ""
}

if worstSubStatus > status {
status = worstSubStatus
desc = worstDesc
}

return nil
}()
if err != nil {
printStatus(pathToFile, StatusUnknown, err.Error())
return
status = StatusUnknown
desc = err.Error()
}

return
}

type Status int

const (
StatusOK = iota
StatusVulnerable
StatusPatched
StatusMaybe
StatusUnknown
StatusMaybe
StatusVulnerable
)

func printStatus(fileName string, status int, desc string) {
func printStatus(fileName string, status Status, desc string) {
printMutex.Lock()
defer printMutex.Unlock()

Expand Down

0 comments on commit ae6491d

Please sign in to comment.