working version, for release
This commit is contained in:
16
Makefile
16
Makefile
@@ -1,11 +1,10 @@
|
|||||||
|
|
||||||
PREFIX = ~/bin
|
PREFIX = ~/bin
|
||||||
|
|
||||||
build:
|
build:
|
||||||
bash -c '. config.env && \
|
bash -c '. config.env && \
|
||||||
mkdir -p scripts && \
|
mkdir -p scripts && \
|
||||||
cp src/ssh-backdoor scripts/ssh-backdoor && \
|
cp src/ssh-backdoor scripts/ssh-backdoor && \
|
||||||
cp src/ssh-backdoor-connect-local scripts/ssh-backdoor-connect-local && \
|
|
||||||
cp src/ssh-backdoor-connect scripts/ssh-backdoor-connect && \
|
cp src/ssh-backdoor-connect scripts/ssh-backdoor-connect && \
|
||||||
sed \
|
sed \
|
||||||
-e "s/{{BACKDOORHOST}}/$${BACKDOORHOST}/g" \
|
-e "s/{{BACKDOORHOST}}/$${BACKDOORHOST}/g" \
|
||||||
@@ -15,19 +14,26 @@ build:
|
|||||||
-e "s/{{BACKDOORHOST}}/$${BACKDOORHOST}/g" \
|
-e "s/{{BACKDOORHOST}}/$${BACKDOORHOST}/g" \
|
||||||
-e "s/{{BACKDOORPORT}}/$${BACKDOORPORT}/g" \
|
-e "s/{{BACKDOORPORT}}/$${BACKDOORPORT}/g" \
|
||||||
-e "s,{{BACKDOORURL}},$${BACKDOORURL},g" \
|
-e "s,{{BACKDOORURL}},$${BACKDOORURL},g" \
|
||||||
-e "s,{{BACKDOORURLPATH}},$${BACKDOORURLPATH},g" \
|
|
||||||
src/ssh-backdoor-open > scripts/ssh-backdoor-open && \
|
src/ssh-backdoor-open > scripts/ssh-backdoor-open && \
|
||||||
chmod +x scripts/* && \
|
chmod +x scripts/* && \
|
||||||
true'
|
true'
|
||||||
|
|
||||||
install: build
|
install: build
|
||||||
bash -c '. config.env && \
|
bash -c '. config.env && \
|
||||||
cp -av scripts/ssh-backdoor-open "$${BACKDOORURLPATH}" && \
|
if [[ -n "$${BACKDOORURLPATH}" ]]; then cp -av scripts/ssh-backdoor-open "$${BACKDOORURLPATH}"; fi && \
|
||||||
|
if [[ -n "$${CLIENTURLPATH}" ]]; then cp -av scripts/ssh-backdoor-open "$${BACKDOORURLPATH}"; fi && \
|
||||||
mkdir -p ${PREFIX} && \
|
mkdir -p ${PREFIX} && \
|
||||||
cp -av scripts/ssh-backdoor ${PREFIX}/ssh-backdoor && \
|
cp -av scripts/ssh-backdoor ${PREFIX}/ssh-backdoor && \
|
||||||
cp -av scripts/ssh-backdoor-connect-local ${PREFIX}/ssh-backdoor-connect-local && \
|
|
||||||
cp -av scripts/ssh-backdoor-connect ${PREFIX}/ssh-backdoor-connect && \
|
cp -av scripts/ssh-backdoor-connect ${PREFIX}/ssh-backdoor-connect && \
|
||||||
true'
|
true'
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf scripts
|
rm -rf scripts
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
bash -c '\
|
||||||
|
rm -fv ${PREFIX}/ssh-backdoor && \
|
||||||
|
rm -fv ${PREFIX}/ssh-backdoor-connect && \
|
||||||
|
if [[ -f "$${BACKDOORURLPATH}" ]]; then rm -fv $${BACKDOORURLPATH}; fi && \
|
||||||
|
true
|
||||||
|
'
|
||||||
|
|||||||
33
README.md
Normal file
33
README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# What?
|
||||||
|
|
||||||
|
This is a backdoor for servers in NAT networks.
|
||||||
|
|
||||||
|
One server on the public internet acts as a backdoor server, where other
|
||||||
|
computers connect, creating reverse tunnels to their ports 22.
|
||||||
|
|
||||||
|
The program manages random ports that are then available at the server localhost.
|
||||||
|
|
||||||
|
# install
|
||||||
|
|
||||||
|
configure config.env and run `make install`
|
||||||
|
|
||||||
|
- ssh-backdoor will go to ~/bin/ssh-backdoor
|
||||||
|
- Servers behind NAT should access the ssh-backdoor-open script over a http(s) server
|
||||||
|
- Clients that want to connect to the backdoored servers should be able to access
|
||||||
|
ssh-backdoor-connect script
|
||||||
|
- use the 'ad-hoc-www-server' if no proper http server available
|
||||||
|
|
||||||
|
# running
|
||||||
|
|
||||||
|
- NATted servers must copy their `id_rsa.pub` to backdoor server's `authorized_keys`
|
||||||
|
- Clients should do the same, for ease of access
|
||||||
|
- Have NATted servers run `ssh-backdoor-open` at boot (in cron or otherwise)
|
||||||
|
- Use the ssh-backdoor command directly, or ssh-backdoor-connect from client machines
|
||||||
|
to connect
|
||||||
|
|
||||||
|
|
||||||
|
# utils
|
||||||
|
|
||||||
|
- `ssh-list` lists all processes with ssh and backdoor
|
||||||
|
- `ssh-kill-all` kills all ssh connections (except the current parent), and all python processes
|
||||||
|
|
||||||
8
ad-hoc-www-server
Executable file
8
ad-hoc-www-server
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd $( dirname $( readlink -f $0 ) )
|
||||||
|
set -e
|
||||||
|
. config.env
|
||||||
|
|
||||||
|
cd "$ADHOCSERVERROOT"
|
||||||
|
python3 -m http.server $ADHOCSERVERPORT
|
||||||
13
config.env.example
Normal file
13
config.env.example
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Host name of the SSH server (and user name)
|
||||||
|
BACKDOORHOST=admin@my.server.org
|
||||||
|
# Port of the SSH server
|
||||||
|
BACKDOORPORT=22
|
||||||
|
# Where to download the ssh-backdoor-open and ssh-backdoor-connect script (may be left empty)
|
||||||
|
BACKDOORURL=https://my.server.org/pub/ssh-backdoor-open
|
||||||
|
CLIENTURL=https://my.server.org/pub/ssh-backdoor-connect
|
||||||
|
# Location of the dowloadable script at the server (may be empty)
|
||||||
|
BACKDOORURLPATH=/home/admin/www/pub/ssh-backdoor-open
|
||||||
|
CLIENTURLPATH=/home/admin/www/pub/ssh-backdoor-connect
|
||||||
|
# Ad-hoc web server port (if used)
|
||||||
|
ADHOCSERVERPORT=8080
|
||||||
|
ADHOCSERVERROOT=/home/admin/www/pub/
|
||||||
196
src/ssh-backdoor
196
src/ssh-backdoor
@@ -6,6 +6,7 @@ import psutil
|
|||||||
import random
|
import random
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time, os, sys
|
import time, os, sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
def setup_options():
|
def setup_options():
|
||||||
''' Setup the command line options '''
|
''' Setup the command line options '''
|
||||||
@@ -20,44 +21,6 @@ def setup_options():
|
|||||||
type = str,
|
type = str,
|
||||||
help = "Sqlite file for database: %(default)s"
|
help = "Sqlite file for database: %(default)s"
|
||||||
)
|
)
|
||||||
# TODO --connect (replace ssh-local-connect)
|
|
||||||
parser.add_argument(
|
|
||||||
"--clear",
|
|
||||||
action = 'store_true',
|
|
||||||
dest = 'clear',
|
|
||||||
default = False,
|
|
||||||
help = "Clear the database of everything, first"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--kill",
|
|
||||||
action = 'store',
|
|
||||||
dest = 'kill',
|
|
||||||
default = None,
|
|
||||||
type = str,
|
|
||||||
help="Kill processes of given ID"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--list","-l",
|
|
||||||
action = 'store_true',
|
|
||||||
dest = 'list',
|
|
||||||
default = False,
|
|
||||||
help = "List ports"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--list-names",
|
|
||||||
action = 'store_true',
|
|
||||||
dest = 'list_names',
|
|
||||||
default = False,
|
|
||||||
help = "List alive host names only"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--query",
|
|
||||||
action = 'store',
|
|
||||||
dest = 'query',
|
|
||||||
default = None,
|
|
||||||
type = str,
|
|
||||||
help="Query port for an id"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--quiet", "-q",
|
"--quiet", "-q",
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
@@ -65,22 +28,78 @@ def setup_options():
|
|||||||
default = False,
|
default = False,
|
||||||
help = "Quiet operation: %(default)s"
|
help = "Quiet operation: %(default)s"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--wait", "-w",
|
subparsers = parser.add_subparsers(
|
||||||
action = 'store_true',
|
help = "Help for subcommand",
|
||||||
dest = 'wait',
|
dest = 'command'
|
||||||
default = False,
|
|
||||||
help = "Enter infinite loop"
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser_clear = subparsers.add_parser(
|
||||||
|
'clear',
|
||||||
|
help = "Clear the database of everything"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_connect = subparsers.add_parser(
|
||||||
|
'connect',
|
||||||
|
help = "Connect to a backdoor"
|
||||||
|
)
|
||||||
|
parser_connect.add_argument(
|
||||||
|
dest = "id",
|
||||||
|
help = "Backdoor ID to connect to"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_kill = subparsers.add_parser(
|
||||||
|
'kill',
|
||||||
|
help = "Kill a backdoor"
|
||||||
|
)
|
||||||
|
parser_kill.add_argument(
|
||||||
|
dest = "id",
|
||||||
|
help = "Backdoor ID to kill"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_list = subparsers.add_parser(
|
||||||
|
"list",
|
||||||
|
help = "List ports"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_list_names = subparsers.add_parser(
|
||||||
|
"list-names",
|
||||||
|
help = "List alive host names only"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_query = subparsers.add_parser(
|
||||||
|
"query",
|
||||||
|
help="Query port for an id"
|
||||||
|
)
|
||||||
|
parser_query.add_argument(
|
||||||
|
dest = "id",
|
||||||
|
help = "Backdoor ID to query"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser_open = subparsers.add_parser(
|
||||||
|
"open",
|
||||||
|
help = "Open a new port. Returns the port number"
|
||||||
|
)
|
||||||
|
parser_open.add_argument(
|
||||||
action = 'store',
|
action = 'store',
|
||||||
dest = 'id',
|
dest = 'id',
|
||||||
default = None ,
|
|
||||||
type = str,
|
type = str,
|
||||||
nargs = '?',
|
help="Id name for backdoor"
|
||||||
help="Id name for port"
|
)
|
||||||
|
|
||||||
|
parser_wait = subparsers.add_parser(
|
||||||
|
"keep",
|
||||||
|
help = "Keep updating alive status (for 1 hour)"
|
||||||
|
)
|
||||||
|
parser_wait.add_argument(
|
||||||
|
action = 'store',
|
||||||
|
dest = 'id',
|
||||||
|
type = str,
|
||||||
|
help="Id name for backdoor"
|
||||||
)
|
)
|
||||||
options=parser.parse_args()
|
options=parser.parse_args()
|
||||||
|
if options.command == None:
|
||||||
|
parser.print_help(sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
@@ -254,52 +273,83 @@ class DataBase:
|
|||||||
if len(result) == 0:
|
if len(result) == 0:
|
||||||
return port
|
return port
|
||||||
|
|
||||||
|
def connect_backdoor(self, id):
|
||||||
|
self.db = self.conn.cursor()
|
||||||
|
self.db.execute("SELECT port,pid FROM ports WHERE id = ?", (id,))
|
||||||
|
result = self.db.fetchall()
|
||||||
|
if len(result) == 0:
|
||||||
|
eprint("No such ID")
|
||||||
|
return
|
||||||
|
port = result[0][0]
|
||||||
|
pid = result[0][1]
|
||||||
|
if not self.is_running(pid):
|
||||||
|
eprint("Backdoor not open")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = id.split("@")[0]
|
||||||
|
os.execlp(
|
||||||
|
"ssh",
|
||||||
|
"ssh",
|
||||||
|
"-o", "UserKnownHostsFile=/dev/null",
|
||||||
|
"-o", "StrictHostKeyChecking=no",
|
||||||
|
"-tt", "-XYC",
|
||||||
|
"-p", str(port),
|
||||||
|
"%s@localhost"%( user, )
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
opts=setup_options()
|
opts=setup_options()
|
||||||
db = DataBase(opts.DB)
|
db = DataBase(opts.DB)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
if opts.clear:
|
if opts.command == "clear":
|
||||||
db.clear()
|
db.clear()
|
||||||
|
|
||||||
if opts.list_names:
|
if opts.command == "list-names":
|
||||||
for row in db.list():
|
for row in db.list():
|
||||||
if row[5]:
|
if row[-1]:
|
||||||
print(row[0])
|
print(row[0])
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if opts.list:
|
if opts.command == "list":
|
||||||
print(tabulate(
|
print(tabulate(
|
||||||
db.list(),
|
db.list(),
|
||||||
headers = ['Id','Port','Host','Age','PID','Die','Alive']
|
headers = ['Id','Port','Host','Age','PID','Die','Alive']
|
||||||
))
|
))
|
||||||
|
|
||||||
if opts.query != None:
|
if opts.command == "query":
|
||||||
port = db.get_port(opts.query)
|
port = db.get_port(opts.id)
|
||||||
if port == None:
|
if port == None:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(port)
|
print(port)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if opts.kill:
|
if opts.command == "kill":
|
||||||
db.set_to_die(opts.kill)
|
db.set_to_die(opts.id)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if opts.id != None:
|
if opts.command == "connect":
|
||||||
|
db.connect_backdoor(opts.id)
|
||||||
|
|
||||||
|
if opts.command == "open":
|
||||||
print(db.update(opts.id))
|
print(db.update(opts.id))
|
||||||
if opts.wait:
|
|
||||||
ewrite(
|
if opts.command == "keep":
|
||||||
" Connected\r"
|
print(db.update(opts.id))
|
||||||
)
|
ewrite(
|
||||||
while True:
|
" Connected\r"
|
||||||
if time.time() - start_time > 3600:
|
)
|
||||||
sys.exit(0)
|
while True:
|
||||||
db.check_die()
|
# Run 1 hour, then exit to reconnect
|
||||||
db.update(opts.id)
|
if time.time() - start_time > 3600:
|
||||||
for i in range(10):
|
sys.exit(0)
|
||||||
time.sleep(10 * random.random())
|
db.check_die()
|
||||||
ewrite(
|
db.update(opts.id)
|
||||||
" " +
|
for i in range(10):
|
||||||
time.strftime("%c") +
|
time.sleep(10 * random.random())
|
||||||
"\r"
|
ewrite(
|
||||||
)
|
" " +
|
||||||
|
time.strftime("%c") +
|
||||||
|
"\r"
|
||||||
|
)
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ BACKDOORHOST={{BACKDOORHOST}}
|
|||||||
BACKDOORPORT={{BACKDOORPORT}}
|
BACKDOORPORT={{BACKDOORPORT}}
|
||||||
_list() {
|
_list() {
|
||||||
echo 'usage: [-auto] user@host'
|
echo 'usage: [-auto] user@host'
|
||||||
_ssh bin/ssh-backdoor -l
|
_ssh bin/ssh-backdoor list
|
||||||
ids=( $( _ssh bin/ssh-backdoor --list-names ) )
|
ids=( $( _ssh bin/ssh-backdoor list-names ) )
|
||||||
if [[ ${#ids[@]} -eq 0 ]]; then
|
if [[ ${#ids[@]} -eq 0 ]]; then
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
@@ -33,6 +33,8 @@ _ssh() {
|
|||||||
-o UserKnownHostsFile=/dev/null \
|
-o UserKnownHostsFile=/dev/null \
|
||||||
-o StrictHostKeyChecking=no \
|
-o StrictHostKeyChecking=no \
|
||||||
-o ConnectTimeout=10 \
|
-o ConnectTimeout=10 \
|
||||||
|
-o ServerAliveInterval=15 \
|
||||||
|
-o ServerAliveCountMax=3 \
|
||||||
-p ${BACKDOORPORT} ${BACKDOORHOST} \
|
-p ${BACKDOORPORT} ${BACKDOORHOST} \
|
||||||
"$@"
|
"$@"
|
||||||
#~ -o "ExitOnForwardFailure yes" \
|
#~ -o "ExitOnForwardFailure yes" \
|
||||||
@@ -48,17 +50,15 @@ for (( i=1; i<=$#; i++ )); do
|
|||||||
host="${!i}"
|
host="${!i}"
|
||||||
done
|
done
|
||||||
|
|
||||||
port=$( _ssh bin/ssh-backdoor --query "$host" )
|
port=$( _ssh bin/ssh-backdoor query "$host" )
|
||||||
[[ $? -ne 0 ]] && {
|
[[ $? -ne 0 ]] && {
|
||||||
echo No such id
|
echo No such id
|
||||||
_list
|
_list
|
||||||
}
|
}
|
||||||
login=(${host//@/ })
|
|
||||||
while :; do
|
while :; do
|
||||||
_ssh \
|
_ssh \
|
||||||
-tt \
|
-tt \
|
||||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
|
bin/ssh-backdoor connect "$host"
|
||||||
-tt -XYC -p $port ${login[0]}@localhost
|
|
||||||
[[ $? -eq 0 ]] && exit
|
[[ $? -eq 0 ]] && exit
|
||||||
[[ "$auto_reconnect" -ne 1 ]] && { exit $?; }
|
[[ "$auto_reconnect" -ne 1 ]] && { exit $?; }
|
||||||
echo Auto-reconnect
|
echo Auto-reconnect
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
_list() {
|
|
||||||
echo usage: user@host
|
|
||||||
ssh-backdoor -l
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
[[ -z "$1" ]] && _list
|
|
||||||
|
|
||||||
port=$( ssh-backdoor --query "$1" )
|
|
||||||
[[ $? -ne 0 ]] && {
|
|
||||||
echo No such id
|
|
||||||
_list
|
|
||||||
}
|
|
||||||
login=(${1//@/ })
|
|
||||||
set -x
|
|
||||||
exec ssh \
|
|
||||||
-o UserKnownHostsFile=/dev/null \
|
|
||||||
-o StrictHostKeyChecking=no \
|
|
||||||
-tt -XYC -p $port ${login[0]}@localhost
|
|
||||||
@@ -31,13 +31,13 @@ USER=$( id -u -n )
|
|||||||
echo use of ssh-add is encouraged
|
echo use of ssh-add is encouraged
|
||||||
( sleep 3; printf "%d\r" $SECONDS ) &
|
( sleep 3; printf "%d\r" $SECONDS ) &
|
||||||
while true; do
|
while true; do
|
||||||
port=$( _ssh bin/ssh-backdoor $USER@$HOSTNAME )
|
port=$( _ssh bin/ssh-backdoor open $USER@$HOSTNAME )
|
||||||
[[ -z "$port" ]] && { sleep 2; continue; }
|
[[ -z "$port" ]] && { sleep 2; continue; }
|
||||||
echo "$port port assigned"
|
echo "$port port assigned"
|
||||||
#~ _ssh pkill -a -f $USER@$HOSTNAME
|
#~ _ssh pkill -a -f $USER@$HOSTNAME
|
||||||
_ssh \
|
_ssh \
|
||||||
-R $port:localhost:22 \
|
-R $port:localhost:22 \
|
||||||
bin/ssh-backdoor -w $USER@$HOSTNAME || {
|
bin/ssh-backdoor keep $USER@$HOSTNAME || {
|
||||||
true
|
true
|
||||||
# failed
|
# failed
|
||||||
#_ssh bin/ssh-kill $USER@$HOSTNAME $port || true
|
#_ssh bin/ssh-kill $USER@$HOSTNAME $port || true
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ps axuw | grep -e [s]sh -e [p]ython3
|
|
||||||
|
|
||||||
4
utils/ssh-list
Executable file
4
utils/ssh-list
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ps axuw | grep -e [s]sh -e [b]ackdoor
|
||||||
|
|
||||||
Reference in New Issue
Block a user