From e50612501781d12ed2bbc6c0b5f89918e6e9122d Mon Sep 17 00:00:00 2001 From: kurita0 <4556927+kurita0@users.noreply.github.com> Date: Tue, 28 Mar 2023 21:07:10 +0900 Subject: [PATCH] feat(wp): support csh, no sudo scan (#1523) Co-authored-by: MaineK00n --- config/config.go | 1 + config/config_windows.go | 1 + scanner/base.go | 93 +++++++++++++++++++++++++++++----------- subcmds/discover.go | 1 + 4 files changed, 72 insertions(+), 24 deletions(-) diff --git a/config/config.go b/config/config.go index 5c18b0b046..85f2baff72 100644 --- a/config/config.go +++ b/config/config.go @@ -278,6 +278,7 @@ type WordPressConf struct { OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"` DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"` CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"` + NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"` } // IsZero return whether this struct is not specified in config.toml diff --git a/config/config_windows.go b/config/config_windows.go index adce777957..a2865dd37a 100644 --- a/config/config_windows.go +++ b/config/config_windows.go @@ -276,6 +276,7 @@ type WordPressConf struct { OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"` DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"` CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"` + NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"` } // IsZero return whether this struct is not specified in config.toml diff --git a/scanner/base.go b/scanner/base.go index b75b786600..0d5da0bd10 100644 --- a/scanner/base.go +++ b/scanner/base.go @@ -817,20 +817,48 @@ func (d *DummyFileInfo) IsDir() bool { return false } // Sys is func (d *DummyFileInfo) Sys() interface{} { return nil } +func (l *base) buildWpCliCmd(wpCliArgs string, suppressStderr bool, shell string) string { + cmd := fmt.Sprintf("%s %s --path=%s", l.ServerInfo.WordPress.CmdPath, wpCliArgs, l.ServerInfo.WordPress.DocRoot) + if !l.ServerInfo.WordPress.NoSudo { + cmd = fmt.Sprintf("sudo -u %s -i -- %s --allow-root", l.ServerInfo.WordPress.OSUser, cmd) + } else if l.ServerInfo.User != l.ServerInfo.WordPress.OSUser { + cmd = fmt.Sprintf("su %s -c '%s'", l.ServerInfo.WordPress.OSUser, cmd) + } + + if suppressStderr { + switch shell { + case "csh", "tcsh": + cmd = fmt.Sprintf("( %s > /dev/tty ) >& /dev/null", cmd) + default: + cmd = fmt.Sprintf("%s 2>/dev/null", cmd) + } + } + return cmd +} + func (l *base) scanWordPress() error { if l.ServerInfo.WordPress.IsZero() || l.ServerInfo.Type == constant.ServerTypePseudo { return nil } + + shell, err := l.detectShell() + if err != nil { + return xerrors.Errorf("Failed to detect shell. err: %w", err) + } + l.log.Info("Scanning WordPress...") - cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root", - l.ServerInfo.WordPress.OSUser, - l.ServerInfo.WordPress.CmdPath, - l.ServerInfo.WordPress.DocRoot) + if l.ServerInfo.WordPress.NoSudo && l.ServerInfo.User != l.ServerInfo.WordPress.OSUser { + if r := l.exec(fmt.Sprintf("timeout 2 su %s -c exit", l.ServerInfo.WordPress.OSUser), noSudo); !r.isSuccess() { + return xerrors.New("Failed to switch user without password. err: please configure to switch users without password") + } + } + + cmd := l.buildWpCliCmd("core version", false, shell) if r := exec(l.ServerInfo, cmd, noSudo); !r.isSuccess() { return xerrors.Errorf("Failed to exec `%s`. Check the OS user, command path of wp-cli, DocRoot and permission: %#v", cmd, l.ServerInfo.WordPress) } - wp, err := l.detectWordPress() + wp, err := l.detectWordPress(shell) if err != nil { return xerrors.Errorf("Failed to scan wordpress: %w", err) } @@ -838,18 +866,44 @@ func (l *base) scanWordPress() error { return nil } -func (l *base) detectWordPress() (*models.WordPressPackages, error) { - ver, err := l.detectWpCore() +func (l *base) detectShell() (string, error) { + if r := l.exec("printenv SHELL", noSudo); r.isSuccess() { + if t := strings.TrimSpace(r.Stdout); t != "" { + return filepath.Base(t), nil + } + } + + if r := l.exec(fmt.Sprintf(`grep "^%s" /etc/passwd | awk -F: '/%s/ { print $7 }'`, l.ServerInfo.User, l.ServerInfo.User), noSudo); r.isSuccess() { + if t := strings.TrimSpace(r.Stdout); t != "" { + return filepath.Base(t), nil + } + } + + if isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) { + if r := l.exec("ps -p $$ | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() { + return strings.TrimSpace(r.Stdout), nil + } + + if r := l.exec("ps -p %self | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() { + return strings.TrimSpace(r.Stdout), nil + } + } + + return "", xerrors.New("shell cannot be determined") +} + +func (l *base) detectWordPress(shell string) (*models.WordPressPackages, error) { + ver, err := l.detectWpCore(shell) if err != nil { return nil, err } - themes, err := l.detectWpThemes() + themes, err := l.detectWpThemes(shell) if err != nil { return nil, err } - plugins, err := l.detectWpPlugins() + plugins, err := l.detectWpPlugins(shell) if err != nil { return nil, err } @@ -866,11 +920,8 @@ func (l *base) detectWordPress() (*models.WordPressPackages, error) { return &pkgs, nil } -func (l *base) detectWpCore() (string, error) { - cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root 2>/dev/null", - l.ServerInfo.WordPress.OSUser, - l.ServerInfo.WordPress.CmdPath, - l.ServerInfo.WordPress.DocRoot) +func (l *base) detectWpCore(shell string) (string, error) { + cmd := l.buildWpCliCmd("core version", true, shell) r := exec(l.ServerInfo, cmd, noSudo) if !r.isSuccess() { @@ -879,11 +930,8 @@ func (l *base) detectWpCore() (string, error) { return strings.TrimSpace(r.Stdout), nil } -func (l *base) detectWpThemes() ([]models.WpPackage, error) { - cmd := fmt.Sprintf("sudo -u %s -i -- %s theme list --path=%s --format=json --allow-root 2>/dev/null", - l.ServerInfo.WordPress.OSUser, - l.ServerInfo.WordPress.CmdPath, - l.ServerInfo.WordPress.DocRoot) +func (l *base) detectWpThemes(shell string) ([]models.WpPackage, error) { + cmd := l.buildWpCliCmd("theme list --format=json", true, shell) var themes []models.WpPackage r := exec(l.ServerInfo, cmd, noSudo) @@ -900,11 +948,8 @@ func (l *base) detectWpThemes() ([]models.WpPackage, error) { return themes, nil } -func (l *base) detectWpPlugins() ([]models.WpPackage, error) { - cmd := fmt.Sprintf("sudo -u %s -i -- %s plugin list --path=%s --format=json --allow-root 2>/dev/null", - l.ServerInfo.WordPress.OSUser, - l.ServerInfo.WordPress.CmdPath, - l.ServerInfo.WordPress.DocRoot) +func (l *base) detectWpPlugins(shell string) ([]models.WpPackage, error) { + cmd := l.buildWpCliCmd("plugin list --format=json", true, shell) var plugins []models.WpPackage r := exec(l.ServerInfo, cmd, noSudo) diff --git a/subcmds/discover.go b/subcmds/discover.go index 63da18f50f..5bec414a3c 100644 --- a/subcmds/discover.go +++ b/subcmds/discover.go @@ -240,6 +240,7 @@ host = "{{$ip}}" #cmdPath = "/usr/local/bin/wp" #osUser = "wordpress" #docRoot = "/path/to/DocumentRoot/" +#noSudo = false #[servers.{{index $names $i}}.portscan] #scannerBinPath = "/usr/bin/nmap"