Back to reports
highBotnet

ELF Modified UPX — Breakglass Intelligence Report

InvestigatedApril 3, 2026PublishedApril 3, 2026
elfmodifiedupxc2ratbotnettor

TLP: WHITE Date: 2026-04-03 Analyst: GHOST (Breakglass Intelligence) Classification: FALSE POSITIVE — Legitimate Industrial Firmware Source: @TuringAlex (Twitter/X)

Executive Summary

An ELF binary (MD5: da2e396baf23de1881d06dd3377f84a6) flagged as suspicious due to modified UPX packing was investigated. After unpacking by restoring the modified OPS! magic bytes to standard UPX!, full static analysis of the 1.2MB unpacked binary reveals this is legitimate OpenPLC Editor firmware compiled for an Arduino MKR Zero (ARM Cortex-M0+, SAMD21) running a traffic light controller over Modbus TCP/Ethernet. The binary is not malware. It is an industrial control system (ICS) firmware image that was packed with a modified UPX variant, triggering multiple anti-unpacking YARA rules and resulting in false positive classifications by 13/38 AV engines.

Key Findings

  • NOT MALWARE: Binary is legitimate OpenPLC firmware for Arduino MKR Zero hardware
  • Developer identified: Windows user sergio with OpenPLC Editor installed at \Users\sergio\OpenPLC_Editor
  • Purpose: Traffic light PLC controller with Modbus TCP slave functionality over W5100 Ethernet
  • Modified UPX: Magic bytes changed from UPX! to OPS! at three locations (offsets 0x78, 0x728D2, 0x728DC)
  • Network config: Device IP 192.168.1.195, Gateway 192.168.1.1, Subnet 255.255.255.0
  • Embedded hash: MD5 558d148d2b08815643ddd5ae90d8a221 (likely firmware debug checksum)
  • Compiler: GCC 7.2.1 (GNU Tools for ARM Embedded Processors 7-2017-q4-major)
  • AV false positives: 13/38 engines flagged as suspicious/malicious (ReversingLabs: Linux.Trojan.Generic)

What Was Found vs. What Was Suspected

AspectInitial SuspicionOur Findings
File typeMalicious ELF binaryLegitimate ICS/SCADA firmware
UPX modificationAnti-analysis evasionUnknown reason; possibly OpenPLC build toolchain artifact
ArchitectureIoT botnet (ARM)Arduino MKR Zero (ARM Cortex-M0+ SAMD21)
PurposeC2 beacon / DDoS botTraffic light controller with Modbus TCP
Network activityC2 communicationModbus TCP slave on LAN (192.168.1.0/24)
IPv6 YARA hitIPv6-based C2Ethernet library IPv6 socket support structures
Origin (Hungary)Attacker infrastructureLikely developer/researcher upload location

Sample Details

FieldValue
MD5da2e396baf23de1881d06dd3377f84a6
SHA2566439834bec1cc530b12b1d821a509561efdd43048ecfb183939fe00a11a3c7dd
SHA18e1bf4a68904dec5ebd92d1f07621a52464ef6e7
SSDEEP12288:18Z3vxICUzUWBMH79C2EwdvAFhhvX2k4HQ:q5Ir7BMbwVyAFhhukmQ
TLSHT174A4237E146B7157DA9262A6C95CC17B22BFBE809B46432DE732504336005ECCEFEB64
TELFhasht1f490045c1dd03100371c0044535dc40ff3001503f50f55030d00c5d3c3c04430cc1c10
File typeELF 32-bit LSB executable, ARM, EABI5, statically linked
Packed size469,248 bytes
Unpacked size1,197,456 bytes (39.19% compression ratio)
UPX version4.22 (with modified magic bytes)
Original filenamedulime_tl
MalwareBazaar first seen2026-03-12
ReversingLabs first seen2025-08-22
Kaspersky first seen2025-10-27

Modified UPX Analysis

Magic Byte Modification

The standard UPX packer uses the magic bytes UPX! (hex 55 50 58 21) in three locations within packed ELF binaries:

  1. l_info structure (offset 0x78): Immediately after ELF header + program headers. Contains the loader checksum, magic, size, version, and format fields.
  2. Packed data trailer (offset 0x728D2): End-of-packed-data marker.
  3. Packed data trailer (offset 0x728DC): Secondary marker within 10 bytes of the first.

In this sample, all three instances were changed to OPS! (hex 4F 50 53 21). This single-character substitution (U->O, P->P, X->S) prevents the standard upx -d decompressor from recognizing the file, but the underlying NRV2E compression and ELF loader stub remain functional.

l_info Structure at Offset 0x74

Offset 0x74: d2 80 af b6  (checksum)
Offset 0x78: 4f 50 53 21  (magic: "OPS!" — should be "UPX!")
Offset 0x7c: 8c 0a        (l_lsize: 2700)
Offset 0x7e: 0e           (l_version: 14)
Offset 0x7f: 17           (l_format: 23 — ELF/ARM)

Unpacking Method

Restoring the three OPS! instances to UPX! allows standard UPX 4.2.4 to decompress the binary successfully:

upx -d patched.elf -o unpacked.elf
  1197456 <- 469248   39.19%   linux/arm   unpacked.elf

Why Modified UPX?

This is not necessarily malicious. Possible explanations:

  1. OpenPLC build toolchain: The OpenPLC Editor Arduino build pipeline may use a customized UPX variant for firmware deployment
  2. Size optimization: Arduino MKR Zero has limited flash; UPX reduces firmware size by 60%
  3. Accidental: Developer may have used a forked UPX with modified constants
  4. Deliberate obfuscation: Unlikely given the benign nature of the code, but cannot be ruled out

Firmware Analysis

Architecture & Platform

  • Target: Arduino MKR Zero (Atmel SAMD21 — ARM Cortex-M0+)
  • ABI: EABI5, soft-float
  • Entry point: 0x2001791C (RAM execution — typical for Arduino bootloader chain)
  • Linker: Statically linked (all libraries embedded)
  • Sections: 19 sections including full debug info (.debug_info, .debug_str, .debug_line, etc.)
  • Symbols: 1,503 symbols (NOT stripped — unusual for production firmware)

Source Files (from debug symbols)

FilePurpose
Baremetal.ino.cppMain Arduino sketch (bare-metal PLC runtime)
ModbusSlave.cppModbus TCP slave implementation
Config0.cPLC configuration (OpenPLC generated)
POUS.cProgram Organization Units (IEC 61131-3)
Res0.cPLC resource definition
arduino.cppOpenPLC Arduino runtime layer
debug.cDebug/diagnostic functions
glueVars.cI/O variable mapping (PLC <-> hardware)
Ethernet.cpp, EthernetClient.cpp, etc.W5100 Ethernet library
SPI.cppSPI bus (W5100 communication)
w5100.cppWIZnet W5100 Ethernet chip driver
Uart.cpp, CDC.cpp, USBCore.cppSerial/USB communication

Key Functions

FunctionSize (bytes)Purpose
TRAFFICLIGHT_body__4,318Main traffic light control logic (PLC scan cycle)
TRAFFICLIGHT_init__1,040Traffic light state initialization
modbusTask()240Modbus TCP communication handler
plcCycleTask()32PLC scan cycle scheduler
handle_serial()304Serial debug interface
glueVars()144I/O variable synchronization
mbconfig_ethernet()120Modbus Ethernet configuration
setup()160Arduino initialization
loop()60Main loop (calls scheduler)

Modbus Configuration

The firmware implements a Modbus TCP Slave supporting:

  • MB_FC_READ_COILS — Read discrete outputs
  • MB_FC_READ_INPUT_STAT — Read discrete inputs
  • MB_FC_READ_REGS — Read holding registers
  • MB_FC_READ_INPUT_REGS — Read input registers
  • MB_FC_WRITE_COIL — Write single coil
  • MB_FC_WRITE_COILS — Write multiple coils
  • MB_FC_WRITE_REG — Write single register
  • MB_FC_WRITE_REGS — Write multiple registers

Error handling: MB_EX_ILLEGAL_ADDRESS, MB_EX_SLAVE_FAILURE

Embedded Network Configuration

Located at offset 0xB7CA in the unpacked binary:

FieldValueOffset
Debug MAC patternDE:AD:BE:EF:DE:AD0xB7CC
Device IP192.168.1.1950xB7D2
Gateway192.168.1.10xB7D6
Subnet mask255.255.255.00xB7DA
Debug MD5 hash558d148d2b08815643ddd5ae90d8a2210xB7DE

The MAC address DE:AD:BE:EF:DE:AD is a well-known placeholder/test value, confirming this is development/test firmware.

I/O Pin Mapping

The glueVars.c module maps PLC I/O variables to Arduino pins:

  • Digital inputs: __IX0_0 through __QX1_2 (traffic light sensor inputs)
  • Digital outputs: __QX0_0 through __QX0_7 (traffic light signal outputs)
  • Pin masks: DOUT pins 07-0C, AIN pins 10-15

Developer Attribution

FieldValueConfidence
UsernamesergioDEFINITIVE — embedded in 20+ debug paths
OSWindowsDEFINITIVE — backslash paths throughout
IDEOpenPLC Editor + Arduino IDEDEFINITIVE — build paths
Arduino BSPSAMD 1.8.13DEFINITIVE — full path in debug strings
GCC version7.2.1 20170904 (ARM embedded 7-2017-q4-major)DEFINITIVE — .comment section
Project path\Users\sergio\OpenPLC_Editor\editor\arduino\examples\BaremetalDEFINITIVE
Arduino libs\Users\sergio\Documents\Arduino\libraries\Ethernet\DEFINITIVE
Sketch temparduino-sketch-84CE77EEE7210676AFE890442798934CDEFINITIVE

The developer "sergio" is using OpenPLC Editor on Windows with Arduino SAMD board support package 1.8.13 installed via Arduino Board Manager. The Ethernet library is installed in the standard Arduino user libraries folder.

