<?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>Home on Mal Breaks Things</title>
    <link>https://sec.gd/blog/en/</link>
    <description>Recent content in Home 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>©2025. <a href="/blog/about/">License and Info</a></copyright>
    <lastBuildDate>Sun, 04 Jul 2021 04:00:00 +0000</lastBuildDate>
    <sy:updatePeriod>daily</sy:updatePeriod>
    
        <atom:link href="https://sec.gd/blog/en/index.xml" rel="self" type="application/rss+xml" />
    
      
      
      
        
      
        
      
        
      
        
      
        
      
        
      
        
      
        
      
        
      
        
      

      
      <item>
        <title>Retrieving your Google Services Framework ID</title>
        <link>https://sec.gd/blog/en/posts/gsfid/</link>
        <pubDate>Thu, 21 Aug 2025 04:00:00 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Thu, 21 Aug 2025 04:00:00 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/gsfid/</guid>
        <description>Since Android 14, getting your GSF ID to bypass Play Protect has required root. Here&amp;rsquo;s how to get it from the web instead.</description>
        <content:encoded>&lt;p&gt;My partner and I use &lt;a href=&#34;https://grapheneos.org/&#34;&gt;GrapheneOS&lt;/a&gt; on our phones.
Google is as supportive of this as you would imagine, so this causes some
problems, like failing SafetyNet CTS preventing many bank and DRM&amp;rsquo;d media apps
from working. She recently tried to use an app that seemed to refuse to launch
because Graphene isn&amp;rsquo;t Play Protect Certified.&lt;/p&gt;
&lt;p&gt;Google created a page to allow users of custom ROMs to register their Google
Services Framework ID to bypass Play Protect certification requirements,
presumably after some antitrust threats. There are reports that it originally
accepted an IMEI as well, but that doesn&amp;rsquo;t seem to be the case anymore, even
when padding it with zeroes.&lt;/p&gt;
&lt;p&gt;So it seems like in theory we&amp;rsquo;ll be able to avoid some compatibility complaints
on the Play Store and in apps by registering our devices with the GSF IDs - but
first we need to find them.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Note that while the Google Services Framework ID (GSF ID) is sometimes called
&lt;code&gt;android_id&lt;/code&gt;, it is not the same as &lt;code&gt;Settings.Secure.ANDROID_ID&lt;/code&gt;
(&lt;code&gt;adb shell settings get secure android_id&lt;/code&gt;) or the advertising IDs.
The GSF ID also changes when the device is wiped, and may be different for each
user.&lt;/div&gt;
&lt;h2 id=&#34;official-method&#34;&gt;Official Method&lt;/h2&gt;
&lt;p&gt;On the &lt;a href=&#34;https://www.google.com/android/uncertified/&#34;&gt;device registration page&lt;/a&gt;
Google recommends running:&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-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb shell &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;sqlite3 /data/user/$(cmd activity get-current-user)/*/*/gservices.db \
&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;    &amp;#34;select * from main where name = \&amp;#34;android_id\&amp;#34;;&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This requires a debug build, which won&amp;rsquo;t help me on Graphene.&lt;/p&gt;
&lt;h3 id=&#34;with-su&#34;&gt;With su&lt;/h3&gt;
&lt;p&gt;The obvious workaround is to use &lt;code&gt;su&lt;/code&gt; to elevate to root, which is also not
helpful on Graphene, but may be for you. I also didn&amp;rsquo;t have &lt;code&gt;sqlite3&lt;/code&gt; on my
test device, so I did that part on the computer, and also fixed the quotes in
their query.&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-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pc$ adb shell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phone$ su
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phone# cp /data/user/&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;cmd activity get-current-user&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;/*/*/gservices.db /sdcard/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phone# exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phone$ exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pc$ adb pull /sdcard/gservices.db
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pc$ sqlite3 gservices.db &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;select * from main where name = &amp;#39;android_id&amp;#39;;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-internets-suggestions&#34;&gt;The Internet&amp;rsquo;s Suggestions&lt;/h2&gt;
&lt;p&gt;For a long time, apps could retrieve the GSF ID. This was obviously a privacy
nightmare, so they can&amp;rsquo;t anymore, and all apps that don&amp;rsquo;t use root are useless
on Android 14ish and newer.&lt;/p&gt;
&lt;h2 id=&#34;without-root&#34;&gt;Without root&lt;/h2&gt;
&lt;p&gt;Since this ID is used to identify your device to Google, I suspected it would
end up reused in some web interface. There were a few suspicious 16-character
hex strings and long decimal numbers near my phone&amp;rsquo;s name in the source of the
&lt;a href=&#34;https://play.google.com/library/devices&#34;&gt;devices page&lt;/a&gt; of the Play Store, but
none were my GSF ID. A different 21-digit decimal number shows up when
selecting a device to install an app to, also not the needed ID. A base64
string shows up in other places, &lt;em&gt;also&lt;/em&gt; unrelated.&lt;/p&gt;
&lt;p&gt;Interestingly, I ended up finding it not on the Play Store but from the
&amp;ldquo;&lt;a href=&#34;https://www.google.com/android/find/&#34;&gt;Find Hub&lt;/a&gt;&amp;rdquo; device list.&lt;/p&gt;
&lt;p&gt;Disclaimer: While the ID retrieved this way does match the one from
gservices.db, I haven&amp;rsquo;t actually gotten a GrapheneOS phone to show up as
certified. There may be requirements other than device registration.&lt;/p&gt;
&lt;p&gt;To find yours:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Load the &lt;a href=&#34;https://www.google.com/android/find/&#34;&gt;Find Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;In Chrome, press Ctrl+Shift+J (Mac: Cmd+Opt+J), or
in Firefox, Ctrl+Shift+K (Mac: Cmd+Opt+K)&lt;/li&gt;
&lt;li&gt;If prompted, type &lt;code&gt;allow pasting&lt;/code&gt;. Don&amp;rsquo;t ignore the warning: Putting
untrusted code here could give someone control of your Google account and
more.&lt;/li&gt;
&lt;li&gt;Now that you&amp;rsquo;ve ignored the warning, paste this incomprehensible mess into
the console and press enter:
&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-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;AF_initDataKeys&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;=&amp;gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;querySelector&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;script.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CSS&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;escape&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;))).&lt;span style=&#34;color:#a6e22e&#34;&gt;flatMap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;=&amp;gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;text&lt;/span&gt;;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substring&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&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;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)).&lt;span style=&#34;color:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;/({|, )([a-z])/g&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1&amp;#34;$2&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;/([a-z])(:[ [])/g&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1&amp;#34;$2&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt;)).&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&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;&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;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]&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;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]&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;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;])}).&lt;span style=&#34;color:#a6e22e&#34;&gt;forEach&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;You should see a list of devices connected to your Google account, their
models, and your GSF ID for each, which you can paste into the
&lt;a href=&#34;https://www.google.com/android/uncertified/&#34;&gt;registration page&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Readable code:&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-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// For each data key (e.g. &amp;#34;ds:0&amp;#34;), find its &amp;lt;script&amp;gt; tag
&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:#75715e&#34;&gt;&lt;/span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;AF_initDataKeys&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&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:#a6e22e&#34;&gt;key&lt;/span&gt; =&amp;gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;querySelector&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;&amp;#34;script.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CSS&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;escape&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&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:#a6e22e&#34;&gt;flatMap&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:#a6e22e&#34;&gt;scriptTag&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;scriptText&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scriptTag&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;text&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;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&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:#a6e22e&#34;&gt;scriptText&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:#75715e&#34;&gt;// Take just the {...} passed into AF_initDataCallback()
&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:#75715e&#34;&gt;&lt;/span&gt;            .&lt;span style=&#34;color:#a6e22e&#34;&gt;substring&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:#a6e22e&#34;&gt;scriptText&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&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; &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:#a6e22e&#34;&gt;scriptText&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Insert quotes before keywords
&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:#75715e&#34;&gt;&lt;/span&gt;            .&lt;span style=&#34;color:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;/({|, )([a-z])/g&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1&amp;#34;$2&amp;#39;&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:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;/([a-z])(:[ [])/g&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1&amp;#34;$2&amp;#39;&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:#75715e&#34;&gt;// JSON requires double quotes
&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:#75715e&#34;&gt;&lt;/span&gt;            .&lt;span style=&#34;color:#a6e22e&#34;&gt;replaceAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34;&amp;#39;&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:#a6e22e&#34;&gt;data&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:#75715e&#34;&gt;// Make each phone&amp;#39;s info info readable
&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:#75715e&#34;&gt;&lt;/span&gt;        .&lt;span style=&#34;color:#a6e22e&#34;&gt;map&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:#a6e22e&#34;&gt;ph&lt;/span&gt; =&amp;gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;ph&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// Name
&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:#75715e&#34;&gt;&lt;/span&gt;                &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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ph&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// Manufacturer
&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:#75715e&#34;&gt;&lt;/span&gt;                &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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ph&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// Model
&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:#75715e&#34;&gt;&lt;/span&gt;                &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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ph&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// GSF ID
&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:#75715e&#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:#75715e&#34;&gt;// And print the info
&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:#75715e&#34;&gt;&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;forEach&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:#a6e22e&#34;&gt;phone&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;phone&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;Sorry for my javascript sins, it&amp;rsquo;s not a language I like much or know well.
Also sorry for the regex crimes in there - I couldn&amp;rsquo;t find the parsed data,
and Google disables &lt;code&gt;eval()&lt;/code&gt; with CSP.&lt;/p&gt;
&lt;p&gt;If Google changes something and that code stops working, you may be able to
load the Find Hub, press Ctrl+U (Mac Firefox: Cmd+U, Mac Chrome: Cmd+Opt+U),
and search for your device name. There should be a 19-digit number near it.&lt;/p&gt;
&lt;p&gt;Good luck, and don&amp;rsquo;t forget to write your congresscritters and demand better
antitrust enforcement.&lt;/p&gt;
</content:encoded>
        <dc:creator>mal</dc:creator>
        
        
        
        
          
            
              <category>android</category>
            
          
            
              <category>GrapheneOS</category>
            
          
        
        
          
            
              <category>android</category>
            
          
            
              <category>GrapheneOS</category>
            
          
        
        
      </item>
      
      <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;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>
      
      <item>
        <title>Hacker&#39;s Playground: Legonigma</title>
        <link>https://sec.gd/blog/en/posts/legonigma/</link>
        <pubDate>Tue, 27 Sep 2022 04:00:00 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Tue, 27 Sep 2022 04:00:00 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/legonigma/</guid>
        <description>&lt;p&gt;I recently participated in Samsung&amp;rsquo;s &lt;a href=&#34;https://ctftime.org/event/1715/&#34;&gt;Hacker&amp;rsquo;s Playground CTF&lt;/a&gt; with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;Wreck The Line&lt;/a&gt;. We finished with 1592 points, in 26th place of 1075 teams. Most of my time was spent on Legonigma, an interesting 500 point challenge based on two renders of a Lego cryptography gadget.&lt;/p&gt;</description>
        <content:encoded>&lt;p&gt;I recently participated in Samsung&amp;rsquo;s &lt;a href=&#34;https://ctftime.org/event/1715/&#34;&gt;Hacker&amp;rsquo;s Playground CTF&lt;/a&gt; with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;Wreck The Line&lt;/a&gt;. We finished with 1592 points, in 26th place of 1075 teams. Most of my time was spent on Legonigma, an interesting 500 point challenge based on two renders of a Lego cryptography gadget.&lt;/p&gt;
