Skip to content

fix(implant): services list panics on nil error on Windows (#1989)#2249

Merged
moloch-- merged 1 commit intoBishopFox:masterfrom
Moriz82:fix/services-windows-nil-deref
Apr 22, 2026
Merged

fix(implant): services list panics on nil error on Windows (#1989)#2249
moloch-- merged 1 commit intoBishopFox:masterfrom
Moriz82:fix/services-windows-nil-deref

Conversation

@Moriz82
Copy link
Copy Markdown
Contributor

@Moriz82 Moriz82 commented Apr 21, 2026

Bug

Running services against a Windows beacon can kill the beacon with a nil pointer deref. The implant panics and the session dies.

Cause

servicesListHandler in implant/sliver/handlers/handlers_windows.go calls err.Error() with no nil check:

serviceInfo, err := service.ListServices(servicesReq.Hostname)
servicesResp := &sliverpb.Services{
    Details:  serviceInfo,
    Error:    err.Error(),   // nil deref when err == nil
    Response: &commonpb.Response{},
}

ListServices returns (list, nil) when every service reads without error. Calling .Error() on nil → 0xc0000005, process exits.

Fix

Add the nil guard. One helper, one check:

func buildServicesResp(details []*sliverpb.ServiceDetails, err error) *sliverpb.Services {
    errStr := ""
    if err != nil {
        errStr = err.Error()
    }
    return &sliverpb.Services{
        Details:  details,
        Error:    errStr,
        Response: &commonpb.Response{},
    }
}

Why it doesn't repro easily

A beacon running as a normal user hits access-denied on a bunch of services during openService / Config() / Query(). Those failures get collected into serviceErrors and ListServices returns a non-nil error — so the buggy err.Error() call is safe. That's why most operators never see this crash.

The bug only fires when every service reads cleanly (no errors at all). On modern Win10/11 that's hard to hit even as SYSTEM because services like WaaSMedicSvc are PPL-protected and will fail for anyone. But it's not impossible — older Windows versions, stripped-down VMs, or just the right host config hits it and the beacon dies.

Reproducing it deliberately

To force the code path, add one line to ListServices (implant/sliver/service/service_windows.go, near line 195):

operationError = nil // REPRO: force nil error to exercise the bug path

Then build sliver-server, generate a Windows beacon, run it on any Win VM, and call services — the unpatched beacon panics, the patched beacon returns results normally.

Fixes #1989

@Moriz82 Moriz82 requested a review from a team as a code owner April 21, 2026 00:49
@Moriz82 Moriz82 requested a review from dvargas-bishop April 21, 2026 00:49
@Moriz82 Moriz82 force-pushed the fix/services-windows-nil-deref branch from 9d617c7 to 2cb9891 Compare April 21, 2026 01:03
servicesListHandler called err.Error() unconditionally after
service.ListServices(). On a healthy Windows host ListServices returns
nil error, causing a nil pointer dereference that crashed the implant.

serviceDetailHandler in the same file already guards correctly with
if err != nil. Apply the same pattern to servicesListHandler by
extracting response construction into a buildServicesResp helper with
a proper nil check.

Verified on Windows 11 VM: unfixed helper panics with "runtime error:
invalid memory address or nil pointer dereference" on the nil-error
path; fixed helper passes.

Fixes BishopFox#1989
@Moriz82 Moriz82 force-pushed the fix/services-windows-nil-deref branch from 2cb9891 to f83dc42 Compare April 21, 2026 01:13
@moloch-- moloch-- merged commit e2a009d into BishopFox:master Apr 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows services command crashes implant

2 participants