shadow1ng/fscan · error

local_pe_not_specified

Error message

local_pe_not_specified

What it means

WinBITSPlugin.Scan requires a local PE file path from session.Config.WinPEFile because the BITS-based persistence technique uploads/executes a local executable. When the config field is empty, Scan immediately returns a failed Result with the localized message for key "local_pe_not_specified". It is a configuration-validation failure, not a runtime fault.

Source

Thrown at plugins/local/winbits.go:29

	"strings"

	"github.com/shadow1ng/fscan/common"
	"github.com/shadow1ng/fscan/common/i18n"
	"github.com/shadow1ng/fscan/plugins"
)

type WinBITSPlugin struct {
	plugins.BasePlugin
}

func NewWinBITSPlugin() *WinBITSPlugin {
	return &WinBITSPlugin{BasePlugin: plugins.NewBasePlugin("winbits")}
}

func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
	pePath := session.Config.WinPEFile
	if pePath == "" {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
	}
	if _, err := os.Stat(pePath); err != nil {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
	}

	absPath, _ := filepath.Abs(pePath)
	baseName := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))
	jobName := fmt.Sprintf("WindowsUpdate_%s", baseName)

	var output strings.Builder

	// 创建任务并提取 GUID
	out, err := exec.Command("bitsadmin", "/create", "/download", jobName).CombinedOutput()
	if err != nil {
		output.WriteString(i18n.Tr("winbits_create_task_failed", strings.TrimSpace(string(out))) + "\n")
		return &plugins.Result{Success: false, Output: output.String()}
	}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Set the WinPEFile value in the scan config (the CLI flag/config key that populates session.Config.WinPEFile) before enabling winbits.
  2. Verify the config file/profile actually contains that key and that it's under the correct section.
  3. If running programmatically, populate session.Config.WinPEFile with an absolute path to a valid PE before calling Scan.
  4. Check the tool's current usage docs in case the option name changed in your version.

Example fix

// before
session.Config.WinPEFile == ""  // -> local_pe_not_specified
// after (programmatic)
session.Config.WinPEFile = "C:\\tools\\payload.exe"
// CLI equivalent:
//   <tool> --winpe-file C:\tools\payload.exe --plugin winbits
Defensive patterns

Strategy: validation

Validate before calling

// Validate config before invoking the plugin
if session.Config.WinPEFile == "" {
    return errors.New("winbits requires --winpe-file / session.Config.WinPEFile to be set")
}

Try / catch

result := plugin.Scan(ctx, host, session)
if result != nil && !result.Success && result.Error.Error() == i18n.GetText("local_pe_not_specified") {
    // print usage hint: supply the local PE path option
}

Prevention

When it happens

Trigger: Scan is invoked while session.Config.WinPEFile == "" — i.e., the winbits plugin was enabled without setting the local PE file option.

Common situations: User enabled the winbits module but forgot the corresponding flag/config key (e.g., --winpe-file), config file loaded from the wrong profile, or the field name changed between tool versions so the old key is silently ignored.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/5d4fc96022073d76. Report an issue: GitHub.