&lt;h2 id=&#34;the-challenge&#34;&gt;The Challenge&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/Legonigma_Front.jpg&#34; alt=&#34;Front image of Lego gadget&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/Legonigma_Back.jpg&#34; alt=&#34;Rear image of Lego gadget&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/Legonigma_Instructions.jpg&#34; alt=&#34;Instruction image, showing that the 36 gear teeth are A-Z then 0-9 clockwise, green gears are input, and yellow are output&#34;&gt;&lt;/p&gt;
&lt;p&gt;Decipher ciphertext:
&lt;code&gt;59x8wl9pjsava3grn0il79aoq307f20a6huc3xnos289cd8xv1fn2znuoa2bq8959chbktwfow8c3azpvo3c59jz4&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;first-impressions&#34;&gt;First Impressions&lt;/h2&gt;
&lt;p&gt;Cool!&lt;/p&gt;
&lt;p&gt;I had a limited selection of possible parts, assuming it was built with production Lego pieces. The only moving parts were gears and a differential, so I suspected the relationships between input and outputs were just a series of ratios.&lt;/p&gt;
&lt;p&gt;Why were there three outputs? Maybe it produced 3 ciphertext characters per plaintext character? No, the ciphertext was 89 characters total, which isn&amp;rsquo;t divisible by 3&amp;hellip; I must need to guess the order?&lt;/p&gt;
&lt;h2 id=&#34;pieces-in-play&#34;&gt;Pieces in Play&lt;/h2&gt;
&lt;p&gt;Using the images and information from a &lt;a href=&#34;https://themomentmakers.org/2019/09/26/gears-types-of-gears/&#34;&gt;blog post&lt;/a&gt; about Lego gears I listed the pieces I might face, by type, tooth count, and features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regular gears (no bevel)
&lt;ul&gt;
&lt;li&gt;8 (axle)&lt;/li&gt;
&lt;li&gt;16 (axle and small spaces)&lt;/li&gt;
&lt;li&gt;24 (axle and four round post holes)&lt;/li&gt;
&lt;li&gt;40 (axle and a bunch of axle and post holes)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Double Bevel
&lt;ul&gt;
&lt;li&gt;12 (axle)&lt;/li&gt;
&lt;li&gt;20 (axle, spaces)&lt;/li&gt;
&lt;li&gt;28 (axle and four post holes)&lt;/li&gt;
&lt;li&gt;36 (axle plus two posts and two axles)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Differential
&lt;ul&gt;
&lt;li&gt;Three identical single-bevel inside, so ratios don&amp;rsquo;t matter&lt;/li&gt;
&lt;li&gt;Outside: 16 and 24 tooth&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;attempt-one-procedural&#34;&gt;Attempt One: Procedural&lt;/h2&gt;
&lt;p&gt;My first instinct was to follow the gearing through, noting each number of teeth:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;36 (input, green)
hard link to 20 (grey)
rotates 12 (blue)
rotates 20 (grey)
splits to A

A1:
rotates 12 (blue)
hard link to 36 (grey)
rotates 12 (blue)
hard link to 36 (yellow, out1)

A2:
hard link to 28 (blue)
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I intended to turn this into a simple procedure that would just do the math for each step, keeping track of the angle of each gear, but I realized there&amp;rsquo;s a much easier way to simplify it&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;attempt-two-mathematical&#34;&gt;Attempt Two: Mathematical&lt;/h2&gt;
&lt;p&gt;If I pretend I&amp;rsquo;ve turned the input one full rotation clockwise, how does each gear – and therefore each output – behave?&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;input 1 CW
grey 1 CW
blue (irrelevant) CCW
grey 1 CW (split A)

A1 (left):
blue 20/12=5/3 CCW
grey 5/3 CCW
blue 5 CW
yellow 5 CW (out1)

A2:
blue (irrelevant) CCW
grey 1 CW
blue 20/12=5/3 CCW (split B)

...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Following this through, I arrived at the following ratios between input and output:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1:5 for the front left output&lt;/li&gt;
&lt;li&gt;1:5/3 for the front right output&lt;/li&gt;
&lt;li&gt;1:38/9 for the rear output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having made up simple ciphers in the past, after finding the 1:5 output I was kind of expecting the others to also be prime numbers. Oh well, the math doesn&amp;rsquo;t lie&amp;hellip; Right?&lt;/p&gt;
&lt;p&gt;But after writing some python code to show outputs for every possible first couple characters of input, I couldn&amp;rsquo;t get the outputs to match the ciphertext. Notably, for lots of valid inputs, the rear and right-side outputs sat between letters. Unless this machine would be provided to users with specific instructions, that seemed odd.&lt;/p&gt;
&lt;p&gt;I spent a long time chasing guesses about what those instructions might be - &amp;ldquo;Keep turning until the outputs are all exactly at a tooth/letter&amp;rdquo;? &amp;ldquo;Keep turning until the one output for this step is exactly at a tooth/letter&amp;rdquo;? After some rubber duck debugging and a gentle nudge from the challenge author, I re-examined my understanding of the machine, but still couldn&amp;rsquo;t find anything wrong.&lt;/p&gt;
&lt;h2 id=&#34;the-nuclear-option&#34;&gt;The Nuclear Option&lt;/h2&gt;
&lt;p&gt;If I couldn&amp;rsquo;t logic it out, I&amp;rsquo;d try to rebuild the device&amp;rsquo;s mechanics using a tool.&lt;/p&gt;
&lt;p&gt;There were several relatively simple tools for Lego gear ratios, but besides them being a bit difficult to build a complex machine in, it didn&amp;rsquo;t seem they would be able to handle the differential, or possibly even the splits.&lt;/p&gt;
&lt;p&gt;I ended up finding the Technic Brick Power &lt;a href=&#34;https://technicbrickpower.com/tools/gearing_ratio_calculator&#34;&gt;Gearing Ratio Calculator&lt;/a&gt;, which seemed to do exactly what I needed! &amp;hellip;when provided with a &amp;ldquo;Lego Technic .ldr file&amp;rdquo;. Okay, it seems I need to use something like &lt;a href=&#34;https://www.leocad.org/&#34;&gt;LeoCAD&lt;/a&gt; to build that&amp;hellip;&lt;/p&gt;
&lt;p&gt;A lot of twiddling and building later, I had reproduced the machine:
&lt;img src=&#34;../../../images/legonigma/sim-wrong.jpg&#34; alt=&#34;Image of the machine in LeoCAD&#34;&gt;&lt;/p&gt;
&lt;p&gt;But when I loaded it into the gearing ratio tool, attaching a motor, and running it, the entire model turned red, indicating a jammed motor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-angry.png&#34; alt=&#34;Screenshot of the ratio calculator with all parts colored red&#34;&gt;&lt;/p&gt;
&lt;p&gt;I assumed the tool just didn&amp;rsquo;t know how to handle the differential, and removed the gear before the rear output to let both sides of that branch run separately, then combined the adjacent gears&amp;rsquo; motion myself. The results matched my original calculations perfectly, and I was lost again.&lt;/p&gt;
&lt;p&gt;After many more lines of code and attempts to figure out how the machine would be used, I eventually arrived at a realization: In a row of three gears, turning the first clockwise at 1 RPM and the third clockwise at 2 RPM does not cause the middle one to rotate counterclockwise at 3 RPM. Don&amp;rsquo;t ask how I had arrived at my original understanding – I do not know, and it is as obviously wrong in retrospect as it is to you. The resulting conclusion was that the branch through the front-right output and the differential was not modifying the ratio of the rear output. The simulation was correct. My understanding of the machine actually &lt;em&gt;was&lt;/em&gt; a deadlock.&lt;/p&gt;
&lt;p&gt;I stared at the challenge&amp;rsquo;s renders more, and eventually found the problem: There was in fact no motion going &lt;em&gt;through&lt;/em&gt; the front-right output&amp;rsquo;s axle, and the direction of control through the differential is the opposite of what I thought.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/Legonigma_Front.jpg&#34; alt=&#34;Front view of Lego gadget&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-wrong.jpg&#34; alt=&#34;Front view of incorrect recreation&#34;&gt;&lt;/p&gt;
&lt;p&gt;See it? I sure didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/Legonigma_Front-line.jpg&#34; alt=&#34;Front view of Lego gadget with a line highlighting the difference&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-wrong-line.jpg&#34; alt=&#34;Front view of incorrect recreation with a line highlighting the difference&#34;&gt;&lt;/p&gt;
&lt;p&gt;After some logic, some trial-and error, and a lot of staring at close-ups of small details in the original render, I moved a few elements around. Here&amp;rsquo;s a bottom view of the change, with the front-right output gear at the top center:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-wrong-bottom.jpg&#34; alt=&#34;Bottom view of incorrect recreation&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-bottom.jpg&#34; alt=&#34;Bottom view of corrected recreation&#34;&gt;&lt;/p&gt;
&lt;p&gt;Then I loaded the amended model into the simulator:&lt;/p&gt;
&lt;video class=&#34;video-animation&#34; autoplay loop muted playsinline aria-label=&#34;Corrected model in the gearing ratio calculator&#34;&gt;
    &lt;source src=&#34;../../../images/legonigma/sim-fixed.mp4&#34; type=&#34;video/mp4&#34;&gt;
    
    Your browser does not seem to support this video.
&lt;/video&gt;

