sessionkit

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 22, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

README

sessionkit

契约包,无工具。

本包实现 capkit 的 Session 契约(docs §5.1)及其 opener:一个新的传输只需 实现 core.Session 的三个方法(Exec / Info / Close,可选 Upload / Download / Tunnel),下游所有 kit(privesc、lat、persist、 cleanup、internalnet、container)就能不改代码地跑在它上面。

提供什么

  • Manager:默认的 core.SessionManager,按 kind 注册 core.SessionOpener(ssh / winrm / smb / cli / webshell …), 按 ID 追踪活动会话
  • 传输适配器:SSHOwner / SSHSession(含上传/下载/隧道)、 WinRMOpener / WinRMSession、SMBOpener / SMBSession、 CLIOpener / CLISession(本地命令执行)

给谁用

宿主 runtime:把 Manager 作为 core.SessionManager 端口注入,在装配期 注册需要的 opener;各后渗透 kit 通过该端口拿会话。

工具在哪里

工具不在本包注册:session_open / session_exec / session_upload / session_download / tunnel_open / session_list / session_close 全部由 kits/shellkit 声明与分发(见 kits/shellkit/capability.go), shellkit 把 capkit 端口转接给 sessionkit 的 Manager。本包因此是 契约包, 无工具:没有 Manifest(),没有 ToolSpec,也没有 Call。

Documentation

Overview

Package sessionkit implements the capkit Session contract (docs §5.1) and the openers for it. A new transport only implements Session's three methods plus SessionManager plumbing; every downstream kit (privesc, lat, persist, cleanup, internalnet, container) then works against it unchanged.

SessionManager is a port owned by the host. This package supplies a default implementation plus an SSH adapter (real connections, host-injected key material) and a CLI adapter (local command execution) so the contract is exercised end to end without a host-side implementation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CLIOpener

type CLIOpener struct {
	// Runner is required: CLIOpener holds no execution path of its own.
	Runner core.ProcessRunner
	// AllowedCommands, when non-empty, restricts the first token of every
	// command. Empty means unrestricted (host's responsibility).
	AllowedCommands []string
	// DefaultShell overrides the detected shell interpreter.
	DefaultShell string
}

CLIOpener runs commands as a local process through the host's ProcessRunner port. It is the reference adapter: it needs no credentials and no network, so it makes the Session contract testable end to end and is useful for local agent-side tasks.

Routing through ProcessRunner (never os/exec) keeps the "kits never spawn a subprocess themselves" boundary intact (docs §6.4): the host decides whether local execution is gated, audited and sandboxed. A host that wants a fully gated local transport passes adapters/exec.New(scope, limiter, audit); one that only needs host-side local commands passes adapters/exec.NewLocal().

func (*CLIOpener) Open

func (o *CLIOpener) Open(_ context.Context, spec core.SessionSpec) (core.Session, error)

Open returns a CLI session. spec.Host is ignored; "local" is conventional.

type CLISession

type CLISession struct {
	// contains filtered or unexported fields
}

CLISession is a local-process Session.

func (*CLISession) Close

func (s *CLISession) Close() error

func (*CLISession) Exec

func (s *CLISession) Exec(ctx context.Context, cmd string, opts core.ExecOpts) (core.Output, error)

func (*CLISession) Info

func (s *CLISession) Info() core.SessionInfo

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager is the default SessionManager. Openers are registered per kind ("ssh", "winrm", "smb", "cli", "webshell", ...) by the host; the manager tracks live sessions by ID and hands out Sessions to callers.

func NewManager

func NewManager(idFn func(string) string, nowFn func() time.Time) *Manager

NewManager builds a Manager. idFn/nowFn are optional (defaults: random-ish counter id, time.Now).

func (*Manager) Close

func (m *Manager) Close(id string) error

Close closes and untracks one session. Closing an unknown ID is not an error (idempotent: agents retry after timeouts).

func (*Manager) CloseAll

func (m *Manager) CloseAll() error

CloseAll closes every tracked session and returns the joined errors.

func (*Manager) Get

func (m *Manager) Get(id string) (core.Session, bool)

Get returns a live session by ID.

func (*Manager) List

func (m *Manager) List() []core.SessionInfo

List returns metadata for all live sessions, ordered by ID.

func (*Manager) Open

func (m *Manager) Open(ctx context.Context, spec core.SessionSpec) (core.SessionInfo, error)

Open creates and tracks a session.

func (*Manager) RegisterOpener

func (m *Manager) RegisterOpener(kind string, opener core.SessionOpener)

RegisterOpener installs an opener for a session kind.

type SMBOpener

type SMBOpener struct {
	// Runner is required.
	Runner core.ProcessRunner
	// Binary overrides the smbclient path; default "smbclient".
	Binary string
	// Share is the share name when the session spec does not carry one in
	// Options["share"].
	Share string
	// Artifacts stages uploads locally (smbclient needs a real file path).
	// Upload stays unavailable when it is nil.
	Artifacts core.ArtifactStore
	// Timeout bounds one smbclient invocation; default 60s.
	Timeout time.Duration
}

SMBOpener opens an SMB share session. SMB is not an HTTP protocol and capkit has no raw-TCP port, so the transport is the sanctioned ProcessRunner route (docs §6.4: every external tool is a subprocess): commands are driven through smbclient, its password carried in the environment rather than the command line so it never lands in the process list or the audit trail.

The session is stateless per command — SMB has no remote shell here, so Exec runs smbclient subcommands (ls/get/put/del/mkdir …). An authentication failure surfaces on the first Exec, not at Open, because Open issues no traffic.

func (*SMBOpener) Open

func (o *SMBOpener) Open(_ context.Context, spec core.SessionSpec) (core.Session, error)

Open records the target parameters. No traffic is issued, so this only fails on a missing runner or an unusable host.

type SMBSession

type SMBSession struct {
	// contains filtered or unexported fields
}

SMBSession is an SMB share foothold driven through smbclient.

func (*SMBSession) CanUpload

func (s *SMBSession) CanUpload() bool

CanUpload reports whether uploads are possible (an ArtifactStore is wired).

func (*SMBSession) Close

func (s *SMBSession) Close() error

Close is a no-op: smbclient connections live for one invocation.

func (*SMBSession) Download

func (s *SMBSession) Download(ctx context.Context, remote string) (io.ReadCloser, error)

Download reads a remote file with smbclient's cat command, so no local staging is needed.

func (*SMBSession) Exec

func (s *SMBSession) Exec(ctx context.Context, cmd string, opts core.ExecOpts) (core.Output, error)

Exec runs one smbclient command list (e.g. "ls", "get a.txt b.txt").

func (*SMBSession) Info

func (s *SMBSession) Info() core.SessionInfo

func (*SMBSession) Upload

func (s *SMBSession) Upload(ctx context.Context, src io.Reader, remote string) error

Upload stages data locally through the ArtifactStore and pushes it with smbclient's put command.

type SSHOwner

type SSHOwner struct {
	// HostKeyCallback defaults to ssh.InsecureIgnoreHostKey when nil. Hosts
	// should inject a pinned callback.
	HostKeyCallback ssh.HostKeyCallback
	// Dialer overrides the TCP dialer (hosts route through proxies here).
	Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
}

SSHOwner opens a real SSH foothold. It implements Session (Exec/Info/Close) plus the optional Uploader/Downloader/Tunneler capabilities from §5.1, so downstream kits get file transfer and port forwarding for free.

The opener authenticates with a password or a PEM private key supplied in SessionSpec.Secret; the host is responsible for resolving that secret from the Sealer at the edge and for scope approval before calling Open.

func (*SSHOwner) Open

func (o *SSHOwner) Open(ctx context.Context, spec core.SessionSpec) (core.Session, error)

Open dials, authenticates and returns a live SSH session.

type SSHSession

type SSHSession struct {
	// contains filtered or unexported fields
}

SSHSession is a live SSH foothold.

func (*SSHSession) Close

func (s *SSHSession) Close() error

func (*SSHSession) Download

func (s *SSHSession) Download(ctx context.Context, remote string) (io.ReadCloser, error)

Download reads remote via cat (stdout streamed back).

func (*SSHSession) Exec

func (s *SSHSession) Exec(ctx context.Context, cmd string, opts core.ExecOpts) (core.Output, error)

Exec runs cmd through a new SSH session channel.

func (*SSHSession) Info

func (s *SSHSession) Info() core.SessionInfo

func (*SSHSession) Tunnel

func (s *SSHSession) Tunnel(ctx context.Context, spec core.TunnelSpec) (core.Tunnel, error)

Tunnel opens a remote dial through the SSH connection.

func (*SSHSession) Upload

func (s *SSHSession) Upload(ctx context.Context, src io.Reader, remote string) error

Upload streams src to remote using cat > path (base64-free, binary safe).

type WinRMOpener

type WinRMOpener struct {
	// HTTP is required and must be the gate-aware client.
	HTTP core.HTTPDoer
	// TLS selects https (5986) over http (5985).
	TLS bool
	// Port overrides the default for the chosen scheme.
	Port int
	// OperationTimeoutMS bounds one WSMan call; default 60000.
	OperationTimeoutMS int
}

WinRMOpener opens a Windows Remote Management foothold. WinRM is a SOAP protocol over HTTP(S), so it rides the host's core.HTTPDoer port: scope, rate limiting and audit apply to every WSMan call exactly as they do to any other HTTP request (docs §3.1: sessionkit owns SSH/WinRM/SMB/CLI transports).

Authentication is HTTP Basic over a TLS endpoint by default, which is the documented "unencrypted on 5986/TLS" setup. Hosts that need NTLM/Kerberos terminate the auth in their HTTPDoer (a proxying Doer) and pass the target URL through unchanged.

func (*WinRMOpener) Open

func (o *WinRMOpener) Open(ctx context.Context, spec core.SessionSpec) (core.Session, error)

Open creates a remote shell on the target and returns a session bound to it.

type WinRMSession

type WinRMSession struct {
	// contains filtered or unexported fields
}

WinRMSession is a live WinRM foothold. Each Exec runs cmd.exe /c through the remote shell.

func (*WinRMSession) Close

func (s *WinRMSession) Close() error

Close deletes the remote shell; the WinRM protocol has no connection to drop.

func (*WinRMSession) Exec

func (s *WinRMSession) Exec(ctx context.Context, cmd string, opts core.ExecOpts) (core.Output, error)

Exec runs a command line through cmd.exe /c and returns its output.

func (*WinRMSession) Info

func (s *WinRMSession) Info() core.SessionInfo

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL