<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" 
  xmlns:content="http://purl.org/rss/1.0/modules/content/" 
  xmlns:dc="http://purl.org/dc/elements/1.1/" 
  xmlns:atom="http://www.w3.org/2005/Atom" 
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" 
  xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Radio on Mal Breaks Things</title>
    <link>https://sec.gd/blog/en/tags/radio/</link>
    <description>Recent content in Radio on Mal Breaks Things</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <managingEditor>mal@sec.gd (mal)</managingEditor>
    <webMaster>mal@sec.gd (mal)</webMaster>
    <copyright>&amp;copy;{year}. [License and Info](/blog/about/)</copyright>
    <lastBuildDate>Sun, 28 Jan 2024 23:00:00 +0000</lastBuildDate>
    <sy:updatePeriod>daily</sy:updatePeriod>
    
        <atom:link href="https://sec.gd/blog/en/tags/radio/index.xml" rel="self" type="application/rss+xml" />
    
    
    
      <item>
        <title>Long Distance 2</title>
        <link>https://sec.gd/blog/en/posts/long-distance-2/</link>
        <pubDate>Sun, 28 Jan 2024 23:00:00 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Sun, 28 Jan 2024 23:00:00 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/long-distance-2/</guid>
        <description>&lt;p&gt;This weekend I participated in the &lt;a href=&#34;https://ctftime.org/event/2172/&#34;&gt;Real World CTF&lt;/a&gt; with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;WreckTheLine&lt;/a&gt;. Unlike many other CTFs, these challenges were all based on real applications and systems. It&amp;rsquo;s interesting being able to use (and gain) domain knowledge, and while contrived challenges are fun, exploiting a system that exists in the real world – on the real internet – is another level of engagement.&lt;/p&gt;</description>
        <content:encoded>&lt;![CDATA[&lt;p&gt;This weekend I participated in the &lt;a href=&#34;https://ctftime.org/event/2172/&#34;&gt;Real World CTF&lt;/a&gt; with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;WreckTheLine&lt;/a&gt;. Unlike many other CTFs, these challenges were all based on real applications and systems. It&amp;rsquo;s interesting being able to use (and gain) domain knowledge, and while contrived challenges are fun, exploiting a system that exists in the real world – on the real internet – is another level of engagement.&lt;/p&gt;
&lt;h2 id=&#34;challenge&#34;&gt;Challenge&lt;/h2&gt;
&lt;p&gt;This &lt;code&gt;misc&lt;/code&gt; &lt;a href=&#34;https://github.com/chaitin/Real-World-CTF-6th-Challenges/tree/main/Long%20Range%202&#34;&gt;challenge&lt;/a&gt; consisted of a 290 MB WAV file named &lt;code&gt;486_375MHz-1MSps-1MHz.wav&lt;/code&gt;, an 8 MB &lt;code&gt;flash_dump&lt;/code&gt;, and a mandate to recover the information contained in the transmission:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Of late, whispers doth persist behind mine back. Yesterday, under the studio tower, a peculiar contraption was found by me. I am most intrigued to discover the content of their discourse.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;rf&#34;&gt;RF&lt;/h2&gt;
&lt;p&gt;The WAV file metadata showed 51 seconds, 2 channels, 24 bit resolution, and 1 MHz sample rate. Audibly, it was a mostly silent with several bursts of data, sounding like a pop followed by buzzing.&lt;/p&gt;
&lt;p&gt;Audacity was in the mood for 3 hours of plugin updates, so I used &lt;a href=&#34;https://www.sonicvisualiser.org/&#34;&gt;Sonic Visualiser&lt;/a&gt;, which showed the bursts of data in the waveform.
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/1-waveform.png&#34; alt=&#34;Waveform showing two channels of silence followed by a short loud burst and a longer textured section, repeated twice&#34;&gt;
Zooming in, things became more interesting - FM?
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/2-waveform-zoom.png&#34; alt=&#34;Waveform zoomed in to show the individual squiggles getting closer together and farther apart over time in both channels&#34;&gt;
We can use the spectrogram tool to see the distribution of energy (color) across frequencies (Y axis) over time (X axis), with an interesting result&amp;hellip;
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/3-waterfall.jpg&#34; alt=&#34;Waveform for context, and spectrogram showing that the high energy pulse is zigzagging up and down in frequency during the data transmission&#34;&gt;
And further into the data section, discontinuities in the frequency sweeps - Probably the symbols that we needed recover data from.
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/4-waterfall-detail.png&#34; alt=&#34;Another part of the data transmission, where the spectrogram zigzag repeatedly jumps to a different part of the zig or zag&#34;&gt;&lt;/p&gt;
&lt;p&gt;A teammate, qwertboy, had linked a &lt;a href=&#34;https://org.anize.rs/rwctf-2023/misc/long-range&#34;&gt;writeup&lt;/a&gt; of last year&amp;rsquo;s Long Distance challenge by the &lt;code&gt;organizers&lt;/code&gt; team, where they had a similar file containing a RF capture, and found the flag by decoding the LoRaWAN traffic.&lt;/p&gt;
&lt;p&gt;What I was seeing matched signals they found. Both had similar patterns in the waveform and demodulated FM, and after setting up GNU Radio, in the constellation display.&lt;/p&gt;
&lt;h2 id=&#34;flash-image&#34;&gt;Flash Image&lt;/h2&gt;
&lt;p&gt;My first port of call with an unknown firmware image is usually &lt;code&gt;binwalk&lt;/code&gt;. In this case the signatures and strings it found led me to believe that this was an image for an ESP32, used mesh networking, and (incorrectly) that it might be for an IoT lightbulb or lighting controller.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ binwalk flash_dump

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
88595         0x15A13         Neighborly text, &amp;#34;neighbors a simple (0 id) broadcast&amp;#34;
109607        0x1AC27         HTML document header
109988        0x1ADA4         HTML document footer
113954        0x1BD22         Neighborly text, &amp;#34;Neighbor Info module config: Ambient Lighting&amp;#34;
114583        0x1BF97         Neighborly text, &amp;#34;Neighbor Info module config: Ambient Lighting&amp;#34;
118036        0x1CD14         Neighborly text, &amp;#34;NeighborsKET from Node 0x%x to Node 0x%x (last sent by 0x%x)&amp;#34;

[...]
155668        0x26014         Unix path: /home/runner/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src/SPI.cpp
173532        0x2A5DC         AES S-Box
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Extracting the identified files with &lt;code&gt;binwalk -e&lt;/code&gt; found assorted HTML and CSS, along with a JSON blob from 0x3A7000:&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-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Meshtastic&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;short_name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Meshtastic&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;start_url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Meshtastic web app&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;icons&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/icon.svg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;sizes&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;any&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image/svg+xml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;theme_color&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#67ea94&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;background_color&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#67ea94&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;display&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;standalone&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So I knew early that we&amp;rsquo;re working with &lt;a href=&#34;https://meshtastic.org/&#34;&gt;Meshtastic&lt;/a&gt;, but didn&amp;rsquo;t yet understand LoRa vs LoRaWAN. Reading through the site found &lt;a href=&#34;https://meshtastic.org/docs/overview/radio-settings&#34;&gt;radio settings&lt;/a&gt; to help with decoding, the Meshtastic &lt;a href=&#34;https://meshtastic.org/docs/overview/mesh-algo&#34;&gt;packet header format&lt;/a&gt; to help with parsing, and an &lt;a href=&#34;https://meshtastic.org/docs/overview/encryption&#34;&gt;overview of the encryption&lt;/a&gt;. I later found a &lt;a href=&#34;https://meshtastic.discourse.group/t/meshtastic-lora-packet-size/7953/9&#34;&gt;diagram&lt;/a&gt; of a LoRa Meshtastic packet which was useful, but note the backwards flags field.&lt;/p&gt;
&lt;h2 id=&#34;lora&#34;&gt;LoRa&lt;/h2&gt;
&lt;p&gt;I spent quite a while trying to get &lt;a href=&#34;https://github.com/rpp0/gr-lora&#34;&gt;rpp0/gr-lora&lt;/a&gt; set up (it officially requires the long-dead python2) and working, and a while more seeing if &lt;a href=&#34;https://github.com/tapparelj/gr-lora_sdr&#34;&gt;tapparelj/gr-lora_sdr&lt;/a&gt; or its fork &lt;a href=&#34;https://github.com/martynvdijke/gr-lora_sdr&#34;&gt;martynvdijke/gr-lora_sdr&lt;/a&gt; (as used by the AUR package) were any more cooperative. In the end, I replaced the python2-foo dependencies with python3-foo, and it didn&amp;rsquo;t complain. Still, the correct configuration for the decoder eluded me.&lt;/p&gt;
&lt;p&gt;Saturday morning started with another teammate, tcode2k16, finding a potential signal decoding result before I&amp;rsquo;d finished breakfast. We individually chased our tails for a while on this, and it turned out to have two issues - The decoded data was incorrect, and we were confusing LoRa (physical layer) with LoRaWAN (a communication protocol built on LoRa) and trying to parse the payload as the latter.&lt;/p&gt;
&lt;h2 id=&#34;we-need-to-go-deeper&#34;&gt;We Need to Go Deeper&lt;/h2&gt;
&lt;p&gt;Once tcode was making progress on decoding and parsing, I went back to the firmware image. The source for this build, less any CTF modifications, is at &lt;a href=&#34;https://github.com/meshtastic/firmware/tree/v2.2.14.57542ce&#34;&gt;meshtastic/firmware@v2.2.14.57542ce&lt;/a&gt;, and tcode found a &lt;a href=&#34;https://github.com/meshtastic/firmware/blob/v2.2.14.57542ce/src/mesh/Channels.cpp#L10&#34;&gt;default AES key&lt;/a&gt; there, but we should check for a custom one in flash.&lt;/p&gt;
&lt;p&gt;To start, I dropped the image into a hex editor, which wasn&amp;rsquo;t particularly useful until I looked into how ESP-IDF partitioning works. The default partition table isn&amp;rsquo;t at the beginning of flash, but at 0x8000.&lt;/p&gt;
&lt;p&gt;Rather than spend time parsing the partition table correctly, I guessed the layout based on the hex dump:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00008000  aa 50 01 02 00 90 00 00  00 50 00 00 6e 76 73 00  |.P.......P..nvs.|
00008010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00008020  aa 50 01 00 00 e0 00 00  00 20 00 00 6f 74 61 64  |.P....... ..otad|
00008030  61 74 61 00 00 00 00 00  00 00 00 00 00 00 00 00  |ata.............|
00008040  aa 50 00 10 00 00 01 00  00 00 25 00 61 70 70 00  |.P........%.app.|
00008050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00008060  aa 50 00 11 00 00 26 00  00 00 0a 00 66 6c 61 73  |.P....&amp;amp;.....flas|
00008070  68 41 70 70 00 00 00 00  00 00 00 00 00 00 00 00  |hApp............|
00008080  aa 50 01 82 00 00 30 00  00 00 10 00 73 70 69 66  |.P....0.....spif|
00008090  66 73 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |fs..............|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Much later I realized the partition table, human-readable with extra info, is also available right in the firmware repository as &lt;a href=&#34;https://github.com/meshtastic/firmware/blob/v2.2.14.57542ce/partition-table.csv&#34;&gt;partition-table.csv&lt;/a&gt;. Here&amp;rsquo;s that version, to save at least one of us some squinting at hex:&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-csv&#34; data-lang=&#34;csv&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;# Name&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;   Type&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; SubType&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; Offset&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;  Size&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; Flags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;nvs&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;      data&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; nvs&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;     0x009000&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; 0x005000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;otadata&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;  data&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; ota&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;     0x00e000&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; 0x002000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;app&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;      app&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;  ota_0&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;   0x010000&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; 0x250000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;flashApp&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; app&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;  ota_1&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;   0x260000&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; 0x0A0000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spiffs&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;   data&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; spiffs&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;  0x300000&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt; 0x100000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;NVS&amp;rdquo; is used by the ESP-IDF &lt;a href=&#34;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html&#34;&gt;Non-Volatile Storage Library&lt;/a&gt;, which seemed like a good place to store settings. Carve out 0x5000 bytes starting at 0x9000 in the image with &lt;code&gt;dd if=flash_dump bs=$((0x1000)) skip=9 count=5 of=nvs.bin&lt;/code&gt;, and parse it with &lt;code&gt;nvs_tool.py&lt;/code&gt; from the &lt;a href=&#34;https://github.com/espressif/esp-idf/tree/b3f7e2c8a4d354df8ef8558ea7caddc07283a57b/components/nvs_flash/nvs_partition_tool&#34;&gt;ESP-IDF repository&lt;/a&gt;: &lt;code&gt;python nvs_tool.py -i nvs.bin&lt;/code&gt;. Unfortunately none of the data it held looked like a 128-bit or 256-bit AES key, or for that matter, any of the other configuration parameters I was expecting.&lt;/p&gt;
&lt;p&gt;Where else would the firmware store its configuration? Looking back at the partition table, &amp;ldquo;nvs&amp;rdquo; was a bust, &amp;ldquo;otadata&amp;rdquo; seems update-related, &amp;ldquo;app&amp;rdquo; is probably the running code, &amp;ldquo;flashApp&amp;rdquo; may be for in-progress updates, or &amp;ldquo;spiffs&amp;rdquo;. The &amp;ldquo;SPI Flash FileSystem&amp;rdquo; sounded promising, so I extricated it with &lt;code&gt;dd if=flash_dump bs=$((0x100000)) skip=3 count=1 of=spiffs.bin&lt;/code&gt;, but &lt;a href=&#34;https://github.com/igrr/mkspiffs&#34;&gt;igrr/mkspiffs&lt;/a&gt; didn&amp;rsquo;t like it. &lt;code&gt;file&lt;/code&gt; wasn&amp;rsquo;t familiar. &lt;code&gt;hexdump&lt;/code&gt; showed this at the beginning of the file:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;00000000  03 00 00 00 f0 0f ff f7  6c 69 74 74 6c 65 66 73  |........littlefs|
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ah. littlefs on a partition named spiffs.  Probably some backwards-compatibility thing&amp;hellip;&lt;/p&gt;
&lt;p&gt;Regardless, the &lt;a href=&#34;https://github.com/littlefs-project/littlefs&#34;&gt;littlefs readme&lt;/a&gt; had a lot of useful tools. &lt;a href=&#34;https://github.com/tniessen/littlefs-disk-img-viewer&#34;&gt;tniessen/littlefs-disk-img-viewer&lt;/a&gt; is a webapp with a &lt;a href=&#34;https://tniessen.github.io/littlefs-disk-img-viewer/&#34;&gt;live demo&lt;/a&gt;, which after some block size guessing (4096) was able to read the filesystem.
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/5-littlefs.png&#34; alt=&#34;littlefs viewer showing spiffs.bin open, that 121/256 blocks are used, and two folders inside named “prefs” and “static”&#34;&gt;
&lt;code&gt;static/&lt;/code&gt; held the Meshtastic webui resources, and &lt;code&gt;prefs/&lt;/code&gt; had &lt;code&gt;channels.proto&lt;/code&gt;, &lt;code&gt;config.proto&lt;/code&gt;, and &lt;code&gt;db.proto&lt;/code&gt;, which I downloaded.&lt;/p&gt;
&lt;h3 id=&#34;protobuf&#34;&gt;Protobuf&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://protobuf.dev/&#34;&gt;Protobuf&lt;/a&gt; (protocol buffers) is a relatively common data interchange system, which Meshtastic uses for both preferences and over-the-air communication. At first I tried to use &lt;code&gt;protoc&lt;/code&gt; with the Meshtastic &lt;a href=&#34;https://github.com/meshtastic/protobufs/tree/c845b7848eebb11150ca0427773303bf8758e533/meshtastic&#34;&gt;protobuf definitions&lt;/a&gt; to produce Python code to read the files, and then &lt;a href=&#34;https://www.protobufpal.com/&#34;&gt;protobufpal&lt;/a&gt;, but they weren&amp;rsquo;t parsing the prefs files, so in the interest of time I ended up using &lt;a href=&#34;https://github.com/mildsunrise/protobuf-inspector&#34;&gt;mildsunrise/protobuf-inspector&lt;/a&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ protobuf_inspector &amp;lt;channels.proto
root:
    1 &amp;lt;chunk&amp;gt; = message:
        2 &amp;lt;chunk&amp;gt; = message:
            2 &amp;lt;chunk&amp;gt; = bytes (1)
                0000   01                                                                       .
        3 &amp;lt;varint&amp;gt; = 1
    1 &amp;lt;chunk&amp;gt; = message:
        1 &amp;lt;varint&amp;gt; = 1
        2 &amp;lt;chunk&amp;gt; = message:
            2 &amp;lt;chunk&amp;gt; = bytes (32)
                0000   CE F8 DB 8E 8E 60 17 FD 6D CC A2 1D B8 A1 47 6D 45 14 80 AC D7 F4 F9 F7  .....`..m.....GmE.......
                0018   69 A7 63 F5 28 C0 11 F7                                                  i.c.(...
            3 &amp;lt;chunk&amp;gt; = &amp;#34;Buddies&amp;#34;
            4 &amp;lt;32bit&amp;gt; = 0x00000001 / 1 / 1.40130e-45
        3 &amp;lt;varint&amp;gt; = 2
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 2, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 3, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 4, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 5, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 6, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    1 &amp;lt;chunk&amp;gt; = message(1 &amp;lt;varint&amp;gt; = 7, 2 &amp;lt;chunk&amp;gt; = empty chunk)
    2 &amp;lt;varint&amp;gt; = 22
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The leading number associates a value with its attribute in the protobuf definition. The root seems to be an array of Channel objects, so within each of those we should be able to look for the attribute numbers in &lt;a href=&#34;https://github.com/meshtastic/protobufs/blob/c845b7848eebb11150ca0427773303bf8758e533/meshtastic/channel.proto&#34;&gt;channel.proto&lt;/a&gt;. Channel-&amp;gt;2 is a &lt;code&gt;ChannelSettings settings&lt;/code&gt;, and ChannelSettings-&amp;gt;2 is &lt;code&gt;bytes psk&lt;/code&gt;. We&amp;rsquo;ve found our channel key!&lt;/p&gt;
&lt;p&gt;Since then I&amp;rsquo;ve realized that &lt;code&gt;prefs/channels.proto&lt;/code&gt; isn&amp;rsquo;t a &lt;code&gt;Channel&lt;/code&gt; from channel.proto, it&amp;rsquo;s a &lt;code&gt;ChannelFile&lt;/code&gt; from &lt;code&gt;deviceonly.proto&lt;/code&gt;, so here&amp;rsquo;s the interesting parts in a more readable format:&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-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;channels&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;...&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PRIMARY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;channel_num&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;psk&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#ae81ff&#34;&gt;206&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;248&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;219&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;142&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;142&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;96&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;253&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;109&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;204&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;162&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;29&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;184&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;161&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;71&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;109&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#ae81ff&#34;&gt;69&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;172&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;215&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;244&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;249&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;247&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;105&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;167&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;245&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;192&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;247&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Buddies&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uplink_enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;downlink_enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SECONDARY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;followed&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;empty&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;role:&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;DISABLED&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;channels&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the LoRa part of &lt;code&gt;prefs/config.proto&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-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;lora&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;ignore_incoming&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;use_preset&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;modem_preset&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LONG_FAST&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;bandwidth&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;spread_factor&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;coding_rate&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;frequency_offset&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CN&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;hop_limit&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tx_enabled&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tx_power&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;channel_num&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;66&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;override_duty_cycle&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;sx126x_rx_boosted_gain&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;override_frequency&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We no longer have to guess our LoRa settings, we can just copy the &lt;code&gt;LONG_FAST&lt;/code&gt; parameters from the &lt;a href=&#34;https://meshtastic.org/docs/overview/radio-settings&#34;&gt;radio settings&lt;/a&gt; page!&lt;/p&gt;
&lt;h2 id=&#34;back-to-decoding&#34;&gt;Back to Decoding&lt;/h2&gt;
&lt;p&gt;With known radio settings we could revisit the GNU Radio flow graph with gr-lora. Here&amp;rsquo;s what I ended up with:
&lt;a href=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/lora_RX.grc&#34;&gt;download grc&lt;/a&gt;
&lt;img src=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/lora_RX.svg&#34; alt=&#34;GNU Radio flow graph. Both channels from WAV file source are converted from floats to complex numbers, sent through a bypassed Throttle block, then to a disabled QT GUI Sink block and a LoRa Receiver block&#34;&gt;&lt;/p&gt;
&lt;p&gt;And its output: &lt;a href=&#34;https://sec.gd/blog/en/posts/long-distance-2/resources/lora_RX.log&#34;&gt;full log&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Bits (nominal) per symbol: 	5.5
Bins per symbol: 	2048
Samples per symbol: 	8192
Decimation: 		4
 2d 31 e0 bc 4b 6c fa c4 c0 6d fa 66 26 d2 02 0b 08 a7 92 b3 78 fb 63 77 d7 e0 54 d7 4f 67 1e c0 2d f1 8c 7d 04 66 c9 31 bb 22 40 0f c9 ec 25 c8 71 33 (Klmf&amp;amp;xcwTOg-}f1&amp;#34;@%q3)
[...]
 22 31 70 ff ff ff ff c4 c0 6d fa 5f 8a 54 22 02 04 a7 92 53 1f 89 a3 6f ea 30 18 c9 ce b7 e7 1f a3 cd 72 71 ed a7 3a (m_T&amp;#34;So0rq:)
 09 11 40/usr/include/c++/13.2.1/bits/stl_vector.h:1125: std::vector&amp;lt;_Tp, _Alloc&amp;gt;::reference std::vector&amp;lt;_Tp, _Alloc&amp;gt;::operator[](size_type) [with _Tp = unsigned char; _Alloc = std::allocator&amp;lt;unsigned char&amp;gt;; reference = unsigned char&amp;amp;; size_type = long unsigned int]: Assertion &amp;#39;__n &amp;lt; this-&amp;gt;size()&amp;#39; failed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The crash may have been because of my python2/python3 change. I hoped it wasn&amp;rsquo;t preventing decoding of the message with the flag, and it turned out fine.&lt;/p&gt;
&lt;p&gt;This still looked a bit nonsensical consider the Meshtastic &lt;a href=&#34;https://meshtastic.org/docs/overview/mesh-algo&#34;&gt;header format&lt;/a&gt;. When aligning the first part of each message, I would have expected to see repeated source and destination IDs, channel hash bytes, and padding, and flag bytes with the high nibble empty.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;DEST_NODEID SRC_NODEID_ PKT_UNIQ_ID FL CH PAD__ DATA...
2d 31 e0 bc 4b 6c fa c4 c0 6d fa 66 26 d2 02 0b 08 a7 92 b3 78 fb ...
1b 31 e0 c4 c0 6d fa bc 4b 6c fa 29 5d 91 38 03 08 a7 92 12 19 7e ...
49 31 20 c4 c0 6d fa bc 4b 6c fa a6 41 be 1e 0b 08 a7 92 b9 4d 99 ...
1b 31 e0 bc 4b 6c fa c4 c0 6d fa 0f 21 39 44 03 08 a7 92 b8 56 c7 ...
5f 30 00 ff ff ff ff c4 c0 6d fa a3 f3 0f 12 03 08 a7 92 aa c1 8d ...
5f 30 00 ff ff ff ff c4 c0 6d fa a3 f3 0f 12 02 08 a7 92 aa c1 8d ...
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are some columns that do have the properties I would expect, though&amp;hellip; Let&amp;rsquo;s shift the column headers over a byte at a time and see if they line up:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;?? ?? ?? DEST_NODEID SRC_NODEID_ PKT_UNIQ_ID FL CH PAD__ DATA...
2d 31 e0 bc 4b 6c fa c4 c0 6d fa 66 26 d2 02 0b 08 a7 92 b3 78 fb ...
1b 31 e0 c4 c0 6d fa bc 4b 6c fa 29 5d 91 38 03 08 a7 92 12 19 7e ...
49 31 20 c4 c0 6d fa bc 4b 6c fa a6 41 be 1e 0b 08 a7 92 b9 4d 99 ...
1b 31 e0 bc 4b 6c fa c4 c0 6d fa 0f 21 39 44 03 08 a7 92 b8 56 c7 ...
5f 30 00 ff ff ff ff c4 c0 6d fa a3 f3 0f 12 03 08 a7 92 aa c1 8d ...
5f 30 00 ff ff ff ff c4 c0 6d fa a3 f3 0f 12 02 08 a7 92 aa c1 8d ...
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That looks better, the fields all had the properties I expected. The leading 3 bytes ended up being the LoRa header, as seen in the &lt;a href=&#34;https://meshtastic.discourse.group/t/meshtastic-lora-packet-size/7953/9&#34;&gt;diagram&lt;/a&gt; - Payload length, coding rate, CRC flag, header CRC, padding.&lt;/p&gt;
&lt;h2 id=&#34;on-to-parsing&#34;&gt;On to Parsing&lt;/h2&gt;
&lt;p&gt;Disassembling the headers in python was relatively straightforward, but decrypting the Meshtastic payload was aggravating. The encrypt and decrypt functions are the same for AES-CTR, and for us are in &lt;a href=&#34;https://github.com/meshtastic/firmware/blob/v2.2.14.57542ce/src/platform/esp32/ESP32CryptoEngine.cpp#L40&#34;&gt;ESP32CryptoEngine.cpp&lt;/a&gt;. I should have looked at the relevant bits for other platforms, since they must all be compatible and &lt;a href=&#34;https://github.com/meshtastic/firmware/blob/v2.2.14.57542ce/src/platform/rp2040/rp2040CryptoEngine.cpp#L17&#34;&gt;others&lt;/a&gt; are more straightforward, but I didn&amp;rsquo;t. The problem boiled down to me chasing endianness issues before double checking that I was putting the &lt;a href=&#34;https://github.com/meshtastic/firmware/blob/v2.2.14.57542ce/src/mesh/CryptoEngine.cpp#L30&#34;&gt;parts of the nonce&lt;/a&gt; together in the wrong order or trying to decrypt other messages.&lt;/p&gt;
&lt;p&gt;While I worked on building a custom &lt;code&gt;Counter&lt;/code&gt; for PyCryptodome, tcode used my parsing and the python-mbedtls&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; library to successfully decrypt it. A few minutes later I got mine working, using the PyCryptodome, the default &lt;code&gt;Counter&lt;/code&gt;, and the correct nonce ordering and message.&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; Crypto.Cipher &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; AES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; Crypto.Util &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Counter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pkt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bytes&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fromhex(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;683060ffffffffc4c06dfa8899c2020304a7925001502e35d73ab793c3e9ad6acc9da6a4955bc56b8054e9989d76f5355cf2868b90bffae321d51077be4e1774fc074f63a4c0af6ba38f33a829b0784bdadbcc738b16e930e741c48f4d6c0cab012e5605122dce40eaeb7b7626&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;psk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bytes&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fromhex(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CEF8DB8E8E6017FD6DCCA21DB8A1476D451480ACD7F4F9F769A763F528C011F7&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lora_header &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkt[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;has_crc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (lora_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lora_payload &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkt[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;:]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lora_payload_crc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; lora_payload[&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:] &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; has_crc &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; has_crc:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    lora_payload &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; lora_payload[:&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lora_payload_len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; lora_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; len(lora_payload) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; lora_payload_len:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Warning: Incorrect payload length. expected &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;, got &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            lora_payload_len, len(lora_payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_header &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; lora_payload[:&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_dest &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_src &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_packet_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_flags &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_flags_hop_limit &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0b111&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_flags_want_ack &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (mt_flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_channel_hash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_header_padding &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_header[&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_payload &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; lora_payload[&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;:]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nonce &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mt_packet_id &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\0&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; mt_src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cipher &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AES&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;new(psk, AES&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;MODE_CTR, initial_value&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, nonce&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;nonce)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mt_payload_decrypted &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cipher&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decrypt(mt_payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;open(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;decrypt.out&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;wb&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;write(mt_payload_decrypted)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(mt_payload_decrypted)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;victory&#34;&gt;Victory!&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;b&amp;#39;\x08\x01\x12Talright alright. the key is rwctf{No_h0p_th1s_tim3_c831bcad725935ba25c0a3708e49c0c8}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fully parsed:&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-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;portnum&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TEXT_MESSAGE_APP&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;payload&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alright alright. the key is rwctf{No_h0p_th1s_tim3_c831bcad725935ba25c0a3708e49c0c8}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks to tcode for working with me on this challenge. At one point during decoding they said &amp;ldquo;I was doing something silly&amp;rdquo;. In my experience, that&amp;rsquo;s all of programming, CTFing, and many other technical endeavors. I hope this post was worth the read despite its length, but I think it&amp;rsquo;s important to not gloss over the challenges and mistakes instead of reinforcing anyone&amp;rsquo;s imposter syndrome.&lt;/p&gt;
&lt;p&gt;WreckTheLine finished in 7th place of 2291 teams. This challenge was worth 320 points out of our 1662 (19%), and was solved by a total of 9 teams.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I would recommend against using Synss/python-mbedtls for real cryptography. It has basically no documentation I can find besides examples, and what is there (docstrings) is scary.
For &lt;a href=&#34;https://github.com/Synss/python-mbedtls/blob/ce46bdefc0e5234dd0d3c4e63ce5c2d9fe8555e5/src/mbedtls/cipher/AES.py#L60&#34;&gt;example&lt;/a&gt;, &lt;code&gt;AES.new(key, mode, iv, ad)&lt;/code&gt; (note that iv=nonce+counter, effectively):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;iv: The initialization vector (IV). The IV is required for every mode but ECB and CTR where it is ignored. If not set, the IV is initialized to all 0, which should not be used for encryption.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;AES-CTR must &lt;em&gt;never&lt;/em&gt; use the same (key, nonce, counter) twice or its security properties are broken. Luckily failing to specify an &lt;code&gt;iv&lt;/code&gt; parameter does produce an error. Additionally, the &lt;code&gt;ad&lt;/code&gt; (Associated Data / Additional Authenticated Data, I assume) parameter is not even in the docstring.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;]]></content:encoded>
        <dc:creator>mal</dc:creator>
        <media:content url="https://sec.gd/blog/images/long-distance-2/4-waterfall-detail.png" medium="image"><media:title type="html">featured image</media:title></media:content>
        
        <media:content url="https://sec.gd/blog/images/long-distance-2/4-waterfall-detail.png" medium="image"><media:title type="html">meta image</media:title></media:content>
        
          
            
              <category>real world ctf</category>
            
          
            
              <category>radio</category>
            
          
            
              <category>misc</category>
            
          
        
        
          
            
              <category>ctf</category>
            
          
        
        
      </item>
    
  </channel>
</rss>