├── .gitignore ├── LICENSE ├── README.md ├── issh ├── issh.termux.sh └── isshd.service /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, Tyler Nijmeh 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # issh 2 | Insecure shelling via netcat 3 | 4 | # Install 5 | For a typical Linux system, putting this script in the PATH variable should be enough. 6 | - `curl -L https://git.io/JBWnf > /usr/local/bin/issh && chmod +x /usr/local/bin/issh` 7 | 8 | # Features 9 | - Support embedded systems that lack OpenSSL/OpenSSH 10 | - Upwards of 10x faster (see benchmarks) 11 | - Android support 12 | - Relies almost exclusively on [toybox](http://landley.net/toybox/about.html) 13 | - Acts as both a server and client 14 | - Supports fully interactive clients 15 | - Supports filtering of external connections 16 | 17 | # Benchmarks against OpenSSH 18 | Since we do not rely on OpenSSL, we are able to get a reply from a server in significantly less time using issh. In this benchmark, we compare `sshpass -p ssh host@localhost ` against `./issh -c "sh"` and `./issh -C localhost`. 19 | 20 | - OpenSSH: ~150ms avg latency 21 | - issh: ~15ms avg latency 22 | 23 | # Examples 24 | You can use issh for a variety of tasks. Here's a few examples to get you started. 25 | 26 | ### Remote non-interactive shell 27 | - Server: `./issh -d` (`-d` forks our server to the background) 28 | - Client: `echo "whoami" | ./issh -C localhost` 29 | 30 | ### Remote interactive shell (no auth) 31 | Note that for interactive shells, we should do a few things: 32 | 1) Use a login shell, so we source our profile dotfile 33 | 2) Use an interactive shell to handle TTY commands 34 | 3) Redirect STDERR to STDOUT, so our client can see it 35 | - Server: `./issh -d -c "sh -li 2>&1"` 36 | - Client: `./issh -C localhost -t` (connects as an interactive tty) 37 | 38 | ### Remote interactive shell (su auth) 39 | - Server: `./issh -d -c "su -c 'sh -li' - username 2>&1"` 40 | - Client: `./issh -C localhost -t` (greeted with su asking for password; if success, dropped into `sh -li`) 41 | 42 | ### Remote interactive shell (custom auth) 43 | - Server: `./issh -d -c "./auth.sh"` 44 | - Server: Create an authentication script that should be presented to the client on connect. Here's an example. Ideally, your password would not be stored in plaintext in the script. Other authentication ideas could be to use SSL or GPG keys. **Authentication is not provided by issh.** 45 | ```sh 46 | #!/usr/bin/env bash 47 | echo -n "Enter secret key: " 48 | read -r key 49 | [[ "$key" == "password123" ]] && bash -li 2>&1 50 | ``` 51 | - Client: `./issh -C localhost -t` (connects as an interactive tty) 52 | - Client: `Enter secret key: password123` 53 | 54 | ### Public system API 55 | - Server: `./issh -d -c "cat /proc/loadavg"` 56 | - Client: `SERVER_LOADAVG="$(./issh -C localhost)"` 57 | 58 | # Systemd 59 | You can start issh on bootup using systemd. The default configuration creates an interactive bash session. 60 | 1) `cp systemd/isshd.service /etc/systemd/system/` 61 | 2) `chmod +x /etc/systemd/system/isshd.service` 62 | 3) `systemctl enable --now isshd` 63 | 64 | # Android 65 | Since issh is built on top of toybox instead of typical GNU tools, we can support a wider variety of devices, including Android. 66 | 67 | ### Opening a privileged ADB shell session 68 | A useful concept is allowing a regular user to gain ADB-level access without needing to be constantly connected to a computer, nor needing wireless debugging or an ADB binary of any kind. 69 | 70 | 1) Using a computer, start an `adb shell` 71 | 2) Pull the `issh` script somewhere local (i.e., /sdcard/Download/) 72 | 3) `sh issh -d -c "sh -li 2>&1"` 73 | 74 | Now, on a client (which can be the device itself via a standard terminal emulator), we can connect to this session locally. 75 | 1) `sh issh -C localhost -t` 76 | 2) `pm grant com.example.app android.permission.PRIVILEDGED_PERMISSION_EXAMPLE` 77 | 78 | In this case, our client does not need to use a computer to gain ADB-level access since we have an open issh session. 79 | 80 | ### Benefits 81 | 1) Avoiding ADB protocol entirely 82 | 2) Avoiding cross-compiling ADB binary 83 | 3) Avoiding external programs that rely on binary executables 84 | 4) Compatibility with Android 6+ (instead of Android 10+) 85 | 5) Wireless debugging is no longer necessary 86 | 87 | ### Termux 88 | You can launch an issh session in Termux as well. However, Termux lacks toybox, so we must add it to our PATH variable from the Android system. Use the built-in Termux issh wrapper to automate the process: 89 | 1) `./issh.termux.sh` 90 | -------------------------------------------------------------------------------- /issh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Constants 4 | MODE_SERVER="server" 5 | MODE_CLIENT="client" 6 | 7 | # Global options 8 | MODE="$MODE_SERVER" 9 | PORT=65432 10 | 11 | # Server options 12 | COMMAND="sh 2>&1" 13 | DAEMON=false 14 | LOCAL=false 15 | 16 | # Client options 17 | INTERACTIVE=false 18 | ADDRESS="localhost" 19 | 20 | # Display usage for this script 21 | usage() { 22 | echo "Insecure shelling via netcat 23 | 24 | Usage: $0 [-h] [-p PORT] [-c COMMAND] [-d] [-l] [-C ADDRESS] [-L] [-t] 25 | -h Show this screen 26 | -p PORT Port to listen/connect on (default: $PORT) 27 | 28 | Server options: 29 | -c COMMAND Command to run when client connects (default: $COMMAND) 30 | -d Fork to background; run as daemon 31 | -l Only allow localhost connections 32 | 33 | Client options: 34 | -C ADDRESS Connect to an open session (default: $ADDRESS) 35 | -L Connect to an open localhost session 36 | -t Use raw TTY for interactivity" 37 | } 38 | 39 | # Make sure we have everything we need to run 40 | assert_dependencies() { 41 | if ! command -v toybox &>/dev/null 42 | then 43 | echo "Toybox binary inaccessible" 44 | exit 1 45 | fi 46 | } 47 | 48 | # Check if port is out of range 49 | is_port_within_range() { 50 | [[ "$1" -gt 1 && "$1" -lt 65535 ]] 51 | } 52 | 53 | # Bail if port is out of range 54 | assert_port_within_range() { 55 | if ! is_port_within_range "$1" 56 | then 57 | echo "Port is out of range (1-65535): $1" 58 | exit 1 59 | fi 60 | } 61 | 62 | # Check if port is in use currently 63 | is_port_available() { 64 | ! toybox netstat -lpn 2>/dev/null | toybox grep -w ".*:$1" &>/dev/null 65 | } 66 | 67 | # Bail if port is taken 68 | assert_port_available() { 69 | if ! is_port_available "$1" 70 | then 71 | echo "Port is in use: $1" 72 | exit 1 73 | fi 74 | } 75 | 76 | # Parse arguments passed to us and set relevant variables 77 | parse_options() { 78 | while getopts ":hp:c:dlC:Lt" opt 79 | do 80 | case "$opt" in 81 | h) 82 | usage 83 | exit 0 84 | ;; 85 | p) 86 | PORT="$OPTARG" 87 | assert_port_within_range "$PORT" 88 | ;; 89 | c) 90 | COMMAND="$OPTARG" 91 | ;; 92 | d) 93 | DAEMON=true 94 | ;; 95 | l) 96 | LOCAL=true 97 | ;; 98 | C) 99 | MODE="$MODE_CLIENT" 100 | ADDRESS="$OPTARG" 101 | ;; 102 | L) 103 | MODE="$MODE_CLIENT" 104 | ADDRESS="localhost" 105 | ;; 106 | t) 107 | INTERACTIVE=true 108 | ;; 109 | *) 110 | usage 111 | exit 1 112 | ;; 113 | esac 114 | done 115 | } 116 | 117 | # Host a server 118 | server() { 119 | assert_port_available "$PORT" 120 | 121 | # Handle arguments that should be given to netcat 122 | nc_args=( 123 | "-L" 124 | "-p" "$PORT" 125 | ) 126 | [[ "$LOCAL" == true ]] && nc_args+=("-s" "localhost") 127 | 128 | if [[ "$DAEMON" == true ]] 129 | then 130 | toybox setsid toybox nc "${nc_args[@]}" sh -c "$COMMAND" & 131 | else 132 | toybox nc "${nc_args[@]}" sh -c "$COMMAND" 133 | fi 134 | } 135 | 136 | # Connect to a server 137 | client() { 138 | [[ "$INTERACTIVE" == true ]] && stty raw -echo icrnl opost 139 | toybox nc "$ADDRESS" "$PORT" 140 | [[ "$INTERACTIVE" == true ]] && stty sane 141 | } 142 | 143 | parse_options "$@" 144 | assert_dependencies 145 | 146 | if [[ "$MODE" == "$MODE_SERVER" ]] 147 | then 148 | server 149 | elif [[ "$MODE" == "$MODE_CLIENT" ]] 150 | then 151 | client 152 | fi 153 | -------------------------------------------------------------------------------- /issh.termux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Android standard ToyBox binary 4 | toybox() { 5 | /system/bin/toybox "$@" 6 | } 7 | export -f toybox 8 | 9 | # Execute script with Android raw shell script 10 | exec ./issh "$@" 11 | -------------------------------------------------------------------------------- /isshd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Persistent issh root login daemon 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=issh -c "bash -li 2>&1" 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | --------------------------------------------------------------------------------