docs(reports): Kaiten/STD timeline follow-up and API review addendum - #27
docs(reports): Kaiten/STD timeline follow-up and API review addendum#27rdmmf wants to merge 19 commits into
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Corrects the single-family conclusion: the collection also contains a Kaiten/STD lineage (the *net samples), found by enumerating the symbols actually present instead of probing for expected Mirai names. - §7 Kaiten/STD family: attack API, IRC C2, cross-family libc false friends - §8 static-libc mass: 82-99% of functions per sample, and why raw similarity scores are mostly a toolchain measurement - Appendix A: all 50 leaf clusters, Appendix B: the 29 unclustered files - API review: doc gaps 4.11-4.14 (no name enumeration, libc-dominated scores, silent noise drop, member/files envelope split) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… exclude it
- family report §2.1: 26 of 50 leaf clusters are UPX stubs; table of every
filter attempted and how each one fails
- API review §4.15: bin_sim/search file-tag filters silently ignore any tag
containing a colon (rsplit(":",1) in _file_tag_union), reproduced with a
colon-free control tag; one-line fix suggested
- API review §4.16: unknown query params silently ignored (no 400)
- API review §4.17: min_funcs is max(a,b), so stub-vs-real pairs survive
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d samples The 82-99% figures come from a regex allowlist over function names, not from clustering. Records the limits (extrapolated from symbolised samples, allowlist makes malware share a lower bound) and the cluster-based method that would measure it properly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ation Symbol-name patterns over the symbolised samples give a cheap library seed set; propagating the tag across each seed's cluster reaches the stripped siblings the regex cannot see. Four-step pipeline in family report 8.3, API-side note in the review. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each section now opens with the API calls that produced it, the trap that wasted time, and the insight worth carrying to the next collection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Took all 50 leaves mechanically; the tree is strictly binary so that is the maximally-split view. Parents carry the campaign-level groupings (node 197 = whole boatnet set at 0.875, node 268 = whole iran group at 0.748). Adds a cohesion-cut recipe and the caveat that too low a threshold merges families. Corrects Appendix B: only 2 files are truly unclustered, not 29 - the other 27 sit in internal nodes and were an artefact of the leaf-only selection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same Kaiten/STD code base ten months apart: A's malware function set is a strict subset of B's (28 shared, 19 added). Documents why the 0.107 score understates it (cross-ISA + libc volume) and uses name-set Jaccard instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds Step 8 (two-file diff via table=&limit=0, and the symbol-set shortcut when both sides keep symbols) plus three gaps: unique_to_a/b never flag that a name appears on both sides (86 cases here, 24 provably identical), diff scores are not comparable across ISAs or libc builds, and there is no set operation between two files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up analysis on the mirai7 7b70/botnet version diff, using the API: - The eight 2026-02-09 *net samples share an identical 59-symbol malware set across 8 architectures: one cross-compiled build, not a timeline. The family reduces to two generations, 2025-04 and 2026-02. - The same-ISA A-vs-net diff (both MIPS:LE) shows 36 of 37 malware functions matching at similarity 1.000; only processCmd changed. This corrects the earlier report's "modified in place" section, whose sockprintf/main/print deltas were SuperH4 decompilation artefacts. - The command table is 29 entries read off MIPS, not the 13 recovered from SuperH4. - DNSw is a DNS flood handler dispatched from processCmd, not DNS-based C2 resolution as hypothesised. - The C2 host is a .data char* array (commServer) with default port 6982; confirmed unreachable through the API. The API addendum records new findings: avg_features on matched diff rows is max() rather than a mean, functions_metadata uses `name` where the search endpoints use `function_name`, matched rows can pair differently named functions without flagging it, the score penalises containment, and there is no way to read a data section or resolve a DAT_ symbol. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mermaid sankey in the timeline report: the 37 functions carried from the 2025-04 build bucketed by role, the 22 that first appear in 2026-02, and the 12 the 2026-03 fork lifted. Bucket membership is tabulated below the diagram so the flow widths are checkable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mermaid's sankey-beta lexer rejects non-ASCII characters in node names, including inside double-quoted fields, so the middot separators made the diagram fail to parse. Verified with mermaid-cli 11: the diagram now renders with all 13 nodes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The reports on this branch are the background for #28 — a proposal to turn the timeline built by hand here into a family evolution view in BSimVis. Reports referenced there:
The rendered diagram ( |
The Kaiten method (symbol-set diff) does not transfer to the Mirai side: only 4 of 164 files kept symbols, and those four use four different naming conventions for the same modules (attack_tcp_syn / flood_syndata / udpplain_thread). The analysis therefore runs on similarity clusters, with symbol names used only as labels. 100 symbols -> 101 clusters -> 54 capabilities across 80 reachable files: - The shared core is RNG, config table and checksums, present in 61-96 % of reachable samples across the whole five-month window. - xor_init and table_init share a cluster: a rename, not a new capability. - mipsel's flood_* and nova.mipsel's *_thread cluster only with themselves, so those forks rewrote the attack layer rather than renaming it. - Clusters resolve modules, not individual attack methods: one cluster holds ten different attack_* variants that share a packet loop. Includes a sankey of capability first-appearance waves by role, the per-role reach table, an explicit list of what the timeline is not, and the API gaps that made it a 380-call job. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Added the same analysis for the Mirai side of the collection: The Kaiten method did not transfer. Only 4 of 164 Mirai files kept symbols, and those four use four different names for the same modules ( What the clusters showed that names could not:
|
One function per role, seven of the eight taken from a single binary (nuclear.arm7); the exploit scanner exists only in mipsel, which is why it sits at 1 % reach. Two C2 addresses surfaced that the collection's cc_ip metadata does not record: raw.flameblox.com with fallback 87.120.191.32:5221 (nuclear.arm7), and 94.26.106.197 (arm7). The endianness reading of both constants is flagged as needing confirmation against a big-endian sibling. The exploit scanner is CVE-2017-17215 (Huawei HG532 UPnP), identified from the hard-coded digest credentials and port 37215 in the SOAP payload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three reports on collection mirai_unpacked_and_renamed3, mirroring the mirai7 set: family report, Kaiten timeline, Mirai timeline. The collection is mirai7 with upx -d applied and the packed MD5 kept in the filename, which makes the two joinable. Across the 55 matched pairs the same binaries go from 231 to 12,446 functions and 1,619 recovered symbol names, so most of what the mirai7 reports could not read is now readable. Main findings: - Vortax, a new Go family (8 samples, package vortax_server, C2 5.175.221.69:9111), undetected by ClamAV and absent from mirai7 - Kaiten's two newest builds drop 21 of the 59 functions its 2026-02 peak had, contradicting the mirai7 "nothing is ever dropped" result - chernobyl.mips is a Kaiten/Mirai hybrid: Kaiten attacks, Mirai config-table, killer and string runtime - symbolised Mirai seeds 4 -> 13, six of them recovered by unpacking, including an Aisuru merge visible in a single file Analysis is read-only through the REST API. The libc-similarity trap and the cross-ISA blind spot from the mirai7 reports both reproduce; neither is fixed by unpacking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ction Third per-family companion to the unpacked3 family report, replacing an earlier draft that restated the family report and left its central claims unverified. Vortax: the 2026-03-26 build is a strict symbol subset of the 2026-04-05 build (4364 of 4372, 8 symbols added = StartDNS + StartGREIP and their wrappers); full C2 command grammar recovered from main.main; C2 confirmed on x86-64 only, checked rather than assumed on both MIPS:BE samples. xnxn: config is AES-128-CBC with the key in .rodata, decrypted on three architectures across both build dates -- feather-daddy.duckdns.org:54128 to itzmeyourbro.duckdns.org:54128, token unchanged. The rebuild changes exactly one function of 257, and 10 of 11 architecture pairs still score 1.000 in bin_sim. Attribution: 79 of 257 functions share clusters with the p* Mirai campaign and none of them is bot code, so the 0.28 Jaccard is a shared build toolchain, not lineage; the ClamAV Mirai label on all 22 files is wrong. Family report section 6 and conclusions updated to match; its deliberate "unattributed" verdict is restored. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Vortax sankey had no split -- two sources into one sink, nothing dropped -- so it encoded no flow. Replaced with a short note on why the Kaiten sankey works and this one would not. The build-history timeline is now a gantt on a real date axis. The spacing is the finding: xnxn ships twice, 39 days apart, 11 arches each; Vortax ships four times inside 11 days. A category-per-column timeline flattened that away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rtax Go No binary cluster holds exactly the 8 Vortax files. Cluster 262 holds 7 of them plus mipsle, and excludes the x86-64 sample. Applying the section 2.5 test to mipsle: 260 functions shared with Vortax MIPS64, all Go stdlib and runtime, zero of the 29 vortax_server/main symbols. mipsle is a stripped Go binary that is not Vortax, so cluster 262 is named "vortax x7 + mipsle (Go runtime cut)" rather than "vortax". Also corrects the family report: mipsle's isolation is not an unshared libc, it has no libc -- it is Go, and the only other Go in the collection is Vortax. New section 1.3 records that the 8 files are 2 code versions and about 5 distinct binaries (one same-build pair at 1.000, three ARM sub-targets differing only in unnamed functions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Follow-up analysis requested on
doc/reports/mirai7_diff_7b70_vs_botnet.md, driven entirely through the BSimVis API.New reports
doc/reports/mirai7_kaiten_timeline.md— the analysisdoc/reports/api_pivoting_review_followup.md— API usability addendumFindings
*netsamples carry an identical 59-symbol malware set across 8 architectures — one cross-compiled build. The family is two generations (2025-04, 2026-02), not a gradient.Avsnetdiff (both MIPS:LE) puts 36 of 37 malware functions at similarity 1.000; onlyprocessCmdchanged (967 → 2153 features). This corrects the earlier report — itssockprintf+316 %,main+78 % andprint+32 % deltas were SuperH4 decompilation artefacts.CSGO,GTAV,TF2,R6-DROP,R6-LAG) were previously invisible.DNSwis a flood handler, dispatched asDNS <target> <port> <secs>— not DNS-based C2 resolution..datachar *array (commServer), default port 6982, confirmed unreachable through the API.API issues raised
avg_featureson matched diff rows ismax(), not a meanfunctions_metadatausesname, search endpoints usefunction_nameNone, reads as "diff has no names"SendSTD_HEX→SendHOME1at 1.000)diff?table=carries no scoreDAT_symbol read./scripts/wt-test.sh— 278/278 passed.🤖 Generated with Claude Code