diff --git a/config/config.go b/config/config.go index 5fdc5cf..4b4fd05 100644 --- a/config/config.go +++ b/config/config.go @@ -49,10 +49,12 @@ const ( KernelModule ArtifactType = iota // KernelExploit is the privilege escalation exploit KernelExploit + // Script for information gathering or automation + Script ) func (at ArtifactType) String() string { - return [...]string{"module", "exploit"}[at] + return [...]string{"module", "exploit", "script"}[at] } // UnmarshalTOML is for support github.com/naoina/toml @@ -63,6 +65,8 @@ func (at *ArtifactType) UnmarshalTOML(data []byte) (err error) { *at = KernelModule } else if strings.Contains(stypelower, "exploit") { *at = KernelExploit + } else if strings.Contains(stypelower, "script") { + *at = Script } else { err = fmt.Errorf("Type %s is unsupported", stype) } @@ -77,6 +81,8 @@ func (at ArtifactType) MarshalTOML() (data []byte, err error) { s = "module" case KernelExploit: s = "exploit" + case Script: + s = "script" default: err = fmt.Errorf("Cannot marshal %d", at) } @@ -129,6 +135,8 @@ type Artifact struct { SourcePath string SupportedKernels []KernelMask + Script string + Qemu struct { Cpus int Memory int diff --git a/debug.go b/debug.go index 52fa23f..3dcd3a2 100644 --- a/debug.go +++ b/debug.go @@ -170,20 +170,29 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) { return } - buildDir, outFile, output, err := build(tmp, ka, ki, g.Config.Docker.Timeout.Duration) - if err != nil { - log.Print(err, output) - return - } + var buildDir, outFile, output, remoteFile string - remoteFile := "/tmp/exploit" - if ka.Type == config.KernelModule { - remoteFile = "/tmp/module.ko" - } + if ka.Type == config.Script { + err = q.CopyFile("root", ka.Script, ka.Script) + if err != nil { + return + } + } else { + buildDir, outFile, output, err = build(tmp, ka, ki, g.Config.Docker.Timeout.Duration) + if err != nil { + log.Print(err, output) + return + } - err = q.CopyFile("user", outFile, remoteFile) - if err != nil { - return + remoteFile = "/tmp/exploit" + if ka.Type == config.KernelModule { + remoteFile = "/tmp/module.ko" + } + + err = q.CopyFile("user", outFile, remoteFile) + if err != nil { + return + } } // Copy all test files to the remote machine diff --git a/examples/script/.out-of-tree.toml b/examples/script/.out-of-tree.toml new file mode 100644 index 0000000..813ffa0 --- /dev/null +++ b/examples/script/.out-of-tree.toml @@ -0,0 +1,11 @@ +# out-of-tree configuration file +# docs at https://out-of-tree.io +name = "out-of-tree script example" +type = "script" + +script = "script.sh" + +[[supported_kernels]] +distro_type = "Ubuntu" +distro_release = "22.04" +release_mask = ".*" diff --git a/examples/script/README.md b/examples/script/README.md new file mode 100644 index 0000000..db0d8f1 --- /dev/null +++ b/examples/script/README.md @@ -0,0 +1,3 @@ +# out-of-tree script example + +See .out-of-tree.toml diff --git a/examples/script/script.sh b/examples/script/script.sh new file mode 100644 index 0000000..a1475fc --- /dev/null +++ b/examples/script/script.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +uname -a + +ls /proc | grep config diff --git a/pew.go b/pew.go index 5695329..2c68c4f 100644 --- a/pew.go +++ b/pew.go @@ -266,6 +266,10 @@ func build(tmp string, ka config.Artifact, ki config.KernelInfo, return } +func runScript(q *qemu.System, script string) (output string, err error) { + return q.Command("root", script) +} + func testKernelModule(q *qemu.System, ka config.Artifact, test string) (output string, err error) { @@ -300,12 +304,16 @@ func testKernelExploit(q *qemu.System, ka config.Artifact, func genOkFail(name string, ok bool) (aurv aurora.Value) { state.Overall += 1 + s := " " + name + if name == "" { + s = "" + } if ok { state.Success += 1 - s := " " + name + " SUCCESS " + s += " SUCCESS " aurv = aurora.BgGreen(aurora.Black(s)) } else { - s := " " + name + " FAILURE " + s += " FAILURE " aurv = aurora.BgRed(aurora.White(aurora.Bold(s))) } return @@ -347,15 +355,19 @@ func dumpResult(q *qemu.System, ka config.Artifact, ki config.KernelInfo, ki.DistroRelease, ki.KernelRelease) colored := "" - if ka.Type == config.KernelExploit { + switch ka.Type { + case config.KernelExploit: colored = aurora.Sprintf("[*] %40s: %s %s", distroInfo, genOkFail("BUILD", res.Build.Ok), genOkFail("LPE", res.Test.Ok)) - } else { + case config.KernelModule: colored = aurora.Sprintf("[*] %40s: %s %s %s", distroInfo, genOkFail("BUILD", res.Build.Ok), genOkFail("INSMOD", res.Run.Ok), genOkFail("TEST", res.Test.Ok)) + case config.Script: + colored = aurora.Sprintf("[*] %40s: %s", distroInfo, + genOkFail("", res.Test.Ok)) } additional := "" @@ -398,6 +410,20 @@ func dumpResult(q *qemu.System, ka config.Artifact, ki config.KernelInfo, func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka config.Artifact, res *phasesResult, remoteTest string) (err error) { + // Copy all test files to the remote machine + for _, f := range ka.TestFiles { + if f.Local[0] != '/' { + if res.BuildDir != "" { + f.Local = res.BuildDir + "/" + f.Local + } + } + err = q.CopyFile(f.User, f.Local, f.Remote) + if err != nil { + slog.Error().Err(err).Msg("copy test file") + return + } + } + switch ka.Type { case config.KernelModule: res.Run.Output, err = q.CopyAndInsmod(res.BuildArtifact) @@ -407,18 +433,6 @@ func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka config.Artifact } res.Run.Ok = true - // Copy all test files to the remote machine - for _, f := range ka.TestFiles { - if f.Local[0] != '/' { - f.Local = res.BuildDir + "/" + f.Local - } - err = q.CopyFile(f.User, f.Local, f.Remote) - if err != nil { - slog.Error().Err(err).Msg("copy test file") - return - } - } - res.Test.Output, err = testKernelModule(q, ka, remoteTest) if err != nil { slog.Error().Err(err).Msg(res.Test.Output) @@ -440,6 +454,15 @@ func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka config.Artifact } res.Run.Ok = true // does not really used res.Test.Ok = true + case config.Script: + res.Test.Output, err = runScript(q, remoteTest) + if err != nil { + slog.Error().Err(err).Msg(res.Test.Output) + return + } + slog.Info().Msg(res.Test.Output) + res.Run.Ok = true + res.Test.Ok = true default: slog.Fatal().Msg("Unsupported artifact type") } @@ -568,7 +591,10 @@ func testArtifact(swg *sizedwaitgroup.SizedWaitGroup, ka config.Artifact, result := phasesResult{} defer dumpResult(q, ka, ki, &result, dist, tag, binaryPath, db) - if binaryPath == "" { + if ka.Type == config.Script { + result.Build.Ok = true + testPath = ka.Script + } else if binaryPath == "" { // TODO: build should return structure start := time.Now() result.BuildDir, result.BuildArtifact, result.Build.Output, err =