Skip to content

Unqualified PowerShell invocation enables local executable hijacking and scanner-result forgery #7

Closed

Description

@okba14

Summary

At commit be33c6e3b8625644817c2e52f88ecb6a7e479fdf, the Windows host module invokes PowerShell using the unqualified name powershell:

  • scan/adint_scan/modules/host.py:62-64
  • scan/adint_scan/modules/host.py:129-146
_PS = ["powershell", "-NoProfile", "-NonInteractive",
       "-ExecutionPolicy", "Bypass", "-Command"]

subprocess.run(_PS + [cmd], ...)

On Windows, an executable name without a directory component is resolved through the Windows executable search order, including the current directory. A local attacker who can place or control a powershell.exe in a searched location can therefore execute it when Zero Breach performs its Windows checks.

Evidence

A native Windows fixture named powershell.exe was placed in a temporary current directory. The following call executed the fixture rather than the system PowerShell:

subprocess.run([
    "powershell", "-NoProfile", "-NonInteractive",
    "-Command", "Write-Output fixture"
])

Observed result:

rc=0
stdout='[]\n'
marker=FAKE_POWERSHELL_WINDOWS

The project source also places the host checks inside no_network(), while scan/adint_scan/netguard.py:13-15 explicitly states that subprocesses are not blocked. In a separate safe integration harness using the real host.run() path, a replacement executable returned synthetic DNS JSON and caused:

status=HITS
hit_count=2
synthetic_ioc_in_result=True
guard_attempts=[]

The synthetic indicator was not present in any local artifact; it was supplied only by the replacement executable. No external network connection, real IOC, or user data was used.

Impact

This allows a local attacker who controls a searched executable location to run arbitrary code with the scanner's user privileges and falsify scan results. The replacement process can also perform network activity outside the Python no_network() guard.

The impact is normally limited to the scanner user's privileges. It is higher if the scanner is run as Administrator or by an elevated automated service. This report does not claim remote exploitation or privilege escalation.

Suggested fix

Resolve PowerShell to a trusted absolute path under %SystemRoot%\System32 and verify that it is local and expected before execution. Alternatively, replace these PowerShell calls with native Windows APIs. If a trusted executable cannot be resolved, report the affected checks as UNKNOWN rather than continuing with an unverified executable.

References

Activity

  1. interplains commented on Oct 20, 2026

    @interplains
    Owner

    Confirmed — thank you for the detailed report and the proof-of-concept.

    You're right on both points. powershell was invoked by bare name, so Windows could resolve a planted powershell.exe from the current directory before System32, and because the tool asks users to run from their Downloads folder that directory is user-writable. The forged-results consequence you demonstrated through the real host.run() path follows directly from it.

    Fix in #8: the interpreter is pinned to its absolute System32 path (never resolved through the search order), and the host checks now run in a controlled working directory so the child cannot inherit a hostile CWD either. Regression tests assert the path is absolute. It will go out in the next signed release.

    Credited to you in the commit and PR. Thanks again for the clear write-up.

  2. okba14 commented on Oct 20, 2026

    @okba14
    Author

    Thank you for confirming the issue and for preparing the fix.

    I appreciate the absolute System32 path, the controlled working directory, and the regression tests covering the executable resolution behavior.

    I will verify the fix once the next signed release is available. Thank you also for the credit.

  3. interplains commented on Oct 20, 2026

    @interplains
    Owner

    @okba14 The fix is now released in v0.1.7: https://github.com/interplains/zero-breach/releases/tag/v0.1.7

    The release is signed; SHA256SUMS.txt and its signature are attached, so you can verify zero-breach.py (SHA-256 9431426a940a3a9bdea617017030e0fa7b155693c3b2d25d97960d1eb262ae4e). PowerShell is now resolved by its absolute System32 path and runs in a controlled working directory.

    Thank you again for the clear report and proof-of-concept. You are credited for this finding in the v0.1.7 release notes.

  4. added 2 commits that reference this issue on Oct 20, 2026
  5. okba14 commented on Oct 20, 2026

    @okba14
    Author

    Thank you for releasing v0.1.7 and for crediting my report.

    I verified the signed artifact and tested it on Windows with a native powershell.exe placed in the current directory.
    Result:

    PowerShell used:
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
    
    Controlled working directory:
    C:\WINDOWS
    
    Hostile powershell.exe executed:
    false
    The fix works and prevents the reported CWD hijacking.
    One minor note: --version reports 0.1.6 (single-file build) although the artifact is from the v0.1.7 release.
    Thank you again for the quick fix and the credit.
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions