172 lines
6.7 KiB
Text
172 lines
6.7 KiB
Text
|
|
/*
|
|
* BastionGuard™ — AUR Supply-Chain Detection
|
|
* Copyright (C) 2025–2026 Calogero Scarnà
|
|
*
|
|
* Rileva PKGBUILD e file .install compromessi.
|
|
* Pensato per il vettore della campagna "atomic-lockfile / Atomic Arch"
|
|
* (giugno 2026) ma generalizzato per intercettare compromissioni future.
|
|
*
|
|
* NOTA: queste regole girano su FILE DI TESTO (PKGBUILD, *.install, package.json),
|
|
* NON su ELF. Per questo il gate e' "uint32(0) != 0x7f454c46": vogliamo il
|
|
* VETTORE, non il payload. Il payload ELF lo coprono le tue regole cookie-stealer.
|
|
*
|
|
* Licenza: GPLv3. "BastionGuard" e' un marchio e non e' coperto dalla GPL.
|
|
*/
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* 1) IOC SPECIFICI DELLA CAMPAGNA — confidenza massima
|
|
* ------------------------------------------------------------------------- */
|
|
rule AUR_Atomic_Lockfile_Campaign_IOC
|
|
{
|
|
meta:
|
|
description = "AUR: IOC campagna atomic-lockfile / Atomic Arch (giugno 2026)"
|
|
severity = "critical"
|
|
score = 95
|
|
response = "quarantine"
|
|
author = "BastionGuard"
|
|
reference = "PKGBUILD -> npm atomic-lockfile -> preinstall -> ELF src/hooks/deps"
|
|
date = "2026-06"
|
|
|
|
strings:
|
|
$ioc1 = "atomic-lockfile" ascii nocase
|
|
$ioc2 = "src/hooks/deps" ascii nocase
|
|
|
|
// marker di contesto AUR per ridurre i FP su testi che ne parlano soltanto
|
|
$ctx1 = "pkgname=" ascii
|
|
$ctx2 = "pkgver=" ascii
|
|
$ctx3 = /\bpackage\s*\(\s*\)/
|
|
$ctx4 = /\bprepare\s*\(\s*\)/
|
|
$ctx5 = /\bpost_install\s*\(\s*\)/
|
|
$ctx6 = "\"preinstall\"" ascii // package.json
|
|
|
|
condition:
|
|
uint32(0) != 0x7f454c46 and
|
|
filesize < 1MB and
|
|
(
|
|
$ioc1 // "atomic-lockfile" e' gia' distintivo
|
|
or ($ioc2 and any of ($ctx*)) // il path da solo e' piu' generico
|
|
)
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* 2) PACKAGE MANAGER JS IN PKGBUILD/.install — vettore principale
|
|
* npm/bun/npx/pnpm/yarn che entrano dove non dovrebbero
|
|
* ------------------------------------------------------------------------- */
|
|
rule AUR_PKGBUILD_JS_PackageManager_Vector
|
|
{
|
|
meta:
|
|
description = "AUR: npm/bun/npx/pnpm/yarn in PKGBUILD o .install (vettore tipo atomic-lockfile)"
|
|
severity = "high"
|
|
score = 80
|
|
response = "quarantine_or_confirm"
|
|
author = "BastionGuard"
|
|
fix_notes = "npm in build()/package() di un progetto Node e' legittimo: per questo NON basta npm. Richiediamo npm DENTRO una scriptlet .install (gira come root) OPPURE accanto a lifecycle preinstall/postinstall."
|
|
|
|
strings:
|
|
$pm1 = "npm install" ascii
|
|
$pm2 = "npm ci" ascii
|
|
$pm3 = "npx " ascii
|
|
$pm4 = "bun install" ascii
|
|
$pm5 = "bunx" ascii
|
|
$pm6 = "pnpm " ascii
|
|
$pm7 = /yarn\s+(add|install)/
|
|
|
|
// scriptlet .install -> eseguite come root da pacman
|
|
$inst1 = /\bpost_install\s*\(\s*\)/
|
|
$inst2 = /\bpost_upgrade\s*\(\s*\)/
|
|
$inst3 = /\bpre_install\s*\(\s*\)/
|
|
$inst4 = /\bpre_upgrade\s*\(\s*\)/
|
|
|
|
// lifecycle npm sospetti in PKGBUILD/package.json
|
|
$life1 = "preinstall" ascii
|
|
$life2 = "postinstall" ascii
|
|
|
|
condition:
|
|
uint32(0) != 0x7f454c46 and
|
|
filesize < 1MB and
|
|
1 of ($pm*) and
|
|
(1 of ($inst*) or 1 of ($life*))
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* 3) REMOTE EXEC — download pipato verso shell / eval / base64 decode
|
|
* Il classico curl|sh nascosto in build()/prepare()/scriptlet
|
|
* ------------------------------------------------------------------------- */
|
|
rule AUR_PKGBUILD_RemoteExec_Pipe_Shell
|
|
{
|
|
meta:
|
|
description = "AUR: download remoto pipato a shell, o decode/eval (RCE in fase di build/install)"
|
|
severity = "critical"
|
|
score = 90
|
|
response = "quarantine"
|
|
author = "BastionGuard"
|
|
fix_notes = "I sorgenti legittimi si scaricano via array source=() verificato da sha256sums. curl|sh inline dentro le funzioni e' il segnale: questo NON matcha source=()."
|
|
|
|
strings:
|
|
// contesto: deve essere un PKGBUILD o una .install
|
|
$ctx1 = "pkgname=" ascii
|
|
$ctx2 = /\bbuild\s*\(\s*\)/
|
|
$ctx3 = /\bprepare\s*\(\s*\)/
|
|
$ctx4 = /\bpackage\s*\(\s*\)/
|
|
$ctx5 = /\bpost_install\s*\(\s*\)/
|
|
$ctx6 = /\bpost_upgrade\s*\(\s*\)/
|
|
|
|
// download -> shell
|
|
$pipe1 = /curl[^\n]{0,300}\|\s*(ba)?sh\b/
|
|
$pipe2 = /wget[^\n]{0,300}\|\s*(ba)?sh\b/
|
|
$pipe3 = /\$\(\s*(curl|wget)[^\n)]{0,200}\)\s*\|\s*(ba)?sh/
|
|
|
|
// offuscamento -> shell
|
|
$dec1 = /base64\s+(-d|--decode)[^\n]{0,120}\|\s*(ba)?sh/
|
|
$dec2 = /eval\s+["'`$]?\(?\s*(curl|wget|base64)/
|
|
$dec3 = /(curl|wget)[^\n]{0,200}\|\s*base64\s+(-d|--decode)/
|
|
|
|
condition:
|
|
uint32(0) != 0x7f454c46 and
|
|
filesize < 1MB and
|
|
any of ($ctx*) and
|
|
any of ($pipe*, $dec*)
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* 4) .install SCRIPTLET — rete o persistenza in contesto root
|
|
* Le scriptlet .install girano come root: rete/persistenza qui = quasi sempre malevolo
|
|
* ------------------------------------------------------------------------- */
|
|
rule AUR_Install_Scriptlet_Network_Or_Persistence
|
|
{
|
|
meta:
|
|
description = "AUR .install: scriptlet root con accesso rete o meccanismi di persistenza"
|
|
severity = "high"
|
|
score = 78
|
|
response = "quarantine_or_confirm"
|
|
author = "BastionGuard"
|
|
fix_notes = "'systemctl enable' e' sconsigliato ma talvolta usato da pacchetti aggressivi: tenuto come segnale debole. I segnali forti sono rete + autostart/cron/ld.so.preload/bashrc."
|
|
|
|
strings:
|
|
$sl1 = /\bpost_install\s*\(\s*\)/
|
|
$sl2 = /\bpost_upgrade\s*\(\s*\)/
|
|
$sl3 = /\bpre_install\s*\(\s*\)/
|
|
$sl4 = /\bpre_upgrade\s*\(\s*\)/
|
|
|
|
// rete (rarissima e sospetta in una scriptlet)
|
|
$net1 = /\bcurl\s/
|
|
$net2 = /\bwget\s/
|
|
$net3 = /\bnc\s+-/
|
|
$net4 = "/dev/tcp/" ascii
|
|
|
|
// persistenza
|
|
$per1 = "crontab" ascii
|
|
$per2 = "/etc/systemd/system/" ascii
|
|
$per3 = "/etc/profile.d/" ascii
|
|
$per4 = ".config/autostart" ascii
|
|
$per5 = "ld.so.preload" ascii
|
|
$per6 = /(>>?|tee)[^\n]{0,40}\.bashrc/
|
|
$per7 = "systemctl enable" ascii
|
|
|
|
condition:
|
|
uint32(0) != 0x7f454c46 and
|
|
filesize < 1MB and
|
|
1 of ($sl*) and
|
|
(1 of ($net*) or 1 of ($per*))
|
|
}
|