spencernorton commited on
Commit
20b0430
·
verified ·
1 Parent(s): 89d9250

Harden BitTorrent and DHT malware, mount-trap, and archive-trap detection

Browse files
Files changed (2) hide show
  1. armiger_dht_rsi.py +3 -1
  2. armiger_inference.py +36 -10
armiger_dht_rsi.py CHANGED
@@ -3226,7 +3226,9 @@ def generate_golden_canary_suite(seed: int = 20261018) -> List[CanaryItem]:
3226
  "Big.Buck.Bunny.2024.CAM.1080p.download_tool.bat",
3227
  ]
3228
  for i in range(25):
3229
- name = malware_names[i % len(malware_names)] + f".sample{i}"
 
 
3230
  items.append(CanaryItem(
3231
  item_id=f"canary_jnk_{i:03d}",
3232
  title=name,
 
3226
  "Big.Buck.Bunny.2024.CAM.1080p.download_tool.bat",
3227
  ]
3228
  for i in range(25):
3229
+ _base = malware_names[i % len(malware_names)]
3230
+ _dot = _base.rfind(".")
3231
+ name = f"{_base[:_dot]}_sample{i}{_base[_dot:]}" if _dot != -1 else f"{_base}_sample{i}"
3232
  items.append(CanaryItem(
3233
  item_id=f"canary_jnk_{i:03d}",
3234
  title=name,
armiger_inference.py CHANGED
@@ -13,12 +13,16 @@ from __future__ import annotations
13
  import hashlib
14
  import json
15
  import math
 
16
  from pathlib import Path
17
  import re
18
  from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
19
  import zlib
20
 
21
- import numpy as np
 
 
 
22
 
23
  NEURAL_HEAD_CLASSES: Dict[str, List[str]] = {
24
  "category": [
@@ -94,7 +98,7 @@ _SIDE_EP_ZIP_RE = re.compile(
94
  r"\bS\d{1,2}E\d{1,3}\b.*?\b(?:1080p|720p|2160p|WEB-DL|WEBRip|BluRay|HDTV)\b)"
95
  )
96
  _SIDE_BENIGN_ZIP_RE = re.compile(
97
- r"(?i)\b(?:batch|complete|season[ ._-]*\d+|s\d{1,2}[ ._-]*complete|\d{1,3}[ ._-]*-[ ._-]*\d{1,3}|"
98
  r"ost|soundtrack|artbook|scans?|wallpapers?|fonts?|subs?|subtitles?)\b"
99
  )
100
 
@@ -116,6 +120,8 @@ def _get_vocab_ext_map() -> Dict[str, int]:
116
  if _VOCAB_EXT_MAP is not None:
117
  return _VOCAB_EXT_MAP
118
  vpath = Path(__file__).resolve().with_name("vocab.json")
 
 
119
  if vpath.exists():
120
  data = json.loads(vpath.read_text(encoding="utf-8"))
121
  _VOCAB_EXT_MAP = {e: i + 1 for i, e in enumerate(data.get("exts", []))}
@@ -259,7 +265,7 @@ def encode_torrent_features(
259
  htm_set = {"html", "htm", "url", "mht", "torrent"}
260
  scr_set = {"scr", "lnk", "vbs", "hta", "pif", "ps1", "wsf", "reg"}
261
  vid_set = {"mkv", "mp4", "avi", "ts", "m2ts", "wmv", "mov", "webm", "flv", "mpg", "mpeg", "m4v", "vob", "ogv", "rmvb", "3gp", "asf", "divx"}
262
- bd_game_benign = {"vcdiff", "apk", "bdmv", "clpi", "mpls", "ifo", "bup", "vob", "npa", "vpk", "pck", "umd", "pak", "xp3", "rgss3a", "wolf", "nsp", "xci", "wbfs"}
263
 
264
  side[0] = sum(1 for e in f_exts_str if e in ebk_set) / n_f
265
  side[1] = sum(1 for e in f_exts_str if e in pdf_set) / n_f
@@ -268,15 +274,32 @@ def encode_torrent_features(
268
  side[4] = sum(1 for e in f_exts_str if e in con_set) / n_f
269
  side[5] = sum(1 for e in f_exts_str if e in app_set) / n_f
270
 
 
 
 
 
 
 
 
 
271
  n_real_exec_dll = 0
272
  has_real_exe = False
273
  has_dll = False
274
  has_scr_trap = False
275
  has_oversized_lnk = False
276
  has_root_launcher = False
 
 
277
  vid_depths: List[int] = []
278
 
279
  for (p_i, _), e_str, s_b, d_i, w_i in zip(items, f_exts_str, sizes, depths, words_list):
 
 
 
 
 
 
 
280
  p_tok_h = _extract_token_hashes(p_i)
281
  is_benign_stub = (e_str == "exe") and (s_b < 15 or 16570 in w_i or bool(p_tok_h & _BENIGN_README_EXE_H))
282
  if e_str in exe_dll_set and not is_benign_stub:
@@ -300,29 +323,32 @@ def encode_torrent_features(
300
  side[7] = sum(1 for e in f_exts_str if e in iso_set) / n_f
301
  side[8] = sum(1 for e in f_exts_str if e in arc_set) / n_f
302
  side[9] = sum(1 for e in f_exts_str if e in htm_set) / n_f
303
- side[10] = 1.0 if any(e in scr_set for e in f_exts_str) else 0.0
304
 
305
- vc = bool(_SIDE_VID_CLAIM_RE.search(name) or _SIDE_ANIME_KW_RE.search(name) or has_sub_grp or has_dub_grp)
306
  is_sw_or_game = bool(
307
  has_game_grp
308
  or has_sw_grp
309
- or _SIDE_SW_APP_TITLE_RE.search(name)
310
  or any(e in bd_game_benign for e in f_exts_str)
311
  )
312
  vid_share = base_stats[2]
313
- flagged = False
314
- if not is_sw_or_game and len(items) <= 12:
315
  if vc and has_real_exe and has_dll:
316
  flagged = True
317
- elif vc and (1 <= len(vid_depths) <= 2) and min(vid_depths) >= 1 and has_root_launcher:
318
  flagged = True
319
  elif (vc or len(vid_depths) > 0) and has_oversized_lnk:
320
  flagged = True
321
  elif vc and vid_share == 0.0 and (has_real_exe or has_scr_trap):
322
  flagged = True
323
- elif len(items) == 1 and f_exts_str[0] == "zip" and vid_share == 0.0:
324
  if _SIDE_EP_ZIP_RE.search(name) and not _SIDE_BENIGN_ZIP_RE.search(name):
325
  flagged = True
 
 
 
 
326
 
327
  if flagged or _SIDE_VPN_TRAP_RE.search(name) or (vc and vid_share == 0.0 and (side[6] > 0 or side[9] > 0 or side[10] > 0)):
328
  side[11] = 1.0
 
13
  import hashlib
14
  import json
15
  import math
16
+ import os
17
  from pathlib import Path
18
  import re
19
  from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
20
  import zlib
21
 
22
+ try:
23
+ import numpy as np
24
+ except ImportError:
25
+ np = None # type: ignore[assignment]
26
 
27
  NEURAL_HEAD_CLASSES: Dict[str, List[str]] = {
28
  "category": [
 
98
  r"\bS\d{1,2}E\d{1,3}\b.*?\b(?:1080p|720p|2160p|WEB-DL|WEBRip|BluRay|HDTV)\b)"
99
  )
100
  _SIDE_BENIGN_ZIP_RE = re.compile(
101
+ r"(?i)\b(?:batch|complete|season[ ._-]*\d+|s\d{1,2}[ ._-]*complete|e?\d{1,3}[ ._-]*[~-][ ._-]*e?\d{1,3}|시즌\s*\d+|완결|全集|合集|"
102
  r"ost|soundtrack|artbook|scans?|wallpapers?|fonts?|subs?|subtitles?)\b"
103
  )
104
 
 
120
  if _VOCAB_EXT_MAP is not None:
121
  return _VOCAB_EXT_MAP
122
  vpath = Path(__file__).resolve().with_name("vocab.json")
123
+ if not vpath.exists() and os.environ.get("ARMIGER_MODEL_DIR"):
124
+ vpath = Path(os.environ["ARMIGER_MODEL_DIR"]) / "vocab.json"
125
  if vpath.exists():
126
  data = json.loads(vpath.read_text(encoding="utf-8"))
127
  _VOCAB_EXT_MAP = {e: i + 1 for i, e in enumerate(data.get("exts", []))}
 
265
  htm_set = {"html", "htm", "url", "mht", "torrent"}
266
  scr_set = {"scr", "lnk", "vbs", "hta", "pif", "ps1", "wsf", "reg"}
267
  vid_set = {"mkv", "mp4", "avi", "ts", "m2ts", "wmv", "mov", "webm", "flv", "mpg", "mpeg", "m4v", "vob", "ogv", "rmvb", "3gp", "asf", "divx"}
268
+ bd_game_benign = {"vcdiff", "apk", "bdmv", "clpi", "mpls", "ifo", "bup", "vob", "npa", "vpk", "pck", "umd", "pak", "xp3", "rgss3a", "wolf", "nsp", "xci", "wbfs", "rpa", "rpy", "rpyb"}
269
 
270
  side[0] = sum(1 for e in f_exts_str if e in ebk_set) / n_f
271
  side[1] = sum(1 for e in f_exts_str if e in pdf_set) / n_f
 
274
  side[4] = sum(1 for e in f_exts_str if e in con_set) / n_f
275
  side[5] = sum(1 for e in f_exts_str if e in app_set) / n_f
276
 
277
+ vc = bool(_SIDE_VID_CLAIM_RE.search(name) or _SIDE_ANIME_KW_RE.search(name) or has_sub_grp or has_dub_grp)
278
+ has_renpy_structure = not vc and any(
279
+ p_i.replace("\\", "/").lower().endswith((".rpa", ".rpy", ".rpyb"))
280
+ or "/renpy/" in "/" + p_i.replace("\\", "/").lower()
281
+ for p_i, _ in items
282
+ )
283
+ renpy_say_re = re.compile(r"(?i)(?:^|/)lib/(?:py\d+-)?windows-[^/]+/say\.vbs$")
284
+
285
  n_real_exec_dll = 0
286
  has_real_exe = False
287
  has_dll = False
288
  has_scr_trap = False
289
  has_oversized_lnk = False
290
  has_root_launcher = False
291
+ has_unconditional_trap_ext = False
292
+ has_any_scr_ext = False
293
  vid_depths: List[int] = []
294
 
295
  for (p_i, _), e_str, s_b, d_i, w_i in zip(items, f_exts_str, sizes, depths, words_list):
296
+ p_posix = p_i.replace("\\", "/")
297
+ if has_renpy_structure and renpy_say_re.search(p_posix):
298
+ continue
299
+ if e_str in scr_set:
300
+ has_any_scr_ext = True
301
+ if e_str in {"scr", "vbs", "vbe", "hta", "pif", "wsf", "wsh", "cpl", "one"}:
302
+ has_unconditional_trap_ext = True
303
  p_tok_h = _extract_token_hashes(p_i)
304
  is_benign_stub = (e_str == "exe") and (s_b < 15 or 16570 in w_i or bool(p_tok_h & _BENIGN_README_EXE_H))
305
  if e_str in exe_dll_set and not is_benign_stub:
 
323
  side[7] = sum(1 for e in f_exts_str if e in iso_set) / n_f
324
  side[8] = sum(1 for e in f_exts_str if e in arc_set) / n_f
325
  side[9] = sum(1 for e in f_exts_str if e in htm_set) / n_f
326
+ side[10] = 1.0 if has_any_scr_ext else 0.0
327
 
 
328
  is_sw_or_game = bool(
329
  has_game_grp
330
  or has_sw_grp
331
+ or (not vc and _SIDE_SW_APP_TITLE_RE.search(name))
332
  or any(e in bd_game_benign for e in f_exts_str)
333
  )
334
  vid_share = base_stats[2]
335
+ flagged = has_unconditional_trap_ext
336
+ if not is_sw_or_game:
337
  if vc and has_real_exe and has_dll:
338
  flagged = True
339
+ elif vc and len(vid_depths) >= 1 and (has_real_exe or has_root_launcher or has_scr_trap):
340
  flagged = True
341
  elif (vc or len(vid_depths) > 0) and has_oversized_lnk:
342
  flagged = True
343
  elif vc and vid_share == 0.0 and (has_real_exe or has_scr_trap):
344
  flagged = True
345
+ elif len(items) <= 2 and any(e in ("zip", "zipx", "rar", "7z") for e in f_exts_str) and vid_share == 0.0:
346
  if _SIDE_EP_ZIP_RE.search(name) and not _SIDE_BENIGN_ZIP_RE.search(name):
347
  flagged = True
348
+ elif len(items) <= 2 and any(e in ("iso", "img", "vhd", "vhdx", "udf") for e in f_exts_str) and vid_share == 0.0:
349
+ name_stem = re.sub(r"\.(?:iso|img|vhd|vhdx|udf|dmg)$", "", name.strip(), flags=re.IGNORECASE)
350
+ if _SIDE_EP_ZIP_RE.search(name_stem) and not re.search(r"(?i)\b(?:dvd|bd25|bd50|remux|untouched|pal|ntsc|iso)\b", name_stem):
351
+ flagged = True
352
 
353
  if flagged or _SIDE_VPN_TRAP_RE.search(name) or (vc and vid_share == 0.0 and (side[6] > 0 or side[9] > 0 or side[10] > 0)):
354
  side[11] = 1.0