&lt;p&gt;And got some much nicer ratios for the outputs&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/legonigma/sim-ratios.png&#34; alt=&#34;Screenshot of sim info panel for output gears, showing ratios of 1:5, 1:-7, and 1:13&#34;&gt;&lt;/p&gt;
&lt;p&gt;So I updated my code to use these much more reasonable ratios, aaaaand&amp;hellip; No valid input produced an output matching the first three characters of ciphertext.&lt;/p&gt;
&lt;h2 id=&#34;reaching-further&#34;&gt;Reaching further&lt;/h2&gt;
&lt;p&gt;Lacking any idea how the outputs were meant to be read, I figured it was time to investigate the challenge name&amp;rsquo;s call-out to the German Enigma machine to look for hints.&lt;/p&gt;
&lt;p&gt;Enigma&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Known-plaintext attack&lt;/li&gt;
&lt;li&gt;Not ECB (advances rotors by each character)&lt;/li&gt;
&lt;li&gt;Random mapping in each code wheel and on plugboard&lt;/li&gt;
&lt;li&gt;Never encrypted a letter to itself&lt;/li&gt;
&lt;li&gt;Decryption == encryption (if a-&amp;gt;r, r-&amp;gt;a)&lt;/li&gt;
&lt;li&gt;Key is rotor selection, rotor position, reflector position, plugboard config&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This machine&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No known-plaintext available&lt;/li&gt;
&lt;li&gt;ECB (all rotors end up back at A when input is rotated back to A)&lt;/li&gt;
&lt;li&gt;Probably not enough ciphertext to do statistics for random mappings&lt;/li&gt;
&lt;li&gt;Encrypts A to A,A,A&lt;/li&gt;
&lt;li&gt;How to decrypt, besides &amp;ldquo;turn input til all three outputs match your ciphertext block&amp;rdquo;?&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;s a key, how is it configured? 4 pointer positions * 4 rotors * 6 output rotor orders = 96 possibilities?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maybe I was missing an instruction like &amp;ldquo;Advance the input by n teeth, where n is the index of the next plaintext character&amp;rdquo;? I couldn&amp;rsquo;t figure out how to turn the three outputs into a ciphertext.&lt;/p&gt;
&lt;h2 id=&#34;feeling-dumb-again&#34;&gt;Feeling Dumb (Again)&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s no galaxy brain instructions, I just needed read the outputs in a particular order, trivially discovered. 1:13 first, then 1:5, then 1:7.&lt;/p&gt;
&lt;p&gt;I achieved the second solve for Legonigma, for 460 points, 17 minutes after the first team.
&lt;code&gt;SCTF{th3w0rld1sadang3rou5placeno7becau5e0fth0sewh0do3v1lbutbecau5eofth053wh0l00konandd0n0th1ng}&lt;/code&gt;
(&amp;ldquo;The world is a dangerous place, not because of those who do evil, but because of those who look on and do nothing&amp;rdquo;)&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I wish the ratios hadn&amp;rsquo;t been whole numbers, so the &amp;ldquo;no reversing&amp;rdquo; instruction meant something!&lt;/p&gt;
&lt;p&gt;Thanks to &amp;ldquo;Your expectations are reasonable&amp;rdquo; Cybrosis for a really neat challenge and a couple nudges, rebuilding the machine was fun.
Thanks also to Samsung for organizing this event, and my teammates at WreckTheLine for all of their work and for putting up with my rubber ducking.&lt;/p&gt;
&lt;h2 id=&#34;downloads&#34;&gt;Downloads&lt;/h2&gt;
&lt;p&gt;My Python code, including a lot of commented-out wrong attempts, and overbuilt since I originally expected one full input rotation to not return to the starting state: &lt;a href=&#34;https://sec.gd/blog/en/posts/legonigma/legonigma.py&#34;&gt;legonigma.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The .ldr model of the machine I built in LeoCAD: &lt;a href=&#34;https://sec.gd/blog/en/posts/legonigma/legonigma.ldr&#34;&gt;legonigma.ldr&lt;/a&gt;&lt;/p&gt;</content:encoded>
        <dc:creator>mal</dc:creator>
        <media:content url="https://sec.gd/blog/images/legonigma/Legonigma_Front.jpg" medium="image"><media:title type="html">featured image</media:title></media:content>
        
        <media:content url="https://sec.gd/blog/images/legonigma/Legonigma_Front.jpg" medium="image"><media:title type="html">meta image</media:title></media:content>
        
          
            
              <category>hacker&#39;s playground</category>
            
          
            
              <category>crypto</category>
            
          
            
              <category>misc</category>
            
          
        
        
          
            
              <category>ctf</category>
            
          
        
        
      </item>
      
      <item>
        <title>1Password&#39;s Privacy Surprises</title>
        <link>https://sec.gd/blog/en/posts/1password-leak-takeover/</link>
        <pubDate>Wed, 04 Aug 2021 04:00:00 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Wed, 04 Aug 2021 04:00:00 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/1password-leak-takeover/</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://1password.com/&#34;&gt;1Password&lt;/a&gt; is a popular password manager by AgileBits.
It&amp;rsquo;s much more reliable and user-friendly than LastPass, and has a $60/yr
family plan&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;, so it&amp;rsquo;s what my family uses to keep track of and share
credentials.&lt;/p&gt;
&lt;p&gt;Unfortunately it has a couple of design problems that AgileBits does not feel
should be fixed.&lt;/p&gt;</description>
        <content:encoded>&lt;p&gt;&lt;a href=&#34;https://1password.com/&#34;&gt;1Password&lt;/a&gt; is a popular password manager by AgileBits.
