roadmap edit

This commit is contained in:
2026-08-06 20:19:30 +03:00
parent 243ef303c5
commit 3b7d01c748
+39 -39
View File
@@ -7,9 +7,9 @@ Scope: winpwn is built for a local Windows-only CTF. The goal is to let a player
who understands an exploit technique (overflow, UAF, IOCTL abuse, token stealing) who understands an exploit technique (overflow, UAF, IOCTL abuse, token stealing)
work at that level instead of on WinAPI struct layouts and Go plumbing. work at that level instead of on WinAPI struct layouts and Go plumbing.
Legend: done · 🚧 partial · planned. Legend: [+] done · [+-] partial · [-] planned.
## Core ergonomics — ## Core ergonomics — [+]
- `Context` ([context.go](context.go)): `Arch` (x86/x64), `LogLevel`, `Timeout`, - `Context` ([context.go](context.go)): `Arch` (x86/x64), `LogLevel`, `Timeout`,
`Newline`. Note: `P16/P32/P64` are little-endian only and do not read `Newline`. Note: `P16/P32/P64` are little-endian only and do not read
@@ -29,7 +29,7 @@ Legend: ✅ done · 🚧 partial · ⬜ planned.
- Tube API ([tube.go](tube.go)): `Send*`/`Recv*`/`RecvRegex`/`RecvPred`/ - Tube API ([tube.go](tube.go)): `Send*`/`Recv*`/`RecvRegex`/`RecvPred`/
`Interactive`/`Close`. `Interactive`/`Close`.
## PE tooling — ## PE tooling — [+]
- Parsing ([pe.go](pe.go), [sections.go](sections.go)): `ImageBase`, - Parsing ([pe.go](pe.go), [sections.go](sections.go)): `ImageBase`,
`EntryPoint`, PE32 and PE32+ via a unified `header()` helper, per-section `EntryPoint`, PE32 and PE32+ via a unified `header()` helper, per-section
@@ -52,13 +52,13 @@ Legend: ✅ done · 🚧 partial · ⬜ planned.
`DisableTLSCallbacks`, `PatchBytes`/`PatchBytesAtOffset`, `RecalculateChecksum`. `DisableTLSCallbacks`, `PatchBytes`/`PatchBytesAtOffset`, `RecalculateChecksum`.
Deferred: Deferred:
- `AddSection`: append a new section for payload injection. Requires - [-] `AddSection`: append a new section for payload injection. Requires
growing the header area and recomputing `SizeOfImage`/`SizeOfHeaders`; needs growing the header area and recomputing `SizeOfImage`/`SizeOfHeaders`; needs
round-trip tests against real binaries. round-trip tests against real binaries.
- `DynPE` (analogue of `DynELF`): given one memory-read primitive, walk a - [-] `DynPE` (analogue of `DynELF`): given one memory-read primitive, walk a
loaded module's export directory at runtime to resolve symbols. loaded module's export directory at runtime to resolve symbols.
## Live-process introspection — ## Live-process introspection — [+]
Reads a PE inside a running process, resolving a module base via the PEB. Reads a PE inside a running process, resolving a module base via the PEB.
@@ -78,7 +78,7 @@ Reads a PE inside a running process, resolving a module base via the PEB.
`Modules`, `AllSymbols`; caches one `PEFile` per DLL. `SymbolVA`/ `Modules`, `AllSymbols`; caches one `PEFile` per DLL. `SymbolVA`/
`ListLoadedModules` for one-off lookups. (Analogue of `p.libs`/`p.symbols`.) `ListLoadedModules` for one-off lookups. (Analogue of `p.libs`/`p.symbols`.)
## Minidump — ## Minidump — [+]
[minidump.go](minidump.go): `OpenMinidump` parses `MINIDUMP_HEADER`/ [minidump.go](minidump.go): `OpenMinidump` parses `MINIDUMP_HEADER`/
`MINIDUMP_DIRECTORY` and decodes `ModuleListStream` (`Modules()`) and `MINIDUMP_DIRECTORY` and decodes `ModuleListStream` (`Modules()`) and
@@ -87,25 +87,25 @@ Reads a PE inside a running process, resolving a module base via the PEB.
context (`CONTEXT` blob) is not decoded — its layout is arch-specific with XSAVE context (`CONTEXT` blob) is not decoded — its layout is arch-specific with XSAVE
padding; use `RawStream`. Works without `GOOS=windows`. padding; use `RawStream`. Works without `GOOS=windows`.
## Shellcode & encoding — 🚧 ## Shellcode & encoding — [+-]
- `ShellcodeWinExec(cmd)` ([shellcraft.go](shellcraft.go), - [+] `ShellcodeWinExec(cmd)` ([shellcraft.go](shellcraft.go),
[shellcode/asm/winexec_x64.asm](shellcode/asm/winexec_x64.asm)): [shellcode/asm/winexec_x64.asm](shellcode/asm/winexec_x64.asm)):
position-independent x64, resolves kernel32 via the PEB position-independent x64, resolves kernel32 via the PEB
(`shellcode/asm/resolver.inc`), calls `WinExec` by name. Assembled ahead of (`shellcode/asm/resolver.inc`), calls `WinExec` by name. Assembled ahead of
time with NASM; `.asm` source kept alongside the `.bin`. time with NASM; `.asm` source kept alongside the `.bin`.
- `ExecuteShellcode` ([shellcode_exec_windows.go](shellcode_exec_windows.go)): - [+] `ExecuteShellcode` ([shellcode_exec_windows.go](shellcode_exec_windows.go)):
runs a template locally for validation. runs a template locally for validation.
- More templates on the same resolver base: `MessageBoxA`, reverse shell via - [-] More templates on the same resolver base: `MessageBoxA`, reverse shell via
raw `WS2_32`, a standalone `LoadLibraryA`+`GetProcAddress` primitive (current raw `WS2_32`, a standalone `LoadLibraryA`+`GetProcAddress` primitive (current
`find_export` only walks an already-loaded module). `find_export` only walks an already-loaded module).
- Token-stealing shellcode (see Driver/LPE). - [-] Token-stealing shellcode (see Driver/LPE).
- Encoders: alphanumeric and XOR bad-character avoidance. - [-] Encoders: alphanumeric and XOR bad-character avoidance.
- `asm`/assemble direction. Disassembly exists (`ROP.Disassemble` via - [-] `asm`/assemble direction. Disassembly exists (`ROP.Disassemble` via
`x86asm`); assembling would use cgo bindings to the `keystone/` engine `x86asm`); assembling would use cgo bindings to the `keystone/` engine
(walled off by its own `go.mod`, [keystone/go.mod](keystone/go.mod)). (walled off by its own `go.mod`, [keystone/go.mod](keystone/go.mod)).
## Debugger — ## Debugger — [+]
[debugger_windows.go](debugger_windows.go) wraps the Windows Debug API [debugger_windows.go](debugger_windows.go) wraps the Windows Debug API
(`DebugActiveProcess`/`WaitForDebugEvent`/`ContinueDebugEvent`/ (`DebugActiveProcess`/`WaitForDebugEvent`/`ContinueDebugEvent`/
@@ -128,21 +128,21 @@ padding; use `RawStream`. Works without `GOOS=windows`.
- `Step()` in response to an `EventBreakpoint` behaves like `Continue` (resuming - `Step()` in response to an `EventBreakpoint` behaves like `Continue` (resuming
past a software breakpoint already requires an internal single-step). past a software breakpoint already requires an internal single-step).
## Networking & transports — 🚧 ## Networking & transports — [+-]
- Named pipes ([pipe_windows.go](pipe_windows.go)): `ServePipe(name)`/ - [+] Named pipes ([pipe_windows.go](pipe_windows.go)): `ServePipe(name)`/
`DialPipe(name)`, both returning a `*Tube`. `ServePipe` uses `DialPipe(name)`, both returning a `*Tube`. `ServePipe` uses
`PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED`; each `ReadFile`/`WriteFile` blocks `PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED`; each `ReadFile`/`WriteFile` blocks
on `GetOverlappedResult`, so the handle behaves as a blocking on `GetOverlappedResult`, so the handle behaves as a blocking
`io.ReadWriteCloser`. `pipeConn.Close()` is idempotent (`sync.Once`) because `io.ReadWriteCloser`. `pipeConn.Close()` is idempotent (`sync.Once`) because
the duplex handle is used as both `Tube.stdin` and `Tube.stdout`. the duplex handle is used as both `Tube.stdin` and `Tube.stdout`.
- `Listen`: TCP listener tube for reverse shells (`net.Listen`). - [-] `Listen`: TCP listener tube for reverse shells (`net.Listen`).
- TLS transport (`Remote` with `tls.Dial`). - [-] TLS transport (`Remote` with `tls.Dial`).
- SSH transport (`golang.org/x/crypto/ssh`). - [-] SSH transport (`golang.org/x/crypto/ssh`).
- Process-tree cleanup: `Spawn` should kill the whole tree on `Close()` via a - [-] Process-tree cleanup: `Spawn` should kill the whole tree on `Close()` via a
Windows Job Object. Windows Job Object.
## CLI — 🚧 ## CLI — [+-]
[cmd/winpwn/main.go](cmd/winpwn/main.go), additive to the library. [cmd/winpwn/main.go](cmd/winpwn/main.go), additive to the library.
@@ -151,25 +151,25 @@ integer), `hex`/`unhex`/`hexdump`, `rop` (`-search`/`-regex`; no unfiltered dump
mode), `disasm`, `exports`, `imports`, `heap`. mode), `disasm`, `exports`, `imports`, `heap`.
Open: Open:
- `winpwn asm`: blocked on the Keystone integration. - [-] `winpwn asm`: blocked on the Keystone integration.
- `winpwn template`: scaffold a new solve script (partly covered by - [-] `winpwn template`: scaffold a new solve script (partly covered by
[cmd/pwninit](cmd/pwninit/main.go)). [cmd/pwninit](cmd/pwninit/main.go)).
## Driver / LPE (Ring 0) — ## Driver / LPE (Ring 0) — [-]
- Device handle + IOCTL wrapper: `OpenDevice(name)` over `CreateFileA`, - [-] Device handle + IOCTL wrapper: `OpenDevice(name)` over `CreateFileA`,
`(*Device).IOCTL(code, in)` over `DeviceIoControl`, handling output-buffer `(*Device).IOCTL(code, in)` over `DeviceIoControl`, handling output-buffer
sizing and error mapping. sizing and error mapping.
- Token-stealing shellcode (x86 and x64), parameterized by a - [-] Token-stealing shellcode (x86 and x64), parameterized by a
`KernelOffsets{Process, ActiveProcessLinks, Token}` struct. `KernelOffsets{Process, ActiveProcessLinks, Token}` struct.
- Kernel info-leak helpers over the common `NtQuerySystemInformation` classes. - [-] Kernel info-leak helpers over the common `NtQuerySystemInformation` classes.
## Heap exploitation — 🚧 ## Heap exploitation — [+-]
Heap struct-parsing layer. All decoders work against any `io.ReaderAt`; only Heap struct-parsing layer. All decoders work against any `io.ReaderAt`; only
finding a heap address in a live process needs Windows syscalls. finding a heap address in a live process needs Windows syscalls.
- NT Heap foundation ([heap.go](heap.go)): `_HEAP`/`_HEAP_SEGMENT`/ - [+] NT Heap foundation ([heap.go](heap.go)): `_HEAP`/`_HEAP_SEGMENT`/
`_HEAP_ENTRY` + `DecodeHeapEntry` (XOR against `_HEAP.Encoding`). Offsets from `_HEAP_ENTRY` + `DecodeHeapEntry` (XOR against `_HEAP.Encoding`). Offsets from
`dt ntdll!_HEAP` on build 10.0.26100; decode validated against `!heap -a` for `dt ntdll!_HEAP` on build 10.0.26100; decode validated against `!heap -a` for
three allocations (see `TestDecodeHeapEntryMatchesLiveGroundTruth`). three allocations (see `TestDecodeHeapEntryMatchesLiveGroundTruth`).
@@ -177,9 +177,9 @@ finding a heap address in a live process needs Windows syscalls.
`EntriesWithUserData`, `AdjacentBusyPairs`. `UserSize` = `EntriesWithUserData`, `AdjacentBusyPairs`. `UserSize` =
`Size*HeapEntrySize - UnusedBytes` (no separate header subtraction — `Size*HeapEntrySize - UnusedBytes` (no separate header subtraction —
`UnusedBytes` already accounts for the header). `UnusedBytes` already accounts for the header).
- `ListProcessHeaps(pid)` ([heap_windows.go](heap_windows.go)): PEB walk via - [+] `ListProcessHeaps(pid)` ([heap_windows.go](heap_windows.go)): PEB walk via
`NtQueryInformationProcess(ProcessBasicInformation)`. `NtQueryInformationProcess(ProcessBasicInformation)`.
- NT Heap LFH ([heap_lfh.go](heap_lfh.go)): `ReadLFHBuckets`, - [+] NT Heap LFH ([heap_lfh.go](heap_lfh.go)): `ReadLFHBuckets`,
`FindLFHBucket` (searches `BlockSize >= wantSize + 16`; LFH blocks include the `FindLFHBucket` (searches `BlockSize >= wantSize + 16`; LFH blocks include the
16-byte header), `ActiveSubsegment`, `AllSubsegments`, `ReadLFHSubsegment` 16-byte header), `ActiveSubsegment`, `AllSubsegments`, `ReadLFHSubsegment`
(BusyBitmap validated), `CalibrateLFHFirstBlockOffset`, `BlockAddress`, (BusyBitmap validated), `CalibrateLFHFirstBlockOffset`, `BlockAddress`,
@@ -187,22 +187,22 @@ finding a heap address in a live process needs Windows syscalls.
`SegmentInfoArrays[bucket]` is populated (build-specific); `SegmentInfoArrays[bucket]` is populated (build-specific);
`_HEAP_USERDATA_HEADER.EncodedOffsets` is obfuscated — `_HEAP_USERDATA_HEADER.EncodedOffsets` is obfuscated —
`CalibrateLFHFirstBlockOffset` uses a known-address calibration instead. `CalibrateLFHFirstBlockOffset` uses a known-address calibration instead.
- Segment Heap outer layer ([heap_segment.go](heap_segment.go)): - [+] Segment Heap outer layer ([heap_segment.go](heap_segment.go)):
`ReadSegmentHeap` (Signature/GlobalFlags + VS/LFH summaries), VS subsegment `ReadSegmentHeap` (Signature/GlobalFlags + VS/LFH summaries), VS subsegment
walk, LFH bucket enumeration. VS `_HEAP_VS_CHUNK_HEADER.Sizes` and Segment LFH walk, LFH bucket enumeration. VS `_HEAP_VS_CHUNK_HEADER.Sizes` and Segment LFH
`BlockOffsets.EncodedData` are XOR-encoded and not decoded. Adjacency is `BlockOffsets.EncodedData` are XOR-encoded and not decoded. Adjacency is
handled by `AdjacentAddressPairs`/`FindAdjacentPair` on leaked addresses, which handled by `AdjacentAddressPairs`/`FindAdjacentPair` on leaked addresses, which
needs no chunk-header decode. needs no chunk-header decode.
- `winpwn heap <pid> [-walk]` CLI subcommand. - [+] `winpwn heap <pid> [-walk]` CLI subcommand.
- BSTR/client-spray generator (lower priority; `SprayAndFind` covers the - [-] BSTR/client-spray generator (lower priority; `SprayAndFind` covers the
generic retry/search loop). generic retry/search loop).
## Go-native additions — ## Go-native additions — [-]
- `Pool`: fan out one exploit across N parallel connections via a bounded - [-] `Pool`: fan out one exploit across N parallel connections via a bounded
goroutine pool. goroutine pool.
- Race-condition primitives: fire N goroutines at a target behind a barrier. - [-] Race-condition primitives: fire N goroutines at a target behind a barrier.
- Cancellable `Interactive`: propagate a `context.Context` into both copy - [-] Cancellable `Interactive`: propagate a `context.Context` into both copy
goroutines so the stdin-forwarding goroutine does not outlive the tube. goroutines so the stdin-forwarding goroutine does not outlive the tube.
## Testing ## Testing