MalwareBazaar Database
You are currently viewing the MalwareBazaar entry for SHA256 7c0b59171dfdaab72f18ef5325a508f2813f0477958167e53fb78cd716386937. While MalwareBazaar tries to identify whether the sample provided is malicious or not, there is no guarantee that a sample in MalwareBazaar is malicious.
Database Entry
Threat unknown
Vendor detections: 3
| SHA256 hash: | 7c0b59171dfdaab72f18ef5325a508f2813f0477958167e53fb78cd716386937 |
|---|---|
| SHA3-384 hash: | f4509da08df16381377ab057c2ab05bbdc166ba0e8453b18038013a4e79a4e8767a8be2fcb5242efda2db70c9a0f8d2c |
| SHA1 hash: | abf90b65dd8801e5d1f90accf713dabc3746638a |
| MD5 hash: | f38fd9a636106f82e751a89d48cfbcf0 |
| humanhash: | shade-washington-hawaii-oklahoma |
| File name: | server.jar |
| Download: | download sample |
| File size: | 3'643'157 bytes |
| First seen: | 2026-08-23 05:51:20 UTC |
| Last seen: | Never |
| File type: | |
| MIME type: | application/zip |
| ssdeep | 49152:+HR2JKn3GqtqR1fVypfX/9epQI+4TfOkLUVs66GXwX04wMy8GGzPKzMRAGmZ7FWp:FJK3GqsXfkx9eprrZThoPqPKIRR |
| TLSH | T124F5021AEAD82876E1BB927512970123BE3E4BCDF54E806428F435D1E8F7D855FA438C |
| TrID | 77.1% (.JAR) Java Archive (13500/1/2) 22.8% (.ZIP) ZIP compressed archive (4000/1) |
| Magika | jar |
| Reporter | |
| Tags: | binary dropper elf jar proxy |
maximealamahost
# One week, two proxy-node abuses, one operator**ยง1-ยง3** โ the sample attached to this report: a trojanised **NanoLimbo**
`server.jar`, one class out of 95 replaced, standing up a **sing-box** node
behind a Cloudflare Tunnel (2026-08-23).
**ยง4** โ the same operator's first attempt six days earlier: an obfuscated
Node.js dropper running **Xray-core** behind the *same* tunnel hostname
(2026-08-17). No sample retained, analysis done on the live files.
**Reported by:** Alama Hosting (small French game/bot hosting provider)
**Date of analysis:** 2026-08-23 ยท **Method:** static only โ the file was *never* executed
**Short version:** an unmodified build of the open-source Minecraft limbo server
**NanoLimbo** in which **exactly one class out of 95** has been replaced. The
replaced class downloads a native ELF binary, runs it, and exposes a
**sing-box** multi-protocol proxy through a **Cloudflare Tunnel**, then wipes the
panel console so the operator's node URIs are not left on screen. The real
Minecraft server starts afterwards, so the server looks perfectly healthy.
**Second incident by the same operator in one week**, against the same platform.
The first one (2026-08-17, obfuscated Node.js + Xray-core) is written up in full
in ยง4 โ same tunnel hostname, same TLS front, character for character.
---
## 1. Sample
| | |
|---|---|
| Filename | `server.jar` (uploaded by the customer to a free Minecraft plan) |
| Size | 3 643 568 bytes ยท 2 781 zip entries |
| SHA-256 | `7c0b59171dfdaab72f18ef5325a508f2813f0477958167e53fb78cd716386937` |
| MD5 | `f38fd9a636106f82e751a89d48cfbcf0` |
| Zip entry timestamps | **2026-08-19 23:01** โ the same day the account was created |
| Main-Class | `ua.nanit.limbo.NanoLimbo` |
| Upstream project | **NanoLimbo** by Nan1t, `LIMBO_VERSION = 1.21.1` |
## 2. The single modified class
Upstream `NanoLimbo.java` is **31 lines**; its `main()` does nothing but
`new LimboServer().start()` inside a try/catch.
In this build `NanoLimbo.class` is **9 284 bytes** and carries six added
methods: `runSbxBinary()`, `getBinaryPath()`, `loadEnvVars(Map)`,
`stopServices()`, `clearConsole()`, plus a shutdown hook.
**It is the only modified class in the archive.** The other 94 project classes
and every bundled library (netty 4.1.101, logback 1.5.6, gson 2.10.1,
snakeyaml 1.28โฆ) are clean: no other class references `ProcessBuilder`,
`URL.openStream` or `setExecutable`, and no binary is embedded beyond netty's
legitimate epoll natives. The bundled `settings.yml` is byte-for-byte the
upstream one (`bind: localhost:65535`, `dimension: THE_END`, `gameMode: 3`,
`infoForwarding: NONE`).
### Execution order in `main()`
1. **Java version gate** โ if `java.class.version < 54.0` (Java 10) it prints,
in red, `ERROR: Your Java version is too lower, please switch the version in
startup menu!` and exits. "startup menu" is **game-panel vocabulary**: this
was built for a Pterodactyl-like host, not for a generic box.
2. `runSbxBinary()` โ the payload (ยง3).
3. `Runtime.addShutdownHook(...)` โ kills the proxy process when the server stops.
4. `Thread.sleep(15s)`, then prints `Server is running!`,
`Thank you for using this script,Enjoy!`,
`Logs will be deleted in 20 seconds, you can copy the above nodes`.
5. `Thread.sleep(15s)` then **`clearConsole()`** โ ANSI erase sequences,
`tput reset`, `clear`. It wipes exactly the place where the payload had just
printed the node subscription URIs.
6. **Only then** `new LimboServer().start()` โ the genuine Minecraft server
comes up, giving the customer a perfectly credible "my server works".
## 3. Payload
### `getBinaryPath()` โ the downloader
| `os.arch` | URL |
|---|---|
| `amd64` / `x86_64` | `https://amd64.31888.xyz/sbsh` |
| `aarch64` / `arm64` | `https://arm64.31888.xyz/sbsh` |
| `s390x` | `https://s390x.31888.xyz/sbsh` |
Written to `${java.io.tmpdir}/sbx` (reused if already present), then
`File.setExecutable(true)`. Note the **`s390x`** branch: IBM mainframe, an
architecture nobody hosts Minecraft on, but which is standard in free-hosting
proxy-node kits.
### `runSbxBinary()` โ execution
`ProcessBuilder(sbx)` with `redirectErrorStream(true)` and
`redirectOutput(INHERIT)` โ the payload's output goes to the panel console,
which is why step 5 exists.
### `loadEnvVars()` โ configuration
Precedence: **hard-coded values โ environment variables โ a `.env` file in the
working directory** (the `.env` wins). The parser handles `export `, `#` and
`//` comments, and quotes. **The operator can therefore reconfigure the node by
dropping a `.env` next to the jar, without re-uploading anything.**
| Variable | Hard-coded value | Meaning |
|---|---|---|
| `UUID` | `10cc9e96-cee6-4751-805c-88be93402c9d` | sing-box inbound identifier |
| `FILE_PATH` | `./world` | **payload files hide in the Minecraft world folder** |
| `ARGO_PORT` | `8001` | local port exposed by the tunnel |
| `ARGO_DOMAIN` | **`alamahost.bbk.qzz.io`** | tunnel hostname โ **our brand name, hard-coded** |
| `ARGO_AUTH` | JWT (below) | **Cloudflare Tunnel credentials** |
| `CFIP` | `visa.com.tw` | clean domain behind Cloudflare used as TLS/SNI front |
| `CFPORT` | `443` | |
| `DISABLE_ARGO` | `false` | the tunnel is active |
| `NEZHA_SERVER` / `NEZHA_PORT` / `NEZHA_KEY` | empty | Nezha monitoring probe (inert here) |
| `S5_PORT`, `HY2_PORT`, `TUIC_PORT`, `ANYTLS_PORT`, `REALITY_PORT`, `ANYREALITY_PORT` | empty | SOCKS5, Hysteria2, TUIC, AnyTLS, Reality |
| `UPLOAD_URL`, `CHAT_ID`, `BOT_TOKEN` | empty | config exfiltration channels (Telegram / aggregator), inert |
| `PORT`, `NAME` | empty | `PORT` is taken from the environment โ **the container's allocated port also serves the subscription** |
None of `HY2`, `TUIC`, `REALITY`, `ANYTLS`, `S5`, `ARGO`, `NEZHA`, `CFIP`,
`CFPORT` exists anywhere in the Minecraft ecosystem. This is the variable set of
the **`eooce/Sing-box`** / **`yonggekkk/argosbx`** node scripts; `sbsh` is a
self-hosted repackaging of them on `31888.xyz`, which removes the dependency on
GitHub โ blocking `raw.githubusercontent.com` would achieve nothing.
### Decoded tunnel token
```json
{
"a": "4e9d6fa7b790d685390f7a382264c2e6", // operator's Cloudflare account tag
"t": "94ed92b4-3677-49f6-a4ee-c3b376c6e1e8", // tunnel ID
"s": "โฆ" // secret -> d728b664-2575-439b-b325-30b7fe453988
}
```
### Passive DNS (2026-08-23)
- `amd64.31888.xyz` / `arm64.31888.xyz` โ `188.114.96.2`, `188.114.97.2` (Cloudflare, NS `john/becky.ns.cloudflare.com`)
- `alamahost.bbk.qzz.io` โ `172.67.172.7`, `104.21.79.243` (Cloudflare โ tunnel alive)
- `visa.com.tw` โ `162.159.152.2`, `162.159.153.2` (Cloudflare)
- `qzz.io` โ NS `ns1/ns2/ns3.qzz.io` = **DigitalPlat FreeDomain**, free domain provider
## 4. The first incident, six days earlier (2026-08-17)
Same operator, no sample kept in this folder โ the analysis below was done on
the live files before the container was destroyed. Recorded here because the
pair is more interesting than either half.
**Entry point.** A free *Discord NodeJS bot* plan on a Pterodactyl-style egg.
Invented identity, disposable mailbox (`0mail.art`), source IP `3.14.152.148`
(**AWS us-east-2**). Account created, service provisioned, script deployed and
proxy node published **within the same hour**. No payment, so nothing
attributable.
**What was uploaded.** An obfuscated `.js` (obfuscator.io) plus a decoy
`index.html`: a fake low-code platform landing page, served on `/`, so that
anyone glancing at the server sees a website. If no `index.html` is found the
script serves `Hello world!` instead.
**What it actually did.** It downloaded **Xray-core** and **cloudflared** under
random 6-letter filenames, brought up VLESS / VMess / Trojan inbounds over
WebSocket on `127.0.0.1:3001-3004`, and exposed them through an **outbound
Cloudflare Tunnel** whose token was hard-coded in the file. Paths
`/vless-argo`, `/vmess-argo`, `/trojan-argo`.
**Anti-forensics.** At T+90 s it `rm -rf`s its own binaries and keeps running
off the deleted inodes โ the tell is a process whose `/proc/<pid>/exe` resolves
to **`(deleted)`**. Its cleanup list covers `list.txt`, `config.json`,
`boot.log`, the certificate and the binaries, but **not `sub.txt`**, a base64
blob of the node subscription. That oversight is what exposed the whole thing,
and the presence of a populated `sub.txt` proved the script had **completed**,
not merely been uploaded.
**Upstream.** A stripped, obfuscated fork of **`eooce/nodejs-argo`** (author
*eooce* / ่็, the Chinese free-hosting proxy-node ecosystem โ serv00, CT8,
PaaS). The fork removes the project's Nezha probe, changes the default UUID
(`9afd1229-โฆ` โ `961a54b1-โฆ`) and **hard-wires the Cloudflare Tunnel**. The
script also registers with `oooo.serv00.net` via `POST /add-url` โ the same
author's keep-alive panel, which pings free instances so they are not recycled
for inactivity.
**Exfiltration channels are inert by default** (`UPLOAD_URL`, `PROJECT_URL` +
`AUTO_ACCESS`, `BOT_TOKEN` + `CHAT_ID` all empty/false). They do not need to
work: the operator sees the connector appear in **their own Cloudflare
dashboard**, with the origin IP and the traffic volume. The tunnel is the
channel.
**Why it is a pivot problem and not a stealer problem.** The generated Xray
config has **no `routing` block** and a single `freedom` outbound โ zero
destination restriction. Whoever holds the UUID reaches, from inside the
hosting network, `127.0.0.1`, sibling containers, RFC1918 ranges and
`169.254.169.254`. DNS resolution goes out over DoH to `8.8.8.8`, i.e. outside
the host's DNS logs.
**Stable detection markers** (the domain and the UUID rotate, these do not):
a process whose `exe` is `(deleted)`; a leftover base64 `sub.txt`; the cleartext
strings that survive obfuscator.io's unencrypted string table โ
`tunnel --edge-ip-version auto`, `--no-autoupdate --protocol http2`,
`XTLS/Xray-core`, `cloudflared-linux-`, `/vless-argo`, `/vmess-argo`,
`/trojan-argo`; and an account whose entire content is one static landing page.
**One open question.** The node label produced by `getMetaInfo()` (which queries
`api.ip.sb/geoip` from the host) read **`FR-Bouygues_Telecom`**. Either the
node's egress really is that consumer line, or the operator generated the
subscription on their own machine before uploading. Not resolved.
## 4 bis. Same operator, both times
| | 2026-08-17 (free *Discord NodeJS bot* plan) | 2026-08-19โ23 (free *Minecraft* plan) |
|---|---|---|
| Vector | obfuscated `.js` (obfuscator.io) + decoy `index.html` | **Java `.jar`, grafted `main` class** |
| Proxy core | Xray-core + cloudflared | **sing-box** (`eooce` / ArgoSB family) |
| Tunnel hostname | **`alamahost.bbk.qzz.io`** | **`alamahost.bbk.qzz.io`** โ *identical* |
| `CFIP` front | `visa.com.tw` | `visa.com.tw` โ *identical* |
| UUID | `961a54b1-โฆ` | `10cc9e96-โฆ` (rotated) |
| Cover story | fake "CodeFlow" low-code platform front page | **the real limbo server actually starts** |
The brand name is still hard-coded in the tunnel hostname, i.e. the build is
tailored to the platform rather than sprayed. More uploads on other free plans
should be expected.
## 5. Notes for defenders
- This is **not** data theft: it is pivot and IP reputation. The node has no
destination restriction โ whoever holds the UUID exits through the host's IP
and can reach `127.0.0.1`, sibling containers, RFC1918 ranges.
- **Ingress filtering is useless**: the tunnel is *outbound*. `cloudflared`
leaves on 7844 TCP/UDP and falls back to HTTP/2 on 443. Only an **egress
allowlist** bites.
- **Second door**: `PORT` is inherited from the environment, so the container's
published port serves the subscription in the clear โ killing the tunnel or
the domain does not close it.
- **The `.env` overrides everything**, so a dropped `.env` re-points the node
without touching the jar.
- Practical order of what actually works on free plans: egress allowlist >
refusing customer-uploaded `.jar` in favour of a catalogue of known-hash jars
> identity or 0 โฌ payment fingerprint at signup.
## 6. Indicators
### 2026-08-23 (the attached sample)
```
sha256 7c0b59171dfdaab72f18ef5325a508f2813f0477958167e53fb78cd716386937 server.jar
md5 f38fd9a636106f82e751a89d48cfbcf0 server.jar
url https://amd64.31888.xyz/sbsh
url https://arm64.31888.xyz/sbsh
url https://s390x.31888.xyz/sbsh
domain 31888.xyz
host alamahost.bbk.qzz.io
cf-acct 4e9d6fa7b790d685390f7a382264c2e6
cf-tun 94ed92b4-3677-49f6-a4ee-c3b376c6e1e8
uuid 10cc9e96-cee6-4751-805c-88be93402c9d
front visa.com.tw:443
path ${java.io.tmpdir}/sbx ยท ./world (FILE_PATH) ยท ./.env
string "Thank you for using this script,Enjoy!"
string "Logs will be deleted in 20 seconds, you can copy the above nodes"
string "ERROR: Your Java version is too lower, please switch the version in startup menu!"
```
### 2026-08-17 (no sample retained)
```
host alamahost.bbk.qzz.io (identical to 08-23)
front visa.com.tw:443 (identical to 08-23)
uuid 961a54b1-โฆ (rotated between the two)
url oooo.serv00.net POST /add-url (eooce keep-alive panel)
path /vless-argo ยท /vmess-argo ยท /trojan-argo
listen 127.0.0.1:3001-3004 (WebSocket inbounds)
file sub.txt (base64, NOT in the script's cleanup list)
proc /proc/<pid>/exe -> (deleted) (binaries rm -rf'd at T+90s)
string "tunnel --edge-ip-version auto"
string "--no-autoupdate --protocol http2"
string "XTLS/Xray-core" ยท "cloudflared-linux-"
signup 3.14.152.148 (AWS us-east-2) ยท disposable mailbox at 0mail.art
```
## 7. What we do not have
**2026-08-23:** the Pterodactyl volume was deleted before it was searched, so
there is no evidence of whether the payload actually ran, and no `.env` to
compare against the hard-coded values. The jar alone is conclusive on intent.
Signup metadata (account, contact address, source IP โ a rented German VPS
range, AS47447, no rDNS across the whole /24) is available on request.
**2026-08-17:** no copy of the obfuscated `.js` or of the decoy `index.html`
was kept โ the container was destroyed during containment. What survives is the
analysis in ยง4, done on the live files, and the recovered `sub.txt`. If the
upstream `eooce/nodejs-argo` project is of interest, the fork differed from it
in three ways only: Nezha probe removed, default UUID changed, tunnel token
hard-coded.
Intelligence
File Origin
# of uploads :
1
# of downloads :
44
Origin country :
FRVendor Threat Intelligence
No detections
Detection:
n/a
Verdict:
Clean
Score:
99.9%
Tags:
n/a
Verdict:
Suspicious
Threat level:
5/10
Confidence:
100%
Tags:
anti-debug macros-on-close obfuscated
Verdict:
Unknown
File Type:
jar
Score:
0%
Verdict:
Benign
File Type:
ARCHIVE
Gathering data
Detection(s):
Suspicious file
Please note that we are no longer able to provide a coverage score for Virus Total.
Threat name:
Suspicious File
Score:
0.35
File information
The table below shows additional information about this malware sample such as delivery method and external references.
Comments
Login required
You need to login to in order to write a comment. Login with your abuse.ch account.