build(baseline): constituents+generator skeleton

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 <imre@illusion.hu>
Assisted-by: claude-code@claude-opus-4-8
This commit is contained in:
LÁZÁR Imre AI Agent 2026-07-16 09:40:46 +02:00
parent 317c952b5f
commit bd48d89480
12 changed files with 301 additions and 4 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
out/
*.pyc
__pycache__/
.venv/

53
PROVENANCE.md Normal file
View File

@ -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.

View File

@ -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)

78
RUNBOOK.md Normal file
View File

@ -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/<slug>/pristine/` | extracted upstream package (with manifest) | 2 — `lib/jmap.py` manifest-map |
| `packages/<slug>/cadline.patch` | our legit delta on that module (optional) | 2 — `patch -p1` after map |
| `deployed/<slug>/` | no-source extension, vetted deployed files (deployed layout) | 3 — direct rsync |
| `cadline/<slug>/` | 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/<slug>/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.

79
build-baseline.sh Executable file
View File

@ -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)"

0
cadline/.gitkeep Normal file
View File

0
deployed/.gitkeep Normal file
View File

0
lib/.gitkeep Normal file
View File

61
malware-iocs.md Normal file
View File

@ -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).

21
malware-iocs.paths Normal file
View File

@ -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

0
overrides/.gitkeep Normal file
View File

0
packages/.gitkeep Normal file
View File