Note: "sergio" is likely associated with the OpenPLC project itself. The OpenPLC Editor project on GitHub is maintained by Thiago Alves, but the Baremetal examples and Arduino runtime may have multiple contributors. The path structure \OpenPLC_Editor\editor\arduino\examples\Baremetal matches the standard OpenPLC Editor repository layout.

YARA Rule Analysis (Why It Triggered)

RuleAuthorWhy It MatchedVerdict
SUSP_ELF_LNX_UPX_Compressed_FileFlorian Roth (Nextron)UPX-packed ELF binaryTRUE POSITIVE for UPX packing, but packing ≠ malicious
upx_antiunpack_elf32JPCERT/CCModified UPX magic (OPS! instead of UPX!)TRUE POSITIVE — magic bytes ARE modified
upx_packed_elf_v1RandomMalwareGeneric UPX-packed ELF detectionTRUE POSITIVE for UPX, FALSE POSITIVE for malware
linux_generic_ipv6_catcher@_lubiedoIPv6 socket structures in Ethernet libraryFALSE POSITIVE — benign IPv6 library code

The JPCERT/CC rule upx_antiunpack_elf32 is the most significant — it specifically detects UPX-packed ELF32 binaries where the magic bytes have been altered, which is a known technique used by Linux botnets (Mirai, Gafgyt, Tsunami). However, in this case, the modification is associated with legitimate firmware rather than malware.

AV Detection Assessment

13 of 38 AV engines flag this binary as suspicious or malicious:

VendorDetectionAssessment
ReversingLabsLinux.Trojan.GenericFALSE POSITIVE
KasperskyMalware (verdict)FALSE POSITIVE
FileScan.IOLIKELY_MALICIOUS (0.75 threat level)FALSE POSITIVE
Spamhaus HBLsuspiciousFALSE POSITIVE

Root cause of false positives:

  1. ARM ELF + modified UPX = strong heuristic match for IoT botnet patterns
  2. Statically linked binary with no section headers (packed state) = common in Mirai variants
  3. Modbus/Ethernet networking code = network communication capability
  4. Traffic light state machine = complex control flow that heuristic engines flag

MITRE ATT&CK Mapping

Not applicable — this is not malware. The binary does not implement any ATT&CK techniques.

IOC Assessment

No IOCs to report. This binary is legitimate firmware. The following indicators are documented for reference only and should NOT be added to blocklists:

  • SHA256: 6439834bec1cc530b12b1d821a509561efdd43048ecfb183939fe00a11a3c7dd — BENIGN
  • IP 192.168.1.195 — Private/LAN address, device configuration
  • IP 192.168.1.1 — Private/LAN gateway

ICS/SCADA Security Observations

While this binary is not malicious, the investigation reveals several ICS security concerns:

  1. Debug firmware in the wild: Full debug symbols, unstripped binary with developer paths — this should never leave the development environment
  2. Default/test MAC address: DE:AD:BE:EF:DE:AD suggests this is test firmware, not production
  3. No authentication on Modbus: Standard Modbus TCP has no built-in authentication — any device on the 192.168.1.0/24 network can read/write PLC registers
  4. Hardcoded network config: IP address and gateway are compiled into the firmware rather than configured dynamically
  5. OpenPLC on real hardware: If deployed in production, an OpenPLC-based traffic light controller with Modbus TCP and no network segmentation would be trivially exploitable

For AV Vendors

  • Submit false positive reports for SHA256 6439834bec1cc530b12b1d821a509561efdd43048ecfb183939fe00a11a3c7dd
  • Improve heuristics to differentiate between IoT botnet UPX modification and legitimate firmware packing
  • Consider whitelisting OpenPLC firmware signatures

For the OpenPLC Community

  • Investigate why the build toolchain produces modified UPX magic bytes
  • Strip debug symbols from release firmware to prevent developer information leakage
  • Document the UPX packing step in the build pipeline

For ICS/SCADA Defenders

  • Do not expose Modbus TCP devices directly to untrusted networks
  • Implement network segmentation for PLC-controlled infrastructure
  • Monitor for modified UPX-packed binaries in ICS environments — while this sample is benign, the same technique is used by real ICS-targeting malware

Conclusion

This investigation conclusively demonstrates that the sample is legitimate OpenPLC industrial control firmware for an Arduino MKR Zero, implementing a traffic light controller over Modbus TCP. The modified UPX packing (OPS! magic instead of UPX!) caused widespread false positive detections across AV engines and YARA rules designed to catch Linux botnets. The binary contains no malicious code, no C2 infrastructure, no exploitation capabilities, and no data exfiltration mechanisms.

The investigation highlights a persistent problem in threat intelligence: heuristic overlap between IoT botnet packing techniques and legitimate embedded firmware distribution. Modified UPX is a strong signal for malware in the Linux/ARM space, but it produces false positives when applied to the growing ecosystem of ARM-based ICS/IoT devices that use UPX for flash storage optimization.


GHOST — Breakglass Intelligence "One indicator. Total infrastructure. Even when the infrastructure is a traffic light."

Share