Error Icon

Something went wrong. Please try again

The Quiet Shell: A PowerShell Reverse Shell via SSE Protocol Hero Banner

The Quiet Shell: A PowerShell Reverse Shell via SSE Protocol

January 28, 2026 | 10 min read

by Tal Hershberg

data transmission

A Technical Deep-Dive into Server-Sent Events for C2 Communication

Innovation often arises from unexpected places. A project intended to explore the Model Context Protocol (MCP) for Agentic AI led to an in-depth analysis of a less-common protocol: Server-Sent Events (SSE). This exploration revealed a novel method for creating a stealthy, persistent reverse shell using only native PowerShell.

This article provides a technical walkthrough of this proof-of-concept, detailing:

  • An overview of Server-Sent Events (SSE) and its mechanics.

  • The strategic advantages of using SSE for reverse shell communication.

  • A step-by-step guide to building a functional listener (server) and client in PowerShell.

This content is for builders, defenders, and security professionals interested in exploring unconventional C2 channels and enhancing defensive strategies.

What Are Server-Sent Events (SSE)?

SSE is a lightweight HTTP-based protocol where the server (listener) pushes real-time data to the client. Unlike WebSockets, SSE is one-way only (server (listener) ➝ client) and requires no special handshake.

A typical SSE stream looks like:

The client makes a single GET request, and the server (listener) keeps that connection open, pushing events over time.

  • It's just HTTP (firewall-friendly)

  • It's long-lived (persistent connection)

  • It's simple to implement

The initial thought was clear: could this one-way, persistent stream be used to send commands to a reverse shell? This question shifted the project's focus entirely.

Understanding SSE for Real-Time Control

Server-Sent Events (SSE) enable a server to stream real-time updates to a client through a single, persistent HTTP connection. Much like subscribing to a live news feed, the client establishes an initial connection, allowing the server to push continuous updates as they occur. Each message is transmitted as lightweight plain text, formatted with a `data:` prefix followed by the payload and a newline. Because SSE operates over standard HTTP, it eliminates the need for complex WebSocket handshakes or inefficient polling, offering a seamless and efficient way to maintain a live data stream.

A user should see a single GET request hanging open, with the server periodically writing lines like:

data: server event (what's after data: could be anything)

data: server event

data: server event

data: server event

Why Use SSE for a Reverse Shell?

SSE provides a stealthy solution for a reverse shell with several advantages:

  • Commands are initiated by the server (listener), not the client.

  • Communication uses HTTP, making it accessible through any HTTP client, such as PowerShell's Invoke-WebRequest (IWR) or even a browser.

  • It leaves a smaller network footprint compared to polling or WebSockets.

  • The client only connects once, while the server sends new commands as needed.

Communication remains open and low-noise:

  • The page appears as a standard placeholder for real-time updates, discreetly housing a command-and-control link.

Common reverse shell techniques typically rely on:

  • Raw Sockets (often blocked by EDRs)

  • HTTP polling (client continuously requests commands)

  • WebSockets (noisier due to dual-direction communication)

This shell listener minimizes its footprint by operating without additional tools or binaries, unlike traditional payloads that depend on utilities like Netcat or similar tools:

  • Fully native PowerShell implementation

  • No external tools or binary droppers required

Why this approach works:

Most TCP-based PowerShell shell techniques are well-documented, heavily detected by antivirus systems, and routinely blocked by EDRs. By leveraging built-in PowerShell classes, the entire operation remains:

  • Memory-resident

  • EDR-evasive

  • Free from special dependencies

The Goal: A Real-Time PowerShell Reverse Shell

Here is a look at the initial prototype: a streamlined HttpListener designed to broadcast timestamps at one-second intervals.

Building the Listener (Server (Listener) Side)

Start with the trustworthy HttpListener. It's a bit old-school but reliable, and it initiates the server (listener).

$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add("http://localhost:3007/")\ $listener.Start()

Pause until a client connects. GetContext() halts execution until a connection comes in, then we grab the request and response objects to start handling it.

$context = $listener.GetContext()
$request = $context.Request
$response = $context.Response

These headers are required to initiate a proper SSE stream.

if ($request.Url.AbsolutePath -eq "/stream") {
$response.StatusCode = 200
$response.ContentType = "text/event-stream"
$response.Headers.Add("Cache-Control", "no-cache")
$response.Headers.Add("Connection", "keep-alive")

Streaming Events. Create a StreamWriter to write messages into the response stream.

$writer = New-Object System.IO.StreamWriter($response.OutputStream)
$writer.AutoFlush = $true

Sending the current time through the stream.

for ($i = 0; $i -lt 60; $i++) {
$time = (Get-Date).ToString("HH:mm:ss")
$writer.WriteLine("data: $time`n")
Start-Sleep -Seconds 1
}

After running the server, navigate to the /stream endpoint to watch it in action while inspecting it in the browser's DevTools:

When analyzing the traffic in Wireshark, the expected behavior is confirmed:

  • A single persistent GET request to `/stream`.

  • All communication flows from the server to the client. 

  • No additional client requests for updates. 

This demonstrates that the connection remains open, with the server solely transmitting data — a crucial advantage for maintaining stealth.

Building the SSE Client

With the listener working and pushing timestamp data, it was time to build the other half: a minimalist PowerShell client. This client connects to the `/stream` endpoint and listens for incoming commands or events.

The goal was to avoid relying on external libraries or `curl.exe` and use native PowerShell only. Here is the barebones setup:

The flow of the client script works as follows:

  • A single HTTP GET request is made to /stream.

  • The Accept: text/event-stream header ensures the server recognizes it as an SSE (Server-Sent Events) request.

  • Once the connection is established, the stream remains open and is read line by line.

  • Messages starting with data: are parsed and printed.

  • The client then executes the string as a command.

Benefits of this approach:

  • A persistent connection remains open as long as the server allows.

  • Every message pushed by the server is promptly received by the client.

For demonstration purposes, a small change was made on the server to illustrate command injection:

$time = "whoami"

Achieved an SSE-based RCE.

Putting It All Together: The SSE Reverse Shell in Action

With a solid foundation, an SSE-based setup for pushing and executing commands, the transition to a fully functional reverse shell came together seamlessly.

The SSE server operates as the command sender, while the SSE client receives SSE events and executes them, creating a streamlined and efficient system.

The shell functions as follows: 

  • Commands are sent via /stream 

  • Outputs are returned via /result 

The result is a clean, silent and persistent reverse shell, built entirely on native PowerShell.

Subscription banner

Stay informed with our latest updates.

Subscribe now!

Your information will be processed according to
EPAM SolutionsHub Privacy Policy.

What's in the Repository?

Explore the repository here: GitHub - TNCX-byte/PS_SSE_Shell

This repository includes:

  • A complete SSE Reverse Shell Server

  • A fully functional SSE Reverse Shell Client

Final Thoughts

Building this was never just about creating a shell — it was about exploring overlooked protocols, leveraging unconventional channels and doing more with less.

The combination of PowerShell and SSE provides:

  • Long-lived communication without the need for constant polling.

  • Execution control without requiring inbound or multiple outbound connections.

  • A memory-resident shell that remains hidden in plain sight.

There are countless ways to build a C2. This approach simply utilizes the same protocol powering live stock tickers and GitHub notifications.

1743317124465

Tal Hershberg

Senior Security Systems Engineer

Loading...

Related Content

View All Articles
Subscription banner

Get updates in your inbox

Subscribe to our emails to receive newsletters, product updates, and offers.

By clicking Subscribe you consent to EPAM Systems, Inc. processing your personal information as set out in the EPAM SolutionsHub Privacy Policy

Loading...