#!/bin/sh
# ============================================================================
# iKuai libjson_script.so.0 backdoor probe  (busybox-ash compatible)
# ----------------------------------------------------------------------------
# Detects the ELF backdoor that impersonates OpenWrt libubox's libjson_script,
# targeting iKuai routers.  C2: 47.80.111.129:7380
#
# Reference (first-hand IDA reversing, 2026-08-10):
#   SHA256  4e6276cc400b3b9e9616d04474b64a8fa0c35375b9673ab41a92a6d5bce72d8d
#
# EXIT CODES / SIDE EFFECT:
#   - Any hit  -> writes an EMPTY marker file  /etc/log/libjson_script
#                 (persistent partition sda5), prints [INFECTED] lines, exit 1
#   - Clean    -> removes stale marker if present, prints CLEAN, exit 0
#
# The legitimate iKuai file is  /lib/libjson_script.so.20210516  (libubox,
# ~12KB, exports json_script_file_from_blobmsg).  This probe never flags it.
# ============================================================================

MARK="/etc/log/libjson_script"      # empty-file tag on a hit (persistent)
BD_SHA="4e6276cc400b3b9e9616d04474b64a8fa0c35375b9673ab41a92a6d5bce72d8d"
C2_IP="47.80.111.129"
HITS=""

