From bd48d894801ee14d6805191af6952c16ac1efba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=81Z=C3=81R=20Imre=20AI=20Agent?= Date: Thu, 16 Jul 2026 09:40:46 +0200 Subject: [PATCH] build(baseline): constituents+generator skeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-architect the baseline as constituents + a generator script (build-baseline.sh) instead of a checked-out deployed tree: a deployed Joomla docroot differs from the repo/source layout, so the script manifest-maps packaged extensions (lib/jmap.py), places no-source and Cadline files, applies core overrides, excludes malware/data, and emits out/ = the code baseline the operator HIDS verifier consumes. Adds RUNBOOK.md (recipe+inventory), PROVENANCE.md (upstream map), malware-iocs. Signed-off-by: LÁZÁR Imre Assisted-by: claude-code@claude-opus-4-8 --- .gitignore | 4 +++ PROVENANCE.md | 53 +++++++++++++++++++++++++++++++ README.md | 9 +++--- RUNBOOK.md | 78 +++++++++++++++++++++++++++++++++++++++++++++ build-baseline.sh | 79 ++++++++++++++++++++++++++++++++++++++++++++++ cadline/.gitkeep | 0 deployed/.gitkeep | 0 lib/.gitkeep | 0 malware-iocs.md | 61 +++++++++++++++++++++++++++++++++++ malware-iocs.paths | 21 ++++++++++++ overrides/.gitkeep | 0 packages/.gitkeep | 0 12 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 .gitignore create mode 100644 PROVENANCE.md create mode 100644 RUNBOOK.md create mode 100755 build-baseline.sh create mode 100644 cadline/.gitkeep create mode 100644 deployed/.gitkeep create mode 100644 lib/.gitkeep create mode 100644 malware-iocs.md create mode 100644 malware-iocs.paths create mode 100644 overrides/.gitkeep create mode 100644 packages/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d294fa75 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +out/ +*.pyc +__pycache__/ +.venv/ diff --git a/PROVENANCE.md b/PROVENANCE.md new file mode 100644 index 00000000..03ad5957 --- /dev/null +++ b/PROVENANCE.md @@ -0,0 +1,53 @@ +# PROVENANCE — extension → upstream map + +Per-extension origin for the baseline. `SUBMODULE`/`packages/` = source obtainable +(manifest-mapped); `deployed/` = no obtainable source (vetted live files, upstream URL +kept for reference only); `cadline/` = Cadline own-code. "modified" = Cadline changed +it → the change is a `cadline.patch` (packages/) or documented here (no-source). + +## Upstream-obtainable (packages/ — manifest-mapped) + +| Module | Version | Upstream | State | +|---|---|---|---| +| OneAll Social Login | 5.5.0 | github.com/oneall/social-login-joomla @5.5.0 | **modified** (CRM integration) | +| RemoteImage | 2.0.10 | github.com/asikart/remoteimage @2.0.10 | stock | +| Phoca Commander | 3.0.2 | github.com/PhocaCz/PhocaCommander @3.0.2 | stock | +| Phoca Download | 3.1.2 | github.com/PhocaCz/PhocaDownload @3.1.2 | **modified** (10 files: trial/HU routes/DB) | +| Easy File Uploader | 2.7.8 | github.com/ollily/easyfileuploader | **modified** (3 files: contest upload form) | + +## Git upstream exists but no version-matching package (deployed/, provenance only) + +| Module | Version | Upstream | Note | +|---|---|---|---| +| K2 | 2.8.0 | github.com/getk2/k2 | no 2.8.0 tag → deployed | +| JoomGallery | 3.3.4 | github.com/JoomGallery/JoomGallery | no 3.3.4 tag → deployed | +| Windwalker (lib) | 2.1.18 | github.com/ventoviro/windwalker | branch only → deployed | +| SP Easy Image Gallery | 1.0 | github.com/JoomShaper/SP-Easy-Image-Gallery | no 1.0 → deployed | +| Image Swoop | 1.2.5 | github.com/TemplateMonster-JoomlaTeam/mod_image_swoop | master only → deployed | +| IceMegaMenu | 3.0.1/3.0.0 | github.com/dakuzen/mod_icemegamenu | version mismatch → deployed | + +## No source (deployed/, vetted live files) + +sh404SEF 4.4.4.1791, JCK Editor 6.4.4/6.6.2 (**modified**: menunodes.php CVE-2018-17254 +mitigation — no upstream, Mértanmű fix, documented), SP Page Builder 3.6.2, iCagenda +3.7.15, Akeeba Backup 6.1.1, Convert Forms 3.0.0 (+NR Framework 4.6.26), Regular Labs +Sourcerer 7.4.0 / Advanced Module Manager 7.7.1 / Modals 9.13.0 / library 18.12.3953, +AcyMailing 6.2.0, MightySites 3.2.5/2.1.5, JSN/JoomlaShine 2.5.6, Jumi 3.0.5, TF Learn +1.7.5, Smart Countdown 3.4.5, Smart Shoutbox 3.0.6, Slideshow CK 2.5.2, Social Login & +Share 4.0, Helix3 2.5.5 (clean index.php — live one was infected), and repo-less +modules/plugins/libs/templates (bt_googlemaps, os_touchslider, jflickr, jux/mx/ol +timeline, ut_joomstagram, xpertscroller, anycode, flippingbook, joombig, youtuber, +jw_allvideos/sig, socialnetworks, fancybox, mootable, EUCookieDirectiveLite, extblank, +tmlazyload, p3p, xef, _theme3037, trada). + +## Cadline own-code (cadline/) + +Components: com_showroom, com_albanner, com_alworkshops, com_followedlinks, com_nonprofit, +com_presentation, com_project, com_tcexam, com_versions. Modules: mod_al_applications, +mod_al_login, mod_al_newsletter, mod_al_upload, mod_al_vote, mod_alusers, mod_alworkshops, +mod_course_list, mod_webinar, mod_webinar_list, mod_wsregister. Plugin: content/workshopdates. +Templates: blankframe, category. Submodules (Cadline-internal deployed-layout repos): +`common_cadline_libraries` → git.cadline.hu/cadline_web/cadcommonlib; `maintenance` → +git.cadline.hu/cadline_web/maintenance. Docroot apps: beiratkozas, iskolak, public, phpext. +Docroot PHPs: crashadmin.php, crm_hardlock.class.php, login-external.php, tips.php, +recaptchalib.php, configuration.php. diff --git a/README.md b/README.md index 7146e1a5..fbfe43ad 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ This repo produces the **clean code baseline** of the www.archline.hu docroot (Cadline, Joomla 3.8.11, host `tanis.cadline.hu`) — the post-compromise, malware-free, faithful reproduction of the live server's source files. The baseline is the **input** -to the operator's HIDS baseline-diff verifier (per-vhost known-good reference); the -verification itself runs there, not here. +to the `illusion/hids` verifier (imrcli per-vhost `vanilla_ref`); the verification +itself lives there, not here. ## Model: constituents + a generator script (not a checked-out tree) @@ -39,5 +39,6 @@ installer junk); it is not a target. ## References -- The archline.hu 2026 security audit and incident analysis (operator-held). -- The baseline is consumed by the operator's per-vhost HIDS baseline-diff verifier. +- Audit + baseline method: `cadline/infra` — `docs/audit/archline-hu-2026/` +- Per-vhost baseline tracking: cadline/infra#47 · Incident: cadline/infra#17 +- Verifier (consumer): `illusion/hids` (imrcli) diff --git a/RUNBOOK.md b/RUNBOOK.md new file mode 100644 index 00000000..2f497977 --- /dev/null +++ b/RUNBOOK.md @@ -0,0 +1,78 @@ +# RUNBOOK — building the www.archline.hu baseline + +This repo stores the **constituents** of the clean code baseline, not the deployed +tree. [`build-baseline.sh`](build-baseline.sh) deterministically "deploys" them into +`out/` — the code docroot that `illusion/hids` (imrcli `vanilla_ref`) diffs the live +server against. The deployed layout differs from the repo layout, so the build maps +each constituent to its Joomla-installed location. + +## Goal + +Reproduce the live www.archline.hu **source files as faithfully as possible, minus +malware**. Authority = the live docroot (RO mirror); the previous single-commit +"monolith" baseline is an unvalidated helper only (it dropped manifests and clean +core files, kept junk — not a target). + +## Directory contract + +| Dir | Holds | build-baseline.sh step | +|---|---|---| +| `core/` | Joomla 3.8.11 official full package (deployed form, installer removed) | 1 — rsync minus demo/data | +| `packages//pristine/` | extracted upstream package (with manifest) | 2 — `lib/jmap.py` manifest-map | +| `packages//cadline.patch` | our legit delta on that module (optional) | 2 — `patch -p1` after map | +| `deployed//` | no-source extension, vetted deployed files (deployed layout) | 3 — direct rsync | +| `cadline//` | Cadline own-code (deployed layout) | 4 — direct rsync | +| `overrides/*.patch` | Cadline core modifications (vs vanilla) | 5 — `patch -p1` | +| `malware-iocs.paths` | IOC exclusion safety net | 6 | + +Modified module → **two git commits**: pristine (`packages//pristine/`) then the +delta (`cadline.patch`), so `git diff` documents exactly our change vs upstream. + +## Build & verify + +``` +./build-baseline.sh # → out/ (the deployed code baseline) +``` + +Verification (residual→0, malware/data buckets) lives in **`illusion/hids`** (imrcli), +which consumes `out/` as the per-vhost `vanilla_ref`. This repo only produces the input. + +## Module inventory (categorization) + +### core +- Joomla 3.8.11 — official full package. Clean; live's 3 injected core files (see + `malware-iocs.md`) are restored by using the package version. + +### packages/ — upstream package obtainable (manifest-mapped; provenance + delta) +- `oneallsociallogin` — OneAll 5.5.0, github.com/oneall/social-login-joomla @5.5.0; **modified** (CRM) → cadline.patch +- `remoteimage` — asikart/remoteimage @2.0.10 (stock) +- `phocacommander` — PhocaCz/PhocaCommander @3.0.2 (stock) +- `phocadownload` — PhocaCz/PhocaDownload @3.1.2; **modified** (10 files) → cadline.patch +- `easyfileuploader` — ollily/easyfileuploader; **modified** (3 files) → cadline.patch +- *(K2, JoomGallery, Windwalker: git repos exist but no version-matching package → + currently `deployed/`; promote to `packages/` if a 2.8.0/3.3.4 package is obtained.)* + +### deployed/ — no obtainable package (vetted live files) +K2, JoomGallery, Windwalker; sh404SEF, JCK Editor, SP Page Builder, iCagenda, Akeeba +Backup, Convert Forms (+NR Framework), Regular Labs (Sourcerer/AMM/Modals/lib), +AcyMailing, MightySites, JSN/JoomlaShine, Jumi, TF Learn, Smart Countdown, Smart +Shoutbox, Slideshow CK, Social Login&Share, SP Easy Image Gallery, IceMegaMenu, Image +Swoop, Helix3 (clean index.php), and the repo-less modules/plugins/libs/templates +(bt_googlemaps, os_touchslider, jflickr, *_timeline, ut_joomstagram, xpertscroller, +anycode, flippingbook, joombig, youtuber, jw_allvideos/sig, socialnetworks, fancybox, +mootable, EUCookie, extblank, tmlazyload, p3p, xef, _theme3037, trada, …). +JCK: **modified** (menunodes.php CVE-2018-17254 mitigation) — no upstream, documented +in PROVENANCE.md. + +### cadline/ — Cadline own-code +com_showroom, com_albanner, com_alworkshops, com_followedlinks, com_nonprofit, +com_presentation, com_project, com_tcexam, com_versions; mod_al_*, mod_alusers, +mod_alworkshops, mod_course_list, mod_webinar*, mod_wsregister; plg content/workshopdates; +templates blankframe, category; docroot apps (beiratkozas, iskolak, public, phpext); +docroot PHPs (crashadmin.php, crm_hardlock.class.php, login-external.php, tips.php, +recaptchalib.php, configuration.php). Cadline-internal deployed-layout repos are +**git submodules**: `common_cadline_libraries` → cadcommonlib, `maintenance` → maintenance. + +### overrides/ — Cadline core modifications (23 files) +com_content / com_users (registration/login/reset/remind), mod_login, captcha/recaptcha, +language ini, phpversioncheck — the ~26 legit customizations (§16.1), as patches on vanilla. diff --git a/build-baseline.sh b/build-baseline.sh new file mode 100755 index 00000000..4bc4054b --- /dev/null +++ b/build-baseline.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# +# build-baseline.sh — reproducibly assemble the www.archline.hu clean CODE baseline. +# +# Output (out/) = the deployed docroot (code only), which the illusion/hids +# baseline-diff (imrcli vanilla_ref) verifies the live server against. +# +# The repo stores the baseline CONSTITUENTS, not the deployed tree; this script +# performs the deterministic "deployment" (Joomla manifest-mapping for packaged +# extensions, direct placement for no-source ones), per RUNBOOK.md. +# +# Usage: ./build-baseline.sh [OUT_DIR] (default: ./out) +set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUT="${1:-$ROOT/out}" +JMAP="$ROOT/lib/jmap.py" +log(){ printf '[build] %s\n' "$*"; } + +rm -rf "$OUT"; mkdir -p "$OUT" + +# 1) Joomla core — official 3.8.11 package (deployed form), minus demo assets and +# runtime data dirs (cache/tmp/logs/images are data, not verified code). +log "core: Joomla 3.8.11 (official package)" +rsync -a \ + --exclude='cache/' --exclude='tmp/' --exclude='logs/' \ + --exclude='images/sampledata/' --exclude='images/banners/' --exclude='images/headers/' \ + --exclude='images/joomla_black.png' --exclude='images/powered_by.png' \ + "$ROOT/core/" "$OUT/" + +# 2) Upstream-package extensions — map the pristine package to deployed paths via +# the Joomla manifest, then apply the Cadline delta patch (if the module was +# legitimately modified). git diff pristine<->patch documents our delta. +for pkg in "$ROOT"/packages/*/; do + [ -d "$pkg" ] || continue + name="$(basename "$pkg")" + log "package: $name (manifest-map)" + python3 "$JMAP" --package "$pkg/pristine" --out "$OUT" + if [ -f "$pkg/cadline.patch" ]; then + log "package: $name (apply Cadline delta)" + ( cd "$OUT" && patch -p1 --no-backup-if-mismatch < "$pkg/cadline.patch" ) + fi +done + +# 3) No-source extensions — vetted deployed files (no obtainable package), +# placed directly (already in deployed layout). +for d in "$ROOT"/deployed/*/; do + [ -d "$d" ] || continue + log "deployed: $(basename "$d")" + rsync -a --exclude='.provenance' "$d" "$OUT/" +done + +# 4) Cadline own-code (components/modules/plugins/templates/docroot apps). +for d in "$ROOT"/cadline/*/; do + [ -d "$d" ] || continue + log "cadline: $(basename "$d")" + rsync -a --exclude='.provenance' "$d" "$OUT/" +done + +# 5) Cadline core modifications — patches applied on the vanilla core. +for p in "$ROOT"/overrides/*.patch; do + [ -f "$p" ] || continue + log "override: $(basename "$p")" + ( cd "$OUT" && patch -p1 --no-backup-if-mismatch < "$p" ) +done + +# 6) Safety net — malware IOC + scan artifacts must never appear in the baseline +# (the sources above already exclude them; this is defensive, documented in +# malware-iocs.md / malware-iocs.paths). +log "exclude: malware IOC + scan artifacts" +find "$OUT" \( -name '*.php.json' -o -name '*.phtml.json' -o -name 'h3x_*' -o -name '_h3x_*' \) -delete 2>/dev/null || true +if [ -f "$ROOT/malware-iocs.paths" ]; then + while IFS= read -r ioc; do + [ -z "$ioc" ] && continue + case "$ioc" in \#*) continue;; esac + rm -rf "${OUT:?}/$ioc" + done < "$ROOT/malware-iocs.paths" +fi + +log "baseline built at: $OUT ($(find "$OUT" -type f | wc -l) files)" diff --git a/cadline/.gitkeep b/cadline/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/deployed/.gitkeep b/deployed/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/malware-iocs.md b/malware-iocs.md new file mode 100644 index 00000000..eb5bd039 --- /dev/null +++ b/malware-iocs.md @@ -0,0 +1,61 @@ +# Malware / planted IOC set — www.archline.hu + +Authoritative source: `cadline/infra` incidens-doksi (#17), §7/13/14/16 (human-tracked). +These items are **excluded from the baseline** so the HIDS baseline-diff flags them +on the live server. Machine-readable path list: [`malware-iocs.paths`](malware-iocs.paths). + +## Trojanized core — restored to clean vanilla (NOT patched) + +The 3 injected core files are provided **clean** by the official Joomla 3.8.11 +package in `core/`; the live (malware) versions are simply not used: + +| File | Injection | +|---|---| +| `plugins/authentication/joomla/joomla.php` | credential-stealer, C2 `leitungs-shop.de`, exfil on every login (§16.3) | +| `libraries/joomla/session/storage.php` | session-init loader for the dropped backdoor | +| `libraries/joomla/event/event.php` | framework-level output injector | + +## Dropped core backdoors — excluded (not in vanilla) + +| File | Nature | +|---|---| +| `libraries/joomla/session/cache.php` | obfuscated eVaL backdoor (dropped) | +| `administrator/components/com_joomlaupdate/never.php` | cookie-gated RCE (2026-07-10) | + +## Root webshells — excluded + +- `wp-stomp.php` — SEO-cloaking injector +- `hyjhxp.php` — WSO webshell + +## Attacker modules (entire dir) — excluded + +- `modules/mod_seolite` — chain root (base64+LZW+eval) +- `modules/mod_articles_single` — webshell (the monolith wrongly kept it; §14.2) + +## Dropped webshells inside legit dirs — only the dropped file excluded + +- `modules/mod_al_upload/b8.php` (legit module base kept) +- `modules/mod_course_list/a1.php` (legit module base kept) +- `templates/trada/html/mod_articles_category/meant.php` (legit 2015 template kept) +- `templates/category/tiny.php` (Tiny File Manager backdoor) + +## Template infection / SEO spam + +- `templates/shaper_helix3/index.php` — fbwjedi cloaking block → the clean template + index.php is used (the infected live one is excluded and replaced). +- `templates/system/links.db` — Sape SEO link-spam (23KB serialized). + +## Planted components (entire dir) — excluded + +- `com_extplorer` (planted CVE-carrying file manager, 2024-07-15) +- `com_joml_incf`, `com_sys_rom` (webshells) + +## Scan artifacts (not real files) — excluded + +- `*.php.json`, `*.phtml.json`, `h3x_*`, `_h3x_*` (web-hids inventory outputs) + +## Non-malware note (hygiene, not excluded) + +- `components/com_users/controllers/registration.php` carries a hardcoded reCAPTCHA + secret (Cadline's own leaked secret) — the file stays (real source); the secret is + to be rotated on cleanup. Not quoted here (redaction). diff --git a/malware-iocs.paths b/malware-iocs.paths new file mode 100644 index 00000000..d223c258 --- /dev/null +++ b/malware-iocs.paths @@ -0,0 +1,21 @@ +# Machine-readable malware/planted paths (docroot-relative) excluded from the baseline. +# Consumed by build-baseline.sh step 6. Rationale + IOC detail in malware-iocs.md. +# NOTE: the 3 injected core files (auth/joomla.php, session/storage.php, event/event.php) +# are NOT listed here — they are RESTORED to clean vanilla by the official core package. +wp-stomp.php +hyjhxp.php +libraries/joomla/session/cache.php +administrator/components/com_joomlaupdate/never.php +modules/mod_seolite +modules/mod_articles_single +modules/mod_al_upload/b8.php +modules/mod_course_list/a1.php +templates/trada/html/mod_articles_category/meant.php +templates/category/tiny.php +templates/system/links.db +components/com_extplorer +administrator/components/com_extplorer +components/com_joml_incf +administrator/components/com_joml_incf +components/com_sys_rom +administrator/components/com_sys_rom diff --git a/overrides/.gitkeep b/overrides/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/.gitkeep b/packages/.gitkeep new file mode 100644 index 00000000..e69de29b