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:
parent
317c952b5f
commit
bd48d89480
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
out/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
.venv/
|
||||
53
PROVENANCE.md
Normal file
53
PROVENANCE.md
Normal 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.
|
||||
@ -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
78
RUNBOOK.md
Normal 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
79
build-baseline.sh
Executable 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
0
cadline/.gitkeep
Normal file
0
deployed/.gitkeep
Normal file
0
deployed/.gitkeep
Normal file
0
lib/.gitkeep
Normal file
0
lib/.gitkeep
Normal file
61
malware-iocs.md
Normal file
61
malware-iocs.md
Normal 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
21
malware-iocs.paths
Normal 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
0
overrides/.gitkeep
Normal file
0
packages/.gitkeep
Normal file
0
packages/.gitkeep
Normal file
Loading…
Reference in New Issue
Block a user