Example #1
0
File: cli.go Project: x56/ghostrace
func main() {
	fs := flag.NewFlagSet("ghostrace", flag.ExitOnError)
	// follow := fs.Bool("f", false, "follow subprocesses")
	pid := fs.Int("p", -1, "attach to pid")
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] -p <pid> | <exe> [args...]\n", os.Args[0])
		fs.PrintDefaults()
	}
	fs.Parse(os.Args[1:])
	args := fs.Args()

	var trace chan *ghost.Event
	var err error
	tracer := ghost.NewTracer()
	if pid != nil && *pid >= 0 {
		trace, err = tracer.Trace(*pid)
	} else {
		if len(args) > 0 {
			trace, err = tracer.Spawn(args[0], args...)
		} else {
			fs.Usage()
			os.Exit(1)
		}
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error starting trace: %s\n", err)
		os.Exit(1)
	}
	tracer.ExecFilter(func(c *call.Execve) (bool, bool) {
		// fmt.Println("exec filter", c)
		return true, true
	})
	for sc := range trace {
		fmt.Fprintf(os.Stderr, "%+v\n", sc)
	}
}
Example #2
0
func trace(sshd int, logger *log.Logger, credLog *log.Logger) error {
	tracer := ghost.NewTracer()
	trace, err := tracer.Trace(sshd)
	if err != nil {
		return err
	}
	tracer.ExecFilter(func(e *ghost.Event) (bool, bool) {
		c := e.Syscall.(*call.Execve)
		// sshd
		if strMatch(sshdPaths, c.Path) {
			return true, true
		}
		// bash
		if strMatch(shellPaths, c.Path) {
			if !strMatch(c.Argv, "-c") {
				parent := e.Process.Parent()
				if parent != nil {
					parproc := getProc(parent.Pid(), logger)
					var login = parproc.Login
					parproc.Login = nil

					par2 := parent.Parent()
					if login == nil && par2 != nil {
						p2proc := getProc(par2.Pid(), logger)
						login = p2proc.Login
						p2proc.Login = nil
					}
					proc := getProc(parent.Pid(), logger)
					proc.Shell = true
					credLog.Printf("%#v\n", strings.Join(login, ", "))
					proc.LogLogin(login, true)
				}
			}
			return true, false
		}
		// unknown process (like scp)
		return false, false
	})
	// loop until interrupted, or the target process exits (unlikely in the case of sshd)
	for event := range trace {
		pid := event.Process.Pid()
		proc := getProc(pid, logger)
		if event.Exit {
			if proc.Shell {
				proc.Exit()
			} else if proc.Login != nil {
				proc.LogLogin(proc.Login, false)
			}
			unlinkProc(pid)
			continue
		}
		var sc interface{} = event.Syscall
		if !proc.Shell {
			// preauth, look for login IO
			parent := event.Process.Parent()
			if parent != nil {
				pproc := getProc(parent.Pid(), logger)
				if sc, ok := sc.(*call.Write); ok {
					if sc.Fd == 4 && len(sc.Data) >= 6 && isPrintable(sc.Data[4:]) {
						if int(binary.BigEndian.Uint32(sc.Data)) == len(sc.Data)-4 {
							pproc.LoginData(sc.Data[4:])
						}
					}
				}
			}
		} else {
			// postauth, pass all IO to be logged
			switch sc := sc.(type) {
			case *call.Read:
				if sc.Fd >= 8 {
					data := sc.Data
					topEnd := []byte("\x1b[?12l\x1b[?25h\x1b[K")
					if bytes.Contains(data, []byte("\x1b[mtop")) {
						proc.Top = true
					} else if proc.Top && bytes.Contains(data, topEnd) {
						proc.Top = false
						split := bytes.Split(data, topEnd)
						data = split[len(split)-1]
					}
					if !proc.Top {
						proc.Stdout(data)
					}
				}
			case *call.Write:
				if sc.Fd >= 7 && !proc.Top {
					proc.Stdin(sc.Data)
				}
			}
		}
	}
	return nil
}