Skip to content

RFC: Componentize Jobs, Servers, and C2s into a Framework Pool #416

@terrorbyte

Description

@terrorbyte

We've had a few reoccurring issues in the framework structure for C2s:

  1. c2 itself is a bit of a misnomer. People regularly need to serve up HTTP content (or WebDAV in a recent exploit from me) with HTTPServeFile, but those are technically not a C2. In general, I actually think this makes the instantiation and singleton logic a little hard to understand and use.
  2. We did add clean shutdowns in Unify clean shutdown and update C2 channel with session tracking #358, but the actual internals are a bit sloppy and I don't believe that the logic for shutting down is easy to replicate and should generally not be the job of the implementer to guess. I generally just want to clean up this logic. Additionally, shutdowns should probably be wrapped in a context these days
  3. We have no clean way to handle non-C2 servers or long running components, nor do we have a way to trigger them conditionally once a C2 type is matched for payload generation.
  4. Logic for cleanup after post-exploitation is not a first-class citizen.
  5. Periodic tasks are not common as of now, but having the ability to support them would be cool.

In order to solve these in a bit more of a systemic way I propose creating a component package that would supersede c2 and then allow for other non-c2 server types and other non-server jobs. This would be implemented with a interface that is wrapped around some sort of job management pool. I had been playing around with using gowl completely in place of our current C2 model and I believe it provides a really nice concept for how we could utilize a similar pool (but a bit more tailor made to live in-framework and to allow for non-initial startups).

I think the gowl model of using a centralized propagating context is also probably what we should have done in the first place with our C2 clean shutdown implementation, as it directly supports OS shutdowns and timeouts. It also would allow for an exploit to directly control standup and shutdown of arbitrary components, which could be useful in some conditions.

This would also fully take the place of #219 as a component could be an arbitrary WebDAV server or wrapped by a simple interface.


At the moment my little mock uses the following types for a Pool:

type (
	WorkerName string
	ID         string

	Process interface {
		Name() string
		ID() ID
		CreateFlags()
		Start(ctx context.Context) bool
		Shutdown() bool
		// TODO options?
	}

	Pool interface {
		Start() bool
		Register(p ...Process)
		Kill(ID)
		Status() pool.Status
		Workers() []WorkerName
		WorkerStatus(name WorkerName) worker.Status
		ProcessStats(pid ID) ProcessStats
	}

	ProcessStats struct {
		WorkerName WorkerName
		Process    Process
		Status     process.Status
		StartedAt  time.Time
		FinishedAt time.Time
		ok         bool
	}

	workerPool struct {
		status       pool.Status
		size         int
		queue        chan Process
		wg           *sync.WaitGroup
		processes    *processStatusMap
		workers      []WorkerName
		workersStats *workerStatsMap
		controlPanel *controlPanelMap
		mutex        *sync.Mutex
		isClosed     bool
	}
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-breakRequires breaking the API, tag these for things that are wanted for a major version bumpenhancementNew feature or request

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions