Tricking shells into interactive mode when local PTY's are not available

Overview

Remote Pseudoterminals

Remote Pseudoterminals or "RPTY" is a Rust library which intercepts calls to the Linux kernel's TTY/PTY-related libc functions and executes them on a remote host. Thereby emulating the presence of a local tty kernel object that is operating outside of the local kernel.

It also includes a patched bash shell which is statically linked against the RPTY library and busybox builtins.

⚠️ Warning: Please do not put this library anywhere near production. It is full of unsafe, unethical, cursed code that occasionally works for inexplicable reasons.

Why?

Why does this library exist?

For very bad reasons. I built Tunshell with the goal of easily gaining shell access to ephemeral environments such as AWS Lambda. Similarly to SSH, Tunshell spawns a shell on the remote host and streams it to your local terminal. However, the AWS Lambda environment is very locked down and disables kernel support for creating PTY's thereby making most shells non-interactive.

RPTY goes to extreme lengths (such as intercepting libc functions, overriding stdin/out/err) in order to workaround this restriction and provide a nicer shell experience.

I realised half-way through this project that the "right" way to solve this problem would be by building a client-server shell (not SSH, which is not a shell). A shell where all the interactive elements run on the client and the remote server accepts commands over a socket. However I could not find such a shell. I'll leave this as an exercise to the reader.

How does it work?

For an overview of the TTY/PTY Linus Åkesson has written a superb article that helped me get my head around it.

The best way to understand how RPTY works is to compare it with more familiar constructs.

Local

Take the simple case where you have a local terminal emulator and shell:

Local shell diagram

We can see the PTY is essentially a bidirectional pipe/socket between the terminal and the shell. It performs buffering and processing to provide line-editing and other features. The behavior can be modified by updating the settings (termios).

SSH

In the case of SSH we have a PTY instance on both the client and server:

SSH remote shell diagram

The local ssh client puts the local PTY into "raw mode" disabling all buffering and processing becoming a pass-through.

SSHD creates a PTY instance on the remote host. The PTY on the remote provides the line-editing and interactive features. SSHD spawns a shell and connects its stdin/stdout/stderr to the slave side of the PTY.

RPTY

RPTY removes the requirement of having a PTY instance on the remote host:

RPTY remote shell diagram

The local client (RPTY master) leaves the local PTY settings in-tact. The remote process (RPTY slave) forwards all TTY-related libc function calls from the remote shell to the local client. From the perspective of the remote shell, the function calls are synchronous and blocking which mimics the behavior of native calls into libc.

Modes of operation

In order for RPTY to work it has to be able to be able to intercept calls made to libc functions. There are two supported approaches:

Static-linking

RPTY can be built as a static-archive linked against musl. This archive then needs to be statically linked against the shell at build time. This approach removes runtime dependencies as it is compiled into the shell binary. However, it does not work with exec'd processes making the shell much less useful. This is somewhat mitigated by the bash build script in this repo which statically links to busybox.

Dynamic linking

RPTY can also be built against GNU libc as a shared library. Then it can be injected into any shell at runtime via LD_PRELOAD. This approach should work with any exec'd processes which inherit the LD_PRELOAD environment variable.

Supported targets

Master Slave
x86_64-unknown-linux-musl x86_64-unknown-linux-musl
x86_64-unknown-linux-gnu x86_64-unknown-linux-gnu
x86_64-apple-darwin

See latest actions to find the latest build of the libraries.

You might also like...
A super simple prompt for Fish shell, just shows git info and Vi mode.
A super simple prompt for Fish shell, just shows git info and Vi mode.

vifi is a portmandeau of 'Vi' and 'Fish', because it's a prompt for Fish shell, primarily focused around showing proper indicators when using Vi key bindings.

easy-to-use immediate mode client side Rust web framework
easy-to-use immediate mode client side Rust web framework

An immediate mode web frontend library written in Rust. It builds up VDOM for not having to run too many DOM operations, but as it runs every time any

Example of an dark-mode toggle button based on progressive enhancement

Leptos Starter Template This is a template for use with the Leptos web framework and the cargo-leptos tool. Creating your template repo If you don't h

Super-lightweight Immediate-mode Embedded GUI framework, based on the awesome embedded-graphics library. Written in Rust.

