Skip to content

Commit

Permalink
(fix) error when chrome is not available using chromedp driver
Browse files Browse the repository at this point in the history
fixes #245
  • Loading branch information
leonjza committed Oct 10, 2024
1 parent 1824997 commit 216c03d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 28 deletions.
15 changes: 14 additions & 1 deletion pkg/runner/driver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package runner

import "github.com/sensepost/gowitness/pkg/models"
import (
"fmt"

"github.com/sensepost/gowitness/pkg/models"
)

// ChromeNotFoundError signals that chrome is not available
type ChromeNotFoundError struct {
Err error
}

func (e ChromeNotFoundError) Error() string {
return fmt.Sprintf("chrome not found: %v", e.Err)
}

// Driver is the interface browser drivers will implement.
type Driver interface {
Expand Down
17 changes: 15 additions & 2 deletions pkg/runner/drivers/chromedp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"image"
"log/slog"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
Expand Down Expand Up @@ -117,7 +119,7 @@ func NewChromedp(logger *slog.Logger, opts runner.Options) (*Chromedp, error) {

// witness does the work of probing a url.
// This is where everything comes together as far as the runner is concerned.
func (run *Chromedp) Witness(target string, runner *runner.Runner) (*models.Result, error) {
func (run *Chromedp) Witness(target string, thisRunner *runner.Runner) (*models.Result, error) {
logger := run.log.With("target", target)
logger.Debug("witnessing 👀")

Expand All @@ -143,6 +145,17 @@ func (run *Chromedp) Witness(target string, runner *runner.Runner) (*models.Resu
defer navigationCancel()

if err := chromedp.Run(navigationCtx, network.Enable()); err != nil {
// check if the error is chrome not found related, in which case
// well return a special error type.
//
// this may seem like a strange place to do that, but keep in mind
// this is only really where we'll actually *run* chrome for the
// first time.
var execErr *exec.Error
if errors.As(err, &execErr) && execErr.Err == exec.ErrNotFound {
return nil, &runner.ChromeNotFoundError{Err: err}
}

return nil, fmt.Errorf("error enabling network tracking: %w", err)
}

Expand Down Expand Up @@ -389,7 +402,7 @@ func (run *Chromedp) Witness(target string, runner *runner.Runner) (*models.Resu
}

// fingerprint technologies in the first response
if fingerprints := runner.Wappalyzer.Fingerprint(result.HeaderMap(), []byte(result.HTML)); fingerprints != nil {
if fingerprints := thisRunner.Wappalyzer.Fingerprint(result.HeaderMap(), []byte(result.HTML)); fingerprints != nil {
for tech := range fingerprints {
result.Technologies = append(result.Technologies, models.Technology{
Value: tech,
Expand Down
78 changes: 53 additions & 25 deletions pkg/runner/runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package runner

import (
"context"
"errors"
"log/slog"
"net/url"
Expand Down Expand Up @@ -28,6 +29,10 @@ type Runner struct {
// Targets to scan.
// This would typically be fed from a gowitness/pkg/reader.
Targets chan string

// in case we need to bail
ctx context.Context
cancel context.CancelFunc
}

// New gets a new Runner ready for probing.
Expand Down Expand Up @@ -66,13 +71,17 @@ func NewRunner(logger *slog.Logger, driver Driver, opts Options, writers []write
return nil, err
}

ctx, cancel := context.WithCancel(context.Background())

return &Runner{
Driver: driver,
Wappalyzer: wap,
options: opts,
writers: writers,
Targets: make(chan string),
log: logger,
ctx: ctx,
cancel: cancel,
}, nil
}

Expand Down Expand Up @@ -113,39 +122,58 @@ func (run *Runner) Run() {
// start a worker
go func() {
defer wg.Done()
for target := range run.Targets {
// validate the target
if err := run.checkUrl(target); err != nil {
if run.options.Logging.LogScanErrors {
run.log.Error("invalid target to scan", "target", target, "err", err)
for {
select {
case <-run.ctx.Done():
return
case target, ok := <-run.Targets:
if !ok {
return
}
continue
}

result, err := run.Driver.Witness(target, run)
if err != nil {
if run.options.Logging.LogScanErrors {
run.log.Error("failed to witness target", "target", target, "err", err)
// validate the target
if err := run.checkUrl(target); err != nil {
if run.options.Logging.LogScanErrors {
run.log.Error("invalid target to scan", "target", target, "err", err)
}
continue
}
continue
}

// assume that status code 0 means there was no information, so
// don't send anything to writers.
if result.ResponseCode == 0 {
if run.options.Logging.LogScanErrors {
run.log.Error("failed to witness target, status code was 0", "target", target)
result, err := run.Driver.Witness(target, run)
if err != nil {
// is this a chrome not found error?
var chromeErr *ChromeNotFoundError
if errors.As(err, &chromeErr) {
run.log.Error("no valid chrome intallation found", "err", err)
run.cancel()
return
}

if run.options.Logging.LogScanErrors {
run.log.Error("failed to witness target", "target", target, "err", err)
}
continue
}
continue
}

if err := run.runWriters(result); err != nil {
run.log.Error("failed to write result for target", "target", target, "err", err)
}
// assume that status code 0 means there was no information, so
// don't send anything to writers.
if result.ResponseCode == 0 {
if run.options.Logging.LogScanErrors {
run.log.Error("failed to witness target, status code was 0", "target", target)
}
continue
}

if err := run.runWriters(result); err != nil {
run.log.Error("failed to write result for target", "target", target, "err", err)
}

run.log.Info("result 🤖", "target", target, "status-code", result.ResponseCode,
"title", result.Title, "have-screenshot", !result.Failed)
run.log.Info("result 🤖", "target", target, "status-code", result.ResponseCode,
"title", result.Title, "have-screenshot", !result.Failed)

}
}

}()
}

Expand Down

0 comments on commit 216c03d

Please sign in to comment.