top of page
  • Writer's pictureNikos Laleas

Introducing SMShell: Staying covert using SMS based implant

During OffensiveCon 2023, Markus Vervier, founder/director of PSI, presented his research on security aspects of embedded SIM cards (eSIMs). As part of this research, and with Red Teaming in mind, PSI team developed a Proof of Concept of an SMS based implant.


While WWAN modules might sound a feature from the past, many new Lenovo and Dell laptops now come equipped with eSIM capable modules. This presents an opportunity for adversaries to create new and unexplored out-of-band channels, evading network sensors and corporate filters.

By using SMS messages as a transport mechanism for remote command execution, we were able to highlight the possible attack vectors that could be exploited by malicious actors. This experiment serves as a stark reminder of the necessity for robust security measures in our increasingly interconnected world, as well as the crucial role of offensive security in identifying and mitigating potential threats.


We are not going to delve into the details of eSIMs, but we are going to see how we can (ab)use Windows APIs to achieve our goals.

Note: It is obvious that the following APIs and code snippets require the presence of a WWAN module with a deployed (e)SIM.

The SmsDevice2 class from the Windows.Devices.Sms namespace is what we will be focusing on. This class is part of the Windows Runtime (WinRT) APIs which is normally meant to be used in Universal Windows Platform (UWP) applications which are usually published on Microsoft's store.

Quoting from Microsoft's documentation about the SmsDevice2 class:

This functionality is available only to mobile operator apps and UWP apps given privileged access by mobile network operators, mobile broadband adapter IHV, or OEM. For more information, see Mobile Broadband.

However, it appears that we can use this class from regular desktop apps (non-UWP) without requiring any special privileges.

On top of that, we can register our own handler for the MessageReceived event which, as the name implies, is triggered when a new SMS arrives.

A simple code snippet to register our own handler for incoming SMS:

using System;
using Windows.Devices.Sms;
using Windows.Devices.Enumeration;

static async Task Main(string[] args) {
  try {
    var deviceSelector = SmsDevice2.GetDeviceSelector();
    var smsDevices = await DeviceInformation.FindAllAsync(deviceSelector);
    SmsFilterRule filter = new(SmsMessageType.Text);
    SmsFilterRules filterRules = new(SmsFilterActionType.Accept);
    IList < SmsFilterRule > rules = filterRules.Rules;

    messageRegistration = SmsMessageRegistration.Register("app", filterRules);
    messageRegistration.MessageReceived += MessageReceivedAsync;

    Console.CancelKeyPress += (s, e) => {
      e.Cancel = true;

    try {
      await Task.Delay(-1, cts.Token);
    } catch (TaskCanceledException) {}

    messageRegistration.MessageReceived -= MessageReceivedAsync;
  } catch (Exception ex) {

While the handler can look like this:

private static void MessageReceivedAsync(SmsMessageRegistration sender, SmsMessageReceivedTriggerDetails message) {
  var textMessage = message.TextMessage;
  Console.WriteLine($"Message from {textMessage.From}. Content: {textMessage.Body}");

Gluing everything together, we created a proof of concept and wrote a small implant which executes commands through cmd.exe via SMS. The implant is able to handle longer output than the usual 160 characters contained in a single SMS, by gzipping and splitting the command output into multiple messages.

You can find the project on our team's GitHub:

Demo as presented at OffensiveCon


Our intent is to create a C2 channel so that we can tunnel traditional C2 traffic over SMS. Unfortunately a single SMS consists only of 160 characters. While there is the multi-part SMS option which can transfer up to 918 characters, we have found that it's highly unreliable as, depending on the provider, a longer message can arrive in multiple and randomly split chunks.

So tunneling traditional C2 traffic (i.e. HTTP), where a single check-in request might require 10 or 15 messages, creates heavy delay and therefore timeout issues.

However, this type of implant is ideal for stealthy persistence or running small and simple tasks, such as spawning a new beacon.


Recent Posts

See All


bottom of page