calebstewart / pwncat

Fancy reverse and bind shell handler
https://pwncat.readthedocs.io
MIT License
2.63k stars 258 forks source link

Daemonizing #56

Closed pitust closed 4 years ago

pitust commented 4 years ago

Is your feature request related to a problem? Please describe. pwncat takes a long time to start. Most of this time is loading dependencies and creating a Victim. Describe the solution you'd like Implement a daemonize feature to allow for pwncat to run in the background and connect to it via a much dumber (and therefore faster) socket implementation (eg. the other pwncat or ncat, or a custom-made one especially for this purpose)

calebstewart commented 4 years ago

I'm not exactly clear what you mean. What happens at the beginning is that it starts a pty and grabs few bits of information to identify the remote system. If it's slow, it's because your connection to the remote machine is slow. TryHackMe is notorious for having ungodly slow machines (understandably since they're running thousands of them, presumably). pwncat is basically just grabbing the hostname, the mac address of network cards that are available, and the current shell. Then it identifies which method to use for spawning a pty. Normally, that's script or python, but it checks which one exists first. You need a pty for pwncat to work properly. The only part that isn't strictly necessary is the hostname and mac address part, but without that you have no way to uniquely identify that host. There's only one C2 channel so there's no way to "background" those actions. As with everything that happens in pwncat, it has to wait for them to complete to continue.

calebstewart commented 4 years ago

I might be able to speed it up by compiling multiple of those into one command (essentially an in-memory script) and feeding it to the remote shell, then reading the data back instead of running each individually, but there's not a way to background anything.

pitust commented 4 years ago

No, here is my idea: a new binary, pwncatd, already has all the scripts loaded and it created a victim. When a new request comes to a unix domain socket, it forks and runs as if it was normal pwncat. Main process keeps listening. This is much faster than doing everything when the user actually requests it (or at least, ot starts quicker)

pitust commented 4 years ago

it takes a long time to run Victim() locally. I checked. That is what i want to optimize. I propably wasn't clear about it.

calebstewart commented 4 years ago

I've done some digging, and a large factor was gtfobins.json. The file was (is) huge. We may be able to move to a better file format for this data at some point. Adding to this was the fact that when creating the file format and testing the gtfobins module, we wanted comments in the JSON to allow us to document what was going on. This lead us to the commentjson python module. This module is incredibly slow. I removed all the comments and minified the JSON file, but still was seeing about 2 seconds loading time with a return directly after Victim() in __main__.py (down from 2.7 to be fair).

With that in mind, I took a look at some different python JSON modules. The builtin module clocked in at about 0.98 seconds. orjson isn't compatible with the standard JSON interface so would require some more modification of the gtfobins module to make it work. I tried rapidjson and it clocked in at about 0.8 seconds.

I've settled on rapidjson. I've added it to the requirements.txt and setup.py scripts, and pushed an update. This shaves off about 1.7-2.0 seconds off the startup time (an about 60% speed up for starting up). Hopefully this will help. Any further optimization for the GTFObins data seems unnecessary. I commented out the entire loading process for gtfobins.json and saw little to no increase in performance (at best, on one run I saw 0.77 vice 0.80 seconds).

calebstewart commented 4 years ago

Also, for what it's worth, just starting pwncat and returning just before creating the Victim object now takes about 0.70 while returning just after creating the Victim object takes about 0.80 seconds. So, creating the Victim object now only takes on average about 0.1 seconds. Nothing really happens before that so the rest of the loading time is basically just python loading modules, which python is notoriously bad at.

calebstewart commented 4 years ago

While I don't think the proper solution is creating a pwncat daemon, I appreciate you bringing this up because it forced me to do some digging and find this bug. I understand python can be annoying with it's loading times, and I'll do everything I can to reduce it, but with a lot of imports python is just really slow at starting up.

calebstewart commented 4 years ago

I haven't heard back in more than 2 weeks. I'm going to close this issue. Feel free to reach out if you have any more issues or comments. Thanks!