From 54172afc6d5fa0e0f4b124c5f520014084fae5ef Mon Sep 17 00:00:00 2001 From: nikoproxy Date: Fri, 13 Oct 2023 11:31:34 +0200 Subject: [PATCH] first push --- README.md | 18 ++ torxi.sh | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 528 insertions(+) create mode 100644 README.md create mode 100755 torxi.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..121801a --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +Torxi needs an up and running Docker environment and a non-default docker network. Let's create one: + docker network create --driver=bridge --subnet=192.168.0.0/24 torxi_net + +==== Gateway ==== + echo -e 'FROM alpine:latest \n'\ + 'RUN apk add --update tor iptables iproute2 curl' |\ + docker build -t "torxi_gw" - + +==== Workstation ==== +https://www.kali.org/news/kali-linux-metapackages/ + echo -e 'FROM kalilinux/kali-rolling:latest \n\n'\ + 'RUN apt-get update \n\n'\ + 'RUN apt-get dist-upgrade -y \n\n'\ + 'RUN apt-get install -y apt-utils xfce4 xfce4-terminal kali-linux-core metasploit-framework \n\n'\ + 'RUN apt-get install -y iproute2 curl firefox-esr vim autocutsel iputils-ping \n\n'\ + 'RUN apt-get install -y apt-utils novnc dbus-x11 x11vnc tightvncserver ' |\ + docker build -t "torxi_ws" - + diff --git a/torxi.sh b/torxi.sh new file mode 100755 index 0000000..5226458 --- /dev/null +++ b/torxi.sh @@ -0,0 +1,510 @@ +#!/bin/bash + +###### Configuration ######### +#Gateway IP +_gwIP=192.168.0.254 +#Gateway name +_gwName=torxi_gw +#Workstation name +_wsName=torxi_ws +#Internal network name +_intNW=torxi_net +#Persistence (true/false) +persistence=true +#VNC Target resolution +vncres="$(xrandr | grep -F '*'|awk '{print $1}')" +#Get the name of the default terminal emulator +term=$(ps -o comm= -p "$(($(ps -o ppid= -p "$(($(ps -o sid= -p "$$")))")))") + +#####Output Colors############# +white="\033[1;37m" +red="\033[1;31m" +green="\033[1;32m" +yellow="\033[1;33m" +blue="\033[1;34m" +transparent="\e[0m" + +######################################## +### ANONYMIZING MIDDLEBOX SETTINGS###### +############ FOR TORRC ################# + +#These settings are pushed to the torrc of the gateway container. +_torSettings="VirtualAddrNetworkIPv4 10.192.0.0/10 +Log notice file /root/.tor/notices.log +DataDirectory /root/.tor +Log notice stdout +SocksPort $_gwIP:9050 IsolateSOCKSAuth +SocksPolicy accept 192.168.0.0/24 +SocksPolicy reject * +ControlPort $_gwIP:9051 +CookieAuthentication 1 +HashedControlPassword 16:0430F4846DCB79EB605DAB188CF619860A18B86C20D075B84CB97E0695 +AutomapHostsOnResolve 1 +TransPort $_gwIP:9040 +DNSPort $_gwIP:53" +######################################### +########## Functions #################### + + +function print_banner { + printf "$red%b\n" '████████╗ ██████╗ ██████╗ ██╗ ██╗██╗' + printf "$red%b\n" '╚══██╔══╝██╔═══██╗██╔══██╗╚██╗██╔╝██║' + printf "$red%b\n" ' ██║ ██║ ██║██████╔╝ ╚███╔╝ ██║' + printf "$blue%b\n" ' ██║ ██║ ██║██╔══██╗ ██╔██╗ ██║' + printf "$blue%b\n" ' ██║ ╚██████╔╝██║ ██║██╔╝ ██╗██║' + printf "$blue%b\n" ' ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝' + printf "$white%s$transparent\n" "-------------------------------------" +} + +function startupChecks { + #Make sure we are root + if [ "$(whoami)" != "root" ]; then + printf "$red%s$transparent\n\n" "[This script needs to be run as root or with sudo.]" + exit 1 + fi + + #Is Docker Daemon running? + docker ps &> /dev/null + if [ $? -ne 0 ]; then + printf "$red%s$transparent\n\n" "[Docker daemon not running or permission denied...]" + exit 1 + fi + + # If ping fail no internet connection is present + [[ $(ping -c1 1.1.1.1 > /dev/null) ]] && exit 1 + + #If there are any stopped containers, return 1 (true) or 0 (false) + [[ "$(docker ps -a | grep "$_gwName\|$_wsName")" != "" ]] && return 1 + + rm log &> /dev/null + return 0 +} + +function remove_container { + printf "\n$yellow%s$transparent\n" "[Deleting previously used containers..]" + docker stop $(docker ps -a | grep "$_gwName\|$_wsName" | awk '{ print$1 }') &> /dev/null + docker rm $(docker ps -a | grep "$_gwName\|$_wsName" | awk '{ print$1 }') &> /dev/null +} + +function gw_start { + ########## Start a Containainer from the Gateway Image ########## + printf "$white%s$transparent\n" "Starting a Gateway Container..." + _gwID=$(docker run -it --rm --privileged --name $_gwName -h $_gwName -d $_gwName) + + if [ "$_gwID" != "" ]; then + #printf "%s\n" "ID: $_gwID" + printf "$green%s$transparent\n" "[Success!]" + else + printf "\n$red%s$transparent\n" "[Error getting Container ID. See above errors!]" + return 1 + fi + + ########### Connect Container to internal Network ################ + printf "\n$white%s$transparent\n" "Connecting internal Network..." + docker network connect --ip $_gwIP $_intNW $_gwID + if [ $? -ne 0 ]; then + printf "\n$red%s$transparent\n" "[Error connecting to internal Docker Network.]" + docker kill $_gwID + return 2 + fi + printf "$green%s$transparent\n" "[Success!]" + return 0 +} + +function start_tor { + ########## Start Tor in Container ########## + printf "\n$white%s$transparent\n" "Starting Tor within gateway..." + docker exec -it -d $_gwID sh -c "echo '$_torSettings' > /etc/tor/torrc" + docker exec -it -d $_gwID sh -c "pkill tor" + docker exec -it -d $_gwID sh -c "tor > log" + test="" + declare -i timeout + declare -i try + timeout=0 + try=0 + + while [ "$test" != "100%" ] + do + test=$(docker exec -it $_gwID /bin/sh -c "cat log" | tail -n1 | awk '{ print $6 }' | cut -d':' -f1) + printf "\033[K%s\r" "Connection Status: $test" + sleep 1 + timeout+=1 + if [ $timeout -eq 20 ]; then + if [ "$try" = "3" ]; then + printf "$yellow%s$transparent\n" "[Tried three times. Giving up..]" + sleep 2 + return 1 + fi + try+=1 + printf "$yellow%s$transparent\n" "[Connection timeout. Retry..]" + docker exec -it -d $_gwID /bin/sh -c "pkill tor" + docker exec -it -d $_gwID /bin/sh -c "rm -rf /root/.tor" + sleep 2 + docker exec -it -d $_gwID sh -c "tor > log" + sleep 2 + timeout=0 + + + fi + done + printf "$green%s$transparent\n" "[Success!]" + return 0 +} + +function stop_tor { + printf "\n$white%s$transparent\n" "Stopping Tor in gateway..." + docker exec -it -d $_gwID /bin/sh -c "pkill tor" + docker exec -it -d $_gwID /bin/sh -c "rm -rf /root/.tor" + docker exec -it -d $_gwID /bin/sh -c "rm -rf log" + + if [ "$(docker exec -it -d $_gwID /bin/sh -c "pgrep tor")" = "" ]; then + printf "$green%s$transparent\n" "[Success!]" + else printf "$red%s$transparent\n" "[Stopping Tor was not successful!]" + fi + return 0 +} + +function ipt_rules { + ########## IPTABLES RULES ########### + printf "\n$white%s$transparent\n" "Applying iptables rules..." + #TransPort + _trans_port="9040" + #internal interface name + _inc_if="eth1" + # exlude from Tor + _NON_TOR="127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16" + docker exec -it $_gwID sh -c "iptables -F" + docker exec -it $_gwID sh -c "iptables -X" + docker exec -it $_gwID sh -c "iptables -t nat -F" + docker exec -it $_gwID sh -c "iptables -t nat -X" + ### + #The following iptable rules are recommendations from the Tor Project https://trac.torproject.org/projects/tor/wiki/doc/TransparentProxy + + #docker exec -it $_gwID sh -c "iptables -A OUTPUT -m conntrack --ctstate INVALID -j LOG --log-prefix 'Transproxy ctstate leak blocked: ' --log-uid" + docker exec -it $_gwID sh -c "iptables -A OUTPUT -m conntrack --ctstate INVALID -j DROP" + docker exec -it $_gwID sh -c "iptables -A OUTPUT -m state --state INVALID -j LOG --log-prefix 'Transproxy state leak blocked: ' --log-uid" + docker exec -it $_gwID sh -c "iptables -A OUTPUT -m state --state INVALID -j DROP" + + docker exec -it $_gwID sh -c "iptables -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,FIN -j LOG --log-prefix 'Transproxy leak blocked: ' --log-uid" + docker exec -it $_gwID sh -c "iptables -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,RST ACK,RST -j LOG --log-prefix 'Transproxy leak blocked: ' --log-uid" + docker exec -it $_gwID sh -c "iptables -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,FIN -j DROP" + docker exec -it $_gwID sh -c "iptables -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,RST ACK,RST -j DROP" + + for NET in $NON_TOR; do + docker exec -it $_gwID sh -c "iptables -t nat -A PREROUTING -i $_inc_if -d $NET -j RETURN" + done + + docker exec -it $_gwID sh -c "iptables -t nat -A PREROUTING -i $_inc_if -p udp --dport 53 -j REDIRECT --to-ports 53" + docker exec -it $_gwID sh -c "iptables -t nat -A PREROUTING -i $_inc_if -p udp --dport 5353 -j REDIRECT --to-ports 53" + #docker exec -it $_gwID sh -c "iptables -t nat -A PREROUTING -i $_inc_if -p tcp --syn -j REDIRECT --to-ports $_trans_port" + ##exclude connections to the socket + docker exec -it $_gwID sh -c "iptables -t nat -A PREROUTING -i $_inc_if ! -d 192.168.0.254 -p tcp --syn -j REDIRECT --to-ports $_trans_port" + printf "$green%s$transparent\n" "[Success!]" + return 0 +} + +function ws_start { + ########## Start Workstation Container ############## + printf "\n$white%s$transparent\n" "Starting a Workstaion Container..." + + if [ "$persistence" = "true" ]; then + printf "$blue%s$transparent\n" "Persistence is enabled, mounting local storage." + _wsID=$(docker run -it --rm --privileged --mount src=kali-root,dst=/root --net=$_intNW -e USER=root -h $_wsName --name $_wsName -d $_wsName) + else + printf "$yellow%s$transparent\n" "Persistence is disabled, not mounting local storage." + _wsID=$(docker run -it --rm --privileged --net=$_intNW -e USER=root --name $_wsName -h $_wsName -d $_wsName) + fi + + if [ $? -ne 0 ]; then + printf "\n$red%s$transparent\n" "[Error starting Workstation - is the name correct?]" + exit 1 + fi + + ## Get the IP of the newly created Container + _wsIP=$(docker exec -it $_wsID ip a show dev eth0 |grep -Po ".*(?=/\d\d?)"|awk '{print $2}') + printf "$green%s$transparent\n" "[Success!]" + + ########## Set the gateway as nameserver ########## + printf "\n$white%s$transparent\n" "Setting the gateway as nameserver..." + docker exec -it -d $_wsID sh -c "echo nameserver $_gwIP > /etc/resolv.conf" + if [ "$?" = "0" ]; then + printf "$green%s$transparent\n" "[Success!]" + else printf "$red%s$transparent\n" "[Error!]" + fi + + + + ########## Set the gateway container as the workstation's default gateway ########## + printf "\n$white%s$transparent\n" "Setting default gateway of workstation..." + docker exec -it -d $_wsID sh -c "ip route del default" + docker exec -it -d $_wsID sh -c "ip route add default via $_gwIP" + + ## Check Gateway + _chkgwIP=$(docker exec -it $_wsID sh -c "ip route | head -n1 ") + _chkgwIP=$(echo $_chkgwIP | awk '{ print $3 }') + + if [[ "$_chkgwIP" = "$_gwIP" ]]; then + printf "$green%s$transparent\n" "[Success!]" + else + printf "$red%s$transparent\n" "[Error setting the default gateway]" + echo $_chkgwIP + exit 1 + fi +} + +function checkip { + + printf "\n$white%s$transparent\n" "Checking connection..." + + while true; do + #Check if tor is running in gw container + if [ "$(docker exec -it $_gwID sh -c 'pgrep tor')" = "" ]; then + printf "$yellow%s$transparent\n" "[Tor is not running in gateway]" + return 0 + fi + + # WS_CONTAINER CURL LEAVES '\r' CHAR, IN ORDER TO MATCH REGEX IT HAS TO BE STRIPPED + _torip=$(docker exec -it torxi_ws sh -c "curl --silent checkip.amazonaws.com" | tr -d '\r') + _clearip="$(curl --silent checkip.amazonaws.com)" + + #echo "Host IP: ${_clearip}" + #echo "TOR IP: ${_torip}" + + # Check clear net IP ## + if [[ ! $_clearip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + printf "$red%s$transparent\n" "[Error. Do we have an Internet connection?]" + return 0 + fi + + ## Check public Container IP ## + + if [[ ${_torip} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + + if [ "$_clearip" != "$_torip" ]; then + printf "$green%s$transparent\n" "[Success!]" + break + fi + else + printf "$red%s$transparent\n" "[Error getting an IP Adress!]" + printf "%b\n" "Retry? Tor may needs some time to establish circuits!" + printf "%b" "Choice (y/n): " + read retry + if [ $retry != "y" ]; then return 0; fi + fi + done + geoiplookup ${_torip} + +} + +function geoiplookup { + geoipreply=$(curl -s "ipinfo.io/${1}") + export _geoipmsg="We're surfing from ${1} geolocated at $(echo $geoipreply|jq -r .city), in $(echo $geoipreply|jq -r .region) ($(echo $geoipreply|jq -r .country))" +} + +function start_vnc { + printf "$white%s$transparent\n" "Starting VNC Server in Workstation... (close vncviewer to return to menu)" + + if [ "$_wsIP" = "" ]; then + _wsIP=$(docker exec -it $_wsID ip a show dev eth0 |grep -Po ".*(?=/\d\d?)"|awk '{print $2}') + fi + + _checkvnc=$(docker exec -it -e USER=root $_wsID bash -c "pgrep Xtightvnc") + if [ "$_checkvnc" = "" ]; then + docker exec -e USER=root $_wsID su -c "vncserver :0 -geometry $vncres" + if [ "$?" = "0" ]; then + printf "$green%s$transparent\n" "[VNC-Server started]" + else + printf "$red%s$transparent\n" "[VNC-Server could not be started]" + return 1 + fi + else + printf "$green%s$transparent\n" "[Found running VNC-Server]" + fi + + _checkNOvnc=$(docker exec -it -e USER=root $_wsID bash -c "pgrep -f novnc_proxy") + if [ "$_checkNOvnc" = "" ]; then + docker exec -e USER=root $_wsID sh -c "/usr/share/novnc/utils/novnc_proxy --listen 8081 --vnc localhost:5900 > /dev/null &" + else + printf "$green%s$transparent\n" "[Found running noVNC-Server]" + fi + + export _novncBanner="${green}noVNC instance at http://${_wsIP}:8081/vnc.html?host=${_wsIP}&port=8081$transparent" + + ###Start the client### + #vncviewer ${_wsIP}:5900 + #docker exec -it -e USER=root $_wsID su -c "vncserver -kill :0" + + return 0 +} + +function menu { + ############### MENU ######################## + clear + print_banner + printf "%b\n" "$_geoipmsg" + printf "%b\n\n" "$_novncBanner" + + printf "$blue%s\t$white%s\t%s$transparent\n" "[Workstation]" "Start a Terminal Session" "(t)" + printf "$blue%s\t$white%s\t%s$transparent\n" "[Workstation]" "Start (no)VNC server stack" "(v)" + printf "$yellow%s\t$white%s\t%s$transparent\n" "[Gateway]" "Start a Terminal Session" "(g)" + printf "$yellow%s\t$white%s\t\t\t%s$transparent\n" "[Gateway]" "(Re)Start Tor" "(s)" + printf "$yellow%s\t$white%s\t\t\t%s$transparent\n" "[Gateway]" "Stop Tor" "(x)" + printf "$yellow%s\t$white%s\t\t\t%s$transparent\n" "[Gateway]" "New Identity" "(n)" + printf "%s\t$white%s\t\t%s$transparent\n" "[System]" "Check Connection" "(c)" + printf "%s\t$white%s\t\t%s$transparent\n" "[System]" "Quit and clean up" "(q)" + + while [ "$choice" != "q" ] + do + printf "\n\n%s" "" + printf "%s" "Choice: " + read choice + + ## Connect to work station terminal + if [ "$choice" = "t" ]; then + printf "$white%s$transparent\n" "Connecting to Workstation Terminal.. (type 'exit' to return to menu)" + docker exec -it -e USER=root $_wsID /bin/bash + return 1 + fi + + ## Start and connect workstation VNC + if [ "$choice" = "v" ]; then + start_vnc + return 1 + fi + + ## Check Connection + if [ "$choice" = "c" ]; then + printf "\n%s" "" + checkip + return 1 + fi + + ## New identity via ControlPort + if [ "$choice" = "n" ]; then + printf "\n$white%s$transparent\n" "Getting new identity..." + docker exec -it $_gwID sh -c "(echo authenticate '""'; echo signal newnym; echo quit) | nc $_gwIP 9051" + checkip + return 1 + fi + + ## connect to gateway terminal + if [ "$choice" = "g" ]; then + printf "$white%s$transparent\n" "Connecting to Gateway Terminal.. (type 'exit' to return to menu)" + docker exec -it -e USER=root $_gwID /bin/sh + return 1 + fi + + # (re) start tor + if [ "$choice" = "s" ]; then + start_tor + return 1 + fi + + # stop tor + if [ "$choice" = "x" ]; then + stop_tor + return 1 + fi + + + done + + printf "\n$white%s$transparent\n" "Do you want to remove running containers?" + printf "%s" "Choice [Y/n]: " + read keep + if [ "$keep" != "n" ]; then + remove_container + else + printf "\n$yellow%s$transparent\n" "Keeping containers running." + printf "$yellow%s$transparent\n" "It's a good idea to stop Tor at least. Stop Tor?" + printf "%s$transparent" "Choice (Y/n): " + read stoptor + if [ "$stoptor" != "n" ]; then stop_tor; fi + fi + return 0 +} + +function clean_start { + gw_start + while [ "$?" != "0" ] + do + gw_start + done + + start_tor + while [ "$?" != "0" ] + do + start_tor + done + + ws_start + while [[ "$?" != "0" ]] + do + ws_start + done + + ipt_rules + while [[ "$?" != "0" ]] + do + ipt_rules + done + + checkip + +} + +function resume_start { + + printf "\n$yellow%s$transparent\n" "Some containers were found. Try to restore session?" + printf "%b" "Choice (y/n): " + read restore + + if [ "$restore" = "y" ]; then + ##Get the Gateway ID because the menu needs the variable _gwID + if [ "$(docker ps -a | grep $_gwName | awk '{print $1}' | xargs)" != "" ]; then + + export _gwID=$(docker ps -a | grep $_gwName | awk '{print $1}' | xargs) + printf "\n$green%s$transparent\n" "[Found gateway \"$_gwName\" with ID: $_gwID]" + else + printf "$yellow%s$transparent\n" "No Gateway with name $_gwName was found. Start one?" + printf "$white%s$transparent" "Choice: " + read startgw + if [ "$startgw" = "y" ]; then + gw_start + start_tor + fi + fi + + ##Get the Workstation ID because the menu needs the variable _wsID + if [ "$(docker ps -a | grep $_wsName | awk '{print $1}' | xargs)" != "" ]; then + + export _wsID=$(docker ps -a | grep $_wsName | awk '{print $1}' | xargs) + printf "\n$green%s$transparent\n" "[Found workstation \"$_wsName\" with ID: $_wsID]" + else + printf "$yellow%s$transparent\n" "No Workstation with name $_wsName was found. Start one?" + printf "$white%s$transparent" "Choice (y/n): " + read startws + if [ "$startws" = "y" ]; then + ws_start + fi + fi + checkip + else + remove_container + clean_start + fi +} + + +### Program Logic aka sequence of function calls + +##Banner +print_banner + +#Check wether there is a stored session of containers +startupChecks && clean_start || resume_start + +while true; do + menu && break +done +exit 0