2018-11-25 14:46:29 +00:00
|
|
|
// Copyright 2018 Mikhail Klementev. All rights reserved.
|
|
|
|
// Use of this source code is governed by a AGPLv3 license
|
|
|
|
// (or later) that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-06-10 18:50:30 +00:00
|
|
|
"gopkg.in/logrusorgru/aurora.v1"
|
2019-02-02 21:24:29 +00:00
|
|
|
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/config"
|
|
|
|
"code.dumpstack.io/tools/out-of-tree/qemu"
|
2018-11-25 14:46:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func firstSupported(kcfg config.KernelConfig, ka config.Artifact,
|
|
|
|
kernel string) (ki config.KernelInfo, err error) {
|
|
|
|
|
|
|
|
km, err := kernelMask(kernel)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ka.SupportedKernels = []config.KernelMask{km}
|
|
|
|
|
|
|
|
for _, ki = range kcfg.Kernels {
|
|
|
|
var supported bool
|
|
|
|
supported, err = ka.Supported(ki)
|
|
|
|
if err != nil || supported {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = errors.New("No supported kernel found")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-08-17 09:05:06 +00:00
|
|
|
func handleLine(q *qemu.System) (err error) {
|
2018-11-25 14:46:29 +00:00
|
|
|
fmt.Print("out-of-tree> ")
|
|
|
|
rawLine := "help"
|
|
|
|
fmt.Scanf("%s", &rawLine)
|
|
|
|
params := strings.Fields(rawLine)
|
|
|
|
cmd := params[0]
|
|
|
|
|
|
|
|
switch cmd {
|
|
|
|
case "h", "help":
|
|
|
|
fmt.Printf("help\t: print this help message\n")
|
|
|
|
fmt.Printf("log\t: print qemu log\n")
|
|
|
|
fmt.Printf("clog\t: print qemu log and cleanup buffer\n")
|
|
|
|
fmt.Printf("cleanup\t: cleanup qemu log buffer\n")
|
|
|
|
fmt.Printf("ssh\t: print arguments to ssh command\n")
|
|
|
|
fmt.Printf("quit\t: quit\n")
|
|
|
|
case "l", "log":
|
|
|
|
fmt.Println(string(q.Stdout))
|
|
|
|
case "cl", "clog":
|
|
|
|
fmt.Println(string(q.Stdout))
|
|
|
|
q.Stdout = []byte{}
|
|
|
|
case "c", "cleanup":
|
|
|
|
q.Stdout = []byte{}
|
|
|
|
case "s", "ssh":
|
2019-08-17 09:05:06 +00:00
|
|
|
fmt.Println(q.GetSSHCommand())
|
2018-11-25 14:46:29 +00:00
|
|
|
case "q", "quit":
|
|
|
|
return errors.New("end of session")
|
|
|
|
default:
|
|
|
|
fmt.Println("No such command")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-08-17 09:05:06 +00:00
|
|
|
func interactive(q *qemu.System) (err error) {
|
2018-11-25 14:46:29 +00:00
|
|
|
for {
|
|
|
|
err = handleLine(q)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-25 14:53:56 +00:00
|
|
|
func debugHandler(kcfg config.KernelConfig, workPath, kernRegex, gdb string,
|
2019-08-16 05:25:16 +00:00
|
|
|
dockerTimeout time.Duration, kaslr, smep, smap bool) (err error) {
|
2018-11-25 14:46:29 +00:00
|
|
|
|
|
|
|
ka, err := config.ReadArtifactConfig(workPath + "/.out-of-tree.toml")
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ka.SourcePath == "" {
|
|
|
|
ka.SourcePath = workPath
|
|
|
|
}
|
|
|
|
|
|
|
|
ki, err := firstSupported(kcfg, ka, kernRegex)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
kernel := qemu.Kernel{KernelPath: ki.KernelPath, InitrdPath: ki.InitrdPath}
|
2019-08-17 09:05:06 +00:00
|
|
|
q, err := qemu.NewSystem(qemu.X86x64, kernel, ki.RootFS)
|
2018-11-25 14:46:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-08-16 05:25:16 +00:00
|
|
|
|
|
|
|
q.SetKASLR(kaslr)
|
|
|
|
q.SetSMEP(smep)
|
|
|
|
q.SetSMAP(smap)
|
|
|
|
|
|
|
|
redgreen := func(name string, enabled bool) aurora.Value {
|
|
|
|
if enabled {
|
|
|
|
return aurora.BgGreen(aurora.Black(name))
|
|
|
|
}
|
|
|
|
|
2019-08-16 05:34:10 +00:00
|
|
|
return aurora.BgRed(aurora.Gray(name))
|
2019-08-16 05:25:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("[*] %s %s %s\n", redgreen("KASLR", kaslr),
|
|
|
|
redgreen("SMEP", smep), redgreen("SMAP", smap))
|
|
|
|
|
2018-11-25 14:53:56 +00:00
|
|
|
q.Debug(gdb)
|
2018-11-25 14:46:29 +00:00
|
|
|
coloredGdbAddress := aurora.BgGreen(aurora.Black(gdb))
|
|
|
|
fmt.Printf("[*] gdb runned on %s\n", coloredGdbAddress)
|
|
|
|
|
|
|
|
err = q.Start()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer q.Stop()
|
|
|
|
|
|
|
|
tmp, err := ioutil.TempDir("/tmp/", "out-of-tree_")
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmp)
|
|
|
|
|
|
|
|
outFile, output, err := build(tmp, ka, ki, dockerTimeout)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err, output)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-08-16 05:38:25 +00:00
|
|
|
remoteFile := "/tmp/exploit"
|
2018-11-25 14:46:29 +00:00
|
|
|
if ka.Type == config.KernelModule {
|
2019-08-16 05:38:25 +00:00
|
|
|
remoteFile = "/tmp/module.ko"
|
2018-11-25 14:46:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = q.CopyFile("user", outFile, remoteFile)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
coloredRemoteFile := aurora.BgGreen(aurora.Black(remoteFile))
|
|
|
|
fmt.Printf("[*] build result copied to %s\n", coloredRemoteFile)
|
|
|
|
|
2019-08-17 09:05:06 +00:00
|
|
|
fmt.Printf("\n%s\n", q.GetSSHCommand())
|
2019-08-16 05:34:10 +00:00
|
|
|
fmt.Printf("gdb %s -ex 'target remote %s'\n\n", ki.VmlinuxPath, gdb)
|
2019-08-16 05:25:16 +00:00
|
|
|
|
2019-08-16 06:32:26 +00:00
|
|
|
// TODO set substitute-path /build/.../linux-... /path/to/linux-source
|
|
|
|
|
2018-11-25 14:46:29 +00:00
|
|
|
err = interactive(q)
|
|
|
|
return
|
|
|
|
}
|