karmine05

AXIOS SUPPLY CHAIN COMPROMISE — FLEET IOC HUNT SCRIPT

Mar 31st, 2026
7,445
0
Never
21
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 16.91 KB | Cybersecurity | 0 0
  1. #!/bin/bash
  2. # ============================================================================
  3. # AXIOS SUPPLY CHAIN COMPROMISE — FLEET IOC HUNT SCRIPT
  4. # Author: karmine05
  5. # Date: 2026-03-31
  6. #
  7. # Runs via Fleet Scripts on macOS and Linux endpoints.
  8. # Checks file artifacts, SHA256 hashes, malicious npm packages, running
  9. # processes, codesign abuse, network connections, DNS, and persistence.
  10. # ============================================================================
  11.  
  12. set -u
  13.  
  14. COMPROMISED=0
  15. FINDINGS=""
  16.  
  17. # --- Known SHA256 hashes (Wiz Research IOC appendix) ------------------------
  18. HASH_MACOS_RAT="92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a"
  19. HASH_WIN_STAGE2="617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101"
  20. HASH_LINUX_RAT="fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf"
  21. HASH_DROPPER="58401c195fe0a6204b42f5f90995ece5fab74ce7c69c67a24c61a057325af668"
  22. HASH_AXIOS_0304="59336a964f110c25c112bcc5adca7090296b54ab33fa95c0744b94f8a0d80c0f"
  23. HASH_AXIOS_1141="5bb67e88846096f1f8d42a0f0350c9c46260591567612ff9af46f98d1b7571cd"
  24.  
  25. # --- Helpers ----------------------------------------------------------------
  26.  
  27. log_finding() {
  28.   local category="$1"
  29.   local detail="$2"
  30.   COMPROMISED=1
  31.   FINDINGS="${FINDINGS}\n[HIT] ${category}: ${detail}"
  32.   printf "[HIT] %s: %s\n" "$category" "$detail"
  33. }
  34.  
  35. log_clean() {
  36.   echo "[OK]  $1: No indicators found"
  37. }
  38.  
  39. detect_os() {
  40.   case "$(uname -s)" in
  41.     Darwin*) echo "macos" ;;
  42.     Linux*)  echo "linux" ;;
  43.     *)       echo "unknown" ;;
  44.   esac
  45. }
  46.  
  47. # Cross-platform SHA256 helper
  48. sha256_of() {
  49.   local filepath="$1"
  50.   if command -v shasum &>/dev/null; then
  51.     shasum -a 256 "$filepath" 2>/dev/null | awk '{print $1}'
  52.   elif command -v sha256sum &>/dev/null; then
  53.     sha256sum "$filepath" 2>/dev/null | awk '{print $1}'
  54.   else
  55.     echo "NO_SHA256_TOOL"
  56.   fi
  57. }
  58.  
  59. OS=$(detect_os)
  60. echo "============================================================"
  61. echo "  Axios Supply Chain IOC Hunt (v2 — Wiz Research IOCs)"
  62. echo "  Host: $(hostname)"
  63. echo "  OS:   ${OS} ($(uname -s) $(uname -r))"
  64. echo "  Date: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
  65. echo "============================================================"
  66. echo ""
  67.  
  68. # ============================================================================
  69. # 1. FILE SYSTEM ARTIFACTS
  70. # ============================================================================
  71. echo "--- [1/9] File System Artifacts ---"
  72.  
  73. FOUND_FILES=0
  74.  
  75. # macOS RAT payload
  76. if [ "$OS" = "macos" ]; then
  77.   if [ -f "/Library/Caches/com.apple.act.mond" ]; then
  78.     log_finding "FILE" "macOS RAT payload: /Library/Caches/com.apple.act.mond ($(ls -la /Library/Caches/com.apple.act.mond 2>/dev/null))"
  79.     FOUND_FILES=1
  80.   fi
  81. fi
  82.  
  83. # Linux RAT payload
  84. if [ "$OS" = "linux" ]; then
  85.   if [ -f "/tmp/ld.py" ]; then
  86.     log_finding "FILE" "Linux RAT payload: /tmp/ld.py ($(ls -la /tmp/ld.py 2>/dev/null))"
  87.     FOUND_FILES=1
  88.   fi
  89. fi
  90.  
  91. # Cross-platform temp staging file
  92. for tmp_path in "/tmp/6202033" "/private/tmp/6202033" "${TMPDIR:-/tmp}/6202033"; do
  93.   if [ -f "$tmp_path" ]; then
  94.     log_finding "FILE" "Staging file: ${tmp_path} ($(ls -la "$tmp_path" 2>/dev/null))"
  95.     FOUND_FILES=1
  96.   fi
  97. done
  98.  
  99. [ "$FOUND_FILES" -eq 0 ] && log_clean "File artifacts"
  100. echo ""
  101.  
  102. # ============================================================================
  103. # 2. SHA256 HASH VALIDATION (Wiz Research)
  104. # ============================================================================
  105. echo "--- [2/9] SHA256 Hash Validation ---"
  106.  
  107. FOUND_HASH=0
  108.  
  109. # Build list of (file_path|expected_hash|description) tuples
  110. HASH_CHECKS=()
  111.  
  112. if [ "$OS" = "macos" ]; then
  113.   HASH_CHECKS=(
  114.     "/Library/Caches/com.apple.act.mond|${HASH_MACOS_RAT}|macOS Stage 2 RAT (Mach-O universal binary)"
  115.   )
  116. elif [ "$OS" = "linux" ]; then
  117.   HASH_CHECKS=(
  118.     "/tmp/ld.py|${HASH_LINUX_RAT}|Linux Stage 2 RAT (Python script)"
  119.   )
  120. fi
  121.  
  122. for check in "${HASH_CHECKS[@]}"; do
  123.   IFS='|' read -r fpath expected_hash description <<< "$check"
  124.   if [ -f "$fpath" ]; then
  125.     actual_hash=$(sha256_of "$fpath")
  126.     if [ "$actual_hash" = "$expected_hash" ]; then
  127.       log_finding "SHA256" "CONFIRMED MATCH: ${description}${fpath} (${actual_hash})"
  128.       FOUND_HASH=1
  129.     else
  130.       echo "[INFO] File exists but hash differs: ${fpath}"
  131.       echo "       Expected: ${expected_hash}"
  132.       echo "       Actual:   ${actual_hash}"
  133.     fi
  134.   fi
  135. done
  136.  
  137. # Check npm cache for compromised package tarballs by hash
  138. if command -v npm &>/dev/null; then
  139.   NPM_CACHE_DIR=$(npm config get cache 2>/dev/null || echo "")
  140.   if [ -n "$NPM_CACHE_DIR" ] && [ -d "$NPM_CACHE_DIR" ]; then
  141.     echo "[INFO] Scanning npm cache at ${NPM_CACHE_DIR} for compromised tarballs..."
  142.     for tarball_hash in "$HASH_AXIOS_0304" "$HASH_AXIOS_1141" "$HASH_DROPPER"; do
  143.       CACHE_HIT=$(find "${NPM_CACHE_DIR}" -type f \( -name "*.tgz" -o -name "*.tar.gz" \) 2>/dev/null | head -100 | while read -r tgz; do
  144.         h=$(sha256_of "$tgz")
  145.         if [ "$h" = "$tarball_hash" ]; then
  146.           echo "$tgz"
  147.           break
  148.         fi
  149.       done || true)
  150.       if [ -n "$CACHE_HIT" ]; then
  151.         log_finding "SHA256" "Compromised tarball in npm cache: ${CACHE_HIT} (sha256: ${tarball_hash})"
  152.         FOUND_HASH=1
  153.       fi
  154.     done
  155.   fi
  156. fi
  157.  
  158. [ "$FOUND_HASH" -eq 0 ] && log_clean "SHA256 hash validation"
  159. echo ""
  160.  
  161. # ============================================================================
  162. # 3. MALICIOUS NPM PACKAGES
  163. # ============================================================================
  164. echo "--- [3/9] Malicious npm Packages ---"
  165.  
  166. FOUND_NPM=0
  167.  
  168. # Check global npm for compromised axios versions
  169. if command -v npm &>/dev/null; then
  170.   GLOBAL_AXIOS=$(npm ls -g axios 2>/dev/null | grep -E "axios@(1\.14\.1|0\.30\.4)" || true)
  171.   if [ -n "$GLOBAL_AXIOS" ]; then
  172.     log_finding "NPM-GLOBAL" "Compromised axios installed globally: ${GLOBAL_AXIOS}"
  173.     FOUND_NPM=1
  174.   fi
  175. fi
  176.  
  177. # Search for the dropper dependency and malicious packages in node_modules
  178. MALICIOUS_PKGS=(
  179.   "plain-crypto-js"
  180.   "@shadanai/openclaw"
  181.   "@qqbrowser/openclaw-qbot"
  182. )
  183.  
  184. SEARCH_ROOTS=()
  185. if [ "$OS" = "macos" ]; then
  186.   SEARCH_ROOTS=(/Users/*/node_modules /Users/*/*/node_modules /opt/*/node_modules)
  187. elif [ "$OS" = "linux" ]; then
  188.   SEARCH_ROOTS=(/home/*/node_modules /home/*/*/node_modules /opt/*/node_modules /var/*/node_modules)
  189. fi
  190.  
  191. for root_glob in "${SEARCH_ROOTS[@]}"; do
  192.   for root_dir in $root_glob; do
  193.     [ -d "$root_dir" ] || continue
  194.     for pkg in "${MALICIOUS_PKGS[@]}"; do
  195.       pkg_json="${root_dir}/${pkg}/package.json"
  196.       if [ -f "$pkg_json" ]; then
  197.         pkg_version=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$pkg_json" 2>/dev/null | head -1 || echo "unknown")
  198.         log_finding "NPM-LOCAL" "Malicious package found: ${pkg_json} (${pkg_version})"
  199.         FOUND_NPM=1
  200.       fi
  201.     done
  202.   done
  203. done
  204.  
  205. # Look for setup.js dropper (4,209 bytes) — the stage 1.5 installer
  206. for root_glob in "${SEARCH_ROOTS[@]}"; do
  207.   for root_dir in $root_glob; do
  208.     [ -d "$root_dir" ] || continue
  209.     setup_js="${root_dir}/plain-crypto-js/setup.js"
  210.     if [ -f "$setup_js" ]; then
  211.       log_finding "NPM-LOCAL" "Dropper script found: ${setup_js} ($(ls -la "$setup_js" 2>/dev/null))"
  212.       FOUND_NPM=1
  213.     fi
  214.   done
  215. done
  216.  
  217. # Search for compromised axios versions in local node_modules
  218. for root_glob in "${SEARCH_ROOTS[@]}"; do
  219.   for root_dir in $root_glob; do
  220.     [ -d "$root_dir" ] || continue
  221.     axios_json="${root_dir}/axios/package.json"
  222.     if [ -f "$axios_json" ]; then
  223.       axios_ver=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$axios_json" 2>/dev/null | head -1 || echo "")
  224.       if echo "$axios_ver" | grep -qE '"(1\.14\.1|0\.30\.4)"'; then
  225.         log_finding "NPM-LOCAL" "Compromised axios: ${axios_json} (${axios_ver})"
  226.         FOUND_NPM=1
  227.       fi
  228.     fi
  229.   done
  230. done
  231.  
  232. [ "$FOUND_NPM" -eq 0 ] && log_clean "npm packages"
  233. echo ""
  234.  
  235. # ============================================================================
  236. # 4. RUNNING PROCESSES
  237. # ============================================================================
  238. echo "--- [4/9] Suspicious Processes ---"
  239.  
  240. FOUND_PROC=0
  241.  
  242. # RAT binary names and IOC strings in process list
  243. PROC_PATTERNS=(
  244.   "com.apple.act.mond"
  245.   "ld\.py"
  246.   "stage2\.ps1"
  247.   "6202033"
  248.   "sfrclak"
  249.   "plain-crypto-js"
  250. )
  251.  
  252. PS_OUTPUT=$(ps aux 2>/dev/null || ps -ef 2>/dev/null)
  253.  
  254. for pattern in "${PROC_PATTERNS[@]}"; do
  255.   # Use grep -E for consistent regex behavior on Linux/macOS
  256.   MATCHES=$(echo "$PS_OUTPUT" | grep -Ei "$pattern" | grep -v "grep" | grep -v "axios_ioc_hunt" || true)
  257.   if [ -n "$MATCHES" ]; then
  258.     log_finding "PROCESS" "Pattern '${pattern}' found in running processes:"
  259.     echo "$MATCHES" | while read -r line; do printf "         %s\n" "$line"; done
  260.     FOUND_PROC=1
  261.   fi
  262. done
  263.  
  264. [ "$FOUND_PROC" -eq 0 ] && log_clean "Running processes"
  265. echo ""
  266.  
  267. # ============================================================================
  268. # 5. macOS CODESIGN ABUSE (Wiz Research)
  269. #    The Mach-O RAT self-signs injected payloads via codesign.
  270. # ============================================================================
  271. echo "--- [5/9] macOS Codesign Abuse ---"
  272.  
  273. FOUND_CODESIGN=0
  274.  
  275. if [ "$OS" = "macos" ]; then
  276.   # Check if the RAT binary exists and inspect its signature
  277.   if [ -f "/Library/Caches/com.apple.act.mond" ]; then
  278.     CODESIGN_INFO=$(codesign -dvvv /Library/Caches/com.apple.act.mond 2>&1 || true)
  279.     log_finding "CODESIGN" "RAT binary signature info:"
  280.     echo "$CODESIGN_INFO" | head -20
  281.     FOUND_CODESIGN=1
  282.   fi
  283.  
  284.   # Look for ad-hoc signed or unsigned executables in /Library/Caches
  285.   # (RAT injects and self-signs payloads here)
  286.   ADHOC_BINS=$(find /Library/Caches -type f -perm +111 2>/dev/null | while read -r bin; do
  287.     sig=$(codesign -d --verbose=2 "$bin" 2>&1 || true)
  288.     if echo "$sig" | grep -q "adhoc\|not signed\|invalid"; then
  289.       echo "$bin"
  290.     fi
  291.   done || true)
  292.  
  293.   if [ -n "$ADHOC_BINS" ]; then
  294.     log_finding "CODESIGN" "Suspicious ad-hoc/unsigned executables in /Library/Caches:"
  295.     echo "$ADHOC_BINS" | while read -r line; do echo "         $line"; done
  296.     FOUND_CODESIGN=1
  297.   fi
  298.  
  299.   # Check for recent codesign invocations in unified log (last 1 hour)
  300.   CODESIGN_LOG=$(log show --predicate 'process == "codesign"' --last 1h 2>/dev/null | grep -i "Library/Caches" || true)
  301.   if [ -n "$CODESIGN_LOG" ]; then
  302.     log_finding "CODESIGN" "Recent codesign activity targeting /Library/Caches:"
  303.     echo "$CODESIGN_LOG" | head -10
  304.     FOUND_CODESIGN=1
  305.   fi
  306. else
  307.   echo "[SKIP] macOS-only check — skipping on ${OS}"
  308. fi
  309.  
  310. [ "$FOUND_CODESIGN" -eq 0 ] && [ "$OS" = "macos" ] && log_clean "Codesign abuse"
  311. echo ""
  312.  
  313. # ============================================================================
  314. # 6. NETWORK CONNECTIONS
  315. # ============================================================================
  316. echo "--- [6/9] Network Connections (C2: 142.11.206.73 / sfrclak.com:8000) ---"
  317.  
  318. FOUND_NET=0
  319.  
  320. # Check for connections to C2 IP
  321. if command -v lsof &>/dev/null; then
  322.   C2_LSOF=$(lsof -i @142.11.206.73 2>/dev/null || true)
  323.   if [ -n "$C2_LSOF" ]; then
  324.     log_finding "NETWORK" "Active connection to C2 IP 142.11.206.73:"
  325.     echo "$C2_LSOF"
  326.     FOUND_NET=1
  327.   fi
  328.  
  329.   # Also check port 8000 for any suspicious outbound
  330.   PORT_8000=$(lsof -i :8000 2>/dev/null | grep -v "LISTEN" || true)
  331.   if echo "$PORT_8000" | grep -q "142.11.206.73"; then
  332.     log_finding "NETWORK" "Connection on port 8000 to C2 IP:"
  333.     echo "$PORT_8000" | grep "142.11.206.73"
  334.     FOUND_NET=1
  335.   fi
  336. fi
  337.  
  338. # Netstat fallback
  339. if command -v netstat &>/dev/null; then
  340.   NS_MATCH=$(netstat -an 2>/dev/null | grep "142.11.206.73" || true)
  341.   if [ -n "$NS_MATCH" ]; then
  342.     log_finding "NETWORK" "netstat hit for C2 IP 142.11.206.73:"
  343.     echo "$NS_MATCH"
  344.     FOUND_NET=1
  345.   fi
  346. fi
  347.  
  348. # ss fallback (Linux)
  349. if [ "$OS" = "linux" ] && command -v ss &>/dev/null; then
  350.   SS_MATCH=$(ss -tunap 2>/dev/null | grep "142.11.206.73" || true)
  351.   if [ -n "$SS_MATCH" ]; then
  352.     log_finding "NETWORK" "ss hit for C2 IP 142.11.206.73:"
  353.     echo "$SS_MATCH"
  354.     FOUND_NET=1
  355.   fi
  356. fi
  357.  
  358. [ "$FOUND_NET" -eq 0 ] && log_clean "Network connections"
  359. echo ""
  360.  
  361. # ============================================================================
  362. # 7. DNS RESOLUTION CHECK
  363. # ============================================================================
  364. echo "--- [7/9] DNS Resolution ---"
  365.  
  366. FOUND_DNS=0
  367.  
  368. for domain in "sfrclak.com" "packages.npm.org"; do
  369.   HOSTS_MATCH=$(grep -i "$domain" /etc/hosts 2>/dev/null || true)
  370.   if [ -n "$HOSTS_MATCH" ]; then
  371.     log_finding "DNS" "C2-related entry in /etc/hosts: ${HOSTS_MATCH}"
  372.     FOUND_DNS=1
  373.   fi
  374. done
  375.  
  376. # macOS DNS cache check
  377. if [ "$OS" = "macos" ]; then
  378.   SCUTIL_CHECK=$(scutil --dns 2>/dev/null | grep -i "sfrclak" || true)
  379.   if [ -n "$SCUTIL_CHECK" ]; then
  380.     log_finding "DNS" "sfrclak.com found in macOS DNS config"
  381.     FOUND_DNS=1
  382.   fi
  383. fi
  384.  
  385. # Linux: check systemd-resolved cache if available
  386. if [ "$OS" = "linux" ] && command -v resolvectl &>/dev/null; then
  387.   # Only flag if it actually resolves (contains an IP address)
  388.   RESOLVED_CHECK=$(resolvectl query sfrclak.com 2>&1 || true)
  389.   if echo "$RESOLVED_CHECK" | grep -qE "([0-9]{1,3}\.){3}[0-9]{1,3}"; then
  390.     log_finding "DNS" "sfrclak.com resolved to an active IP via systemd-resolved"
  391.     FOUND_DNS=1
  392.   fi
  393. fi
  394.  
  395. [ "$FOUND_DNS" -eq 0 ] && log_clean "DNS"
  396. echo ""
  397.  
  398. # ============================================================================
  399. # 8. PERSISTENCE MECHANISMS
  400. # ============================================================================
  401. echo "--- [8/9] Persistence ---"
  402.  
  403. FOUND_PERSIST=0
  404.  
  405. IOC_STRINGS="act\.mond\|6202033\|sfrclak\|ld\.py\|wt\.exe\|plain-crypto-js\|stage2\.ps1\|MicrosoftUpdate"
  406.  
  407. # macOS: LaunchDaemons / LaunchAgents
  408. if [ "$OS" = "macos" ]; then
  409.   for plist_dir in \
  410.     /Library/LaunchDaemons \
  411.     /Library/LaunchAgents \
  412.     ~/Library/LaunchAgents; do
  413.     if [ -d "$plist_dir" ]; then
  414.       PLIST_HITS=$(grep -rl "$IOC_STRINGS" "$plist_dir" 2>/dev/null || true)
  415.       if [ -n "$PLIST_HITS" ]; then
  416.         log_finding "PERSIST" "IOC string found in plist(s): ${PLIST_HITS}"
  417.         FOUND_PERSIST=1
  418.       fi
  419.     fi
  420.   done
  421. fi
  422.  
  423. # Linux/macOS: crontab
  424. CRON_HIT=$(crontab -l 2>/dev/null | grep -E "ld\.py|6202033|sfrclak|act\.mond|stage2\.ps1" || true)
  425. if [ -n "$CRON_HIT" ]; then
  426.   log_finding "PERSIST" "IOC string found in user crontab: ${CRON_HIT}"
  427.   FOUND_PERSIST=1
  428. fi
  429.  
  430. # System crontabs
  431. for cron_file in /etc/crontab /etc/cron.d/*; do
  432.   if [ -f "$cron_file" ]; then
  433.     SYS_CRON=$(grep -E "ld\.py|6202033|sfrclak|act\.mond|stage2\.ps1" "$cron_file" 2>/dev/null || true)
  434.     if [ -n "$SYS_CRON" ]; then
  435.       log_finding "PERSIST" "IOC in system cron ${cron_file}: ${SYS_CRON}"
  436.       FOUND_PERSIST=1
  437.     fi
  438.   fi
  439. done
  440.  
  441. # Linux: systemd units
  442. if [ "$OS" = "linux" ]; then
  443.   for unit_dir in /etc/systemd/system /usr/lib/systemd/system ~/.config/systemd/user; do
  444.     if [ -d "$unit_dir" ]; then
  445.       UNIT_HITS=$(grep -rl "ld\.py\|6202033\|sfrclak\|stage2" "$unit_dir" 2>/dev/null || true)
  446.       if [ -n "$UNIT_HITS" ]; then
  447.         log_finding "PERSIST" "IOC in systemd unit(s): ${UNIT_HITS}"
  448.         FOUND_PERSIST=1
  449.       fi
  450.     fi
  451.   done
  452. fi
  453.  
  454. [ "$FOUND_PERSIST" -eq 0 ] && log_clean "Persistence mechanisms"
  455. echo ""
  456.  
  457. # ============================================================================
  458. # 9. SUMMARY
  459. # ============================================================================
  460. echo "--- [9/9] Summary ---"
  461. echo ""
  462.  
  463. if [ "$COMPROMISED" -eq 1 ]; then
  464.   echo "============================================================"
  465.   echo "  RESULT: INDICATORS OF COMPROMISE DETECTED"
  466.   echo "============================================================"
  467.   echo ""
  468.   echo "Findings:"
  469.   printf "%b\n" "$FINDINGS"
  470.   echo ""
  471.   echo "Wiz Research SHA256 reference hashes:"
  472.   echo "  macOS RAT:    ${HASH_MACOS_RAT}"
  473.   echo "  Win stage2:   ${HASH_WIN_STAGE2}"
  474.   echo "  Linux RAT:    ${HASH_LINUX_RAT}"
  475.   echo "  Dropper pkg:  ${HASH_DROPPER}"
  476.   echo "  axios 0.30.4: ${HASH_AXIOS_0304}"
  477.   echo "  axios 1.14.1: ${HASH_AXIOS_1141}"
  478.   echo ""
  479.   echo "Recommended actions:"
  480.   echo "  1. Isolate this host from the network immediately"
  481.   echo "  2. Preserve forensic evidence (memory dump, disk image)"
  482.   echo "  3. Rotate all credentials/tokens accessible from this host"
  483.   echo "     (Wiz: assume credential compromise if malicious packages executed)"
  484.   echo "  4. Check npm cache: npm cache ls 2>/dev/null | grep -E 'axios|plain-crypto'"
  485.   echo "  5. Review git history for lockfile changes in the exposure window"
  486.   echo "     (2026-03-31 00:21 UTC to 03:15 UTC)"
  487.   echo "  6. Scan for secrets in env vars, .env files, API keys, tokens"
  488.   echo "     (RAT transmits system inventory to C2 every 60s)"
  489.   echo ""
  490.   exit 1
  491. else
  492.   echo "============================================================"
  493.   echo "  RESULT: CLEAN — No Axios compromise indicators found"
  494.   echo "============================================================"
  495.   echo ""
  496.   exit 0
  497. fi
  498.  
Tags: NPM axios
Advertisement