Kolibri - A GUI framework made to be as lightweight as its namesake What is Kolibri? Kolibri is an embedded Immediate Mode GUI mini-framework very str

Configurable, extensible, interactive line reader

linefeed linefeed is a configurable, concurrent, extensible, interactive input reader for Unix terminals and Windows console. API Documentation linefe

An interactive cheatsheet tool for the command-line
An interactive cheatsheet tool for the command-line

navi An interactive cheatsheet tool for the command-line. navi allows you to browse through cheatsheets (that you may write yourself or download from

Simple Interactive Terminal Todo App in Rust
Simple Interactive Terminal Todo App in Rust

todo-rs Simple Interactive Terminal Todo App in Rust Quick Start $ cargo run TODO Controls Keys Description k, j Move cursor up and down Shift+K, Shif

Coinlive is an interactive command line tool that displays live cryptocurrency prices.
Coinlive is an interactive command line tool that displays live cryptocurrency prices.

Coinlive is an interactive command line tool that displays live cryptocurrency prices. It can also display simple historical price charts.

A Rust library for building interactive prompts
A Rust library for building interactive prompts

inquire is a library for building interactive prompts on terminals. Demo Source Usage Put this line in your Cargo.toml, under [dependencies]. inquire

Comments
  • About usage

    About usage

    Hi,TimeToogo

    I can now run bash-linux-x86_64 and remote-pty-master tcp:0.0.0.0:1234,but how can I run the slave on remote machine? There seems no slave binary, only library.

    Thanks.

    opened by tkkcc 1
Owner
null
Set Shell Environment Variables across multiple shells with a single configuration file.

Xshe – Cross-Shell Environment Vars xshe allows for setting Shell Environment Variables across multiple shells with a single TOML configuration file.

Ethan Kinnear 9 Dec 16, 2022
A `nix` and `nix-shell` wrapper for shells other than `bash`

nix-your-shell A nix and nix-shell wrapper for shells other than bash. nix develop and nix-shell use bash as the default shell, so nix-your-shell prin

Mercury 15 Apr 10, 2023
Demo Repo for BSides 2024 Live Training: "Blue Crab Shells: Getting Started with Offensive Rust Programming"

Blue Crab Shells: Getting Started with Offensive Rust Programming This repository contains example code for the live training provided for BSides San

The Taggart Institute 6 Apr 9, 2024
A command-line tool aiming to upload the local image used in your markdown file to the GitHub repo and replace the local file path with the returned URL.

Pup A command line tool aiming to upload the local image used in your markdown file to the GitHub repo and replace the local file path with the return

SteveLau 11 Aug 17, 2022
httm prints the size, date and corresponding locations of available unique versions of files residing on ZFS snapshots

httm prints the size, date and corresponding locations of available unique versions of files residing on ZFS snapshots, as well as allowing their interactive viewing and restoration.

null 837 Dec 30, 2022
Extract core logic from qdrant and make it available as a library.

Qdrant lib Why? Qdrant is a vector search engine known for its speed, scalability, and user-friendliness. While it excels in its domain, it currently

Tyr Chen 27 Jan 1, 2024
A lightweight and high-performance order-book designed to process level 2 and trades data. Available in Rust and Python

ninjabook A lightweight and high-performance order-book implemented in Rust, designed to process level 2 and trades data. Available in Python and Rust

Ninja Quant 134 Jul 22, 2024
A lightweight but incredibly powerful and feature-rich BitTorrent tracker. Supports UDP + HTTP(S) and a private tracker mode.

Torrust Tracker Project Description Torrust Tracker is a lightweight but incredibly powerful and feature-rich BitTorrent tracker made using Rust. Feat

Torrust 162 Dec 31, 2022
A simple cli tool to help with wordle in hard mode

Wordking A simple cli tool to help with wordle in hard mode. Usage Run wordking cargo run Wordking will ask for your guesses thus far. Provide your gu

Stephen Spalding 2 Feb 1, 2022
An Intel HAXM powered, protected mode, 32 bit, hypervisor addition calculator, written in Rust.

HyperCalc An Intel HAXM powered, protected mode, 32 bit, hypervisor addition calculator, written in Rust. Purpose None ?? . Mostly just to learn Rust

Michael B. 2 Mar 29, 2022