tor-onion-nginx

This commit is contained in:
rootTHC 2022-05-20 16:59:45 +01:00
parent b2c1831d25
commit 73f5c06926
11 changed files with 160 additions and 38 deletions

@ -3,6 +3,7 @@ VER := 0.1-beta5
all:
make -C guest
make -C host
make -C tor
make -C encfs
FILES_GUEST += "segfault-$(VER)/guest/setup.sh"
@ -24,6 +25,10 @@ FILES_HOST += "segfault-$(VER)/host/fs-root/bin/docker_sshd.sh"
FILES_HOST += "segfault-$(VER)/host/fs-root/etc/ssh/sshd_config"
FILES_HOST += "segfault-$(VER)/host/fs-root/etc/english.txt"
FILES_TOR += "segfault-$(VER)/tor/Dockerfile"
FILES_TOR += "segfault-$(VER)/tor/Makefile"
FILES_TOR += "segfault-$(VER)/tor/fs-root/sf-tor.sh"
FILES_PROVISION += "segfault-$(VER)/provision/init-nordvpn.sh"
FILES_PROVISION += "segfault-$(VER)/provision/init-ubuntu.sh"
FILES_PROVISION += "segfault-$(VER)/provision/sf-fw.service"
@ -40,7 +45,7 @@ FILES_ENCFS += "segfault-$(VER)/encfs/mount.sh"
FILES_ROOT += "segfault-$(VER)/Makefile"
FILES_ROOT += "segfault-$(VER)/docker-compose.yml"
FILES += $(FILES_ROOT) $(FILES_ENCFS) $(FILES_GUEST) $(FILES_HOST) $(FILES_PROVISION)
FILES += $(FILES_ROOT) $(FILES_TOR) $(FILES_ENCFS) $(FILES_GUEST) $(FILES_HOST) $(FILES_PROVISION)
TARX = $(shell command -v gtar 2>/dev/null)
ifndef TARX
TARX := tar

@ -24,15 +24,20 @@ services:
- dns-doh
tor:
image: osminogin/tor-simple
container_name: sf-tor
build: tor
networks:
guest-net:
ipv4_address: 172.24.0.4
nginx-net:
restart: always
dns: 172.24.0.2
depends_on:
- dnsmasq
- nginx
volumes:
- "${SF_BASEDIR}/config/${SF_FQDN:-this}/tor/hidden_service:/var/lib/tor/hidden_service"
- "${SF_BASEDIR}/config/etc/tor/torrc:/config/torrc"
segfault:
container_name: sf-host
@ -42,16 +47,32 @@ services:
restart: always
init: true
dns: 255.255.255.255
ports:
- "${SF_SSH_PORT:-22}:2222"
env_file:
.env
ports:
- "${SF_SSH_PORT:-22}:2222"
volumes:
- "${SF_BASEDIR}/config:/config:ro"
- "${SF_BASEDIR}/config/db:/config/db"
- "${SF_BASEDIR}/data/onion:/onion"
- "/var/run/docker.sock:/var/run/docker.sock"
nginx:
image: nginx
restart: always
dns: 255.255.255.255
networks:
nginx-net:
# ports:
# - 8080:80
volumes:
- "${SF_BASEDIR}/data/onion:/srv/www:ro"
- "${SF_BASEDIR}/config/etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro"
networks:
nginx-net:
driver: bridge
dns-doh-net:
name: sf_dns-doh-net
driver: bridge

@ -31,5 +31,10 @@ Your workstation : ${CDY}${YOURIP:-UNKNOWN}${CN}
VPN Exit Node : ${VPN_DST}
DNS over HTTPS : ${CDG}Cloudflare${CN}
TOR Proxy : ${CDG}172.24.0.4:9050${CN}
Persistent storage: ${CDC}/sec ${CF}(encrypted)${CN}
Persistent storage: ${CDC}/sec ${CF}(encrypted)${CN}"
[[ -e /config/onion_hostname ]] && {
echo -e "\
Your Web Page : ${CDC}http://$(cat /config/onion_hostname)/${SF_HOSTNAME,,}${CN}"
}
echo -e "\
Access with : ${CDC}ssh -o \"SetEnv SECRET=${SF_SEC:-UNKNOWN}\" ${SF_USER:-UNKNOWN}@${SF_FQDN:-UNKNOWN}${CN}"

@ -105,7 +105,7 @@ setup()
xmkdir /sec/usr/share
# Setup or execute rc.local
[[ ! -f /sec/usr/etc/rc.local ]] && setup_rclocal || /bin/bash /sec/usr/etc/rc.local
[[ ! -f /sec/usr/etc/rc.local ]] && { setup_rclocal; true; } || /bin/bash /sec/usr/etc/rc.local
}
DEBUGF "Setting up user's instance..."