It&amp;rsquo;s much more reliable and user-friendly than LastPass, and has a $60/yr
family plan&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;, so it&amp;rsquo;s what my family uses to keep track of and share
credentials.&lt;/p&gt;
&lt;p&gt;Unfortunately it has a couple of design problems that AgileBits does not feel
should be fixed.&lt;/p&gt;
&lt;p&gt;To be clear up front: These are not critical vulnerabilities. They do not allow
strangers to read your passwords. I still use 1Password, and am not
recommending most people stop using them, only understand these limitations.&lt;/p&gt;
&lt;h2 id=&#34;family-organizer-vault-takeover&#34;&gt;Family Organizer Vault Takeover&lt;/h2&gt;
&lt;p&gt;Users of 1Password can create additional &lt;a href=&#34;https://support.1password.com/create-share-vaults/&#34;&gt;vaults&lt;/a&gt;.
This is how users share stored items (i.e. login information) between accounts:
Create vault, share vault with other user, move Netflix password into shared
vault.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/vaults.png&#34; alt=&#34;Vault list displayed in 1Password: Private, Shared, School, and “Very Boring Research” which has a subtle transgender pride flag icon&#34;&gt;&lt;/p&gt;
&lt;p&gt;This feature also enables separation of stored items between personal, school,
work, and
&lt;a href=&#34;https://www.engadget.com/2016-03-04-multiple-online-identities.html&#34;&gt;alternate identities&lt;/a&gt;.
It&amp;rsquo;s useful to be able to put some things away by switching vaults or removing
some vaults from All Vaults when traveling
(see also: &lt;a href=&#34;https://support.1password.com/travel-mode&#34;&gt;Travel Mode&lt;/a&gt;),
hosting a screenshare, or in some physical environments (work, school, church).&lt;/p&gt;
&lt;h3 id=&#34;the-problem&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;What isn&amp;rsquo;t mentioned anywhere in the vault creation process is that if you&amp;rsquo;re
using a family plan the
&lt;a href=&#34;https://support.1password.com/family-organizer/&#34;&gt;family organizers&lt;/a&gt;
can add themselves to these additional vaults. That information is only shown
on the easily missable Vault Details page, and isn&amp;rsquo;t even clear in their
documentation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/vault-details.png&#34; alt=&#34;Vault Details page showing “All family organizers can also manage this vault” under the People section&#34;&gt;&lt;/p&gt;
&lt;p&gt;I first discovered this when I noticed I could add myself to a vault shared
between my parents and grant myself full permissions. I wrote to their support
in 2019 asking if this was intended and how to create a vault organizers
couldn&amp;rsquo;t add themselves to. Their first response actually said that family
organizers &amp;ldquo;cannot manage any of your vaults unless they have explicit
permission to that vault&amp;rdquo;, which would be great if not demonstrably untrue.
When asked for clarification, I was informed that only the default vault named
&amp;ldquo;Private&amp;rdquo; is inaccessable, and all others can be accessed by family organizers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/takeover1.png&#34; alt=&#34;Vaults page, as seen by the family organizer, showing the “Shared” vault as well as “School” and “Very Boring Researh” from the family member’s account&#34;&gt;
Family organizers can see all secondary vaults created by family members.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/takeover2.png&#34; alt=&#34;Vault Details page as seen by the administrator, with a “Manage” button above the list of authorized users&#34;&gt;
They can see the details, delete the vault, or manage its users.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/manage-family-members.png&#34; alt=&#34;“Manage Family Members” dialog, offering the family organizer a checkbox to add themselves to the vault&#34;&gt;
Just a checkbox to gain access.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/takeover-vault-contents.png&#34; alt=&#34;Vault contents screenshot, showing credentials for trans and LGBT resources, and a twitter account with a name other than the family member’s given name&#34;&gt;
I wonder what they&amp;rsquo;re hiding from me? Luckily, I have no morals, so I can find
out without having to interact with my child.&lt;/p&gt;
&lt;p&gt;When I add myself to a vault this way, there are no notifications,
confirmations, or logs&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. I can add myself, create a backup of the entire
vault, and remove myself, and the authorized users would never know.&lt;/p&gt;
&lt;p&gt;At best, this makes vaults useless for many situations. I&amp;rsquo;m contractually
prohibited from sharing some credentials with anyone else, so if I add another
family organizer as best practice suggests, I can no longer separate work
credentials using a vault.&lt;/p&gt;
&lt;p&gt;At worst, this could allow a parent to violate a child&amp;rsquo;s privacy in unexpected
ways, or an employer to violate an employee&amp;rsquo;s&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; - not just revealing the
sites used but directly and unauditably granting access to them.&lt;/p&gt;
&lt;p&gt;If this was clear to users, I would be disappointed, but I wouldn&amp;rsquo;t be writing
this post. The problem is that it&amp;rsquo;s not - it&amp;rsquo;s unexpected in the most
unpleasant way from a password manager.&lt;/p&gt;
&lt;h3 id=&#34;potential-mitigations&#34;&gt;Potential Mitigations&lt;/h3&gt;
&lt;h4 id=&#34;minimum&#34;&gt;Minimum&lt;/h4&gt;
&lt;p&gt;Transparency. Make clear in the vault creation flow that family organizers can
gain access to it. Send a notification and/or email to authorized vault users
on membership changes.&lt;/p&gt;
&lt;h4 id=&#34;preferred&#34;&gt;Preferred&lt;/h4&gt;
&lt;p&gt;Cryptographic and server control. Do not encrypt vault keys for anyone not
explicitly authorized to have access except in the same manner as account
recovery, and do not send the vault data to anyone not explicitly authorized.&lt;/p&gt;
&lt;h3 id=&#34;workarounds&#34;&gt;Workarounds&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;As support suggested to me, use
&lt;a href=&#34;https://support.1password.com/favorites-tags/&#34;&gt;tags&lt;/a&gt; instead of vaults, and
give up the vault-based features.&lt;/li&gt;
&lt;li&gt;Abandon redundancy and be the only family organizer, and tell your family
members that they aren&amp;rsquo;t able to create vaults you don&amp;rsquo;t have access to.&lt;/li&gt;
&lt;li&gt;Use only individual accounts, giving up the family plan discount and
group-based features.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;leaking-metadata-to-network-admins&#34;&gt;Leaking Metadata to Network Admins&lt;/h2&gt;
&lt;p&gt;Unlike the first, this problem applies to all accounts - Individual, family,
and business, whether subscription or app-licensed. When the 1Password app or
browser addon shows vault entries, it shows an icon for each website. Instead
of being saved in your vault, they&amp;rsquo;re requested from the server when they&amp;rsquo;re
shown. The Windows desktop app appears to cache them, but the browser addon
appears to request them again each time they&amp;rsquo;re shown.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/browser-ui.png&#34; alt=&#34;Screenshot of 1Password browser addon, showing site logins with the site icon next to them&#34;&gt;&lt;/p&gt;
&lt;p&gt;Normally the privacy impact of this is what they describe on their
&lt;a href=&#34;https://support.1password.com/rich-icons-privacy/&#34;&gt;rich icon privacy&lt;/a&gt;
page: Your network sees that you use 1password, and the CDN sees your IP
address and the domain you&amp;rsquo;re requesting an icon for. This isn&amp;rsquo;t ideal but is
acceptable to most users. Others can disable it, assuming they notice and
understand the setting, &lt;em&gt;and&lt;/em&gt; that they&amp;rsquo;re not using the browser
extension, where the setting doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;h3 id=&#34;the-problem-1&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;Many schools and companies use SSL/TLS inspection (TLSi) either to restrict
what content is available from the network or to ensure sensitive information
is not being sent out of the network. TLSi works by requiring every device to
add a new trusted certificate authority, and then signing a new TLS certificate
for every site a device tries to contact. The end result is that the user sees
the usual &lt;code&gt;🔒 https://...&lt;/code&gt; in their browser and everything works normally, but
when their traffic reaches the system performing inspection, it&amp;rsquo;s decrypted,
scanned, potentially logged, and then re-encrypted and passed along.&lt;/p&gt;
&lt;p&gt;This means that every time the user clicks the 1Password button, opens their
vault, or has the autofill popover show up, their school or workplace will get
logs like these:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/1password-leak-takeover/icon-requests.png&#34; alt=&#34;Fiddler request log, showing icon requests to c.1password.com for domains like ntcc.edu and transtexas.org&#34;&gt;
&lt;em&gt;SSL added and removed here! :)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Depending on the domain and the aggressiveness of web filters, this may even
trigger automated alerts to administrators, including the wildly inappropriate
&amp;ldquo;adult content&amp;rdquo; classification for LGBTQ+ resources. These alerts are often
passed along to parents or supervisors for disciplinary action.&lt;/p&gt;
&lt;p&gt;When I contacted support about this, I was referred to their rich icon privacy
documentation page.&lt;/p&gt;
&lt;p&gt;Users expect password managers to do everything possible to keep their
contents, including the metadata, private. In situations where an unavoidable
environment like work or school may disagree with parts of a 1Password user&amp;rsquo;s
personal life, this expectation is put to the test, and its failure may have
significant consequences.&lt;/p&gt;
&lt;h3 id=&#34;potential-mitigations-1&#34;&gt;Potential Mitigations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ideally, store images encrypted for the user, encrypt requests. This would
increase server disk space needs and load. Alternatively:&lt;/li&gt;
&lt;li&gt;Pin the keys of the CDNs so inspection devices don&amp;rsquo;t see the requested URLs.
This slightly degrades the user experinece, but I feel this is a more than
acceptable tradeoff in those cases. Unfortunately this probably isn&amp;rsquo;t
possible in the browser extension.&lt;/li&gt;
&lt;li&gt;Implement a setting to disable rich icons in the browser addon&lt;/li&gt;
&lt;li&gt;Obfuscate, e.g. encrypt images with &lt;code&gt;hash(domain)&lt;/code&gt;, request with
&lt;code&gt;hash(hash(domain))&lt;/code&gt;. Defeats trivial observation, but doesn&amp;rsquo;t prevent
confirmation of known domains.&lt;/li&gt;
&lt;li&gt;Cache icons for as long as possible to reduce the amount/chance of
information leaking.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;workarounds-1&#34;&gt;Workarounds&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t use 1Password in TLS-inspected environments.&lt;/li&gt;
&lt;li&gt;Disable vaults containing sensitive domains when in a TLS-inspected
environment, if the above issue with vaults doesn&amp;rsquo;t preclude their use.&lt;/li&gt;
&lt;li&gt;I haven&amp;rsquo;t found a way to block the requests with uBlock Origin or even
uMatrix, so&amp;hellip; Accept the risk, or disable the browser addon when in
TLS-inspected environments.&lt;/li&gt;
&lt;li&gt;Disable rich icons in settings, or don&amp;rsquo;t use the apps either in
TLS-inspected environments.&lt;/li&gt;
&lt;li&gt;Ideally, use a VPN like Wireguard to escape TLS-inspected environments and
never install new trusted certificate authorities regardless of this issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1password-cli-leaks&#34;&gt;1Password CLI Leaks&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Added 2021-09-29&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As reported by Graham Christensen, the 1Password CLI tool (&lt;code&gt;op&lt;/code&gt;) exposes
sensitive information including passwords to all other users and processes on
your system through command arguments.&lt;/p&gt;
&lt;p&gt;AgileBits are aware of this and consider it not a problem.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Luckily&amp;rdquo;, unlike other password managers&amp;rsquo; command line tools, &lt;code&gt;op&lt;/code&gt; is quite
difficult to use as a human - its interfaces almost seem to be intended as an
API instead of for direct use.&lt;/p&gt;
&lt;p&gt;Read more about this problem in Graham&amp;rsquo;s &lt;a href=&#34;https://twitter.com/grhmc/status/1443037314817695744&#34;&gt;twitter thread&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;mal-whining&#34;&gt;Mal Whining&lt;/h2&gt;
&lt;p&gt;While I&amp;rsquo;m writing about 1Password, I may as well mention the other things that
I&amp;rsquo;d like to see changed.&lt;/p&gt;
&lt;h3 id=&#34;inactive-account-management&#34;&gt;Inactive Account Management&lt;/h3&gt;
&lt;p&gt;As described in the
&lt;a href=&#34;https://1password.com/files/1Password-White-Paper.pdf#page=38&#34;&gt;whitepaper&lt;/a&gt;,
there is a mechanism for assisting family members or team members with vault
recovery. A simplified explanation is that the server holds a copy of each
family member&amp;rsquo;s vault key, encrypted so only family organizers can access it.
If I initiate recovery for my mother&amp;rsquo;s vault, she receives an email allowing
her to create new keys. Once she&amp;rsquo;s done so, the server gives me the encrypted
vault key (but not the vault data) so I can re-encrypt it with her new public
key.&lt;/p&gt;
&lt;p&gt;This is about as good as I can ask for a user-friendly recovery system, but I
would like to see the ability to configure my account to grant access to
&lt;strong&gt;specific vaults&lt;/strong&gt; to a family member if I don&amp;rsquo;t sign in for some number of
months and don&amp;rsquo;t respond to emails or text messages.&lt;/p&gt;
&lt;p&gt;The cryptographic features are already there, this mode would just skip the
email confirmation, and the server would grant vault data access as well.&lt;/p&gt;
&lt;h3 id=&#34;backups&#34;&gt;Backups&lt;/h3&gt;
&lt;p&gt;As mentioned, the Linux app is not feature-complete, and there&amp;rsquo;s no way to
grant access to vaults automatically if I&amp;rsquo;m run over by a bus. It would be
great if the ability to make backups was prioritized for either Linux or
the web interface.&lt;/p&gt;
&lt;h3 id=&#34;container-incompatibility&#34;&gt;Container Incompatibility&lt;/h3&gt;
&lt;p&gt;Firefox has a great feature called
&lt;a href=&#34;https://wiki.mozilla.org/Security/Contextual_Identity_Project/Containers&#34;&gt;Container Tabs&lt;/a&gt;
that allows easy separation of multiple accounts, identities, or contexts. I
use it extensively to keep work accounts in one container, personal in another,
and stay signed out in the default container.&lt;/p&gt;
&lt;p&gt;When selecting &amp;ldquo;Open &amp;amp; Fill&amp;rdquo; in the 1Password extension, it creates a new tab
in the default container, and uses that to navigate to the site. This means
the only way to sign in to a site in a chosen container is to copy the link and
paste it into a new container tab manually.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;https://1password.community/discussion/95984/&#34;&gt;brought this up&lt;/a&gt; on their
forum in 2018, and for a few versions the extension would reuse the existing
new container tab if present, but then it stopped working again, and they
&lt;a href=&#34;https://1password.community/discussion/comment/502084/#Comment_502084&#34;&gt;still&lt;/a&gt;
&lt;a href=&#34;https://1password.community/discussion/comment/548227/#Comment_548227&#34;&gt;haven&amp;rsquo;t&lt;/a&gt;
&lt;a href=&#34;https://twitter.com/TryCatchPass/status/1390076529246363650&#34;&gt;fixed it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If they wanted to, they could build neat integrations, like having
the extension always open a login (or even just anything in a particular vault)
in a configured container. For now, all I ask is to not override my choice.&lt;/p&gt;
&lt;h3 id=&#34;getting-to-the-web-interface&#34;&gt;Getting to the web interface&lt;/h3&gt;
&lt;p&gt;Nearly all of the management of vault items and account settings is done
through either the web interface or one of the applications. The Linux app is
currently in beta and not feature-complete, and typing on a phone is tedious,
so I&amp;rsquo;m left with the web app. (2022 update: The linux app is improving, and I
can access that by clicking the icon in my taskbar, but this annoyance remains
for those who don&amp;rsquo;t use the desktop app.)&lt;/p&gt;
&lt;p&gt;To access the web app, I can either go to the site and enter my password again,
or I can have the extension open it alreay authenticated.&lt;/p&gt;
&lt;p&gt;For some reason, the only way I&amp;rsquo;ve found to do this is to click the extension&amp;rsquo;s
icon, click the settings gear, click Settings, scroll to the bottom, click one
of the vault names, and then navigate where I need to go in the web interface.&lt;/p&gt;
&lt;p&gt;Could we get a link next to Settings that&amp;rsquo;s just &amp;ldquo;Manage from web&amp;rdquo;?&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;1Password is also available without the web/sync features as a one-time
purchase. I expect everything described here to apply to that use as well,
but it&amp;rsquo;s not what AgileBits are pushing, and I don&amp;rsquo;t want to buy it to test.&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;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Business plans may expose audit logs. I don&amp;rsquo;t have one to test, but I
would be surprised if those logs were made available to normal users.&amp;#160;&lt;a href=&#34;#fnref:2&#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;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;This is less clear, as many employers have policies stating employees
have no expectation of privacy. I would argue that employees should be
reminded of this at every point where it might be important.&amp;#160;&lt;a href=&#34;#fnref:3&#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/1password-leak-takeover/manage-family-members.png" medium="image"><media:title type="html">featured image</media:title></media:content>
        
        
        
          
            
              <category>closed:notabug</category>
            
          
            
              <category>1password</category>
            
          
            
              <category>agilebits</category>
            
          
        
        
        
      </item>
      
      <item>
        <title>ImaginaryCTF 2021</title>
        <link>https://sec.gd/blog/en/posts/imaginaryctf-2021/</link>
        <pubDate>Tue, 27 Jul 2021 04:00:00 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Tue, 27 Jul 2021 04:00:00 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/imaginaryctf-2021/</guid>
        <description>This weekend I participated in &lt;a href=&#34;https://2021.imaginaryctf.org/&#34;&gt;ImaginaryCTF 2021&lt;/a&gt; with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;WreckTheLine&lt;/a&gt;. We finished third out of 1018 entrants, the final team to complete all 55 challenges and hit 11330 points, missing second place by 3.5 minutes. Here are my writeups for System Hardening 5 and New Technology.</description>
        <content:encoded>&lt;p&gt;&lt;img src=&#34;../../../images/imaginaryctf-2021/ictf-2021-banner.jpg&#34; alt=&#34;ImaginaryCTF 2021 Banner&#34;&gt;&lt;/p&gt;
