VirLabs Blog
Tessera: reverse-engineering a backdoor on forgotten silicon
By VirLabs ·
Hello TILE-Gx
Imagine you open IDA Pro, and you get an error message that reads "undefined or unknown machine type 191". You know this will be an interesting day.
Let's back up a little. While hunting for out of the ordinary, undetected malware samples, I stumbled on a file that appears to target MikroTik routers using a CPU architecture I had never heard of: TILE-Gx. Wikipedia says it's a "very long instruction word" instruction set designed by Tilera for CPUs with many cores (like 72). Long story short, Tilera was acquired by Nvidia and by 2022 the production of TILE-Gx processors had ended. So... why would anyone bother writing malware -- or software at all, really -- for this architecture? It turns out MikroTik used TILE-Gx processors in its CCR1000 series: a line of carrier and ISP-grade routers. This is where the sample really got my attention and I, hopefully, just got yours. The CCR1000 ("Cloud Core Router") line does run on MikroTik's RouterOS, usually comes in a 1U form factor and was marketed to datacenters, hosting providers, and possibly small telecom providers on a budget. Not really something you'd use at home unless you're into something ridiculously oversized. Also not a natural target for your run-of-the mill cybercrime.
According to Shodan, there are about 100k internet-facing CCR1000 routers.
But back to our problem at hand: AI-powered reverse-engineering is great and all that, but only when you can produce decompiled code, or at the very least disassembly. Models may fall back to rawdogging ASM output produced by objdump, but that's a recipe for wasting lots of tokens while missing a lot. Cisco Talos created an IDA plugin in 2019 to add TILE-Gx support but seven years later, it just doesn't work out of the box anymore. So step one was rolling out my own, which I may open-source at some point if there is interest and I get around to cleaning it up.
Anyway, TILE-Gx instructions show up as bundles like: { addx r13, r0, r10 ; addx r11, r10, r12 }. As you see, multiple instructions come together with the intent of being executed in parallel. If the first instruction modified a register, the second one still uses the old value so there's more mental gymnastics involved than usual:

The malware chain
Three files are involved:
| Component | File name | SHA256 | Size | Type |
|---|---|---|---|---|
| Launcher | init.so | 5599b8ea1eb21baf1ded189cf701ccea05aef6e70f69a6226996f92c7e615dea | 70664 bytes | ELF64, little-endian TILE-Gx, shared library |
| Stager | /flash/rw/pckg/net_conf | 454f774be60f8a00d33ead9c5c522b73d09817ec97a0a764c0285ec8537f0573 | 125331 bytes | ELF32, little-endian TILE-Gx, static |
| Unpacked payload | /ram/<name> | 61871a20a13c6c1385c3e91ca2d3162b54f53c527ade0d73e191db12b09a66b1 | 148591 bytes | ELF32, little-endian TILE-Gx, static |
Note: another hash turned up during my research, 4ebf1357c568ae2c7d2e591380de5c5b3f43c697524ea2bd35770d160dcaabdb. It matches the stager's first PT_LOAD segment byte for byte. I'm therefore assuming it to be a file carving of some kind and not a different sample. All these files, obviously, aren't detected by any antivirus engine at the time of writing this, because who has heuristics or even signatures for TILE-Gx?
Here is a rough overview of how those components relate to each other:
flowchart TD
B["init.so (launcher)"]
C["/flash/rw/pckg/net_conf (stager)"]
D["Temporary ELF under /ram (unpacked payload)"]
E["/ram/<service-name> RouterOS service masquerading"]
F["Tessera C2 command loop"]
B -->|"chmod + execve"| C
C -->|"XZ decompresses to /ram then execve"| D
D -->|"creates service-name symlink and re-execs"| E
E --> F
C -.->|"attempts to unlink itself"| C
D -.->|"temporary executable and alias<br/>are subsequently removed"| E
Loader
init.so (VirLabs analysis) is the component from which the chain starts... at least as far as I can tell from the evidence at hand. I don't know its full path on a compromised device, nor how it ends up there in the first place. Although if I know my MikroTik history, I'm betting on an exploit of some kind. The launcher's logic resides in a constructor named initialize_test, referenced by .init_array. Its relevant behavior is small enough to reconstruct:
const char *path = "/flash/rw/pckg/net_conf";
chmod(path, 0777);
char *argv[] = { (char *)path, NULL };
execve(path, argv, NULL);
The /flash/rw path is strongly characteristic of RouterOS, confirming the MikroTik targeting.
Stager
First, this component (VirLabs analysis) attempts to unlink its entering argv[0], then attempts chdir("/"). This theoretically causes /flash/rw/pckg/net_conf to be deleted, which gives me the occasion of noting that since init.so does not deploy it, it could either mean that this chain doesn't use persistence (the router may just be exploited again as needed) or that an unavailable ancestor component is in charge of deploying the various files at play here.
The stager XORs embedded data to decode the /ram string, as well as the expected decompressed size of a second internal blob. The path is expanded to create a random six-character file with the format /ram/[a-pA-P]{6} (i.e., /ram/AbCdEf) with mode 0600. If file creation succeeds, the stager changes the file permissions to 0755, sets the size with ftruncate and maps it with MAP_SHARED and read/write permissions. An embedded XZ decoder writes the second blob (the payload) to this path.
After staging, the wrapper forks and the child calls daemon(1,1) to fully detach from its parent. The final descendant invokes execve with the /ram temporary path as its sole argument and a null environment.
Tessera payload
In addition to the stager's daemonization, the payload has its own startup procedure that creates a symlink to itself in /ram using one of the following names: led, log, macping, mactel, modprobed, moduler, mproxy, net, portman, quickset, resolver, route, sermgr, sys2, user, and www (i.e., /ram/net → /ram/AbCdEf). The payload daemonizes and relaunches itself via the symlink, replacing argv[0] with /nova/bin/<name> using the name picked in the previous step (i.e., /nova/bin/net). The new instance deletes both the symlink and the original extracted payload.
Another XOR decoder recovers an embedded configuration using a 128 byte key (starting with 4c8dd0a3a03e5f3e056ad859872ec1a0…) :
| Offset | Size | Description |
|---|---|---|
0x00 | 32 | Application AES key material |
0x20 | 16 | Identifier GDASRTWATR000088 |
0x30 | 4 | Retry-delay base: 60 |
0x34 | 4 | Failure timer: 0 |
0x38 | 4 | Failure timer threshold: 1814400 (21 days) |
0x3c | 4 | Endpoint text length: 17 |
0x40 | 1 | Endpoint count: 1 |
0x41 | 1 | Watched path length: 10 |
0x42 | 1 | Working directory length: 14 |
0x43 | 1 | (Padding) |
0x44 | 10 | Watched path /ram/.gtew |
0x4e | 14 | Working directory /ram/.JfOIiQe/ |
0x5c | 17 | Endpoint 131.255.4[.]144:443 |
Another string decoded in the binary indicates it could be version v6.5.2 of the implant. The watched path is a file which can force an earlier retry, suggesting that another local component may be able to wake the implant on demand. If the file is touched in any way, Tessera bypasses its configured delay in the next check.
After its setup, Tessera attempts to connect to its C2 server. I was impressed to see it rolls its own TLS stack (possibly derived from axtls). The implemented ClientHello offers TLS 1.2 and a single cipher suite (TLS_RSA_WITH_AES_128_CBC_SHA256) without any compression or extensions. Tessera implements the core record, MAC and key-derivation machinery, but the implementation is deliberately narrow and brittle: it expects a very specific handshake shape and omits much of the normal certificate validation. In particular, it extracts an RSA public key from the server certificate but does not verify the certificate chain, hostname, signature or validity period. This indicates to me that the payload expects the C2 server to behave in a predictable fashion.
Inside TLS, Tessera doesn't use HTTPS despite what the port suggests, but a custom protocol where it performs a second, application-level shared-secret authentication before accepting commands. The implant's packets have the following structure:
| Offset | Size | Description |
|---|---|---|
0x00 | 16 | Random bytes obtained through /dev/urandom; used as IV |
0x10 | 16 | Those bytes XORed with the configured identifier |
0x20 | 4 | Big-endian encrypted-body length |
0x24 | Variable | Encrypted body |
The inner cipher is AES-256-CBC with PKCS#7-style padding. The payload first identifies with the C2 server using a homemade, shared-key-based authentication challenge. Using the hardcoded pre-shared key i~pzv7i?t?E:NVZgpg.3=[mcvo_7XK.? (K), the client and server respectively pick random values C and S, and send each other SHA256(C || S || K) and SHA256(S || C || K) (also respectively). Upon success, the payload sends its version (04 06 v6.5.2) followed with an empty envelope, the server and the client send each other a packet containing K and Tessera enters the main command loop if everything checks out.
Supported commands
Once authenticated, the operator gets a compact remote-administration interface with eleven implemented commands. It supports bidirectional file transfer, arbitrary process execution with optional output capture, filesystem metadata queries, checksumming, session and retry controls, and the update/handoff mechanism discussed later. Commands are placed inside the encrypted body of the server packets and contain at least five bytes: one command byte and a four-byte length, followed by optional arguments. Outbound messages use a different six-byte header: type, auxiliary byte, and four-byte big-endian body length.
| Command | Description |
|---|---|
| 0 | Upload/write file |
| 2 | Download/read file |
| 4 | Execute process, optionally capturing output |
| 10 | Stop C2 loop |
| 12 | Change retry interval |
| 15 | End command session |
| 16 | Query file metadata |
| 18 | Empty/liveness response |
| 20 | XXH32 checksum of data or file |
| 22 | Initiate update |
| 26 | Report update status and implant version |
The command numbering runs from 0 to 26, but only eleven entries are implemented. The remaining values hit a common failure path, suggesting either a sparse protocol by design or functionality absent from this build. Command 22 appears to be the malware's update mechanism: it causes Tessera to stop interacting with the C2 and launch another file in its directory (./.hug.um). If /ram/.5U9XrYaE subsequently appears, the update is considered successful and Tessera exits after deleting its old working directory.
Tessera keeps an approximate inactivity/failure counter, reset by successful commands, while prolonged inability to conduct a useful C2 session eventually causes the implant to stop retrying, remove its working files and exit. With the configuration recovered from this sample, the threshold corresponds roughly to 21 days.
Infrastructure
Tessera’s configuration contains a single C2 address, 131.255.4[.]144:443. I confirmed that endpoint still accepted TLS connections and presented a self-signed RSA-2048 certificate with the following SHA-256 fingerprint: cb960c019ededaea7d1f7ccb2d12f06611ad44455f66c34057087b1c7d6c4b86. The certificate is valid from May 2019 to May 2029 and contains the familiar OpenSSL defaults: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, with no common name or subject alternative names. I couldn't find any indication that this certificate is generic or bundled with known software. This is where we enter speculation territory a little bit, please bear with me.
I'll start with an important piece of evidence: 131.255.4[.]144 is still live. I confirmed that on port 443, this IP responds to Tessera packets I generated and could complete an authentication sequence with the C2 server (the homemade handshake procedure described above). I was able to perform the SHA256(C || S || K) exchange, however the ID GDASRTWATR000088 causes the C2 to terminate connection immediately. Playing around, I noticed that GDASRTWATR000087 is an accepted identifier and allows the communication to continue but unfortunately the samples with this ID seem to use a different AES key and I was left unable to decrypt further packets.
Therefore, I'm assuming that the corresponding self-signed certificate was created by the attackers and that their activities date back to 2019. Yes, this date could be forged, but I find it consistent with the shelf life of MikroTik's CCR1000 series (from 2012 to 2022). It is also possible this certificate was carried over from previous, non-Tessera activity from the same actor, pointing to long-standing activities in any case.
If my hypothesis is correct, its reuse provides a useful infrastructure pivot. Validin recorded the same fingerprint on 12 IP addresses between August 2024 and October 2026. The configured C2 first appears in those observations on April 1, 2025. Several matches form adjacent pairs: 131.255.4[.]143–144, 185.246.128[.]139–140, and 108.181.71[.]52–53. This pattern suggests repeated provisioning of related servers, although the role of each endpoint remains unknown. I was also unable to establish a successful Tessera handshake with any of the additional IPs.
| IP | Hosting company | Date (as observed by Validin) |
|---|---|---|
| 131.255.4[.]144 (known C2) | BAEHOST / InterBS S.R.L. | 2025-04-01 → 2026-10-05 |
| 131.255.4[.]143 | BAEHOST / InterBS S.R.L. | 2025-09-21 → 2026-03-24 |
| 45.76.178[.]105 | Vultr / The Constant Company | 2024-08-23 → 2026-03-24 |
| 64.176.80[.]66 | Vultr / The Constant Company | 2025-09-25 → 2026-03-24 |
| 108.181.71[.]52 | Psychz Networks | 2026-03-19 → 2026-09-20 |
| 108.181.71[.]53 | Psychz Networks | 2026-03-22 → 2026-09-22 |
| 185.225.114[.]212 | IP Fiber Inc. | 2025-04-01 → 2026-09-06 |
| 185.225.114[.]250 | IP Fiber Inc. | 2025-04-01 → 2026-09-09 |
| 185.246.128[.]139 | w1n Ltd. | 2026-02-01 → 2026-09-08 |
| 185.246.128[.]140 | w1n Ltd. | 2026-02-22 → 2026-09-08 |
| 37.148.80[.]56 | Aria Shatel PJSC | 2026-02-26 |
| 92.242.211[.]194 | Respina Networks & Beyond PJSC | 2026-03-12 |
Conclusion
What a fun ride. Tessera combines familiar backdoor functionality with considerable attention to its intended environment. File transfers and command execution are hardly unusual, but the service impersonation, temporary execution paths and cleanup routines show that its developers understood RouterOS. The uneven quality of its TLS implementation also makes “sophisticated” a rather unhelpful label. The attackers invested effort in some places and cut corners where it made sense. Neither observation tells us who they are, and this is the most frustrating thing about this investigation: I couldn't find a single hint pointing towards attribution.
An interesting question is: how much protection an unusual architecture actually provides, and to whom? TILE-Gx makes this implant inconvenient to reverse engineer without making its capabilities particularly exotic. Once the developers had a working build, defenders inherited much of the remaining difficulty: finding suitable tooling, reconstructing its behavior and deciding where to look for traces. An obscure instruction set can make an ordinary backdoor an expensive investigation.
Recent MikroTrick reporting adds urgency to examining MikroTik devices, although I found no evidence connecting those attacks to Tessera. It also highlights a distinction worth keeping in mind during incident response. Reviewing accounts, scripts and scheduled tasks can uncover configuration-based persistence, but it's actually not 100% clear Tessera is persistent. Establishing the integrity of the native code running underneath is a different problem, and Tessera gives us a concrete reason to ask that second question.
Indicators of Compromise
File hashes
5599b8ea1eb21baf1ded189cf701ccea05aef6e70f69a6226996f92c7e615dea Launcher
454f774be60f8a00d33ead9c5c522b73d09817ec97a0a764c0285ec8537f0573 Stager
4ebf1357c568ae2c7d2e591380de5c5b3f43c697524ea2bd35770d160dcaabdb Stager (file carving)
61871a20a13c6c1385c3e91ca2d3162b54f53c527ade0d73e191db12b09a66b1 Tessera (ramdisk)
IP addresses
131.255.4.144 Tessera C2
131.255.4.143 Related infrastructure (same certificate)
45.76.178.105 Related infrastructure (same certificate)
64.176.80.66 Related infrastructure (same certificate)
108.181.71.52 Related infrastructure (same certificate)
108.181.71.53 Related infrastructure (same certificate)
185.225.114.212 Related infrastructure (same certificate)
185.225.114.250 Related infrastructure (same certificate)
185.246.128.139 Related infrastructure (same certificate)
185.246.128.140 Related infrastructure (same certificate)
37.148.80.56 Related infrastructure (same certificate)
92.242.211.194 Related infrastructure (same certificate)
TLS certificates
cb960c019ededaea7d1f7ccb2d12f06611ad44455f66c34057087b1c7d6c4b86 Tessera C2
File paths
/flash/rw/pckg/net_conf Stager
/ram/.JfOIiQe/.hug.um Update path
/ram/.gtew Watched path
/ram/.JfOIiQe/ Working directory
