rpc2socks is a client-server solution that allows to drop and remotely run a custom RPC + SOCKS-through-SMB server application on a Windows target, from a Unix or Windows host.
The client-server pair can be used as a regular SOCKS5 tunnel (see dedicated section below).
Client and server communicate exclusively through a dedicated named pipe over SMB, using a custom and extensible protocol.
The protocol, as well as the client and server sides can welcome additional so-called RPC commands.
rpc2socks-client is a Python3 package and an interactive script that use impacket to communicate with the server-side through SMB protocol (named pipe).
rpc2socks-server is implemented in C++ as a native, statically-linked, Windows console application (or a Service if enabled at compile-time), supporting both 32-bit and 64-bit architectures.
SOCKS-through-SMB tunnel is the main feature of rpc2socks.
Properties:
- SOCKS v5 only
- TCP only
- DNS resolution through SOCKS supported
- No authentication, however user-password auth can be easily added in rpc2socks-server if needed
It is implemented in such a way that it allows to bounce via a Windows host except that the SOCKS proxy here takes its client-side packets from the named pipe connection established between rpc2socks-client and rpc2socks-server. With the SOCKS clients communicating directly with rpc2socks-client.
Thus, rpc2socks-server does not listen on a TCP socket.
+---------+ | firefox | +-+--+--+-+ ^ ^ ^ | | | [SOCKS5 over TCP] v v v +-----+--+--+------+ | rpc2socks | | client CLI | | (unix / windows) | +--------+---------+ ^ | [ rpc2socks-proto ] | [through named pipe] | [ (SMB) ] v +-----+-----+ | rpc2socks | | server | | (windows) | +--+--+--+--+ ^ ^ ^ | | | [TCP] v v v +----+--+--+----+ | The Internets | +---------------+
Note that the rpc2socks-proto
transport depicted here consists of a single
logical link between rpc2socks-client and rpc2socks-server, regardless of
the number of established SOCKS connections and clients.
As a side note, the actual logic of the SOCKS proxy is implemented in rpc2socks-server. rpc2socks-client only acts as a bridge between the SOCKS client(s) and rpc2socks-server.
Client-side requires Python 3.6+ (Unix or Windows) and use impacket as its sole dependency.
Server-side native statically compiled executable requires at least Windows Vista or Windows Server 2008.
rpc2socks client part is located under the cli/
directory.
Although it can be run directly by using the bin/rpc2socks
script (both Unix
and Windows compatible) - which may work already depending on your environment
and as long as impacket dependency is installed - it is safier to have
rpc2socks client installed in its own Python virtual environment.
This is because it implements many workarounds to impacket's issues so impacket
version is frozen in setup.py
in order to avoid any trouble due to a
potential future patch changing lib's behavior.
Fetch rpc2socks from git-where:
$ git clone https://example.com/git/rpc2socks.git rpc2socks-git
Create and activate a virtualenv:
$ python3 -m venv rpc2socks-venv $ . ./rpc2socks-venv/bin/activate
(rpc2socks-venv) $
Install rpc2socks:
(rpc2socks-venv) $ python3 -m pip install -e rpc2socks-git/cli/
Check rpc2socks script is installed:
(rpc2socks-venv) $ rpc2socks --help
- Launch rpc2socks client CLI by giving it the required credentials to the remote Windows target:
(rpc2socks-venv) $ rpc2socks BLOCKCHAINDOMAIN/Carlos@10.1.2.3 Password for "Carlos": <TYPE YOUR PASSWORD> This is rpc2socks prompt. "?" for help. rpc2socks>>>
- Use the
inst
command to copy the server-side executable that is embedded in the client, to the target through SMB, then remote-execute it using WMI, then connect:
rpc2socks>>> inst 10:14:56.114 checking first if remote exe is not already installed and running 10:15:01.219 remote exe does not seem to be running 10:15:01.220 querying host's arch 10:15:01.234 extracting embedded 32-bit exe 10:15:01.269 dropping 32-bit exe to \\10.1.2.3\ADMIN$\winlfo32.exe 10:15:02.367 created remote process 3988 10:15:02.368 remote execution successful 10:15:04.869 trying to connect 10:15:04.869 creating bridge 10:15:04.872 waiting for connection to \\10.1.2.3[445]\pipe\winlfo32 10:15:05.211 connected to \\10.1.2.3[445]\pipe\winlfo32 10:15:05.211 bridge connected
- Note that in case WMI is not accessible, you may want to try the
inst svc
command instead for an SMB-only method. Executable will be copied though SMB, then installed then executed as a service via the Windows Service Manager (still through SMB). - At any time you can use the
st
command (status) to check if connection is still established:
rpc2socks>>> st PROTO: connected to \\10.1.2.3[445]\pipe\winlfo32 SOCKS: listening on 127.0.0.1:8889
While running and connected to the server-side, rpc2socks-client also listens
locally on a TCP port to serve as a SOCKS proxy. It listen on localhost:8889
by default (see --socksbind
command line option).
- Unless you need to reconnect later on (with the
co
command), use theuninst
command to stop remote executable and remove it from filesystem
rpc2socks>>> uninst 10:18:10.581 sending UNSINSTALL command 10:18:10.594 disconnected from \\10.1.2.3[445]\pipe\winlfo32 10:18:12.584 waiting for bridge to close 10:18:13.088 bridge closed 10:18:15.591 deleting remote exe
- Leave the prompt using the
q
command (quit)
rpc2socks>>> q (rpc2socks-venv) $
High speed download of a single and big data chunk (more than a few dozens of MiB) via the SOCKS tunnel may crash rpc2socks-server.
In some conditions - depending on the running environment on both ends, the connectivity and the size of the requested data chunk - to download data through the SOCKS tunnel of rpc2socks at a high speed rate may cause too much data to be buffered by rpc2socks server-side, due to the client-side not being able to follow up at that speed.
In a worst case scenario, this may lead to an unsubtle skyrocketing of the memory usage of the server-side until shameless crash.
For now, it is strongly advised to limit the download speed of your SOCKS client to 5MiB/s maximum - preferably even lower to stay on the safe side - in case you require a download of more than a few dozens of MiB at once.
Side note: ideally an automatic throttling mechanism should be implemented on the server-side. An extra development time that R&D department could not afford at that moment :)
More of a FYI for a significant issue that occurred during the development due to some impacket flaws than an actual issue at usage-level.
Because of the reasons described below in the impacket integration section,
and in order to deal with impacket's I/O limited capabilities,
rpc2socks-client connects to two instances of the same named pipe created
by rpc2socks-server. Where one instance is for read-only and the other one for
write-only operations, both in blocking mode on client side, with dedicated
Python threads and with no (reasonable) timeout so that even SMB transactions
that lead to a PENDING
state can be successful.
A handshake step takes place at connection-time to "configure" each channel and pair them under a single, well identified "logical connection". This is part of rpc2socks-proto logic and makes the code more complex on both ends.
rpc2socks-server is built with Visual Studio 2019.
Solution file is svc/rpc2socks.sln
.
No other version nor compiler tested. Compiler must be C++17 aware.
In case rpc2socks-server source code gets updated, its newly built executables
(32 and 64-bit; console and service) must be re-embedded in rpc2socks-client
source code using script tools/embedsrv.py
.
This feature is for end-user's convenience so that they do not need to build rpc2socks-server themselves.
Steps:
- Open
svc/rpc2socks.sln
solution file with Visual Studio 2019 - Batch build the 4 configurations of rpc2socks-server; that is
ConRelease
andSvcRelease
configurations for bothx86
andx64
architectures - Run
python3 tools/embedsrv.py
. That will updatecli/rpc2socks/embexe_data.py
. - Commit
This section exists so to keep a feedback of the integration of impacket since it has proven itself cumbersome to be integrated in an asynchronous I/O paradigm in a reliable way and in a project bigger than a single script.
rpc2socks I/O have been made more complex than it should be on both client and server sides, for the sole purpose of working around some significant issues found in impacket.
I/O: most if not all impacket's I/O is blocking, which forces the
integrator to create as many threads as required connections since impacket
does not give access to the lower layers (the sockets) from a high level class
like impacket.smbconnection.SMBConnection
for instance.
As a result in rpc2socks-client, two named pipe connections are created - thus two threads dedicated to low-level I/O - and virtually paired so that they can handle respectively read and write operations simultaneously.
SMB: regarding files I/O over SMB - that includes named pipes - impacket
does not deal correctly with SMB's PENDING
response to a READ
request by
not canceling the transaction then leaving the caller unnoticed about this
specific state in case of a timeout (see impacket.smb3.SMB3.recvSMB
).
Making any subsequent READ
request to fail and to end up with the Windows
host forcefully terminating the connection due to protocol violation.
It is worth noting that many impacket's SMB-related example scripts setup huge timeout delays for I/Os - e.g. 100'000 seconds - as a workaround to the issue described above, which is okay'ish for a single script run manually but hardly practicable in bigger projects as timeouts should be handled as being part of I/O interactions.
Side note: impacket's internal state can be spread out commando-style in a
Maniac Mansion - i.e. bloc-level vs. instance-level vs. class-level vs.
global-level - and its way of dealing with errors may vary across multiple
implementations of a same method. See the respective methods of SMB
and
SMB3
classes for instance.
rpc2socks is released under the terms of the BSD-3-Clause license with the following addendum:
If we meet some day, and you think this stuff is worth it, you can buy the author a beer in return.
See the LICENSE
file at the root directory of this project.
We are Lexfo 👋
Twitter: https://twitter.com/LexfoSecurite
GitHub: https://github.com/lexfo