add_hit() { HITS="${HITS}[INFECTED] $1
"; }

# ---------------------------------------------------------------------------
# 1) Backdoor file on disk: libjson_script.so.0 (the ".0" suffix is the tell;
#    ".20210516" is the legit libubox file).  Also match by SHA256 anywhere.
# ---------------------------------------------------------------------------
for d in /lib /usr/lib /tmp /var/tmp /etc /usr/share/misc; do
    [ -d "$d" ] || continue
    for f in "$d"/libjson_script.so.0 "$d"/libjson_script.so.0.*; do
        [ -f "$f" ] && add_hit "backdoor file present: $f"
    done
done

# SHA256 match (covers renamed copies). sha256sum exists on iKuai busybox.
if command -v sha256sum >/dev/null 2>&1; then
    for d in /lib /usr/lib /tmp /var/tmp /usr/share/misc /etc/mnt/ikuai; do
        [ -d "$d" ] || continue
        for f in "$d"/*.so "$d"/*.so.* "$d"/.*.so*; do
            [ -f "$f" ] || continue
            s=$(sha256sum "$f" 2>/dev/null | cut -d' ' -f1)
            [ "$s" = "$BD_SHA" ] && add_hit "backdoor SHA256 match: $f"
        done
    done
fi

# ---------------------------------------------------------------------------
# 2) GWID cache with the backdoor's self-generated "gw-" prefix.
#    Real iKuai GWID is plain 32-hex (no prefix).  The backdoor writes
#    "gw-<16 random bytes hex>" to /usr/share/misc/.runlevel.cache.
# ---------------------------------------------------------------------------
RLC="/usr/share/misc/.runlevel.cache"
if [ -f "$RLC" ]; then
    head -c 3 "$RLC" 2>/dev/null | grep -q "^gw-" \
        && add_hit "backdoor GWID cache: $RLC starts with 'gw-'"
fi

# ---------------------------------------------------------------------------
# 3) Payload drops under /var/tmp: hidden ".<hex>" files/dirs the backdoor
#    creates for __sched__ / __uu__ downloads.  Skip known-legit dotfiles.
# ---------------------------------------------------------------------------
if [ -d /var/tmp ]; then
    for p in /var/tmp/.[0-9a-f]*; do
        [ -e "$p" ] || continue
        base=$(basename "$p")
        # backdoor drop = ".<hex>" (>=6 hex chars). Legit iKuai dotfiles have
        # words/underscores (.client_online_time.lck, .register_check_*, etc).
        echo "$base" | grep -Eq '^\.[0-9a-f]{6,}$' \
            && add_hit "possible payload drop: $p"
    done
fi

# ---------------------------------------------------------------------------
# 4) Live C2 connection to 47.80.111.129 (any port) — parse /proc/net/tcp*.
#    Remote addr is little-endian hex in field 3 (rem_address).
# ---------------------------------------------------------------------------
for pf in /proc/net/tcp /proc/net/tcp6; do
    [ -f "$pf" ] || continue
    # field 3 = rem_address "HHHHHHHH:PPPP"; take the IPv4 (or v4-mapped) part
    awk 'NR>1{print $3}' "$pf" 2>/dev/null | while IFS= read -r ra; do
        h=${ra%:*}
        # for tcp6, IPv4-mapped sits in the last 8 hex chars
        h=$(echo "$h" | sed 's/.*\(........\)$/\1/')
        [ ${#h} -eq 8 ] || continue
        a=$(printf "%d" "0x${h#??????}" 2>/dev/null)
        b=$(printf "%d" "0x$(echo "$h" | cut -c5-6)" 2>/dev/null)
        c=$(printf "%d" "0x$(echo "$h" | cut -c3-4)" 2>/dev/null)
        d=$(printf "%d" "0x$(echo "$h" | cut -c1-2)" 2>/dev/null)
        ip="$a.$b.$c.$d"
        [ "$ip" = "$C2_IP" ] && echo "C2CONN"
    done | grep -q C2CONN && add_hit "live C2 connection to $C2_IP in $pf"
done

# also check ARP / conntrack as a cheap secondary signal
grep -q "$C2_IP" /proc/net/arp 2>/dev/null && add_hit "C2 $C2_IP in ARP table"
[ -f /proc/net/nf_conntrack ] && grep -q "$C2_IP" /proc/net/nf_conntrack 2>/dev/null \
    && add_hit "C2 $C2_IP in conntrack"

# ---------------------------------------------------------------------------
# 5) Process whose exe is deleted or lives under /var/tmp, and whose maps show
#    the backdoor library or its static-crypto fingerprint (mbedTLS + cJSON).
# ---------------------------------------------------------------------------
for pd in /proc/[0-9]*; do
    exe=$(readlink "$pd/exe" 2>/dev/null) || continue
    case "$exe" in
        *"/var/tmp/"*)          add_hit "process exe under /var/tmp: $pd -> $exe" ;;
        *"(deleted)"*)
            # deleted exe is suspicious; confirm with maps fingerprint
            if grep -q "libjson_script.so.0" "$pd/maps" 2>/dev/null; then
                add_hit "deleted-exe process mapping backdoor lib: $pd -> $exe"
            fi
            ;;
    esac
    # any process that mapped the backdoor lib by name
    grep -q "libjson_script.so.0" "$pd/maps" 2>/dev/null \
        && add_hit "process mapped libjson_script.so.0: $pd"
done

# ---------------------------------------------------------------------------
# 6) Backdoor command/marker strings on disk in suspicious locations only
#    (avoid scanning the whole FS — target /var/tmp and any .so.0 already seen).
# ---------------------------------------------------------------------------
for f in /var/tmp/.[0-9a-f]* /lib/libjson_script.so.0 /usr/lib/libjson_script.so.0; do
    [ -f "$f" ] || continue
    if grep -aqE '__sched_cancel__\||__uu__:|__dd__:|/cdn-cgi/bm/cv/result' "$f" 2>/dev/null; then
        add_hit "backdoor command strings in: $f"
    fi
done

# ============================================================================
# Verdict
# ============================================================================
GWID_INFO=""
[ -f /etc/release ] && GWID_INFO=$(grep '^GWID=' /etc/release 2>/dev/null)
HOSTN=$(hostname 2>/dev/null)

if [ -n "$HITS" ]; then
    # write the empty marker tag (persistent partition)
    : > "$MARK" 2>/dev/null || : > "/tmp/libjson_script"
    echo "=========================================================="
    echo " iKuai libjson_script.so.0 BACKDOOR — DETECTED"
    echo " host: $HOSTN   $GWID_INFO"
    echo " time: $(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null)"
    echo " tag : $MARK (empty marker written)"
    echo "----------------------------------------------------------"
    printf '%s' "$HITS"
    echo "=========================================================="
    echo " C2: 47.80.111.129:7380  |  SHA256: $BD_SHA"
    echo " Remediation: isolate device, kill process, remove"
    echo "   libjson_script.so.0 + /usr/share/misc/.runlevel.cache,"
    echo "   audit /var/tmp, rotate all credentials, reflash firmware."
    exit 1
else
    # clean: clear any stale marker from a previous run
    [ -f "$MARK" ] && rm -f "$MARK" 2>/dev/null
    echo "[CLEAN] $HOSTN — no libjson_script.so.0 backdoor indicators. $GWID_INFO"
    exit 0
fi
