Upgrading your bad Shell to amazing Shell

In most reverse shell call backs that you get from your victim computers, they are not a very convenient and stable connections, and do not have the advantages and functionalities that you would get from a ssh shell connection, like the auto-fill, tab, etc.

This Blog post is going to be showing you the steps to upgrade your "Bad Shell" into a "Good Shell", which you can mostly use in any Linux shell which has python3 installed in it.

Upgrading Shell.png > Center

Upgrading the Shell

The examples shows in this blog is part of one of the CTF challenge

  1. Once you have got a shell on your victim computer, check to see if you have python install (mostly all Linux machines will have Python installed in them). If python is installed, then run the following command:
python3 -c 'import pty; pty.spawn("/bin/bash")'
  1. Once you have executed this command you will get a bash shell to interact with. Then press Ctrl + Z (To suspend the current netcat/ reverse shell session).

  2. On the same terminal (you would have your normal terminal now), enter the following command:

stty raw -echo && fg

There you go, a better shell to interact!!!

Pasted image 20260430151627.png#center


How does that work

The following explanations from here are written by an AI (ChatGPT), hence let me know if there are any issues with it.

When you first catch a reverse shell (for example, through nc), what you typically get is a very minimal, non-interactive shell. It’s not a “real” terminal — it’s just a raw stream of input and output over a socket.

That’s why things feel broken:

  • No tab completion
  • No command history
  • Arrow keys don’t work
  • Programs like vim, top, or nano behave strangely or fail
  • Signals like Ctrl + C may kill the whole connection

To understand the upgrade process, you need to know about pseudo-terminals (PTYs).

Step 1: Spawning a PTY with Python

python3 -c 'import pty; pty.spawn("/bin/bash")'

This works because Python’s built-in pty module creates a pseudo-terminal device, which mimics a real terminal.

What this actually does:

  • Allocates a PTY on the target machine
  • Launches /bin/bash attached to that PTY
  • Bridges your raw socket to this new terminal

Why it matters:

Programs like bash behave differently depending on whether they are connected to:

  • a real terminal (TTY/PTY) → full interactive features
  • a pipe/socket → limited, “dumb” mode

Before this step, your shell is just a pipe. After this step, it becomes something much closer to a real terminal session.

Step 2: Suspending the Shell (Ctrl + Z)

When you press:

Ctrl + Z

you are sending a SIGTSTP (terminal stop signal) to the current foreground process.

What happens:

  • Your reverse shell process is suspended locally
  • You return to your own terminal prompt

This is important because now you can reconfigure your local terminal to properly handle the upgraded shell.

Step 3: Fixing Terminal Behaviour with stty

stty raw -echo && fg

This is the step that makes everything feel normal again.

Breaking it down:

stty raw

  • Switches your local terminal into raw mode
  • Input is sent character-by-character, not line-by-line
  • Disables special processing (like Ctrl+C being handled locally)

-echo

  • Prevents your terminal from echoing typed characters
  • Without this, you’d see duplicated input

fg

  • Brings the suspended reverse shell back to the foreground

Why This Fixes the Shell

At this point, you’ve aligned three critical pieces:

  1. Remote side → Now running inside a PTY (via Python)
  2. Local side → Configured to pass input/output transparently (stty raw -echo)
  3. Connection → Still the same socket, but now behaving like a real terminal

This combination allows:

  • Proper signal handling (Ctrl+C, Ctrl+Z)
  • Interactive programs to work correctly
  • Line editing and job control
  • A much more stable and usable shell

The Big Picture

A basic reverse shell is just:
stdin/stdout over a network socket

A fully interactive shell requires:
a terminal interface (TTY/PTY) + proper input/output handling

This technique works by:

  • Adding a PTY on the remote system
  • Configuring your local terminal to match it

Bonus: Why Python?

Python is commonly used here because:

  • It’s installed on most Linux systems by default
  • It provides easy access to PTY functionality (pty.spawn)
  • The one-liner is short and reliable

Other methods (using script, perl, or socat) achieve the same goal, but Python is often the quickest option.

Bonus Info: What is PTY

A PTY (pseudo-terminal) is basically a software-emulated terminal that behaves like a real one.

The idea behind a terminal

Originally, a terminal was a physical device (keyboard + screen) connected to a computer. Programs like bash were designed to talk to that kind of device:

  • They expect interactive input (keystrokes)
  • They handle signals like Ctrl+C
  • They control cursor movement, screen updates, etc.

Modern systems (like Linux) still follow this model — even though the “terminal” is now usually just a window.

What a PTY actually is

A PTY (pseudo-terminal) is a pair of virtual devices created by the OS:

  • Master side → controlled by a program (like your reverse shell or SSH client)
  • Slave side → looks like a real terminal to programs like bash

Think of it like a translator layer:

  • One side talks “program”
  • The other side talks “terminal”

Why PTYs matter

Programs behave differently depending on whether they are connected to a terminal or not.

Without a PTY (your initial reverse shell):

  • Bash thinks it's talking to a pipe/socket
  • No interactive features
  • No proper signal handling
  • Tools like vim break

With a PTY:

  • Bash thinks it's talking to a real terminal
  • Enables:
    • Command history
    • Tab completion
    • Job control (Ctrl+Z, fg)
    • Interactive apps (top, nano, etc.)

Simple analogy

  • Without PTY → like talking over a walkie-talkie (basic input/output)
  • With PTY → like a full phone call with proper interaction

How it fits your reverse shell trick

When you run:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Python:

  1. Creates a PTY
  2. Launches /bin/bash attached to it
  3. Connects that PTY to your network shell

So now:

  • Bash is happy (it sees a terminal)
  • You get a much more “real” shell experience

One-line definition

A PTY (pseudo-terminal) is a virtual terminal interface that allows programs to behave as if they are connected to a real interactive terminal, even when communicating over a network or through another program.