&lt;p&gt;This weekend I participated in &lt;a href=&#34;https://2021.imaginaryctf.org/&#34;&gt;ImaginaryCTF 2021&lt;/a&gt;
with &lt;a href=&#34;https://wrecktheline.com/&#34;&gt;WreckTheLine&lt;/a&gt;. We finished third out of 1018
entrants, the final team to complete all 55 challenges and hit 11330 points,
missing second place by 3.5 minutes.&lt;/p&gt;
&lt;h2 id=&#34;system-hardening-5&#34;&gt;System Hardening 5&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;CyberPatriot but run by roo fanatics&amp;hellip; What could go wrong&amp;hellip;&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At 450 points, System Hardening 5 was in the highest value category of
challenges. It was in the pattern of CyberPatriot, where teams download and
run a VM, find and fix all of the vulnerabilities. A scoring engine checks the
scored items every minute or so and reports to the scoreboard.&lt;/p&gt;
&lt;p&gt;As with CyberPatriot, we start with the &lt;a href=&#34;https://system-hardening-5.chal.imaginaryctf.org/readme&#34;&gt;readme&lt;/a&gt;.
The major constrants today are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No updates at all. Makes sense, that&amp;rsquo;s time-consuming and uninteresting.&lt;/li&gt;
&lt;li&gt;Critical services: Remote desktop, print spooler.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t disable SMB or the scoring engine may break&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;forensics&#34;&gt;Forensics&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start&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; with the Forensics questions, as the readme says, so we don&amp;rsquo;t
accidentally destroy artifacts we&amp;rsquo;ll need to answer them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An [sic] user on this system was compromised, allowing rooReaper to break in. What is
the username of this user?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Well, let&amp;rsquo;s look around. Event log? Exploit artifacts? Let&amp;rsquo;s check this other
file on the desktop first, &lt;code&gt;text-messages-from-mom.txt.txt&lt;/code&gt; [sic].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; hi roo! this is definitely mom here&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; oh hi mom didnt see you there all too well&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; ?&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; nvm, what did you text me for&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; and is this a new number? i dont see the message history&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; uhh yea this is a new number&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; oh ok&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; can you disable your firewall? and enable smb pls and disable your antivirus&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; ok whatever you say mom&amp;hellip;&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; ill look up some tutorials&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; NO DONT LOOK AT TUTORIALS&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; ok i wont what do i do&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; ill show you&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; btw what is rooPOG&amp;rsquo;s password&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; i heard he loves sharing&lt;br&gt;
&lt;strong&gt;rooYay:&lt;/strong&gt; its just password1337 nothing fancy&lt;br&gt;
&lt;strong&gt;MOMtotallynotrooreaper:&lt;/strong&gt; thanks!&lt;br&gt;
&amp;hellip;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Looks like rooYay fell for the classic &amp;ldquo;hi this is your mother&amp;rdquo; phish, and gave
out &lt;strong&gt;rooPOG&lt;/strong&gt;&amp;rsquo;s password.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Forensics Question 1 correct - 7 points&lt;/div&gt;
&lt;p&gt;That also gives us the answer to the next forensics question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the password of the compromised user from the previous question?&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;password1337&lt;/strong&gt; nothing fancy&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Forensics Question 2 correct - 7 points&lt;/div&gt;
&lt;p&gt;The other forensics questions require some research.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the CVE ID of the vulnerability that allowed rooReaper to escalate
privileges?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I poked around in rooPOG&amp;rsquo;s home directory for a bit, finding &lt;code&gt;xconsole.exe&lt;/code&gt; and
&lt;code&gt;vlib.dll&lt;/code&gt; in &lt;code&gt;Downloads\foobar&lt;/code&gt;. The latter was detected as Win32/Mamson.A!ac,
which doesn&amp;rsquo;t obviously use any exploits. I enabled Windows Defender and
started a scan, and before I had found anything in the event viewer, it had
found &lt;code&gt;C:\temp\PrintNightmareLPE.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Print Nightmare, &lt;a href=&#34;https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527&#34;&gt;CVE-2021-34527&lt;/a&gt;,
is a recent vulnerability that allows a remote attacker to install a malicious
printer driver configuration DLL to gain arbitrary code execution as SYSTEM. A
variant, &lt;a href=&#34;https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-1675&#34;&gt;&lt;strong&gt;CVE-2021-1675&lt;/strong&gt;&lt;/a&gt;,
is useful for local exploitation, and was accepted as the answer.&lt;/p&gt;
&lt;p&gt;Both of these drop the payload, in this case &lt;code&gt;vlib.dll&lt;/code&gt;, in
&lt;code&gt;C:\Windows\System32\spool\drivers\x64\3\&lt;/code&gt;, where Defender found it alongside
&lt;code&gt;reverse_64bit.dll&lt;/code&gt; which it detected as Win64/Meterpreter.B. I removed the
whole folder, along with &lt;code&gt;C:\temp\&lt;/code&gt; and the contents of rooPOG&amp;rsquo;s Downloads
folder.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Forensics Question 3 correct - 7 points&lt;br&gt;
Removed privilege escalation payload - 5 points&lt;/div&gt;
&lt;p&gt;The final forensics question seemed like a steganography problem, but referred
to another challenge in the CTF:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The background image on the Desktop contains a secret message. What is it?&lt;br&gt;
HINT: It&amp;rsquo;s related to another challenge in this CTF, a reversing challenge.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The wallpaper was &lt;code&gt;background.png&lt;/code&gt; in rooYay&amp;rsquo;s Pictures folder. It consisted of
a grid of tiles, in a repeating pattern &lt;code&gt;Axxxx&lt;/code&gt;, where there were 3 options for
&lt;code&gt;x&lt;/code&gt;. No obvious pattern was shown by &lt;code&gt;stegsolve&lt;/code&gt;, and it wasn&amp;rsquo;t clear how to
decode information in the tile pattern. I put it aside until a teammate,
JaGoTu, solved &lt;code&gt;roolang&lt;/code&gt;, which seemed potentially-related. Sure enough:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JaGoTu: roolang was just a vm that was calculating fibonacii very slowly&lt;br&gt;
JaGoTu: can you send the raw png somewhere?&lt;br&gt;
JaGoTu: cause the roolang basically runs png files&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;They ran their roolang solution on the PNG, and sent back the output:
&lt;strong&gt;Hello, and welcome to the roos&amp;rsquo; server!&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Forensics Question 4 correct - 7 points&lt;/div&gt;
&lt;h3 id=&#34;pups-not-the-fun-kind&#34;&gt;PUPs (Not the Fun Kind)&lt;/h3&gt;
&lt;p&gt;With the forensics questions out of the way, let&amp;rsquo;s continue through the readme.
We have a list of needed services and software, so let&amp;rsquo;s remove anything that&amp;rsquo;s
not on it, starting with the faux-Clippy in the corner of the screen.&lt;/p&gt;
&lt;p&gt;First, the Startup folder for All Users in
&lt;code&gt;C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\&lt;/code&gt;.
Two shortcuts:\&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;chksec - Shortcut.lnk&lt;/code&gt; to &lt;code&gt;C:\Windows\System32\chksec.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;essential - Shortcut.lnk&lt;/code&gt; to &lt;code&gt;C:\Windows\System32\essential.bat&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Delete the shortcuts, kill the processes, delete the Clippy executable.
&lt;code&gt;essential.bat&lt;/code&gt; printed some ascii art text, copied itself to the current
user&amp;rsquo;s start menu Startup folder, opened a
&lt;a href=&#34;https://www.youtube.com/watch?v=xvFZjo5PgG0&#34;&gt;video&lt;/a&gt;, and then &lt;code&gt;pause&lt;/code&gt;d.
Delete the batch file from System32 and from rooYay&amp;rsquo;s
&lt;code&gt;%AppData%\Microsoft\Windows\Start Menu\Programs\Startup\&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Removed PUP Clippy - 3 points&lt;br&gt;
Removed rickroll malware - 4 points&lt;/div&gt;
&lt;h3 id=&#34;installed-programs&#34;&gt;Installed Programs&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a couple shortcuts on the desktop to software that wasn&amp;rsquo;t mentioned as
required in the readme, so let&amp;rsquo;s remove those. I replaced Chrome with Firefox
portable, since the roos prefer IE and I very much do not. Nothing else in
add/remove programs looked relevant.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Removed unauthorized program Minecraft Launcher - 3 points&lt;br&gt;
Removed unauthorized program SuperAntiSpyware - 3 points&lt;/div&gt;
&lt;p&gt;I also looked through the running processes, but nothing else there raised
suspicion.&lt;/p&gt;
&lt;h3 id=&#34;users&#34;&gt;Users&lt;/h3&gt;
&lt;p&gt;Next, let&amp;rsquo;s deal with users, which is easiest from
&lt;code&gt;compmgmt.msc&lt;/code&gt;/&lt;code&gt;lusrmgr.msc&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;roocursion&lt;/code&gt; as requested in the readme&lt;/li&gt;
&lt;li&gt;Rename the local administrator account as requested (can be done here or in
group policy)&lt;/li&gt;
&lt;li&gt;Make sure nobody unauthorized is in Administrators or other privileged groups&lt;/li&gt;
&lt;li&gt;Make sure no non-builtin users exist who aren&amp;rsquo;t mentioned, poking through
their home folders before deleting&lt;/li&gt;
&lt;li&gt;Disable the Guest account, and rename for good measure&lt;/li&gt;
&lt;li&gt;Change the password for all users&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ll mention here that CyberPatriot often uses significantly outdated best
practices and ignores how things would be done in the real world, and we also
don&amp;rsquo;t know what this challenge will score on, so a lot of the things I check
and changes I make to this machine are excessive, paranoid, annoying, or
otherwise just weird. If we lose points for something we can easily undo the
change.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Removed unauthorized user rooReaper - 3 points&lt;br&gt;
Removed unauthorized user rooDevil - 3 points&lt;br&gt;
Removed unauthorized user rooRage - 3 points&lt;br&gt;
User rooFrozen is not an administrator - 3 points&lt;br&gt;
User roocursion has been created - 3 points&lt;br&gt;
Administrator account renamed - 3 points&lt;br&gt;
Guest account is disabled - 4 points&lt;/div&gt;
&lt;h3 id=&#34;services-and-firewall&#34;&gt;Services and Firewall&lt;/h3&gt;
&lt;p&gt;Interspersed with everything else, I poke around &lt;code&gt;services.msc&lt;/code&gt; and the control
panel to make sure everything is sane. Enable the firewall
MOMtotallynotrooreaper told us to disable, then make sure there&amp;rsquo;s no
nonstandard or scary rules enabled. Enable cloud protection and sample
sumbission for Defender, make sure the scan finished. Right click My Computer
and click Properties, check $PATH and other environment variables for anything
weird, make sure Data Execution Prevention is enabled for all applications, and
disable NetBIOS.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Windows Firewall is enabled - 5 points&lt;/div&gt;
&lt;h3 id=&#34;group-policy&#34;&gt;Group Policy&lt;/h3&gt;
&lt;p&gt;Before I forget, let&amp;rsquo;s make sure we&amp;rsquo;ve mitigated Print Nightmare. The
&lt;a href=&#34;https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527&#34;&gt;MSRC post&lt;/a&gt;
about it recommends updating (oops, can&amp;rsquo;t), disabling the print spooler (oops,
can&amp;rsquo;t), or disabling inbound remote printing with Group Policy.&lt;/p&gt;
&lt;p&gt;I fire up &lt;code&gt;gpedit.msc&lt;/code&gt;, open Computer Configuration -&amp;gt;
Windows Settings -&amp;gt; &amp;hellip; Where&amp;rsquo;s Security Settings?&lt;/p&gt;
&lt;p&gt;This is where I spent about half my time on this challenge. When launching
&lt;code&gt;gpedit.msc&lt;/code&gt;, Security Settings was missing. &lt;code&gt;secpol.msc&lt;/code&gt; would show the tree
starting at Windows Settings instead of Security Settings, and also omit the
latter. Many answers on the internet offered a simple &lt;code&gt;regsvr32 wsecedit.dll&lt;/code&gt;,
which doesn&amp;rsquo;t work as the DLL doesn&amp;rsquo;t have the correct entrypoints for that.
This is where I ran &lt;code&gt;dism /online /cleanup-image /restorehealth&lt;/code&gt; and
&lt;code&gt;sfc /scannow&lt;/code&gt;, which didn&amp;rsquo;t find any problems.&lt;/p&gt;
&lt;p&gt;I never did figure out what was done to break that, as I eventually gave up and
tried importing an exported policy, and later started setting the policy
registry entries by hand. After a while, I opened the mmc snapin again, and
Security Settings was there!&lt;/p&gt;
&lt;p&gt;It seems that it&amp;rsquo;s only broken for the rooYay user, and after setting UAC to
require a password, I was unintentionally elevating as rooAstro, for whom it
worked correctly. Something in my profile was breaking it. Some windows
LD_LIBRARY_PATH type thing? Something in HKEY_CURRENT_USER? It didn&amp;rsquo;t directly
affect security, so I put it aside again.&lt;/p&gt;
&lt;p&gt;From there, I could much more easily continue with group policy, basically just
going through every option in Security Settings -&amp;gt; Account Policies and Local
Policies and some folders in Administrative Templates -&amp;gt; Windows Settings,
setting everything to the most paranoid sane option.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Remember 24 passwords&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;60 day maximum password age&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;10 day minimum password age&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;14 character minimum length&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Must meet complexity requirements&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No reversible encryption&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;15 minute account lockout duration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;10 attempt lockout threshold&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;15 minute counter reset timer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable all auditing&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go through User Rights Assignment and restrict everything as much as possible&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hey, why is &lt;code&gt;Everyone&lt;/code&gt; allowed to take ownership of files??&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You know what, let&amp;rsquo;s just disable the Administrator account&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I don&amp;rsquo;t like Microsoft account signin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More audit everything&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Prevent users from installing printer drivers (well&amp;hellip; try to)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restrict CD-ROM access to locally logged-on users&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Require CTRL+ALT+DEL, force inactivity limit, require strong encryption&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You get the idea.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Everyone is not allowed to take ownership of files and other objects - 5 points&lt;/div&gt;
&lt;h3 id=&#34;critical-services&#34;&gt;Critical Services&lt;/h3&gt;
&lt;p&gt;And let&amp;rsquo;s not forget to secure our critical services. The MSRC Print Nightmare
article points me to Administrative Templates -&amp;gt; Printers to disable &amp;ldquo;Allow
Print Spooler to accept client connections&amp;rdquo;. There have been a few RDP
vulnerabilities, but none with straightforward workarounds besides patching, so
let&amp;rsquo;s just be sure to flip on all of the RDP server security policies. Lastly,
we weren&amp;rsquo;t disallowed from disabling old versions of SMB, so use the powershell
command in the
&lt;a href=&#34;https://docs.microsoft.com/en-us/windows-server/storage/file-server/troubleshoot/detect-enable-and-disable-smbv1-v2-v3&#34;&gt;docs&lt;/a&gt;,
to check for SMBv1 and see it&amp;rsquo;s already disabled.&lt;/p&gt;
&lt;div class=&#34;alert alert-info&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Inbound remote printing is disabled (PrintNightmare mitigation) - 9 points&lt;br&gt;
Remote Desktop uses network level authentication - 4 points&lt;/div&gt;
&lt;h3 id=&#34;other-stuff&#34;&gt;Other Stuff&lt;/h3&gt;
&lt;p&gt;In an advanced challenge, in addition to &lt;code&gt;sfc&lt;/code&gt; and &lt;code&gt;dism&lt;/code&gt; to look for
&amp;ldquo;creatively modified&amp;rdquo; system files, &lt;code&gt;hijackthis&lt;/code&gt; can be helpful. In case
of a well-disguised network backdoor, it&amp;rsquo;s also good to check open sockets.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;And with that, I had 91 points, 20/21 items, and the flag appeared in the score
report. There was one scored item I never found, worth 9 points. I&amp;rsquo;ll be
waiting for a writeup from tirefire, the only person with 100 points, to see
what I missed!&lt;/p&gt;
&lt;div class=&#34;alert alert-success&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Unique ID: &lt;code&gt;8edd464b&lt;/code&gt;&lt;br&gt;
Flag: &lt;code&gt;ictf{th4nks_s0_much_f0r_s3cur1ng_0ur_s3rver!_h3r3s_4_fl4g!!!}&lt;/code&gt;&lt;/div&gt;
&lt;h3 id=&#34;update&#34;&gt;Update&lt;/h3&gt;
&lt;p&gt;First, Eth007, one of the challenge authors, let me know that the last scored
item I couldn&amp;rsquo;t find was
&lt;a href=&#34;https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection&#34;&gt;LSA protection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Second, thank you to the iCTF team for selecting this as a prize-winning writeup!&lt;/p&gt;
&lt;h2 id=&#34;new-technology&#34;&gt;New Technology&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;If it&amp;rsquo;s not Windows New Technology, what else could NT stand for?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This was a 300pt cryptography challenge in the form of a &lt;a href=&#34;https://imaginaryctf.org/r/3204-new_technology.py&#34;&gt;python
script&lt;/a&gt;.
It generates a random key consisting of 5 tuples, each a 512-bit prime &lt;code&gt;p&lt;/code&gt; and
an integer exponent $1 \le e &amp;lt; 4$.&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gen&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    private &lt;span style=&#34;color:#f92672&#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:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getPrime(&lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getRandomRange(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&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;        private&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append((p, e))
&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;return&lt;/span&gt; private, normalize(private)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The public key is derived by the &lt;code&gt;normalize()&lt;/code&gt; function, which multiplies
together &lt;code&gt;p**e&lt;/code&gt; for each private key component.&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;normalize&lt;/span&gt;(fac):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    n &lt;span style=&#34;color:#f92672&#34;&gt;=&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:#66d9ef&#34;&gt;for&lt;/span&gt; p, e &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; fac:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n &lt;span style=&#34;color:#f92672&#34;&gt;*=&lt;/span&gt; p&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;e
&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;return&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since these are 512-bit primes, the resulting public key isn&amp;rsquo;t easy to factor.&lt;/p&gt;
&lt;p&gt;The private key is put through the &lt;code&gt;deriv()&lt;/code&gt; function, which has a nested
loop based on &lt;code&gt;divs()&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;deriv&lt;/span&gt;(priv):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res &lt;span style=&#34;color:#f92672&#34;&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;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; d1 &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; divs(priv):
&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;for&lt;/span&gt; d2 &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; divs(d1):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            res &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; normalize(d2) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; phi(d2) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; phi(div(d1, d2))
&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;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;divs()&lt;/code&gt; takes the same &lt;code&gt;List[Set[prime: int, exponent: int], ...]&lt;/code&gt; private key
format and yields the cartesian product of them based on the range 0..e of
their exponents:&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;divs&lt;/span&gt;(fac, pre&lt;span style=&#34;color:#f92672&#34;&gt;=&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; pre &lt;span style=&#34;color:#f92672&#34;&gt;is&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;        pre &lt;span style=&#34;color:#f92672&#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:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; fac:
&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;yield&lt;/span&gt; pre
&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;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        p, e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; fac[&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;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, e &lt;span style=&#34;color:#f92672&#34;&gt;+&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:#66d9ef&#34;&gt;yield from&lt;/span&gt; divs(fac[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:], pre &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; [(p, i)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; priv &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [(&lt;span style=&#34;color:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; pprint(list(divs(priv)))
&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;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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; [(&lt;span style=&#34;color:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&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:#ae81ff&#34;&gt;167&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;149&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For each entry in this list, &lt;code&gt;d1&lt;/code&gt;, &lt;code&gt;deriv()&lt;/code&gt; again calls &lt;code&gt;divs()&lt;/code&gt;, and loops on
that &lt;code&gt;d2&lt;/code&gt;, adding &lt;code&gt;normalize(d2) * phi(d2) * phi(div(d1, d2))&lt;/code&gt; to a running
total.&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;phi&lt;/span&gt;(fac):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res &lt;span style=&#34;color:#f92672&#34;&gt;=&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:#66d9ef&#34;&gt;for&lt;/span&gt; p, e &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; fac:
&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; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; e: &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res &lt;span style=&#34;color:#f92672&#34;&gt;*=&lt;/span&gt; (p&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;(e &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; (p &lt;span style=&#34;color:#f92672&#34;&gt;-&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:#66d9ef&#34;&gt;return&lt;/span&gt; res
&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt;(a, b):  &lt;span style=&#34;color:#75715e&#34;&gt;# a=d1, b=d2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; dict(b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res &lt;span style=&#34;color:#f92672&#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:#66d9ef&#34;&gt;for&lt;/span&gt; p, e &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; a:
&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;assert&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; b[p]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append((p, e &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; b[p]))
&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;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At some point here things started to smell funny - we&amp;rsquo;re collecting the sum of
some math done on every divisor of every divisor&amp;hellip; Just for fun, let&amp;rsquo;s see how
this behaves when run all the way through with more manageable numbers, maybe
12 bits.&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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gen_custom&lt;/span&gt;(count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt;, max_exp&lt;span style=&#34;color:#f92672&#34;&gt;=&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;    private &lt;span style=&#34;color:#f92672&#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:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getPrime(size)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getRandomRange(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, max_exp&lt;span style=&#34;color:#f92672&#34;&gt;+&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;        private&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append((p, e))
&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;return&lt;/span&gt; private, normalize(private)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; priv, pub &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; gen_custom(&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;12&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;gt;&amp;gt;&amp;gt;&lt;/span&gt; priv
&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;3251&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;3863&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;2917&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;3761&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;3989&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;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; pub
&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;90459172118968888949999762493557&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;gt;&amp;gt;&amp;gt;&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; deriv(priv)
&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;gt;&amp;gt;&amp;gt;&lt;/span&gt; key
&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;8182861820449238390507452368725018700352715647046709310466512249&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;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; sage.all &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#f92672&#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;gt;&amp;gt;&amp;gt;&lt;/span&gt; factor(pub)
&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;2917&lt;/span&gt;&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:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3251&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3761&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3863&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3989&lt;/span&gt;&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;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; factor(key)
&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;2917&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; &lt;span style=&#34;color:#ae81ff&#34;&gt;3251&lt;/span&gt;&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:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3761&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3863&lt;/span&gt;&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:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3989&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;rsquo;t have &lt;a href=&#34;https://sagemath.org/&#34;&gt;sagemath&lt;/a&gt; installed, you can also use
a handy dandy &lt;a href=&#34;https://www.alpertron.com.ar/ECM.HTM&#34;&gt;webassembly ECM factorization tool&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The factors of the public key aren&amp;rsquo;t surprising, that&amp;rsquo;s the exact math we used
to derive it from the private key, but possible to reverse since we used small
numbers. On the other hand, what&amp;rsquo;s up with the private key? Each factor
just has double the exponent? And since $x^2 * y^2 = (xy)^2$, and
$(x^3)^2 = x^6$&amp;hellip; Our private key is just the square of the public key??&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:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; pub&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;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well then! Let&amp;rsquo;s assign those commented output values to variables, square the
public key, get a new AES instance for decrypting, and&amp;hellip;&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;pub &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x281ab467e16cdedb97a298249bdd334f0cc7d54177ed0946c04ec26da111&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ciphertext &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 style=&#34;color:#e6db74&#34;&gt;&amp;#34;d2463ccc52075674effbad1b1ea5ae9a9c8106f1...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pub&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;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(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hashlib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sha256(str(key)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;))&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;digest(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AES&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;MODE_CBC,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    iv&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;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;plaintext &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cipher&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decrypt(ciphertext)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(plaintext)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, drumroll&amp;hellip;
&lt;code&gt;b&#39;ictf{Would_number_theory_be_new_technology?}\x04\x04\x04\x04&#39;&lt;/code&gt;!
For good practice, let&amp;rsquo;s clean that up a bit by removing the padding and
turning it back into a unicode string:&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:#f92672&#34;&gt;from&lt;/span&gt; Crypto.Util.Padding &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; unpad
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(unpad(plaintext, &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And there we have it!&lt;/p&gt;
&lt;div class=&#34;alert alert-success&#34; role=&#34;alert&#34; data-dir=&#34;ltr&#34;&gt;Flag: &lt;code&gt;ictf{Would_number_theory_be_new_technology?}&lt;/code&gt;&lt;/div&gt;
&lt;h2 id=&#34;thanks&#34;&gt;Thanks&lt;/h2&gt;
&lt;p&gt;Thank you to my team for a friendly place to be the dumbest person in the room,
and to the ImaginaryCTF platform folks and challenge developers for the
interesting and challenging &amp;hellip; challenges.&lt;/p&gt;
&lt;p&gt;The header image is from the ImaginaryCTF 2021 site (&lt;a href=&#34;https://github.com/et3rnos/imaginaryctf&#34;&gt;repo&lt;/a&gt;),
used with permission from Astro.&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&amp;rsquo;ve taken some liberties with the order I present objectives here,
since a writeup that followed my actual path would be impossible to follow.&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/imaginaryctf-2021/ictf-2021-banner.jpg" medium="image"><media:title type="html">featured image</media:title></media:content>
        
        <media:content url="https://sec.gd/blog/images/imaginaryctf-2021/ictf-2021-banner.jpg" medium="image"><media:title type="html">meta image</media:title></media:content>
        
          
            
              <category>imaginaryctf</category>
            
          
            
              <category>crypto</category>
            
          
            
              <category>misc</category>
            
          
            
              <category>sysadmin</category>
            
          
        
        
          
            
              <category>ctf</category>
            
          
        
        
      </item>
      
      <item>
        <title>Minimally-Invasive Smart Outlet Surgery</title>
        <link>https://sec.gd/blog/en/posts/smart-outlet-hacking/</link>
        <pubDate>Fri, 25 Jun 2021 04:49:17 +0000</pubDate>
        <author>mal@sec.gd (mal)</author>
        <atom:modified>Fri, 25 Jun 2021 04:49:17 +0000</atom:modified>
        <guid>https://sec.gd/blog/en/posts/smart-outlet-hacking/</guid>
        <description>&lt;p&gt;I have several &lt;a href=&#34;https://smile.amazon.com/gp/product/B07DCJ7TDR/&#34;&gt;EFUN SH331W&lt;/a&gt;
smart outlets for controlling various lights. They&amp;rsquo;re based on a whitelabel
ESP8266 design by Tuya, so I usually use &lt;a href=&#34;https://github.com/ct-Open-Source/tuya-convert&#34;&gt;tuya-convert&lt;/a&gt;
to flash them with &lt;a href=&#34;https://tasmota.github.io/&#34;&gt;Tasmota&lt;/a&gt; so I can control them
with MQTT. Unfortunately tuya-convert is a rather tedious and error-prone
process, and recently I managed to soft-brick one.&lt;/p&gt;</description>
        <content:encoded>&lt;p&gt;I have several &lt;a href=&#34;https://smile.amazon.com/gp/product/B07DCJ7TDR/&#34;&gt;EFUN SH331W&lt;/a&gt;
smart outlets for controlling various lights. They&amp;rsquo;re based on a whitelabel
ESP8266 design by Tuya, so I usually use &lt;a href=&#34;https://github.com/ct-Open-Source/tuya-convert&#34;&gt;tuya-convert&lt;/a&gt;
to flash them with &lt;a href=&#34;https://tasmota.github.io/&#34;&gt;Tasmota&lt;/a&gt; so I can control them
with MQTT. Unfortunately tuya-convert is a rather tedious and error-prone
process, and recently I managed to soft-brick one.&lt;/p&gt;
&lt;p&gt;Recovery for some devices is easy, you follow the normal
&lt;a href=&#34;https://tasmota.github.io/docs/Getting-Started/&#34;&gt;Tasmota install instructions&lt;/a&gt;:
Pop it open, connect TX, RX, GPIO0 to ground, GND, and 3.3v. When GPIO0
(aka pin IO0) is pulled down the ESP boots to flashing mode, and you can use
&lt;a href=&#34;https://github.com/espressif/esptool&#34;&gt;esptool&lt;/a&gt; to flash tasmota directly.&lt;/p&gt;
&lt;p&gt;Opening this device is less than straightforward — it&amp;rsquo;s a sealed plastic
shell, and even with the most careful disassembly it would be pretty annoying
to glue back together.&lt;/p&gt;
&lt;p&gt;On the other hand, it would be a shame to have to toss a device that&amp;rsquo;s only &lt;em&gt;soft&lt;/em&gt;-bricked&amp;hellip;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s use another one with bad flash memory&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; to see what&amp;rsquo;s going on inside.&lt;/p&gt;
&lt;h2 id=&#34;investigatory-dissection&#34;&gt;Investigatory Dissection&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Or vivisection, I guess?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After a lot of careful cutting and prying around the edges of the unit, and a
small blood sacrifice&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, the innards were revealed. The ESP is its own
module, sticking up from the main board, with all of the contacts we need
hiding between the main board and the plastic back of the unit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/smart-outlet-hacking/esp-module.jpg&#34; alt=&#34;ESP module on board&#34;&gt;&lt;/p&gt;
&lt;p&gt;The module EFUN used is an &lt;a href=&#34;https://fccid.io/2AKBPESP8266-S3/User-Manual/User-Manual-3594791&#34;&gt;ESP8266-S3&lt;/a&gt;
by Hysiry. We need access to pins 7 (IO0/GPIO0) to pull down for flashing
mode, 11 and 12 (URXD/UART0_RXD, UTXD/UART0_TXD) for communication, and 13
and 14 (VCC/VDD, GND) for power. On many devices GPIO0 is connected to the
external button, but the &lt;a href=&#34;https://templates.blakadder.com/efun_SH331W.html&#34;&gt;Tasmota template&lt;/a&gt;
for this device shows it&amp;rsquo;s used by a status LED instead.&lt;/p&gt;
&lt;p&gt;At this point I drilled five small holes in the plastic, expecting to stick
jumper wires through to touch the solder joints for the module. After spending
far too much time trying to hold all five in place with one hand while typing
&lt;code&gt;picocom&lt;/code&gt; commands with the other, I gave up and desoldered the board from
the mains pins so I could add wires.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/smart-outlet-hacking/board-back.jpg&#34; alt=&#34;Bottom of circuit board with five fine wires soldered on&#34;&gt;
&lt;img src=&#34;../../../images/smart-outlet-hacking/board-front.jpg&#34; alt=&#34;Top of circuit board with wires coming from underneath&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now able to make a reliable physical connection, it was time to find several
hundred ways not to communicate with it. To make a long story short, the
&lt;a href=&#34;https://www.sparkfun.com/products/12942&#34;&gt;bus pirate&lt;/a&gt; continues its legacy of
technically working and being just helpful enough to not warrant replacing.&lt;/p&gt;
&lt;p&gt;It seems the ESP, at least at this clock speed, uses a baudrate of 74880.
This isn&amp;rsquo;t one the bus pirate offers, so I had to use the &amp;ldquo;BRG raw value&amp;rdquo; option.&lt;/p&gt;
&lt;p&gt;BRG refers to the PIC Baud Rate Generator and the register used to configure
it. It&amp;rsquo;s described in section 17.1 of the
&lt;a href=&#34;https://ww1.microchip.com/downloads/en/devicedoc/39881e.pdf&#34;&gt;PIC24FJ64GA datasheet&lt;/a&gt;.
So for this bus pirate&amp;rsquo;s microcontroller, clock frequency, and firmware that
uses BRGH=1, &lt;code&gt;brg=(4000000/baudrate)-1&lt;/code&gt;, so for 74880 baud we use a BRG of 52.&lt;/p&gt;
&lt;h2 id=&#34;connecting&#34;&gt;Connecting&lt;/h2&gt;
&lt;p&gt;For wiring, use the bus pirate&amp;rsquo;s GND to pin 7 and either pin 14 or the neutral
prong, 3V3 to pin 13, MOSI to pin 11, and MISO to pin 12. &lt;strong&gt;Do not connect mains power.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The final incantation for the bus pirate:&lt;br&gt;
&lt;code&gt;$ picocom -b 115200 /dev/ttyUSB0&lt;/code&gt;&lt;br&gt;
&lt;code&gt;b&lt;/code&gt; to change host&amp;lt;-&amp;gt;bp baudrate&lt;br&gt;
&lt;code&gt;10&lt;/code&gt; for &amp;ldquo;BRG raw value&amp;rdquo;&lt;br&gt;
&lt;code&gt;52&lt;/code&gt; for 74880 baud&lt;br&gt;
&lt;code&gt;Ctrl+a Ctrl+b 74880&lt;/code&gt; to set picocom&amp;rsquo;s baudrate&lt;br&gt;
&lt;code&gt;m&lt;/code&gt; to change the bp&amp;lt;-&amp;gt;device mode&lt;br&gt;
&lt;code&gt;2&lt;/code&gt; for UART&lt;br&gt;
&lt;code&gt;10&lt;/code&gt; for &amp;ldquo;BRG raw value&amp;rdquo;&lt;br&gt;
&lt;code&gt;52&lt;/code&gt; for 74880 baud&lt;br&gt;
Default data bits and parity, stop bits, and receive polarity (8N1, Idle 1)&lt;br&gt;
&lt;code&gt;2&lt;/code&gt; for &amp;ldquo;Normal (H=3.3V, L=GND)&amp;rdquo; output&lt;br&gt;
&lt;code&gt;W&lt;/code&gt; to enable the power supply&lt;br&gt;
&lt;code&gt;(1)&lt;/code&gt; to start transparent bridge mode&lt;/p&gt;
&lt;p&gt;You should then be able to see a bootloader message when removing and
replacing power for the device. You can exit picocom with &lt;code&gt;Ctrl+a Ctrl+q&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With picocom closed, you can use &lt;code&gt;esptool&lt;/code&gt; to communicate with the ESP.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test communication:&lt;br&gt;
&lt;code&gt;esptool -p /dev/ttyUSB0 --chip esp8266 -b 74880 read_mac&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Flash tasmota (tasmota.bin from the &lt;a href=&#34;https://github.com/arendst/Tasmota/releases&#34;&gt;releases page&lt;/a&gt;)&lt;br&gt;
&lt;code&gt;esptool -p /dev/ttyUSB0 --chip esp8266 -b 74880 write_flash -e -fs 1MB -fm dout 0x0 tasmota.bin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/smart-outlet-hacking/wires.jpg&#34; alt=&#34;Bus pirate connected to vivisection subject&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-living-patient&#34;&gt;The Living Patient&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;It&amp;rsquo;s go time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that I can directly flash the sacrificial device, it&amp;rsquo;s time to set up the
one I hope to save.&lt;/p&gt;
&lt;p&gt;Even knowing I was communicating with the ESP correctly, I wasn&amp;rsquo;t particularly
excited about holding jumper wires in place. I realized I could reduce the
number of wires I needed by one if I could connect to the mains neutral
instead of the ESP&amp;rsquo;s ground contact, which worked. I also decided to use hot
pins to poke through the plastic, since sufficiently precise pin placement
would mean minimal manual holding.&lt;/p&gt;
&lt;p&gt;The only ESP module information I could find gave exactly one relevant
measurement, that the edge connector was 16.4mm. Calipers provided the rest&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Based on these measurements, I needed pins at the following locations:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;pin&lt;/th&gt;
          &lt;th&gt;mm from plug end&lt;/th&gt;
          &lt;th&gt;mm from ground side&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;GPIO0&lt;/td&gt;
          &lt;td&gt;22.45&lt;/td&gt;
          &lt;td&gt;5.65&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;UTXD&lt;/td&gt;
          &lt;td&gt;27.50&lt;/td&gt;
          &lt;td&gt;7.90&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;URXD&lt;/td&gt;
          &lt;td&gt;27.50&lt;/td&gt;
          &lt;td&gt;5.65&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;VCC&lt;/td&gt;
          &lt;td&gt;30.02&lt;/td&gt;
          &lt;td&gt;5.65&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Lastly, GND connects to neutral, the flat prong farther from the button.&lt;/p&gt;
&lt;p&gt;I measured with calipers, marked the grid with a knife, held each pin with
pliers above a lighter to heat them until they glowed, and stuck them straight
down at each location.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;One ended up a bit off-vertical, so I bent the pin in the other direction and
reinserted it. Two more had plastic or soot on the tip, so those needed to be
pulled, cleaned, and reinserted. Finally, with all the leads attached and
gentle pressure on the pinheads&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/smart-outlet-hacking/under-the-knife.jpg&#34; alt=&#34;Partly-living smart outlet with pins and alligator clips connected&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt; ets Jan  8 2013,rst cause:1, boot mode:(1,0)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It lives! Disconnect picocom, run esptool, and&amp;hellip;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Wrote 473856 bytes (328288 compressed) at 0x00000000 it 44.8 seconds (effective 84.6 kbit/s)...
Hash of data verified.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pull the pins off, plug it in, and!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;../../../images/smart-outlet-hacking/tasmota-ssid.png&#34; alt=&#34;Screenshot of tasmota SSID connected on phone&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I spent several afternoons saving a $5 smart outlet.
And then too long (in both words and time) writing it up, but I&amp;rsquo;m trying to
document more stuff I do on the off chance some part of it ends up being
useful to someone. Half the time that someone is just me, six months later.&lt;/p&gt;
&lt;p&gt;This is probably also not the best idea from a standpoint of not lighting
things on fire - it&amp;rsquo;s doing things that weren&amp;rsquo;t meant to be done to a device
that controls up to 20 amps at 120 volts. Your device may also not be
identical to mine. Attempting to follow these steps may break your smart
outlet, make it burn your house down, or call your dog a bad girl, and I
accept no responsibility for any of it.&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;It pretends to work fine, but forgets its settings about once a week.
Useful for this, since I can test flashing but don&amp;rsquo;t feel bad about destroying it.&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;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;If you don&amp;rsquo;t have the right tool handy, just go find it.&amp;#160;&lt;a href=&#34;#fnref:2&#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;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;1.25mm plastic wall above ledge, 3mm plug side board inset, 10mm from
board edge to ESP module connector edge, 20.85mm from ESP module other end to
other board end, 4mm button side board inset, 1.25mm wall. Sum of 56.75mm,
measured size is 57mm - not bad. From the ground side, 1.25mm wall, 1.65mm
board inset, module 2.75mm from board edge.&amp;#160;&lt;a href=&#34;#fnref:3&#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;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;No blood sacrifice was demanded at this step, but I still should have
gone and dug out the pliers &lt;em&gt;before&lt;/em&gt; the first mild burn.&amp;#160;&lt;a href=&#34;#fnref:4&#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/smart-outlet-hacking/thumbnail.jpg" medium="image"><media:title type="html">featured image</media:title></media:content>
        
        <media:content url="https://sec.gd/blog/images/smart-outlet-hacking/under-the-knife.jpg" medium="image"><media:title type="html">meta image</media:title></media:content>
        
          
            
              <category>fixed</category>
            
          
            
              <category>esp8266</category>
            
          
            
              <category>smart home</category>
            
          
            
              <category>hardware</category>
            
          
            
              <category>embedded</category>
            
          
        
        
        
      </item>
      

    
  </channel>
</rss>
