diff --git a/framework.go b/framework.go index ea02fc3..51f83f3 100644 --- a/framework.go +++ b/framework.go @@ -71,6 +71,7 @@ import ( "sync/atomic" "time" + "github.com/Masterminds/semver" "github.com/vulncheck-oss/go-exploit/c2" "github.com/vulncheck-oss/go-exploit/c2/channel" "github.com/vulncheck-oss/go-exploit/cli" @@ -428,6 +429,27 @@ func StoreVersion(conf *config.Config, version string) { db.UpdateVerified(conf.Product, true, version, conf.Rhost, conf.Rport) } +// Compare a version to a semantic version constraint using the [Masterminds semver constraints](https://github.com/Masterminds/semver?tab=readme-ov-file#checking-version-constraints). +// Provide a version string and a constraint and if the semver is within the constraint a boolean +// response of whether the version is constrained or not will occur. Any errors from the constraint +// or version will propagate through the framework errors and the value will be false. +func CheckSemVer(version string, constraint string) bool { + c, err := semver.NewConstraint(constraint) + if err != nil { + output.PrintfFrameworkError("Invalid constraint: %s", err.Error()) + + return false + } + v, err := semver.NewVersion(version) + if err != nil { + output.PrintfFrameworkError("Invalid version: %s", err.Error()) + + return false + } + + return c.Check(v) +} + // modify godebug to re-enable old cipher suites that were removed in 1.22. This does have implications for our // client fingerprint, and we should consider how to improve/fix that in the future. We also should be respectful // of other disabling this feature, so we will check for it before re-enabling it. diff --git a/framework_test.go b/framework_test.go new file mode 100644 index 0000000..0c79c48 --- /dev/null +++ b/framework_test.go @@ -0,0 +1,34 @@ +package exploit_test + +import ( + "testing" + + "github.com/vulncheck-oss/go-exploit" +) + +func TestCheckSemVer_Full(t *testing.T) { + if !exploit.CheckSemVer("1.0.0", "<= 1.0.0") { + t.Error("Constraint should have passed") + } + if exploit.CheckSemVer("1.0.0", "> 1.0.0") { + t.Error("Constraint should not have passed") + } +} + +func TestCheckSemVer_BadVersion(t *testing.T) { + if exploit.CheckSemVer("uwu", "<= 1.0.0") { + t.Error("Version was invalid, should not have passed") + } + if exploit.CheckSemVer("1.0.0 ", "<= 1.0.0") { + t.Error("Version was invalid, should not have passed") + } +} + +func TestCheckSemVer_BadConstraint(t *testing.T) { + if exploit.CheckSemVer("1.0.0", "<== 1.0.0") { + t.Error("Constraint was invalid, should not have passed") + } + if exploit.CheckSemVer("1.0.0", "xp") { + t.Error("Constraint was invalid, should not have passed") + } +} diff --git a/go.mod b/go.mod index 023522b..16b33de 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + github.com/Masterminds/semver v1.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 28329c7..c3320b9 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=