@ -5,11 +5,10 @@ FROM alpine:latest
# SSHD clears all environment variable before spwaning shell.
# Any variable that needs to be available inside shell 'segfaultsh'
# needs to be added to docker_sshd.sh
ENV SF_BASEDIR="${SF_BASEDIR:-/dev/null}"
ENV SF_USER="${SF_USER:-root}"
ENV SF_USER_PASSWORD="${SF_USER_PASSWORD:-segfault}"
ENV SF_DNS="${SF_DNS:-172.24.0.2}"
ENV SF_FQDN="${SF_FQDN:-segfault.thc.org}"
ENV SF_FQDN="${SF_FQDN:-SETME.segfault.net}"
ENV SF_ENCFS_SECDIR="${SF_ENCFS_SECDIR:-/dev/shm/encfs-sec}"
ENV SF_ENCFS_RAWDIR="${SF_ENCFS_RAWDIR:-encfs-raw}"
ENV SF_DEBUG="${SF_DEBUG}"

@ -5,6 +5,14 @@ CR="\033[1;31m" # red
CC="\033[1;36m" # cyan
CN="\033[0m" # none
[[ -z $SF_BASEDIR ]] && {
echo -e "${CR}SF_BASEDIR= not set.${CN}"
sleep 5
exit 255
}
[[ -d /config ]] || {
echo -e "${CR}Not found: /config${CN}
--> Try -v ~/segfault/config:config,ro -v ~/segfault/config/db:/config/db"
@ -95,7 +103,7 @@ addgroup -g $(stat -c %g /config/db) sf-dbrw 2>/dev/null # Ignore if already exi
addgroup root sf-dbrw 2>/dev/null # Ignore if already exists.
chmod g+wx /config/db || exit $?
# This will execute 'segfaultsh' on login
# This will execute 'segfaultsh' on root-login (uid=1000)
/usr/sbin/sshd -u0 -p 2222 -D
# /usr/sbin/sshd -u0 -p 2222

@ -65,6 +65,17 @@ exec_errnull()
$*
fi
}
# Overcoming a restricted shell. Write $1 to file in $2
# tofile "foobar \$HOME \"|';id;" world.txt
tofile()
{
local str
# Replace ' with '"'"'
str="${1//\'/\'\"\'\"\'/}"
bash -c "echo '$str'>'$2'"
}
print_disclaimer()
{
echo 1>&2 -e "\
@ -83,7 +94,7 @@ ${CDC}cat >~/.ssh/id_ed25519-lg-${LID} ${CDR}<<__EOF__
${CN}${CF}$(cat /var/run/id_ed25519.luser)
${CDR}__EOF__
${CDC}cat >>~/.ssh/config ${CDR}<<${CDR}__EOF__
${CN}${CF}host ${HOSTNAME,,}.${SF_FQDN//./-}
${CN}${CF}host ${SF_HOSTNAME,,}.${SF_FQDN//./-}
HostName ${SF_FQDN}
IdentityFile ~/.ssh/id_ed25519-lg-${LID}
SetEnv SECRET=${SF_SEC}
@ -91,7 +102,7 @@ ${CDR}__EOF__
${CDC}chmod 600 ~/.ssh/config ~/.ssh/id_ed25519-lg-${LID}${CN}
######################################################################
Thereafter use this command to connect to your server:
--> ${CDC}ssh root@${HOSTNAME,,}.${SF_FQDN//./-}${CN}
--> ${CDC}ssh root@${SF_HOSTNAME,,}.${SF_FQDN//./-}${CN}
----------------------------------------------------------------------"
}
@ -135,6 +146,21 @@ spawn_shell_exit()
exit "$ret"
}
# Generate a mnemonic hostname from LID (e.g. ButterflyCat)
mk_hostname()
{
NUM=$(echo "ibase=16; $(echo "$LID" | md5sum | cut -f1 -d" " | tr 'a-z' A-Z)" | bc)
readarray -t english </etc/english.txt
SF_HOSTNAME="UnknownUnknown"
if [[ "${#english[@]}" -eq 2048 ]]; then
SF_HOSTNAME="${english[$((NUM % 2048))]}"
SF_HOSTNAME+="${english[$(( (NUM / 2048) % 2048 ))]}"
fi
DEBUGF "SF_HOSTNAME=$SF_HOSTNAME"
unset NUM
unset english
}
# Find out if SSHD allocated a TTY
# - Execute `tty' in unrestricted shell (one day a clever hacker will exploit this)
# - Set docker arguments to login-shell if this is a TTY session.
@ -154,33 +180,40 @@ SF_VER="1.1"
# MARKFILE="THIS-DIRECTORY-IS-NOT-ENCRYPTED--DO-NOT-USE-$(date +%s-%N).txt"
MARKFILE="THIS-DIRECTORY-IS-NOT-ENCRYPTED--DO-NOT-USE.txt"
mk_hostname
if [[ -d "/config/db/db-${LID}" ]]; then
echo_pty -n "Connecting to server. Please wait..."
else
print_disclaimer
echo_pty -n "Creating new server. Please wait...."
# A hostname is generated from the LID. Avoid collision when a hostname
# has already been created for a different LID.
[[ -e "/config/db/hn2lid-${SF_HOSTNAME}" ]] && {
lid_old=$(cat "/config/db/hn2lid-${SF_HOSTNAME}")
[[ "$lid_old" -ne "$LID" ]] && {
DEBUGF "$SF_HOSTNAME already used by ${lid_old} (this is ${LID})."
ERREXIT 13 "Hostname Collision. Try again.."
}
unset lid_old
}
IS_NEW_SERVER=1
mkdir -p "/config/db/db-${LID}" || ERREXIT
touch "/config/db/db-${LID}/created.txt" || ERREXIT
[[ -d /config/db/hn/ ]] || exec_devnull mkdir /config/db/hn
tofile "$LID" "/config/db/hn/hn2lid-${SF_HOSTNAME}"
fi
DEBUGF "LID=${LID}"
DEBUGF "LID=${LID} SF_HOSTNAME=${SF_HOSTNAME}"
if [[ "$(exec_errnull docker container inspect "encfs-${LID}" -f '{{.State.Status}}')" != "running" ]]; then
LENCFS_PASS=$(echo -n "EncFS-PASS ${SF_SEC}" | sha512sum | base64 | tr -dc '[:alpha:]' | head -c 16)
# HERE: encfs is not already running for this instance...
# 1st EncFS to put warning into mount-point that it is cleartext (until it's mounted!).
DEBUGF "EncFS-${LID} is not yet running..."
# docker run \
# --rm \
# --env MARKFILE="${MARKFILE}" \
# --env LID="${LID}" \
# --env SF_DEBUG="${SF_DEBUG}" \
# -v "${SF_ENCFS_SECDIR}:/encfs/sec:shared" \
# sf-encfs || ERREXIT 250 "Could not create /sec..."
# 2nd EncFS to mount encrypted to mount-point.
# EncFS to mount encrypted to mount-point.
# Run in background (-d)
# Use exec_devnull to redirect Container-ID to /dev/null (docker run -d).
exec_devnull docker run \
@ -221,21 +254,9 @@ docker exec \
CHECKFILE=1 \
/mount.sh" || ERREXIT 244 "Failed to set up /sec..."
echo_pty -n ".."
echo_pty -n "...."
# Generate a mnemonic hostname from LID (e.g. ButterflyCat)
NUM=$(echo "ibase=16; $(echo "$LID" | md5sum | cut -f1 -d" " | tr 'a-z' A-Z)" | bc)
readarray -t english </etc/english.txt
HOSTNAME="UnknownUnknown"
if [[ "${#english[@]}" -eq 2048 ]]; then
HOSTNAME="${english[$((NUM % 2048))]}"
HOSTNAME+="${english[$(( (NUM / 2048) % 2048 ))]}"
fi
DEBUGF "HOSTNAME=$HOSTNAME"
unset NUM
unset english
echo_pty -n ".."
# Attach to instance if already running
[[ -n $IS_TRY_EXISTING ]] && {
DEBUGF "Attaching to existing instance lg-${LID}..."
@ -250,6 +271,15 @@ echo_pty -n ".."
# HERE: Instance does not exists.
}
### Create ONION directory:
# This script runs under UID=1000 (root) and does not have write permission to
# /onion. Thus jump via docker.
[[ -d "/onion/${SF_HOSTNAME,,}" ]] || {
DEBUGF "Creating /onion/${SF_HOSTNAME,,}"
exec_devnull docker exec sf-host mkdir "/onion/${SF_HOSTNAME,,}"
DEBUGF "ret $?"
}
# Starting GUEST shell
# Challenge: Keep user processes running that got spawned in the background
# even when first instance terminates. Also do not terminate instance
@ -257,7 +287,7 @@ echo_pty -n ".."
# Solution: Spawn a docker in the background that monitors the number of
# processes and use 'docker exec' for every connection.
exec_devnull docker run \
--hostname "sf-${HOSTNAME}" \
--hostname "sf-${SF_HOSTNAME}" \
--rm \
--init \
--name "lg-${LID}" \
@ -269,12 +299,15 @@ exec_devnull docker run \
--env SF_USER="${SF_USER}" \
--env SF_FQDN="${SF_FQDN}" \
--env SF_DEBUG="${SF_DEBUG}" \
--env SF_HOSTNAME="${SF_HOSTNAME}" \
-e SSH_CONNECTION \
-e SSH_CLIENT \
--log-driver "${SF_DOCKER_LOG}" \
--mount type=bind,source="${SF_BASEDIR}/config/etc/ssh/id_ed25519,target=/config/id_ed25519,readonly" \
-v "${SF_BASEDIR}/guest/sf-guest:/usr/local/sf-guest:ro" \
-v "${SF_ENCFS_SECDIR}/user-${LID}:/sec:shared" \
--mount type=bind,source="${SF_BASEDIR}/config/${SF_FQDN:-this}/tor/hidden_service/hostname,target=/config/onion_hostname,readonly" \
--mount type=bind,source="${SF_BASEDIR}/guest/sf-guest,target=/usr/local/sf-guest,readonly" \
-v "${SF_ENCFS_SECDIR}/user-${LID}:/sec:slave" \
-v "${SF_BASEDIR}/data/onion/${SF_HOSTNAME,,}:/onion:shared" \
-d \
sf-guest /usr/local/sf-guest/bin/sf-destructor.sh || ERREXIT 251 "Failed to set up guest instance..."
@ -304,6 +337,10 @@ echo_pty -e "....................[${CG}OK${CN}]"
# Output help of how to connect elegantly
[[ -n $IS_NEW_SERVER ]] && print_ssh_access
DEBUGF "Status: $(docker container inspect "lg-${LID}" -f '{{.State.Status}}')"
[[ -z $SF_DEBUG ]] || {
docker exec "lg-${LID}" ls -ald /root /sec/root
}
# Spawn shell
spawn_shell_exit "$@"
# NOT REACHED

@ -136,7 +136,7 @@ usermod -a -G docker "${SF_HOST_USER}"
# Find out my own hostname
[[ -z $SF_NO_INTERNET ]] && {
IP="$(curl ifconfig.me 2>/dev/null)"
HOST="$(host "$IP")" && HOST="$(echo "$HOST" | sed -E 's/.*name pointer (.*)\.$/\1/g')" || HOST="$(hostname -f)"
HOST="$(host "$IP")" && { HOST="$(echo "$HOST" | sed -E 's/.*name pointer (.*)\.$/\1/g')"; true; } || HOST="$(hostname -f)"
}
# To short or contains illegal characters?

19
tor/Dockerfile Executable file

@ -0,0 +1,19 @@
FROM alpine:edge
RUN apk add --no-cache curl tor && \
(echo -e "\
SocksPort 0.0.0.0:9050\n\
HiddenServiceDir /var/lib/tor/hidden_service/\n\
HiddenServicePort 80 nginx:80\n\
"; cat /etc/tor/torrc.sample) >/etc/tor/torrc && \
echo "DONE"
EXPOSE 9050
HEALTHCHECK --interval=60s --timeout=15s --start-period=20s \
CMD curl -s --socks5 127.0.0.1:9050 'https://check.torproject.org/' | grep -qm1 Congratulations
COPY /fs-root/ /
RUN chmod 755 /sf-tor.sh
CMD ["/sf-tor.sh"]

3
tor/Makefile Executable file

@ -0,0 +1,3 @@
all: Dockerfile
docker build -t sf-tor .

25
tor/fs-root/sf-tor.sh Executable file

@ -0,0 +1,25 @@
#! /bin/ash
CR="\033[1;31m" # red
CG="\033[1;32m" # green
CN="\033[0m" # none
ERREXIT()
{
local code
code="$1"
[[ $? -ne 0 ]] && code="$?"
[[ -z $code ]] && code=99
shift 1
[[ -n "$1" ]] && echo -e >&2 "${CR}ERROR:${CN} $*"
exit "$code"
}
[[ -d /var/lib/tor/hidden_service ]] || ERREXIT 254 "Not found: /var/lib/tor/hidden_services. Forgot -v option?"
chown tor /var/lib/tor/hidden_service || ERREXIT
chmod 700 /var/lib/tor/hidden_service || ERREXIT
echo -e "ONION: ${CG}http://$(cat /var/lib/tor/hidden_service/hostname 2>/dev/null)${CN}"
[[ -f /config/torrc ]] && { exec su -s /bin/ash - tor -c "tor -f /config/torrc"; true; } || exec su -s /bin/ash - tor -c "tor"
# NOT REACHED