<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en_US"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://rickmark.me/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rickmark.me/" rel="alternate" type="text/html" hreflang="en_US" /><updated>2026-10-05T22:27:14+00:00</updated><id>https://rickmark.me/blog/feed.xml</id><title type="html">Rick Mark</title><subtitle>Rick Mark-Penwell writes about Apple platform security, firmware and hardware research, privacy, and fabrication.</subtitle><author><name>Rick Mark-Penwell</name></author><entry><title type="html">Industrial Strength: MakerBot Method X Carbon Fiber</title><link href="https://rickmark.me/blog/industrial-strength-makerbot-method-x-carbon-fiber/" rel="alternate" type="text/html" title="Industrial Strength: MakerBot Method X Carbon Fiber" /><published>2025-11-28T11:18:05+00:00</published><updated>2025-11-28T11:18:05+00:00</updated><id>https://rickmark.me/blog/industrial-strength-makerbot-method-x-carbon-fiber</id><content type="html" xml:base="https://rickmark.me/blog/industrial-strength-makerbot-method-x-carbon-fiber/"><![CDATA[<h3 id="beyond-prototyping">Beyond Prototyping</h3>

<p>When we need parts that can survive a 100mph car chase or support a heavy cinema camera, standard plastic won’t cut it. Enter the <strong>MakerBot Method X CF</strong>.</p>

<h3 id="carbon-fiber-composite">Carbon Fiber Composite</h3>

<p>The Method X prints with Nylon Carbon Fiber, yielding parts with a superior strength-to-weight ratio. We use this machine to fabricate:</p>

<ul>
  <li>Custom lens supports and matte boxes.</li>
  <li>Mounting brackets for our robotic arms.</li>
  <li>Drone replacement chassis parts.</li>
</ul>

<h3 id="heated-chamber-accuracy">Heated Chamber Accuracy</h3>

<p>Unlike open-frame printers, the Method X features a 110°C heated chamber. This ensures dimensional accuracy on large ABS and Nylon prints, preventing warping. This allows us to print interlocking mechanical assemblies that fit perfectly off the build plate.</p>]]></content><author><name>Rick Mark-Penwell</name></author><category term="LoveWins" /><summary type="html"><![CDATA[Beyond Prototyping When we need parts that can survive a 100mph car chase or support a heavy cinema camera, standard plastic won't cut it. Enter the MakerBot Method X CF. Carbon Fiber Composite The Method X prints with Nylon Carbon Fiber, yielding parts with a superior strength-to-weight ratio. We use…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rickmark.me/assets/images/industrial-strength-makerbot-method-x-carbon-fiber/method_x_-_hero_1_1.png" /><media:content medium="image" url="https://rickmark.me/assets/images/industrial-strength-makerbot-method-x-carbon-fiber/method_x_-_hero_1_1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Kinematics in Focus: Edelkrone Ecosystem</title><link href="https://rickmark.me/blog/kinematics-in-focus-edelkrone-ecosystem/" rel="alternate" type="text/html" title="Kinematics in Focus: Edelkrone Ecosystem" /><published>2025-11-28T11:15:25+00:00</published><updated>2025-11-28T11:15:25+00:00</updated><id>https://rickmark.me/blog/kinematics-in-focus-edelkrone-ecosystem</id><content type="html" xml:base="https://rickmark.me/blog/kinematics-in-focus-edelkrone-ecosystem/"><![CDATA[<h3 id="orchestrating-movement">Orchestrating Movement</h3>

<p>In high-end product cinematography, static shots feel dead. To bring a watch, a phone, or a beverage to life, the camera must dance around it with absolute precision. This is where our <strong>Edelkrone</strong> motion control suite takes center stage.</p>

<h3 id="the-4-axis-advantage">The 4-Axis Advantage</h3>

<p>We utilize a synchronized setup featuring the <strong>HeadPLUS</strong>, <strong>SliderPLUS</strong>, <strong>DollyPLUS</strong> and the <strong>JibPLUS</strong>. This combination allows us to program complex 4-axis movements (pan, tilt, slide, and jib) that are perfectly repeatable.</p>

<h3 id="why-repeatability-matters">Why Repeatability Matters</h3>

<p>The magic of kinematics isn’t just smoothness; it’s consistency. For visual effects, we often need to shoot a product in multiple lighting passes or with different background elements. The Edelkrone system executes the exact same camera path every time, allowing us to composite these layers seamlessly in post-production for that “impossible” look.
Whether it’s a macro shot entering a coffee cup or a dynamic reveal of a new tech gadget, this robotics stack ensures every frame is pixel-perfect.</p>]]></content><author><name>Rick Mark-Penwell</name></author><category term="LoveWins" /><summary type="html"><![CDATA[Orchestrating Movement In high-end product cinematography, static shots feel dead. To bring a watch, a phone, or a beverage to life, the camera must dance around it with absolute precision. This is where our Edelkrone motion control suite takes center stage. The 4-Axis Advantage We utilize a synchronized setup featuring…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rickmark.me/assets/images/kinematics-in-focus-edelkrone-ecosystem/see_all_BUNDLE.jpg.webp" /><media:content medium="image" url="https://rickmark.me/assets/images/kinematics-in-focus-edelkrone-ecosystem/see_all_BUNDLE.jpg.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Next-Gen Fabrication: FormLabs Form 4</title><link href="https://rickmark.me/blog/next-gen-fabrication-formlabs-form-4/" rel="alternate" type="text/html" title="Next-Gen Fabrication: FormLabs Form 4" /><published>2025-11-28T11:08:39+00:00</published><updated>2025-11-28T11:08:39+00:00</updated><id>https://rickmark.me/blog/next-gen-fabrication-formlabs-form-4</id><content type="html" xml:base="https://rickmark.me/blog/next-gen-fabrication-formlabs-form-4/"><![CDATA[<h3 id="speed-without-compromise">Speed Without Compromise</h3>

<p>Time is the most valuable asset in production. The <strong>FormLabs Form 4</strong> utilizes a new Low Force Display™ (LFD) print engine that drastically reduces print times compared to the Form 3 series. We are seeing print speeds up to 5 times faster, meaning a prop requested in the morning is ready for painting by lunch.</p>

<p>The ultra-fast draft printing allows for multiple iterations on a design in a day before moving to a more final finish, speciality or other process. As an example we can draft print until the design in perfect then mass produce in custom color resin or move to Carbon Fiber or Chrome Molly and even Stainless Steel on the <strong>Makerbot Method X</strong>!</p>

<h3 id="material-versatility">Material Versatility</h3>

<p>The Form 4’s ability to switch tailored resins allows us to print:</p>

<ul>
  <li>Clear (Yes Transparent) resin can be polished to near optical grade</li>
  <li>Flexible and Elastic</li>
  <li>Custom Color</li>
  <li>Ultra High Durability and Strength</li>
</ul>

<p>On top of all of this, generally the amount of waste resin is low (the “rafts”). Because of the method of printing some amount of “post processing” must be performed to achieve the final part:</p>

<ul>
  <li>Breaking away supports and sanding / removing support joints</li>
  <li>“Washing” with Isopropyl alcohol to remove excess resin</li>
  <li>A final high temp / UV cure phase</li>
</ul>

<h3 id="incredible-reliability">Incredible Reliability</h3>

<p>The number of print failures encountered in hundreds of hours of usage is one. Just one… And to be honest, it was probably the operator (Rick Mark)’s fault. This is unbelievable compared to traditional FDM printing and in fact its so reliable we basically always use it for validation of parts before sending to the Makerbot Method X.</p>]]></content><author><name>Rick Mark-Penwell</name></author><category term="LoveWins" /><summary type="html"><![CDATA[Speed Without Compromise Time is the most valuable asset in production. The FormLabs Form 4 utilizes a new Low Force Display™ (LFD) print engine that drastically reduces print times compared to the Form 3 series. We are seeing print speeds up to 5 times faster, meaning a prop requested in…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rickmark.me/assets/images/next-gen-fabrication-formlabs-form-4/Form-4-Basic-Package_03.png" /><media:content medium="image" url="https://rickmark.me/assets/images/next-gen-fabrication-formlabs-form-4/Form-4-Basic-Package_03.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Reality Capture: Revopoint Miraco &amp;amp; MetroX Workflow</title><link href="https://rickmark.me/blog/reality-capture-revopoint-miraco-metrox-workflow/" rel="alternate" type="text/html" title="Reality Capture: Revopoint Miraco &amp;amp; MetroX Workflow" /><published>2025-11-28T10:49:13+00:00</published><updated>2025-11-28T10:49:13+00:00</updated><id>https://rickmark.me/blog/reality-capture-revopoint-miraco-metrox-workflow</id><content type="html" xml:base="https://rickmark.me/blog/reality-capture-revopoint-miraco-metrox-workflow/"><![CDATA[<h3 id="the-new-standard-in-portable-scanning">The New Standard in Portable Scanning</h3>

<p>At Lumina, mobility meets precision. The <strong>Revopoint Miraco</strong> has revolutionized our on-set workflows. Unlike traditional scanners requiring tethered laptops, the Miraco is a standalone unit. This allows our team to crawl into tight spaces—vehicle interiors, set pieces, and complex organic structures—to capture data without cabling constraints.</p>

<p>In addition, the <strong>Photogrammetric Metrology Kit</strong> allows for scanning full size objects such as vehicles for later use in VR or CGI effects by getting accurate scans with dimensional accuracy.</p>

<h3 id="metrox-when-microns-matter">MetroX: When Microns Matter</h3>

<p>For small, intricate parts requiring sub-millimeter accuracy, we deploy the <strong>Revopoint MetroX</strong>. Its hybrid blue laser technology cuts through reflective surfaces that baffle standard infrared scanners. We use it extensively for:</p>

<ul>
  <li>Reverse engineering parts for jigs and duplication</li>
  <li>Scanning actors’ faces for digital double creation with high-fidelity texture maps.</li>
  <li>Quality control verification on prop fabrication.</li>
</ul>

<p>By combining the Miraco’s large-volume capture with the MetroX’s fine detail, we create a complete digital twin pipeline.</p>]]></content><author><name>Rick Mark-Penwell</name></author><category term="LoveWins" /><summary type="html"><![CDATA[The New Standard in Portable Scanning At Lumina, mobility meets precision. The Revopoint Miraco has revolutionized our on-set workflows. Unlike traditional scanners requiring tethered laptops, the Miraco is a standalone unit. This allows our team to crawl into tight spaces—vehicle interiors, set pieces, and complex organic structures—to capture…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://rickmark.me/assets/images/reality-capture-revopoint-miraco-metrox-workflow/images.jpeg" /><media:content medium="image" url="https://rickmark.me/assets/images/reality-capture-revopoint-miraco-metrox-workflow/images.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">About ‘WIP’</title><link href="https://rickmark.me/blog/about-wip/" rel="alternate" type="text/html" title="About ‘WIP’" /><published>2024-11-30T09:50:19+00:00</published><updated>2024-11-30T09:50:19+00:00</updated><id>https://rickmark.me/blog/about-wip</id><content type="html" xml:base="https://rickmark.me/blog/about-wip/"><![CDATA[<p>Yes, I have ADHD, and so I’ve made the decision to publish early and publish often. You might see articles prefixed with <code class="language-plaintext highlighter-rouge">WIP: </code> (Work in Progress) and those will later be replaced by polished version. This is because I’ve made the decision there’s enough value to make my notes available even if it’s not yet complete.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Yes, I have ADHD, and so I've made the decision to publish early and publish often. You might see articles prefixed with `WIP: ` (Work in Progress) and those will later be replaced by polished version. This is because I've made the decision there's enough value to make my notes available…]]></summary></entry><entry><title type="html">WIP: How did PKI become a joke?</title><link href="https://rickmark.me/blog/wip-how-did-pki-become-a-joke/" rel="alternate" type="text/html" title="WIP: How did PKI become a joke?" /><published>2024-11-30T09:48:06+00:00</published><updated>2024-11-30T09:48:06+00:00</updated><id>https://rickmark.me/blog/wip-how-did-pki-become-a-joke</id><content type="html" xml:base="https://rickmark.me/blog/wip-how-did-pki-become-a-joke/"><![CDATA[<h3 id="tldr">tl;dr</h3>

<p>If your system asks you to both upload a certificate and a private key, or it generates a CSR (certificate signing request) and also gives you the private key, you’re doing PKI wrong…</p>

<p>Also don’t laugh - but this commentary is directly opposed to goals of US national security, but I’ve lived through that being used inappropriately. - signed, Mark</p>

<h1 id="terms">Terms</h1>

<ul>
  <li>PKI - Public Key Cryptography</li>
  <li>CSR - Certificate Signing Request</li>
  <li>Private Key - The key material that matches the public key in a given CSR or Certificate</li>
  <li>CA - Certification Authority - a trusted issuer of certificates</li>
  <li>Public Key Algorithm - the particular mathematical basis for PKI, in practice either RSA (very common) or ECC (elliptical curve, less supported but better). Finally ECDSA or DSA - signature only - not common in TLS.</li>
  <li>PEM - Privacy Enhanced Mail - A form of encoding a private key or certificate in base64 to prevent non-printing or non-copy paste characters for reasons of portability</li>
  <li>BER / DER - Basic Encoding Rules  / Distinguished Encoding Rules - The binary version in ASN.1 for a certificate or private key. Follows rules such as PKCS but often encoded via PEM for ease.</li>
  <li>“Self Signed” - A certificate that is in its own right a CA (Overly simplistic as CA’s also require the extended attribute to become issuers). These are very common in appliances such as the Synology which issues it’s own certificate until a replacement is made.</li>
</ul>

<h1 id="the-beef">The Beef…</h1>

<p>Any system that requires you to both upload the private key material, as well as the certificate is doing PKI wrong. This is because in a PKI system, the private key material is truly private to the system that will use it. If you generate this material on your laptop then upload it, well, your laptop and any virus or MDM also saw that key. Moreover, most truly secure systems such as the TPM or an HSM do not export this material. This means that if you upload this key, it’s not likely to be hardware backed.</p>

<h2 id="the-culprits">The Culprits</h2>

<ul>
  <li>Synology - Synology allows you to upload a key as well as the certificate, but when you go to use the advanced option of “Generate CSR”, you’re placed into the funny scenario of having it be “almost right”. The resulting CSR includes the private key, making the CSR process as pointless as could be. 2/10 stars. Got CSR, failed by providing key.</li>
  <li>Ubiquity - uhgh - BUT LET ME TELL YOU WHY! - (don’t get it twisted, I still run their equipment because at the price point it’s the best - but if I had Cisco money…)
    <ul>
      <li>EVERY device they sell ought have a full TPM or similar concept. Majority of their network stack depends on shared authentication keys. If I had a magic wand</li>
      <li>They blew uBoot - and still won’t disclose their GPL required source.
        <ul>
          <li>They permit a RSA exponent of <code class="language-plaintext highlighter-rouge">0</code> in some devices, and anything raised to zero is… This led to a huge amount of boot time persistent malware that ends up being RMAs that don’t get diagnosed.</li>
          <li>You cannot generate a CSR even from the top of the line Enterprise Fortress Gateway</li>
          <li>If I were them, I’d permit RADIUS and Unifi &lt;-&gt; Unifi devices to use 802.2x with PKI (TLS/TTLS etc) or IPv6 / IPSec based transits. Instead yo get a cheep in-the-clear bearer approach.
            <ul>
              <li>They own the hardware, they can surely embed a Ubiquity ICA (Intermediate CA) cert into PROM (program once ROM) in every device that proves authentic Ubiquity devices.</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>IoT / Anything with Poor Algorithm Support - These are usually devices that support “TLS” but haven’t been updated in a dog’s age. (anyone know how long that phrase means?). These devices do not support upload of a Root CA to permit DPI (deep packet inspection) nor do they support modern key lengths or algorithms. Almost any system gives you a dropdown of RSA lengths from <code class="language-plaintext highlighter-rouge">1024</code>/<code class="language-plaintext highlighter-rouge">2048</code>/<code class="language-plaintext highlighter-rouge">4096</code> - but the truth is it could be a dropdown with an input permitting longer key lengths to provide longevity. Frequently worse yet, these systems are using <code class="language-plaintext highlighter-rouge">nginx</code> and <code class="language-plaintext highlighter-rouge">openssl</code> to do the work, so they are artificially restricting the choices that could produce better security.</li>
</ul>

<h2 id="the-heros">The Heros</h2>

<ul>
  <li>Yubikeys and YubiHSMs provide the ability to provide key attestation. This means there’s a cryptographic way for</li>
  <li>LetsEncrypt - Let’s Encrypt will never accept nor generate a private key. This is the definition of doing PKI right. It receives a CSR, and then upon domain validation issues a (relatively short lived for good reason) certificate.</li>
</ul>

<h2 id="the-anti-heros">The Anti-Heros</h2>

<ul>
  <li>Apple - For a company whose brand is security and privacy to get this SO CLOSE and yet fail is heartbreaking. The SEP permits hardware backed keys, but ONLY if they are <code class="language-plaintext highlighter-rouge">scep256k1</code> (which I’ll admit is a great curve and choice!). There’s no good reason that RSA nor other curves are supported, nor better support for key attestation. (in fact they do such key attestation for a number of other functions such as SIM move as well as iCloud login - find this under</li>
</ul>

<h1 id="recommendations">Recommendations</h1>

<h2 id="internal-use-only-certificates">Internal Use Only Certificates</h2>

<p>The scheme to extend a certificate is pretty common. All that needs be done is an issuance of a new OID (Object Identifier) and my proposal is for two new OIDs</p>

<ul>
  <li>Internal Use Only - A boolean in certificates meaning that they are to be issued and trusted only by origination. This allows for certificates that are clearly distinguished to be trusted by one org vs the world. This bisects the problem of certificates being ambiguous between public internet trust and internal trust. Each IUOU cert should also include a provable “realm” such as the DNS name of the org for which it is applicable.</li>
  <li>Realm - A way to indicate a sphere of control of IUOU. This permits one orgs IUOU to be segmented from another organizations IUOU.</li>
  <li>rDNS Purpose - Instead of requiring a company to register an OUI, we can use reverse DNS names to indicate intended usage. This may be <code class="language-plaintext highlighter-rouge">com.splunk.indexer.forward</code> to indicate the HTTPS endpoint is for forwarding data. This is backward compatible and can be restricted by a SNI (TLS server name indication) like restriction from a certificate to its use in context.</li>
</ul>

<h2 id="key-generation-indicators">Key Generation Indicators</h2>

<ul>
  <li>Inclusion of OUIs for hardware backed, key-never, etc.</li>
  <li>Unwrapping - A new EKU. Unwrapping certificates are used to indicate that the TLS connection is to a dutiful Deep Packet Inspection (DPI) device. These certificates are valid certificates issued to a DPI root CA, but include additional details such as the true certificate. This assists with schemes such as CT (Certificate Transparency) as well as user consent (“The connection is monitored by ‘Some Company Inc’”). This also allows for certificate pinning and DPI to coexist by permitting CT and pinning to occur against the original certificate and chain.</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[tl;dr If your system asks you to both upload a certificate and a private key, or it generates a CSR (certificate signing request) and also gives you the private key, you're doing PKI wrong... Also don't laugh - but this commentary is directly opposed to goals of US national…]]></summary></entry><entry><title type="html">Knowing what you don’t know…</title><link href="https://rickmark.me/blog/knowing-what-you-dont-know/" rel="alternate" type="text/html" title="Knowing what you don’t know…" /><published>2024-10-27T04:30:21+00:00</published><updated>2024-10-27T04:30:21+00:00</updated><id>https://rickmark.me/blog/knowing-what-you-dont-know</id><content type="html" xml:base="https://rickmark.me/blog/knowing-what-you-dont-know/"><![CDATA[<p>Log Rotate, NTP, and how to cover your tracks as an attacker…</p>

<p>It’s not really common knowledge but basically anyone on your network can wipe your logs (security and forensic in many cases).</p>

<p>Almost every modern computer does two things… it uses NTP to get the current date and time, and it rotates log files to prevent a continuous growth of log files on disk that consume all available space. Most of the time this is handled by or called “log rotating” - it often compresses old logs, and deletes older still logs. These two facets can be combined to cover one’s tracks like so…</p>

<p>Imagine I’ve accessed a machine via SSH for a known password for a user, but I do not have root access so my connection would be logged by sshd. Now this is a tell tale sign that compromise has occurred, and therefore puts an attacker at risk. Also imagine that an EoP isn’t desirable to delete said logs.</p>

<p>The simple answer is if you exist in a point of privilege (same network segment where APR or ARP poison routing, live on the router or control the DNS server) it becomes possible to spoof NTP. This is because NTP is a fundamentally insecure protocol (yes there are more secure derivations but these are not well adopted). Now to combine these two details…</p>

<p>If I act as the NTP server, and give an absurdly past or in some cases future time, wait for the victim to query for the time, and then perform my attack, I can leverage logrotated to clean up the logs for me.</p>

<p>This is because the logs would be too old to retain and therefore logrotate would do its job and destroy the evidence. This is even useful as a method of persistence because a change to log rotates config to delete files over 10 years would go unnoticed, since an admin wouldn’t worry of such occurrences.</p>

<p>Now, some implementations of NTP are smart enough to forgo a time shift that is wildly different from the RTC (real time clock). This only works on platforms with a battery and therefore doesn’t work well in embedded systems or Raspberry Pis. Also many times all that is required is either a CMOS reset or the leveraging of any defect that causes a checksum failure of the CMOS triggering such a reset, clearing the clock, which…. then will happily use the provided NTP value!</p>

<p>There are some solutions though! Using a realtime SEIM or log shipping can prevent this by stamping the logs at time of receive, not the time of the machine of origin. Now don’t overly trust this because half the attacks (DNS/Router/APR) are just as capable of denial of service of your log system. In addition not all log shipping is realtime. If it’s scheduled such as nightly it may actually increase confidence in your logs but amplify the issue (they are in two places so must be accurate right??!?)</p>

<p>So, Rick, everything is broken… now what?</p>

<p>Well there’s a solution. By ensuring that logs are using a monotonic increasing counter in addition to the time of the event, we can ensure such “drop outs” are discovered. Additionally by making this counter strengthened by systems such as anti rollback, TEE / signature from enclaves such as the trust zone, TPM or Secure Enclave.</p>

<p>And further further…. a concept like a ZKRollup (zero knowledge rollup) can be used to effectively turn SEIM / logging events into a Merkle tree of hashes, (go ahead and roll your eyes… but yes - you can even place these ZKRollups onto the Ethereum blockchain via a smart contract)</p>

<p>So, know the limits of your logs, know that lack of evidence is not proof of a negative. Most good forensics isn’t finding a smoking gun in the log files but instead correlating log files from multiple systems looking for the signal from the missing or mismatched data.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Log Rotate, NTP, and how to cover your tracks as an attacker… It’s not really common knowledge but basically anyone on your network can wipe your logs (security and forensic in many cases). Almost every modern computer does two things… it uses NTP to get the current date and…]]></summary></entry><entry><title type="html">WIP: iCloud Keychain Poisoning</title><link href="https://rickmark.me/blog/wip-icloud-keychain-poisoning/" rel="alternate" type="text/html" title="WIP: iCloud Keychain Poisoning" /><published>2024-10-05T01:01:31+00:00</published><updated>2024-10-05T01:01:31+00:00</updated><id>https://rickmark.me/blog/wip-icloud-keychain-poisoning</id><content type="html" xml:base="https://rickmark.me/blog/wip-icloud-keychain-poisoning/"><![CDATA[<h1 id="tldr">tl;dr</h1>

<p>If a malicious device is able to join your iCloud keychain (such as a jailbroken iDevice or insecure macOS device) it can pre-populate keychain items with overly permissive or insecure properties.  This can be leveraged with reset tokens, auto and continuity unlock, and other apps to allow lateral movement and access to sessions and tokens.  This is further complicated by factory process and the ability to generate attested SE tokens which are a key part of the movement of secure material such as CarKey, ApplePay etc.</p>

<h1 id="a-history-lesson">A history lesson…</h1>

<p>The iCloud keychain is derived from various prior versions of key storage on the apple platform.  Early versions of the keychain were a flat keychain file, which had the private portions encrypted by the user’s login password.  When the user’s password was reset, often private data such as passwords and keys were lost since the key needed to decrypt them wasn’t provided.When the iPhone shipped, it brought along the keychain concept, and expanded upon it.  iOS devices added the concept of “protection classes” labeled A-D.  These permitted control of when the data was decrypted and available, and is enforced by using a similar method of key derivation from the passcode.  Keys for the level are escrowed with the SEP(the reason you need to enter your passcode at first unlock is this key is absent).The iPhone, and later the T2 and M series Macs inherited the SEP or secure enclave processor back from the iDevice world.  This provided these devices with new features such as non-extractable scep256k1 keys, end-to-end key attestation, and more.</p>

<h1 id="a-typical-secret-flow-upsert">A typical secret flow (upsert)</h1>

<p>Apple’s own documentation is illustrative of managing keychain items by means of searching for the item, and updating it should it exist, and creating it if it does not.</p>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/bbcd0469cd-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1722877954856_8396f76a-e21a-41c8-8aa6-05d1649ccac3.png" alt="" /></p>

<h2 id="variant-a---cloud-theft">Variant A - Cloud Theft</h2>

<p>The following is taken mostly from Apple’s own example code of working with the Keychain, but includes two subtle bugs (to be fair, Apple seems to have also been bit by the same defect!)</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">query</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                            <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                            <span class="n">kSecMatchLimit</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecMatchLimitOne</span><span class="p">,</span>
                            <span class="n">kSecReturnAttributes</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
                            <span class="n">kSecReturnData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">true</span><span class="p">]</span>

<span class="k">var</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">CFTypeRef</span><span class="p">?</span>
<span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemCopyMatching</span><span class="p">(</span><span class="n">query</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">item</span><span class="p">)</span>
<span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>

<span class="k">if</span> <span class="n">status</span> <span class="o">!=</span> <span class="n">errSecItemNotFound</span> <span class="p">{</span>
  <span class="k">let</span> <span class="nv">account</span> <span class="o">=</span> <span class="n">credentials</span><span class="o">.</span><span class="n">username</span>
  <span class="k">let</span> <span class="nv">password</span> <span class="o">=</span> <span class="n">credentials</span><span class="o">.</span><span class="n">password</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="kt">String</span><span class="o">.</span><span class="kt">Encoding</span><span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>
  <span class="k">var</span> <span class="nv">query</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                              <span class="n">kSecAttrAccount</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">account</span><span class="p">,</span>
                              <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                              <span class="n">kSecValueData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span>
                              <span class="n">kSecAttrSynchronizable</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
                              <span class="n">kSecAttrAccessible</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecAttrAccessibleWhenUnlockedThisDeviceOnly</span><span class="p">]</span>

  <span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemAdd</span><span class="p">(</span><span class="n">query</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
  <span class="k">guard</span> <span class="k">let</span> <span class="nv">existingItem</span> <span class="o">=</span> <span class="n">item</span> <span class="k">as?</span> <span class="p">[</span><span class="kt">String</span> <span class="p">:</span> <span class="kt">Any</span><span class="p">]</span>
  <span class="k">let</span> <span class="nv">updateQuery</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecMatchSearchList</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span><span class="p">]]</span>

  <span class="k">let</span> <span class="nv">attributes</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecAttrAccount</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">account</span><span class="p">,</span>
                                   <span class="n">kSecValueData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">password</span><span class="p">]</span>

  <span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemUpdate</span><span class="p">(</span><span class="n">updateQuery</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="n">attributes</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">)</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">!=</span> <span class="n">errSecItemNotFound</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="n">noPassword</span> <span class="p">}</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Did you spot them?  The first of the two bugs is <code class="language-plaintext highlighter-rouge">kSecMatchLimitOne</code>.  Apple’s code and common usage of this are counter intuitive.  It only limits to the first result, but what if two keychain entries match?  Well with the above code you would update one of them, but in a non-deterministic way.  By Apple’s own documentation, this isn’t easy to solve without a two phase fetch:</p>

<ul>
  <li>You can’t combine the <a href="https://developer.apple.com/documentation/security/ksecreturndata"><code class="language-plaintext highlighter-rouge">kSecReturnData</code></a> and <a href="https://developer.apple.com/documentation/security/ksecmatchlimitall"><code class="language-plaintext highlighter-rouge">kSecMatchLimitAll</code></a> options when copying password items, because copying each password item could require additional authentication. Instead, request a reference or persistent reference to the items, then request the data for only the specific passwords that you actually require.</li>
</ul>

<p>This means to properly search for any item, you must do a <code class="language-plaintext highlighter-rouge">kSecMatchLimitAll</code>, handle duplicates, and then get the Data element.The second bug is much worse…. The code above works great in the common case, but what if I have control of a MacBook that is syncing to your iCloud Keychain?  By inserting a keychain entry into the keychain with the server and account values I want to attack, and setting various attributes to less secure values, I can get secrets</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">account</span> <span class="o">=</span> <span class="n">victimAccount</span>
<span class="k">let</span> <span class="nv">server</span> <span class="o">=</span> <span class="s">"appleid.apple.com"</span>

<span class="k">var</span> <span class="nv">query</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                            <span class="n">kSecAttrAccount</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">account</span><span class="p">,</span>
                            <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                            <span class="n">kSecValueData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span>
                            <span class="n">kSecAttrSynchronizable</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
                            <span class="n">kSecAttrAccessible</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecAttrAccessibleAlways</span><span class="p">]</span>
</code></pre></div></div>

<p>This will insert a matching entry into the iCloud keychain, which will happily be synced since we set <code class="language-plaintext highlighter-rouge">kSecAttrSynchronizable</code> to true, and will be available back to the macOS device due to the lowering of the protection level to <code class="language-plaintext highlighter-rouge">kSecAttrAccessibleAlways</code>.  All the attacker needs do, is wait for the victim to use their iDevice and login to the account.</p>

<h2 id="variant-b---agressive-updates">Variant B - Agressive Updates</h2>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">query</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                            <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                            <span class="n">kSecMatchLimit</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecMatchLimitOne</span><span class="p">,</span>
                            <span class="n">kSecReturnAttributes</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
                            <span class="n">kSecReturnData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">true</span><span class="p">]</span>

<span class="k">var</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">CFTypeRef</span><span class="p">?</span>
<span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemCopyMatching</span><span class="p">(</span><span class="n">query</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">item</span><span class="p">)</span>
<span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>

<span class="k">if</span> <span class="n">status</span> <span class="o">!=</span> <span class="n">errSecItemNotFound</span> <span class="p">{</span>
  <span class="k">let</span> <span class="nv">account</span> <span class="o">=</span> <span class="n">credentials</span><span class="o">.</span><span class="n">username</span>
  <span class="k">let</span> <span class="nv">password</span> <span class="o">=</span> <span class="n">credentials</span><span class="o">.</span><span class="n">password</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="kt">String</span><span class="o">.</span><span class="kt">Encoding</span><span class="o">.</span><span class="n">utf8</span><span class="p">)</span><span class="o">!</span>
  <span class="k">var</span> <span class="nv">query</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                              <span class="n">kSecAttrAccount</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">account</span><span class="p">,</span>
                              <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                              <span class="n">kSecValueData</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span>
                              <span class="n">kSecAttrSynchronizable</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
                              <span class="n">kSecAttrAccessible</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecAttrAccessibleWhenUnlockedThisDeviceOnly</span><span class="p">]</span>

  <span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemAdd</span><span class="p">(</span><span class="n">query</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
  <span class="k">guard</span> <span class="k">let</span> <span class="nv">existingItem</span> <span class="o">=</span> <span class="n">item</span> <span class="k">as?</span> <span class="p">[</span><span class="kt">String</span> <span class="p">:</span> <span class="kt">Any</span><span class="p">]</span>

  <span class="k">guard</span> <span class="n">existingItem</span><span class="p">[</span><span class="n">kSecAttrSynchronizable</span><span class="p">]</span> <span class="o">==</span> <span class="kc">false</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="n">noPassword</span> <span class="p">}</span>

  <span class="k">let</span> <span class="nv">updateQuery</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecMatchSearchList</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span><span class="p">]]</span>

  <span class="k">let</span> <span class="nv">attributes</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">kSecClass</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">kSecClassInternetPassword</span><span class="p">,</span>
                                   <span class="n">kSecAttrServer</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">server</span><span class="p">,</span>
                                   <span class="n">kSecAttrAccount</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span> <span class="n">account</span><span class="p">]</span>

  <span class="k">let</span> <span class="nv">status</span> <span class="o">=</span> <span class="kt">SecItemUpdate</span><span class="p">(</span><span class="n">updateQuery</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">,</span> <span class="n">attributes</span> <span class="k">as</span> <span class="kt">CFDictionary</span><span class="p">)</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">!=</span> <span class="n">errSecItemNotFound</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="n">noPassword</span> <span class="p">}</span>
  <span class="k">guard</span> <span class="n">status</span> <span class="o">==</span> <span class="n">errSecSuccess</span> <span class="k">else</span> <span class="p">{</span> <span class="k">throw</span> <span class="kt">KeychainError</span><span class="o">.</span><span class="nf">unhandledError</span><span class="p">(</span><span class="nv">status</span><span class="p">:</span> <span class="n">status</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This variant is similar but also troubling.  The problem is we have even checked for one of our attributes, yet we can still leak a credential.  Can you spot why?  Because we have only returned the first value, we have a 50/50 chance if there are two entries, one local and one iCloud.  When the search returns the local, the guard check passes, but the update operation will update both items!  Why?  Because the selection criteria applies to more than one nearly identical item.<strong>Potential Fix</strong>Apple could introduce a kSecMatchSingleItem that both asserts that there is a single entry (it doesn’t match more than one) but otherwise behaves the same.  This would prevent the variant B.</p>

<h2 id="variant-c---secure-storage">Variant C - Secure Storage</h2>

<p>This variant is focused on key origin and extractability.  Many services may assume that if the access control list is correct, and they create only token backed secrets, that all secrets read are token backed.  This also becomes a problem with SE synced material via attestation certificates.</p>

<h2 id="variant-d---access-control">Variant D - Access Control</h2>

<p>This variant is specific to Apple and the OS (as for most apps, sandbox rules apply).  This variant occurs when a malicious low privileged service creates a secret with broader access such as the access group apple when it should be a more tightly controlled ACL.  This can expose secrets to lower privileged services such as blastdoor and bluetooth.  This is resolved by apple asserting or validating the access group for</p>

<h1 id="oh-continuity">Oh continuity…</h1>

<p>It seems even Apple can make this mistake, and in a big way.  For those with a MacBook or iPhone and Apple Watch, you’ve probably seen or use ContinuityUnlock which is the ability to unlock or login to these devices using the presence of the Watch.  It even flows in reverse!  The Watch can be unlocked by the Phone as well.  After being plagued with some odd security issues myself, and having dug into a ton of the iCloud Keychain model (Octagon Trust, TrustedPeer, CKKS, and the SE restore / sync method), I discovered each time I setup the devices two entries for continuity were being added(Both within the same minute, and both with the same account UUID):</p>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/c6bd7faf66-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1722880925003_image.png" alt="" />
<em>The result of adding an iPad to the circle</em></p>

<p>This is exactly the form of poisoning I referred to, but wait, these continuity values are <em>supposed</em> be synced… what gives?  Well the first major issue is that for the lay person, these aren’t even visible in Keychain Access (View → Show invisible items - which still doesn’t show everything).  Second, the keychain on macOS where this is inspectable lacks substantial relevant details for the item (protection class, SEP backed, etc).Here’s the iCloud item that was used to obtain the decryption key:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>keychain: "/Users/rickmark/Library/Keychains/iCloudBackup.keychain-db"
version: 512
class: "genp"
attributes:
    0x00000007 &lt;blob&gt;="handoff-decryption-key-71C6FAAE-A9CD-48DA-B5B9-460B6C1B2B64"
    0x00000008 &lt;blob&gt;=&lt;NULL&gt;
    "acct"&lt;blob&gt;="handoff-decryption-key-71C6FAAE-A9CD-48DA-B5B9-460B6C1B2B64"
    "cdat"&lt;timedate&gt;=0x32303234303232353231303632375A00  "20240225210627Z\000"
    "crtr"&lt;uint32&gt;=&lt;NULL&gt;
    "cusi"&lt;sint32&gt;=&lt;NULL&gt;
    "desc"&lt;blob&gt;="Handoff Decryption Key"
    "gena"&lt;blob&gt;=&lt;NULL&gt;
    "icmt"&lt;blob&gt;=&lt;NULL&gt;
    "invi"&lt;sint32&gt;=&lt;NULL&gt;
    "mdat"&lt;timedate&gt;=0x32303234303232353231303632375A00  "20240225210627Z\000"
    "nega"&lt;sint32&gt;=&lt;NULL&gt;
    "prot"&lt;blob&gt;=&lt;NULL&gt;
    "scrp"&lt;sint32&gt;=&lt;NULL&gt;
    "svce"&lt;blob&gt;="com.apple.continuity.encryption"
    "type"&lt;uint32&gt;=&lt;NULL&gt;
</code></pre></div></div>

<p>The unfortunate extractability of the key:</p>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/a55db22bf2-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1722882463393_image.png" alt="" /></p>

<p><strong>Bonus Oh-No: iCloud + Setting Sync</strong></p>

<h2 id="various-lateral-moves">Various Lateral Moves</h2>

<ul>
  <li>Rapport - RPIdentity-SameAccountDevice &amp; RPIdentity-FamilyDevice</li>
  <li>Sleep Proxy</li>
  <li>_airplay-p2p._tcp.</li>
  <li>com.apple.continuity.auto-unlock.sync / com.apple.continuity.unlock</li>
  <li>Bluetooth BluetoothLESync</li>
  <li>Secure Element (Stockholm) Sync - SE-PTC &amp; SE-PTA</li>
  <li>WiFi Passwords AirPort /  com.apple.wifip2pd</li>
  <li>Backstop</li>
  <li>DevicePairing</li>
  <li>com.apple.account.idms.password-reset-token</li>
  <li>com.apple.ndoagent.baaCertificates-combined-ucrt / com.apple.mobileactivationd</li>
  <li>MobileBluetooth</li>
  <li>Basic Attestation User Sub CA11</li>
</ul>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/9d2902381a-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1723071403676_image.png" alt="" /></p>

<p>Poisoned Octogon</p>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/e4044b4628-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1723071637245_image.png" alt="" /></p>

<p>Poisoned SOS</p>

<p><img src="/assets/images/wip-icloud-keychain-poisoning/ea2e1cf536-s_3A700D1ED4D34259A09AD0E555C598962DD417CA63A6E34B287B2CA7C0D33EF2_1723071657338_image.png" alt="" /></p>

<h1 id="secure-channel-and-se-backup-and-sync">Secure Channel and SE Backup and Sync</h1>

<h2 id="loose-notes">Loose notes</h2>

<p>Discuss SecureChannelOctagonSOS (Secure Object Sync) != PCS (Protected Cloud Storage)Factory SEP attestation certificatesBAA (Basic Attestation Authority) in the iCloud keychain Circle Formation and TLK RotationOctagon and TLKSharesTrustedPeers - Secure Channel vs RecoveryCKKS - ViewsTPPolicy - TrustedPeer policy objectsxART Recovery Service in the SEP???AKS vs ACS</p>

<h2 id="dedication">Dedication</h2>

<p><strong>To the gas and</strong> oil <strong>industry, and the stalkers it breeds</strong></p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[tl;dr If a malicious device is able to join your iCloud keychain (such as a jailbroken iDevice or insecure macOS device) it can pre-populate keychain items with overly permissive or insecure properties. This can be leveraged with reset tokens, auto and continuity unlock, and other apps to allow lateral…]]></summary></entry><entry><title type="html">A Cautionary Tale…</title><link href="https://rickmark.me/blog/a-cautionary-tale/" rel="alternate" type="text/html" title="A Cautionary Tale…" /><published>2024-07-11T10:10:04+00:00</published><updated>2024-07-11T10:10:04+00:00</updated><id>https://rickmark.me/blog/a-cautionary-tale</id><content type="html" xml:base="https://rickmark.me/blog/a-cautionary-tale/"><![CDATA[<p>Now this will be the most disturbing and truthful of all my public postings. It’s based on 14 years of knowledge and observation of which I rarely speak, given that the intent of majority of these events is to make me seem unreliable and to get me dismissed by law enforcement. But as I experienced a few weeks ago the waking from a dead sleep with the inability to breathe, and what I can only assume was carbon monoxide poisoning based on symptoms (despite having multiple sensors, which did not sound but did in fact blink red indicating some form of fault… details about why Kiddle would build such devices with firmware, a vulernability - I’ll address another day). I without names will give my understanding and profile of the assailant:</p>

<h2 id="deep-fragile-narcissism">Deep Fragile Narcissism</h2>

<p>My attacker was raised with a continuous barrage of others telling him how he was intended for great things. He was surrounded by people looking at legacy and determining that he would match or exceed it. Then he met me. I was raised by upper middle class family, the product of middle class family. My success in life was never attributed to rich parents, good schooling or anything other than raw intellect. While me and this assailant were together, he looked at my ability and societal value as in addition to his own. Afterwards, he saw us as bitter rivals, whereby any success or popularity I had diminished himself. Given the fact that his mother was from humble beginnings herself, and that her success became nothing but a burden to him (in that if he failed to succeed given his advantage he would be pitiable, but excellence would be viewed only as the minimum bar for him), I became a point of sublimation of his rage that he obviously could not express for his mother.</p>

<h3 id="controlling-the-situation-badly">Controlling the Situation, Badly</h3>

<p>Ironically, to reassert the feelings of power that matched with his perceived role in society, he then had to begin to attempt from the periphery to affect my life. He pressured various persons into being in my life to both relay information as well as to affect my decisions. The fact that this person has a military background, with a particular speciality in “military intelligence” comes as no surprise. These people are used to the idea that playing god is their mandate. “No” is not something the ultra wealthy are OK with, so the idea that you resist them in any way fundamentally is so intolerable that destroying you is their only real strategy. That’s why defiance is so irratating. I’d never actually cave to pressures that came from a coward that wouldn’t even after all these years even be as brave enough to have asked for the outcome he wanted (ironically which if he had done at the time would have been acceptable and without resistance), but instead had to believe that his control of others and myself could do so without having to expose himself to the potential rejection of a simple ask. Ironically in the most recent of iterations, he attempted to place me into a relationship with a plant intended to coerce me into marriage. He failed to anticipate that such a clear manipulation would never be successful as no one would marry someone whose entire being exuded a form of distain for oneself. Being used as such a tool does not for a happy marriage make. When this failed, it moved back to the typical set of playbook. Ensure that I was either alone, or only permitted to access the parts of the LGBT community that he had no interest in, being dismissed, lower class, or otherwise unacceptable to him. He decided that there was an artificial wall between what I was able to be and what he wanted me away from. I dared a few weeks ago to cross this line by wanting to participate in the larger LGBT culture in Pride in a major city. The reaction was swift, severe and unneeded. I now realize</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Now this will be the most disturbing and truthful of all my public postings. It's based on 14 years of knowledge and observation of which I rarely speak, given that the intent of majority of these events is to make me seem unreliable and to get me dismissed by law…]]></summary></entry><entry><title type="html">Dynamic Library Hardening - Read Only Thunks</title><link href="https://rickmark.me/blog/dynamic-library-hardening-read-only-thunks/" rel="alternate" type="text/html" title="Dynamic Library Hardening - Read Only Thunks" /><published>2022-07-30T01:23:20+00:00</published><updated>2022-07-30T01:23:20+00:00</updated><id>https://rickmark.me/blog/dynamic-library-hardening-read-only-thunks</id><content type="html" xml:base="https://rickmark.me/blog/dynamic-library-hardening-read-only-thunks/"><![CDATA[<p>#</p>

<h3 id="problem">Problem</h3>

<p>Today, late binding makes use of “thunks” to bind a call site to its eventual import.  These regions are setup as initialized mutable memory, meaning an errant instruction stream may be able to over write the function pointers arbitrarily.  Alternatives include static linking (infeasible due to size and update concerns) as well as early binding before transferring control to the process, and giving up write to the associated pages.  Most programs prefer to do late binding to avoid startup delays.</p>

<h3 id="proposed-solution">Proposed Solution</h3>

<p>By implementing either a page-fault or syscall, processes should be able to get assistance from the kernel to enter a meta-user-mode, or EL3 with privilege to modify the process.  This could immediately be consumed by the dyld functionality to perform binding of thunks in a priveledged user mode (keeping symbol binding in user mode and out of the kernel).  The initial indirect symbols would point to a thunk that would have the kernel pause all threads in the process, wait for them to quinenese, start the privileged thread (single thread for simplicity) which would be able to write the bound symbols and then drop write permission again.
This could even be supported by PAC by allowing the signing operations to occur in privledged mode but not in regular mode.  For this to work arm64e would need bits to control if the arbitrary sign instructions are available.  Another useful flag would be the ability to disable the read/write of keys except in “meta-mode”
Many traditional kernel services could then be moved out to the process meta-mode, decomplicating the kernel.  Modern kernels have absorbed a number of non kernel concerns because of the need for a privledged meta-process execution mode.  For example the creation of new threads via this method would allow stack setup to occur in user mode and simply the passing of a new thread structure into a collection with the only kernel interaction being the global process pause(objectively could be configuratble per entry)</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Problem Today, late binding makes use of “thunks” to bind a call site to its eventual import. These regions are setup as initialized mutable memory, meaning an errant instruction stream may be able to over write the function pointers arbitrarily. Alternatives include static linking (infeasible due to size and update…]]></summary></entry><entry><title type="html">Ubiquity UniFi Security and Boot-chain Analysis</title><link href="https://rickmark.me/blog/ubiquiti-unifi-security-and-boot-chain-analysis/" rel="alternate" type="text/html" title="Ubiquity UniFi Security and Boot-chain Analysis" /><published>2022-07-30T01:21:30+00:00</published><updated>2022-07-30T01:21:30+00:00</updated><id>https://rickmark.me/blog/ubiquiti-unifi-security-and-boot-chain-analysis</id><content type="html" xml:base="https://rickmark.me/blog/ubiquiti-unifi-security-and-boot-chain-analysis/"><![CDATA[<p>#</p>

<h1 id="this-paper-under-revision">This Paper Under Revision</h1>

<p>Due to further analysis, it seems that swapping the secure boot chain for alpine v2 devices early in the boot process via a device tree overlay is possible.  Therefore, this analysis may be based on a malware stack running on a device rather than UniFi’s intended firmware.<a href="https://paper.dropbox.com/doc/YzfFpGsgdrQo4XwVFnRmd">+WIP: Amazon Alpine v2 - Breaking the Secure Boot-Chain</a></p>

<h1 id="the-udm-udm-pro-and-the-unvr">The UDM, UDM-Pro and the UNVR</h1>

<p>These are all devices based on a SoC design from Annapurna Labs (now aquired by Amazon) known as the alpine and built on multi-core AArch64 CPUs.  As the devices are not designed for a graphical display they lack the Mali graphics core, and instead emphasize both PCIe and MII interconnects for high speed networking.  UniFi, putting its own spin on the devices also include a STM32 controller over a USB bus to provide for the touch display at the front of the unit.  The boot chainAs often is the case, it all starts with a Flash SPI chip.  This contains al_boot  which is a customized version of das U-Boot.  Unfortunately Flash SPI is not ROM, and at best can be write protected in regions.  This means there lacks a true root-of-trust link from the SoC to the early boot code.  In order for any device to have a true high integrity boot the OEM public key or public key hash must be burned into OTP ROM.  This is what is done with the iPhone and other Apple devices as SecureROM, the first running code is masked into the actual silicone and immutable.  While this has its own set of problems (see checkm8) it does mean that devices can be restored to health by either restarting them, or restoring them.  This means designers should always favor initial boot phases in ROM not SPI flash.  Qualcomm implements something similar with their PBL (primary boot loader) which will only take one of two paths, dropping to EDL (emergency download mode) waiting for a valid signed payload over an external bus, or booting SBL/XBL with a valid signature.
It does appear that UniFi does do some secure boot verification in later phases, but the break in the chain early makes this fairly pointless.  They also failed to ensure that one stage of the boot chain cannot boot to an earlier stage of the boot chain providing a problem of boot loader re-enterency.  Executing boot loader code with a state that doesn’t match it’s expected state can and does weaken the secure stance of the system (for example configuring hardware registers or memory layout prior calling the boot loader causing a different outcome).
The UDM and UNVR do have U-Boot that allows for TFTP booting a payload (I usually prefer USB DFU mode, but checkm8 showed how much happens in that stack, ideally a high security device could get UART ZMODEM images), which could allow for recovery from deep malware, or provide a tool for integrity attestation.  The UDM-Pro already has a UART connection inside the case, and could very easily expose this using standard network cable “console cable” like they do on other SKUs.  It does appear though that the UDM and UNVR took different approaches to how recovery is handled.  The UDM uses a partition with a uBoot image for recovery, loading a rootfs and kernel, then starting recoveryd  which is pretty much a nginx front end taking an uploaded payload which gets passed to the firmware update routines.
Now here’s where things get weird.  Having only my own devices to analyze it’s hard to tell if the behavior I’m seeing is“as designed” or just more of the “of course this happens to me”.  First thing to note is that on my hardware stack it seems that the kernel is both built with and running debugfs.  It shows as having configured elements of the PCIe bus as both PF(physical functions) and VF (virtual functions).  It is possible the the alpine is using the HV and PF/VF as a form of IOMMU, but this again puts us in a hard position of abusing virtualization hardware for memory isolation (virtualizationprovides this yes, but it is not the intended use, and provides for additional functionality that can weaken the security outcome).</p>

<h2 id="al_boot-and-i2c-devices-in-preboot"><code class="language-plaintext highlighter-rouge">al\_boot</code> and I2C Devices in Preboot</h2>

<p>One fascinating detail of the alpine  hardware is it allows for any i2c (inter-integrated circuit) device defined on the i2c-pld bus to participate in the boot process before the “boot application’. This is similar to option ROM loading in classical PC architecture.  From my experience with the UDM-Pro at least one device does make use of this functionality to execute from stage 2 to stage 3 at “SPD I2C Address 57”.  Stage 3 of al_boot from EEPROM.  Strangely to me the stage 3 loader then re-detects I2C device 57, and executes stage 3 again (with the title “agent_wakeup v2.10”).  The first time stage 3 ends up loading stage 2 again, the second it loads U-Boot.  I think this is just a me thing though as the image is Jenkins-Bootloaders-BL_al_boot_multi-develop-6 which sounds like the developers are given real boot keys, or that there was a production signed al_boot that would boot developer keys…
More clarification is needed as to what I2C device 57 on the i2c-pld bus is.  I suspect it is the SPI flash chip that backs the al_boot stage.  The full boot log is here (<a href="https://gist.github.com/rickmark/f84cc36a7ddf3dd9d76dd9c231855447">https://gist.github.com/rickmark/f84cc36a7ddf3dd9d76dd9c231855447</a>).   You can clearly see stage2, stage3, an I2C device titled agent_wakeup on the i2c-pld bus and back to stage2, stage3, then finally U-Boot.  I still need to gather more information about what I2C device this is and in what way it is modifying the system before causing the system to go back to the initial boot phases.  From a very course gist, it seems to be selecting the FDT (flattened device tree) or modifying it in memory before re-entering the stage2 boot loader.</p>

<h2 id="warning---wilding-here">Warning - Wilding Here</h2>

<p>Since the signing keys are also embedded into the FDT, this might mean a rouge I2C device is able to modify the existing secure boot chain by modifying the FDT and re-entering stage2.  The device would then ignore the call to it by stage3 if it has already executed.</p>

<h2 id="fixing-bad-boot-chains">Fixing Bad Boot Chains</h2>

<p>In the case that a SoC doesn’t provide for the ability to do a stage 1 verification on the next boot stage payload, manufacturers should be using ROM instead of SPI Flash for the next stage of boot-loader.  It would be trivial to create an industry accepted branch of u-boot that does nothing but boot a verified next stage, much like SecureROM.  This would mean that no matter the EoP - a device would always boot a valid signed image (albeit possibly outdated without a monotonic counter providing rollback protection).  While this is not totally foolproof, as a motivated attacker could actually use solder rework to replace the ROM chip… this case means that it would require physical tampering to prevent a physically present restore.</p>

<h2 id="sign-everything-not-in-rom">Sign Everything Not in ROM</h2>

<p>It doesn’t matter if you have marked your SPI flash “write protected”, a screwdriver, 10 minutes and a SPI flasher can make the device evil forever (hears the song Good Girl Gone Bad by Rhianna).  Every portion of mutable storage critical to boot security must be signed.  These systems are now well understood and manufactures can choose between using a manufacturer signing key, or placing a “device signing key” into OTP memory, or a manufacturer signed “device signing key” into EEPROM.  Manufacturer keys are great for portions that are the same on all systems, such as boot loaders.  Device specific keys are great for portions that are specific to the device that the device itself must sign.  This is usually not for boot loader config, but instead runtime configuration.</p>

<h2 id="provide-a-rom-based-recovery-system">Provide a ROM Based Recovery System</h2>

<p>Because “shit happens”, in order to reduce RMA, waste and long term persistence every device should have a “path to health”.  Apple did a decent job of implementing this early with their iPhone / iPod recovery protocols.  The USB specification even includes a fully specified DFU protocol (in fact used by the UDM to configure the STM32 for the LCD display), or using ZMODEM over a console line, or TFTP, just something…</p>

<h1 id="debug-kernels-and-kvm">Debug Kernels and KVM</h1>

<p>For reasons I don’t fully understand, the kernel for the UNVR has kernel debug support on.  I think the goal here is to enable some debug functionality like lock debugging.  If these are normal functions of the kernel, they should be moved out of debug.  Production devices should never need “debug” kernels to be able to diagnose in the field hardware problems.  It gives attackers way too much surface area.  Also one I can’t get my head around here is the building in of KVM.  If the UniFi OS system is based on containers instead of virtualization, then it seems to be an unnecessary and huge risk to the device security.  I know it is somewhat in use from dmesg log lines about setting up PCIe PF and VF(physical and virtual functions).  I think that the bootloader should be disabling EL3 and EL2 early in the boot phase if they are unused.  KVM should also be removed as it can use para-virtualization technology such as QEMU to blue pill the device.  If the case were that KVM was being used to provide strong isolation between applets, which don’t trust eachother I might understand, but as the technique is cgroups and</p>

<h1 id="bsd-openssh-on-the-unvr-and-dropbear-on-the-udmudm-pro">BSD OpenSSH on the UNVR and Dropbear on the UDM/UDM-Pro?</h1>

<p>This is one that makes little sense to me, but could have to do with design differences.  From my looking the UNVR uses traditional and hardened sshd from the OpenBSD project.  On the other hand my UDM-Pro is running both dropbear as well well as an odd script at /sbin/ssh-proxy that looks like:<code class="language-plaintext highlighter-rouge">root@ubnt:/# cat /sbin/ssh-proxy</code> <code class="language-plaintext highlighter-rouge">#!/bin/sh</code><code class="language-plaintext highlighter-rouge">ssh -p "$(cat /etc/unifi-os/ssh_proxy_port)" -o StrictHostKeyChecking=no -q root@localhost -- "$@"</code>I can’t tell if this is again, normal behavior for some reason, but promoting all ssh connections to root seems extreme in this case.
Another interesting quirk of my UDM-Pro, is that it seems to install a SSH key from some part of flash memory.  From my quick reading and understanding, a fixed key like this can given persistent access to the device across reboots without having to place they key directly into the filesystem.  A script at /usr/sbin/ubnt-ssh-keys-install looks like this:<code class="language-plaintext highlighter-rouge"># cat ubnt-ssh-keys-install</code> <code class="language-plaintext highlighter-rouge">#!/bin/sh -e</code>
<code class="language-plaintext highlighter-rouge">DROPBEAR_DIR=/etc/dropbear</code>
<code class="language-plaintext highlighter-rouge">mkdir -p "$DROPBEAR_DIR"</code><code class="language-plaintext highlighter-rouge">offset=$((0xe000))</code><code class="language-plaintext highlighter-rouge">part=$(cat /proc/mtd | grep '"EEPROM"' | sed -e 's/:.*//')</code>
<code class="language-plaintext highlighter-rouge">if [ ! "$part" ]; then</code> <code class="language-plaintext highlighter-rouge">exit 1</code><code class="language-plaintext highlighter-rouge">fi</code>
<code class="language-plaintext highlighter-rouge">mtd=/dev/$part</code><code class="language-plaintext highlighter-rouge">dss_file="$DROPBEAR_DIR"/dropbear_dss_host_key</code><code class="language-plaintext highlighter-rouge">rsa_file="$DROPBEAR_DIR"/dropbear_rsa_host_key</code><code class="language-plaintext highlighter-rouge">rm_offset="s/^[^ ]\+ *//"</code>
<code class="language-plaintext highlighter-rouge">write_key() {</code> <code class="language-plaintext highlighter-rouge">offset=$1</code> <code class="language-plaintext highlighter-rouge">len=$2</code> <code class="language-plaintext highlighter-rouge">file=$3</code> <code class="language-plaintext highlighter-rouge">dd if=$mtd skip=$offset bs=1 count=$len of=$file 2&gt;/dev/null</code> <code class="language-plaintext highlighter-rouge">chmod go-rwx $file</code><code class="language-plaintext highlighter-rouge">}</code>
<code class="language-plaintext highlighter-rouge">magic=$(od -j$offset -N 8 -t x1 $mtd | sed "$rm_offset")</code><code class="language-plaintext highlighter-rouge">if [ "$magic" != "ff ff ff ff 39 31 4e 54" ]; then</code> <code class="language-plaintext highlighter-rouge">echo Bad magic</code> <code class="language-plaintext highlighter-rouge">exit 1</code><code class="language-plaintext highlighter-rouge">fi</code>
<code class="language-plaintext highlighter-rouge">offset=$((offset+8))</code>
<code class="language-plaintext highlighter-rouge">while true; do</code> <code class="language-plaintext highlighter-rouge"># Type: 1 byte, Length: 2 bytes BE</code> <code class="language-plaintext highlighter-rouge">type_len=$(od -j$offset -N 3 -t x1 $mtd | sed "$rm_offset")</code>
 <code class="language-plaintext highlighter-rouge">type=$(echo "$type_len" | cut -d' ' -f1)</code> <code class="language-plaintext highlighter-rouge">len=$((0x$(echo "$type_len" | sed -e "s/^[^ ]\+//" -e "s/ //g")))</code>
 <code class="language-plaintext highlighter-rouge">offset=$((offset+3))</code>
 <code class="language-plaintext highlighter-rouge">case $type in</code> <code class="language-plaintext highlighter-rouge">01) write_key $offset $len $dss_file;;</code> <code class="language-plaintext highlighter-rouge">02) write_key $offset $len $rsa_file;;</code> <code class="language-plaintext highlighter-rouge">*) exit</code> <code class="language-plaintext highlighter-rouge">esac</code> <code class="language-plaintext highlighter-rouge">offset=$((offset + len))</code><code class="language-plaintext highlighter-rouge">done</code></p>

<h1 id="abusing-the-mutable-data-partition-to-override-the-rootfs">Abusing the Mutable Data Partition to Override the rootfs</h1>

<p>In my viewing of /mnt/.rwfs/ it contains a single directory data - this directory creates the entire root filesystem again.  This is then combined with /mnt/.rofs which comes from the boot rootfs.  The overlay of these two create the full system.  Why Ubiquity would elect to allow for a mutable partition to override the entire filesystem, including such things as passwd and the binaries feels like a strange choice.  Yes, some values in /etc have to be mutable sure, but overlaying at the root allows for persistent modification of any part of the rootfs, making cryptographic verification of it, well, silly.  Options here could have included linking the mutable portions of rootfs to the peristent volume, and I think this is a huge area where Linux and embedded devices just, aren’t there yet.  There’s no real way to configure what parts of the file tree are default, read-only, or mutable in a simple clear way.  It takes a hacking together of links, overlays and other such trickery to get this to work.   One can also use MAC (mandatory access controls) and SELinux / AppArmor to further prevent modification of mutable regions that shouldn’t be mutable, but that doesn’t fix offline attacks.  As a final option, scanning the mutable partition to ensure that it has the correct data shape, and doesn’t override key folders such as /lib, /bin/, /sbin and the like before mounting the overlay as a belt and suspenders approach is a great one here.
Going another direction, one could implement full on dm-verity, but that seems overkill given that these immutable root filesystems are small, and easily verified on boot.  The reason this is suggested is because it is a more widely and heavily invested in solution being the basis of Android and Chromebook security.
As a final “new solution” one could create a LSM (Linux Security Module) that enforced that particular parts of the VFS(virtual file system) come from particular backing block devices.  This would allow for a declarative model of the security of the filesystem tree.</p>

<h1 id="udm-pro-and-ram-disk-union-mounting">UDM-Pro and RAM Disk Union Mounting</h1>

<p>In the same vein as above, instead of using a mutable partition as was done on the UNVR, it seems that the UDM-Pro allows for the union mount of the immutable root file system with a RAM disk allowing the overwriting of the rootfsfiles.</p>

<h2 id="slightly-suspicious">Slightly Suspicious…</h2>

<p>While attempting to pull my .rwfs I was first greeted to a SEGFAULT as it seemed to recurse into conf/ though my tarcommand should have correctly respected hard and soft links (wonder if one has a subdirectory hard-link to the parent what happens??).  The second time around I saw this in my output:<code class="language-plaintext highlighter-rouge">tar: Removing leading `/' from member names</code><code class="language-plaintext highlighter-rouge">tar: Removing leading `/' from hard link targets</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/rc2.d/S01ssh: File removed before we read it</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/localtime: File removed before we read it</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/rc4.d/S01ssh: File removed before we read it</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/rc3.d/S01ssh: File removed before we read it</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/mtab: File removed before we read it</code><code class="language-plaintext highlighter-rouge">tar: /mnt/.rwfs/data/etc/rc5.d/S01ssh: File removed before we read it</code></p>

<h1 id="using-ubnt-as-an-alias-to-root">Using ubnt as an Alias to root</h1>

<p>Again, knowing that I only have my devices to analyze, this one shocked me.  By making ubnt and ubnt@localequivalent to UID 0 any user/root privilege separation is not possible.  To me this seems like someone is one cookie grab away (and given that UniFi has really no audit trail of user sessions this is way worse… the new UID product improves this) from enabling and setting SSH / root’s password, logging into the box and gaining persistence.  I honestly question the value of user accessible root in the base “UniFi OS” at all.  All root like operations in the base system should be mediated by privileged tools, such as fwupdate.  As “UniFI OS” is really an embedded system designed to run containers, removing privileged and most of the tool set from the root slice other then what is required to run, upgrade, backup, restore and attest / diagnose should be the goal.</p>

<h2 id="using-a-pam-module-to-allow-login-over-ssh-without-setting-the-password-or-ssh-keys-only">Using a PAM Module to Allow Login over SSH, Without Setting the Password, or SSH Keys Only</h2>

<p>Because of the risk of making /etc/passwd and /etc/shaddow mutable, even if just to set the password hash for SSH access, a PAM module should be used so that these can be set to value where there is not a valid password, or allow them to be generated to random values per boot (dicey because it makes it again mutable…).  Too often either the default password for an embedded device is leaked, cracked, or set by some EoP on the device.  Embedded devices should always prefer SSH public key authentication as this can be FAR stronger like in the case of Yubikey backing.  Also for safety, the device “management console” clearly needs to display the SSH host key to prevent MitM attacks.</p>

<h1 id="if-you-own-the-ecosystem-build-a-pki">If You Own the Ecosystem, Build a PKI</h1>

<p>This is the full subject of another paper, but it comes down to a simple fact.  All device manufactures should place device certificates onto their hardware.  They, if appropriate should also make use of a non-extractable private key via a PUF(physically un-clonable function) to derive this certificate / key into a key that is used per restore / reset.  This prevents a malicious party from simply “running the embedded system” as a QEMU image, and connecting it to the UniFi cloud provider.  This gives strong assurance of connecting to the right device from management consoles.
On top of authenticating the devices to the cloud, if embedded into other devices like the cameras, switches etc, it would allow a much more secure adoption process, knowing that the devices are in-fact both from the same origin.</p>

<h1 id="get-rid-of-executable-scripts-on-embedded-devices-at-least-in-the-root-cgroup">Get Rid of Executable Scripts on Embedded Devices, at Least in the Root CGroup</h1>

<p>This wont be popular, but when it comes to security, bash is trash.  It can’t be signed and is the source of the term “shellcode”.  An embedded device is a closed ecosystem.  There is no reason that all binaries can’t be ELF and signed by the manufacturer.  Along similar lines, there is also no need of Ruby, Python, Perl, Node or any other interpreter in the root slice.  These just provide tools for an attacker to execute arbitrary code once the file is on the device and they can issue an exec call of any kind.  This is not to say signed ELF only is a panacea, many programs fail to properly sanitize their arguments, but it does greatly cripple this down to a few known things.  Adding AppArmor or SELinux greatly fixes those problems of improper input handling</p>

<h1 id="if-the-device-updates-atomically-does-it-need-apt">If the Device Updates Atomically, Does it Need APT?</h1>

<p>Apt is a great tool, but in the case of the root slice of UniFi device, it is probably overkill.  That and its ability to add sources, or change keys may in fact allow an attacker to pull down additional tooling or override the update source.  This concern is only raised because it seems heavyweight to use apt/dpkg to update the 4 Ubiquity applets, which all share a container.  A better design would be a root immutable system, 4 containers (one per applet) and a final “diagnosticcontainer” that contains tools for the power user.  These could easily be handled by a far simpler system then a full apt database and dpkg install process, since they are in reality just downloading a rootfs for each container and some metadata.  And then once inside the container, apt and dpkg is clearly not needed as the container should update atomically.  Any data files can be updated to the mutable data source atomically as well as a second filesystem image.  apt/dpkg are fine in the diagnostic image as various tools may wish to be pulled down.
As an example of the insanity for reasons that utterly escape me I see the entire AArch64 GCC collection on my UDM:<code class="language-plaintext highlighter-rouge">root@ubnt:/usr/bin# ls -la /usr/bin/aarch64*</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   27488 May 10  2017 /usr/bin/aarch64-linux-gnu-addr2line</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   52040 May 10  2017 /usr/bin/aarch64-linux-gnu-ar</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root  354464 May 10  2017 /usr/bin/aarch64-linux-gnu-as</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   22992 May 10  2017 /usr/bin/aarch64-linux-gnu-c++filt</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root 3359704 May 10  2017 /usr/bin/aarch64-linux-gnu-dwp</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   31336 May 10  2017 /usr/bin/aarch64-linux-gnu-elfedit</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   94288 May 10  2017 /usr/bin/aarch64-linux-gnu-gprof</code><code class="language-plaintext highlighter-rouge">lrwxrwxrwx 1 root root       6 May 10  2017 /usr/bin/aarch64-linux-gnu-ld -&gt; ld.bfd</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root 1155088 May 10  2017 /usr/bin/aarch64-linux-gnu-ld.bfd</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root 5425256 May 10  2017 /usr/bin/aarch64-linux-gnu-ld.gold</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   40600 May 10  2017 /usr/bin/aarch64-linux-gnu-nm</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root  195632 May 10  2017 /usr/bin/aarch64-linux-gnu-objcopy</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root  336080 May 10  2017 /usr/bin/aarch64-linux-gnu-objdump</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   52048 May 10  2017 /usr/bin/aarch64-linux-gnu-ranlib</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root  505424 May 10  2017 /usr/bin/aarch64-linux-gnu-readelf</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   27344 May 10  2017 /usr/bin/aarch64-linux-gnu-size</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root   27456 May 10  2017 /usr/bin/aarch64-linux-gnu-strings</code><code class="language-plaintext highlighter-rouge">-rwxr-xr-x 1 root root  195640 May 10  2017 /usr/bin/aarch64-linux-gnu-strip</code></p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[This Paper Under Revision Due to further analysis, it seems that swapping the secure boot chain for alpine v2 devices early in the boot process via a device tree overlay is possible. Therefore, this analysis may be based on a malware stack running on a device rather than UniFi’s…]]></summary></entry><entry><title type="html">Google: From the Citadel to the Dauntless</title><link href="https://rickmark.me/blog/google-from-the-citadel-to-the-dauntless/" rel="alternate" type="text/html" title="Google: From the Citadel to the Dauntless" /><published>2022-07-30T01:20:53+00:00</published><updated>2022-07-30T01:20:53+00:00</updated><id>https://rickmark.me/blog/google-from-the-citadel-to-the-dauntless</id><content type="html" xml:base="https://rickmark.me/blog/google-from-the-citadel-to-the-dauntless/"><![CDATA[<p>#</p>

<p><strong>DANGER: Incomplete analysis and conjecture based on real world observation.</strong></p>

<h1 id="tldr">tl;dr</h1>

<p>Google’s Titan-M (codename citadel) is based on the prior generation of designs for the Chromebook EC (embeddedcontroller - Haven) which mediates the secure boot process.  While Google referrers to regions of the flash known as RO_Aand RO_B these are in fact not read-only but instead write protected.  While the code is verified, it also includes data such as the root-of-trust for the next stage.  The next generation chip known as codename dauntless doubled the size of the non-volatile area of storage, leading to the ability to confuse a citadel chip about the location of RO_* and allowing the writing into RO_B.  As the citadel consulted very early by the Qualcomm XBL boot-loader via a UEFI DXE to verify aboot, this can allow code to run before the Android boot-loader and fastboot giving long term persistence despite a full device wipe and restore.</p>

<h1 id="credit-google-fixed-this-problem">Credit: Google fixed this problem</h1>

<p>Later builds of the dauntless firmware checked for a eFUSE to ensure they don’t run on a citadel device.  It’s not clear when this was added and how many signed copies of early firmware got out before this correction was made, or if the eFUSE was always present and set since they handled this quietly.  It’s also not clear if the oem stage ec.rec and oem citadel rescue process with physical presence could undo this fix (yet, still researching, but it seems that some of the version hashes for PVT that were part of Google’s git history are no longer available).  Many of the affected versions seemed to reference v0.0.3 specifically.</p>

<h1 id="the-titan-m-doesnt-always-update">The Titan-M doesn’t always update…</h1>

<p>One percent of the Titan-Ms don’t reliably update.  That’s a huge failure rate for a security device.  Most early load / boot-kits maintain persistence at all costs as most consumers and even security professionals look the other way to update failures such as these.  I too had this happen to my first Pixel 4a.  Upon inspection using fastboot oem citadel version it became clear that RO_A had the wrong magic, which later was clearly the Dauntless.  I was able to somewhat restore the citadel via fastboot stage ec.rec and fastboot oem citadel rescue, but in reality may have locked in the change to the root-of-trust to the chip, as the goal isn’t entirely to get code execute on the Titan-M but instead to rewrite the portions used by XBL to verify aboot and for Verified Boot.
This also led to a very odd boot configuration for me, where RO_B and RW_A were being selected.  The updater isn’t very tolerant to this configuration by the way.</p>

<h1 id="the-pixel-boot-process-and-qualcomm">The Pixel Boot Process and Qualcomm</h1>

<h2 id="how-to-do-some-debug-nonsense">How to do some debug nonsense…</h2>

<p>A Pixel device will let you watch it’s boot process, if you’re willing to get out the soldering iron and build a custom UART USB-C adapter.  In fact the Citadel will give up a full debug lane to you with fastboot oem citadel suzyq onand the right cable.</p>

<h1 id="the-origins-and-the-haven">The Origins and the “Haven”</h1>

<p>The modern Titan-M in the Pixel 3 and later has it’s roots in the Chromebook EC (embedded controller).  The EC was the“B” series chip named the Haven.  This was evolved into the Titan-M which is known as the “Citadel”.  Google of course does publish some source code in this area but the design and technical documentation is generally internal.  The Titan-M2? (name unknown) will be codenamed the Dauntless (I think they are going to an A, B, C, D series of naming to make generational identification easier ala Ubuntu).</p>

<h1 id="the-pixel-and-the-citadel">The Pixel and the Citadel</h1>

<p>The Pixel uses Qualcomm chips for both the AP (application processor) and BP or radio (Baseband Processor).  Others have written on the boot-up process of the Qualcomm chips.  For the Pixel AP, the PBL verifies and executes first, then xbl_sec which is the EL3 TrustZone loader for the next stage against both the Qualcomm signing keys as well as OEM_PKEY_HASH (the OEM signing key, in this case Google).  This loads what is known as the QSEE or Qualcomm Secure Execution Environment.  The xbl_sec then drops to non-secure EL2 and runs the verified xbl (extendable boot loader).  XBL is a UEFI environment, and therefore follows the same process of PEI (platform initialization), DXE(driver execution environment) and then APP or payload execution.  It lacks a SEC phase as that assurance is provided by PBL and xbl_sec.  XBL then loads the hypervisor <code class="language-plaintext highlighter-rouge">hyp</code> or Qualcomm QHEE, which is in essence a abused EL2 / hypervisor for IOMMU or memory isolation.   The Pixel XBL includes a DXE for interfacing with the Titan-M over SPI, allowing XBL to use the Titan early in the boot process for verification of other boot components.  Unfortunately in this case they have not verified the Titan-M’s security state prior and this allows any compromise of the Titan-M to become an EoP to early boot loader malware.  Bear in mind that all of this is happening before a single pixel is written to the display(no fastboot yet).  The DXE is used to verify aboot` or the Android Bootloader and provides services to it for the security state and dm-verity status.  The Titan-M also includes the root-of-trust for the Android operating system as Google attempted to eject early from dependence on the Qualcomm secure boot chain and bring it back under their own control.</p>

<h1 id="the-citadel--dauntless-bug">The Citadel / Dauntless Bug</h1>

<p>Google made some sensible choices in the layout of the non-volatle memory layout of the Titan-M.  The copied the Chromebook EC design of cutting the memory in half, designating the top half as A and the bottom half as B.  This allows for A/B updating which has the benefit of upgrade as well as failsafe against a bad flash.  They then (unfortunately a misnomer) set the initial portions of A and B to “read-only” and by “read-only” we really mean “write protect” - the difference here is critically important and I urge companies to stop conflating the two.   The Citadel and Dauntless are largely comparable and an evolution.</p>

<h2 id="now-the-bug">Now the bug…</h2>

<p>The Dauntless has a non-volatle memory that is twice the size of the Citadel.   If you flash the Citadel A region with the Dauntless firmware, it will accidentally place the RO_B region into the dauntless RW_A region.  This breaks the security model of write protection and A/B for the Titan-M.  It seems this error only occurred with early builds of the Dauntless firmware, as there is now a one way fuse that disables booting Dauntless code on a Citadel.  It also indicates the failure of ever reusing signing keys between generations of devices that were not co-designed.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[DANGER: Incomplete analysis and conjecture based on real world observation. tl;dr Google’s Titan-M (codename citadel) is based on the prior generation of designs for the Chromebook EC (embeddedcontroller - Haven) which mediates the secure boot process. While Google referrers to regions of the flash known as RO_Aand…]]></summary></entry><entry><title type="html">Using the T2 for Detection and Forensics</title><link href="https://rickmark.me/blog/using-the-t2-for-detection-and-forensics/" rel="alternate" type="text/html" title="Using the T2 for Detection and Forensics" /><published>2022-07-30T01:19:38+00:00</published><updated>2022-07-30T01:19:38+00:00</updated><id>https://rickmark.me/blog/using-the-t2-for-detection-and-forensics</id><content type="html" xml:base="https://rickmark.me/blog/using-the-t2-for-detection-and-forensics/"><![CDATA[<p>#</p>

<h2 id="todays-need">Todays Need</h2>

<p>With the advent of modern security hardware, it has become near impossible to perform comprehensive security auditing of devices used in the field.  This has allowed malware to run at layers of the stack not accessible to traditional endpoint security.  Recent un-patchable hardware vulnerabilities that may have served as vectors for infection can be re-purposed for DFIR purposes, allowing us to mitigate their malicious impact.</p>

<h2 id="new-solutions">New Solutions</h2>

<p>With the recent discoveries of checkm8, blackbird and the subsequent work of checkra1n, we are finally able to directly interact with non-mutable storage on Apple Macs, and some models of iPhone.  This provides a unique opportunity for the following:</p>

<ul>
  <li>Reading raw data from non-volatile storage, allowing full capture in cases of legal or forensics cases</li>
  <li>Interacting with the SEP to potentially pull otherwise encrypted data by brute forcing the password (a working PoC is yet required)</li>
  <li>Comparing the contents of the system to known good baselines for implant detection and surveillance.  (seegithub.com/rickmark/efivalidate)</li>
  <li>Using the debug functionality of the T2 and Intel DCI to capture volatile memory for malware analysis</li>
  <li>Placing “tripwires” into the T2 to detect if the device is restarted without authorization</li>
</ul>

<h2 id="solution-categories">Solution Categories:</h2>

<p><strong>Law Enforcement/Intelligence: Direct Sale</strong></p>

<ol>
  <li>Forensics: Full physical forensic disk recovery with or without a password or filefault key.</li>
  <li>Forensics: Password Retreival - Brute Force</li>
  <li>Tamper Detection: DTrace / Hash Run / Store</li>
  <li>Lawful Warrant: Implement Limited Warrant / Access to Device / Audio Tap</li>
  <li>Lawful Wire: Implement undetectable Screen, camera, Audio Tap for UCEs and Informants.</li>
  <li>Triggered Interdiction or National Security Intervention: End point triggered shutdown / disconnect to prevent communication or computation that might result in immediate harm to  people, infrastructure, etc.</li>
  <li>Hidden Terminal and Desktop and/or novel encryption and communication scheme that evades normal procedures to place malware and or extract information from laptops.</li>
  <li>Self-Destruct: Implementation of triggered secure erase of devices bases on specific triggers or the absence of specific triggers.</li>
  <li>Audio and Video Surveillance of via camera mic and bluetooth or wifi connection.</li>
</ol>

<p><strong>Enterprise:</strong></p>

<ol>
  <li>Implementation of Remote or Local Full Wipe.</li>
  <li>Implementation of Netboot or Network File System</li>
  <li>Backup / Reset to Known State</li>
  <li>Virus, Malware, Tamper Scanning and Protection</li>
  <li>VPN / Proxy</li>
  <li>Enterprise APP and Default Build Distribution and Implementation</li>
  <li>Custom Recovery Environments</li>
  <li>KVM</li>
</ol>

<p><strong>Consumer / Advocacy:</strong></p>

<ol>
  <li>Detect and Remove DEP</li>
  <li>Detect and Remove Geo Restrictions</li>
  <li>App Store Alternative: Mounted</li>
  <li>Disable Camera, Mic, Speaker &amp; Sensor</li>
  <li>Hidden Disk Partition</li>
  <li>Ability to Reflash and Lock Device in Specific Config ie Media Server, VPN / Cache, Simple Terminal Server, etc.</li>
  <li>Tamper Detection, Recording, and Alert</li>
  <li>Wifi / BT Mac Randomization</li>
  <li>Mounting and Booting from Network Drives and/or Locally Stored DMGs</li>
  <li>Low Level Wifi / Bluetooth / Networking Firewall and VPN that persists during Recovery etc.</li>
</ol>

<h2 id="demo---using-chrome-webusb-to-deliver-this-technology">Demo - Using Chrome WebUSB to Deliver This Technology</h2>

<p><img src="/assets/images/using-the-t2-for-detection-and-forensics/d1bff63320-s_E45BFBDCB9E23EE642EF6346F4FE25A02EC16FCEEE5E5471FDDEF207CE13C831_1602995662061_image.png" alt="" /></p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Todays Need With the advent of modern security hardware, it has become near impossible to perform comprehensive security auditing of devices used in the field. This has allowed malware to run at layers of the stack not accessible to traditional endpoint security. Recent un-patchable hardware vulnerabilities that may have served…]]></summary></entry><entry><title type="html">USB Security in the Linux Kernel</title><link href="https://rickmark.me/blog/usb-security-in-the-linux-kernel/" rel="alternate" type="text/html" title="USB Security in the Linux Kernel" /><published>2022-07-30T01:19:03+00:00</published><updated>2022-07-30T01:19:03+00:00</updated><id>https://rickmark.me/blog/usb-security-in-the-linux-kernel</id><content type="html" xml:base="https://rickmark.me/blog/usb-security-in-the-linux-kernel/"><![CDATA[<p>#</p>

<p>Dropbox not only works to ensure that our product is worthy of trust, but we look up and down the entire stack of components for risk and areas of improvement.  Like many companies, we employ Linux servers to power the Dropbox product.  We perform regular patching, secure configuration and performance and security logging, but at times we have to go deeper.</p>

<h1 id="when-usb-was-new">When USB Was New</h1>

<p>Much of the Linux kernel core code is about two decades old, and much of it written by Linus himself and predating the modern computer security industry.  At the time, USB was new, and malicious devices were not part of the threat model, so the code is extremely relaxed to try to accommodate compatibly and reliability over security.  Because of the fact this code is shared across Android phones, Chromebooks, Linux desktops, laptops and servers, its security is paramount in this age.</p>

<h1 id="lack-of-defensive-programming">Lack of Defensive Programming</h1>

<p>Code written during this era predates the modern security practice of defensive coding.  To ensure that mistakes in the code are not exploitable, especially with regard to untrusted input from devices, defensive programming tactics like length validation, canonicalization, and removing overly permissive cases must be employed.  As many of these strategies came into vogue after the initial versions of core USB code, safety conscious revisions are necessary.</p>

<h2 id="examples-of-potentially-exploitable-code">Examples of Potentially Exploitable Code</h2>

<h2 id="unvalidated-length-from-device">Unvalidated Length from Device</h2>

<p><img src="/assets/images/usb-security-in-the-linux-kernel/086df15c9d-s_848B01F014E8BFB84374AC8362E81C8D03D9E184AEAEDFF47C33B172DEE5F69F_1557968770373_image-1.png" alt="" /></p>

<p>Patch as submitted 5/14/2019<a href="https://marc.info/?l=linux-usb&amp;m=155780009303416&amp;w=2">https://marc.info/?l=linux-usb&amp;m=155780009303416&amp;w=2</a><code class="language-plaintext highlighter-rouge">--- drivers/usb/core/config.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)</code>
<code class="language-plaintext highlighter-rouge">diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.cindex 7b5cb28ff..8cb9a136e 100644--- a/drivers/usb/core/config.c+++ b/drivers/usb/core/config.c@@ -33,6 +33,13 @@ static int find_next_descriptor(unsigned char*buffer, int size,</code>
 <code class="language-plaintext highlighter-rouge">/* Find the next descriptor of type dt1 or dt2 */  while (size &gt; 0) {+     if (size &lt; sizeof(struct usb_descriptor_header)) {+         printk( KERN_ERR "usb config: find_next_descriptor "+                          "with size %d not sizeof("+                          "struct usb_descriptor_header)", size );+         break;+     }+  h = (struct usb_descriptor_header *) buffer;  if (h-&gt;bDescriptorType == dt1 || h-&gt;bDescriptorType == dt2)  break;@@ -58,6 +65,13 @@ static voidusb_parse_ssp_isoc_endpoint_companion(struct device *ddev,  * The SuperSpeedPlus Isoc endpoint companion descriptor immediately  * follows the SuperSpeed Endpoint Companion descriptor  */+ if (size &lt; sizeof(struct usb_ssp_isoc_ep_comp_descriptor)) {+        dev_warn(ddev, "Invalid size %d for SuperSpeedPlus isocendpoint companion"+                       "for config %d interface %d altsetting %d ep %d.\n",+                 size, cfgno, inum, asnum, ep-&gt;desc.bEndpointAddress);+        return;+ }+  desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;  if (desc-&gt;bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||      size &lt; USB_DT_SSP_ISOC_EP_COMP_SIZE) {@@ -76,6 +90,14 @@ static void usb_parse_ss_endpoint_companion(structdevice *ddev, int cfgno,  struct usb_ss_ep_comp_descriptor *desc;  int max_tx;</code>
<code class="language-plaintext highlighter-rouge">+ if (size &lt; sizeof(struct usb_ss_ep_comp_descriptor)) {+        dev_warn(ddev, "Invalid size %d of SuperSpeed endpoint"+                       " companion for config %d "+                       " interface %d altsetting %d: "+                       "using minimum values\n",+                 size, cfgno, inum, asnum);+        return;+ }  /* The SuperSpeed endpoint companion descriptor is supposed to  * be the first thing immediately following the endpoint descriptor.  */@@ -103,6 +125,16 @@ static voidusb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,  ep-&gt;desc.wMaxPacketSize;  return;  }++ if ((size - desc-&gt;bLength) &lt; 0 ||+     size &lt; USB_DT_SS_EP_COMP_SIZE) {+        dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "+                       "config %d interface %d altsetting %d ep %d: "+                       "has invalid bLength %d vs size %d\n", desc-&gt;bMaxBurst,+                 cfgno, inum, asnum, ep-&gt;desc.bEndpointAddress,desc-&gt;bLength, size);+        return;+ }+  buffer += desc-&gt;bLength;  size -= desc-&gt;bLength;  memcpy(&amp;ep-&gt;ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);@@ -214,7 +246,24 @@ static int usb_parse_endpoint(struct device*ddev, int cfgno, int inum,  unsigned int maxp;  const unsigned short *maxpacket_maxes;</code>
<code class="language-plaintext highlighter-rouge">+ if (size &lt; sizeof(struct usb_endpoint_descriptor)) {+        dev_warn(ddev, "config %d interface %d altsetting %d has an "+                       "size %d smaller then endpoint descriptor, skipping\n",+                 cfgno, inum, asnum, size);++        return -EINVAL;+ }+  d = (struct usb_endpoint_descriptor *) buffer;++ if ((size - d-&gt;bLength) &lt; 0) {+        dev_warn(ddev, "config %d interface %d altsetting %d has an "+                       "invalid endpoint descriptor of length %d, skipping\n",+                 cfgno, inum, asnum, d-&gt;bLength);++        return -EINVAL;+ }+  buffer += d-&gt;bLength;  size -= d-&gt;bLength;</code>
<code class="language-plaintext highlighter-rouge">@@ -446,7 +495,18 @@ static int usb_parse_interface(struct device*ddev, int cfgno,  int len, retval;  int num_ep, num_ep_orig;</code>
<code class="language-plaintext highlighter-rouge">+ if (size &lt; sizeof(struct usb_interface_descriptor)) {+        dev_err(ddev, "config %d interface %d has an "+                       "invalid endpoint descriptor of length %d, skipping\n",+                 cfgno, inum, size);+    }  d = (struct usb_interface_descriptor *) buffer;++ if ((size - d-&gt;bLength) &lt; 0) {+        dev_err(ddev, "config %d interface %d has an "+                       "invalid endpoint descriptor of length %d, skipping\n",+                 cfgno, inum, d-&gt;bLength);+ }  buffer += d-&gt;bLength;  size -= d-&gt;bLength;</code>
<code class="language-plaintext highlighter-rouge">@@ -514,6 +574,13 @@ static int usb_parse_interface(struct device*ddev, int cfgno,  /* Parse all the endpoint descriptors */  n = 0;  while (size &gt; 0) {+     if (size &lt; sizeof(struct usb_descriptor_header)) {+            dev_err(ddev, "config %d interface %d has an "+                           "invalid endpoint descriptor of length %d,skipping\n",+                     cfgno, inum, size);+            return -EINVAL;+     }+  if (((struct usb_descriptor_header *) buffer)-&gt;bDescriptorType       == USB_DT_INTERFACE)  break;-- 2.11.0</code></p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Dropbox not only works to ensure that our product is worthy of trust, but we look up and down the entire stack of components for risk and areas of improvement. Like many companies, we employ Linux servers to power the Dropbox product. We perform regular patching, secure configuration and performance…]]></summary></entry><entry><title type="html">Work-in-Progress: Using Apple internal builds for RootKits</title><link href="https://rickmark.me/blog/work-in-progress-using-apple-internal-builds-for-rootkits/" rel="alternate" type="text/html" title="Work-in-Progress: Using Apple internal builds for RootKits" /><published>2022-07-30T01:16:22+00:00</published><updated>2022-07-30T01:16:22+00:00</updated><id>https://rickmark.me/blog/work-in-progress-using-apple-internal-builds-for-rootkits</id><content type="html" xml:base="https://rickmark.me/blog/work-in-progress-using-apple-internal-builds-for-rootkits/"><![CDATA[<h1 id="backstory">Backstory</h1>

<p>Found this years ago while being stalked in SF <a href="https://github.com/rickmark/mojo_thor">mojo_thor</a>.  Recently I’ve found
more kernel extensions beyond just <code class="language-plaintext highlighter-rouge">MojoKDP</code> that are involved.  MojoKDP was originally found by running a VM, then
capturing the memory state providing a core dump. (see other repo)</p>

<h2 id="overall-theory">Overall Theory</h2>

<p>Two Possibilities:</p>

<ul>
  <li>Apple signs internal builds for production hardware using production keys allowing anyone
who gains a copy of one to use powerful internal kernel functionality that breaks the
guarantees made in the platform security guide</li>
  <li>Changing a production device to trust DVT/PVT/EVT keys is trivial, then they run internal
builds which have powerful debug capabilities that break the security model.</li>
  <li>Seems this might be related to SMC <code class="language-plaintext highlighter-rouge">MOJO</code> key for switching to non-production builds.</li>
</ul>

<h2 id="the-auxkc-generation-process-and-elides">The AuxKC generation process and <code class="language-plaintext highlighter-rouge">elides</code></h2>

<p>When the AuxKC (auxiliary KC), or kernel extensions approved on Intel systems, is generated the system works by
rebooting to a recovery environment (this prevents tampering with the KC during generation).  A system then
enumerates all kernel extensions loaded and approved and builds the AuxKC as those that are approved and/or loaded
(loading being a proxy for approved in this case) combining all the kext bundles into a single Mach-O file.
The file <code class="language-plaintext highlighter-rouge">elides</code> eliminates the display or error for kexts that are to be included, yet do not have backing
on disk, implying that these kernel extensions can be loaded from DMA or a kernel debug session, which is the only
reason that they would not be present on disk  (yet still valid signed by <code class="language-plaintext highlighter-rouge">@apple</code>).  This further implies that this
is a list of kernel extensions that Apple knows may be loaded by other means but should silently ignore failures on.</p>

<p>The most interesting fact about the <code class="language-plaintext highlighter-rouge">elides</code> list is that it is a subset of the total number of extensions that
are present internally, so is an explicit carve out, one that lists those useful for backdoor, privileged hardware or
signals intelligence.  This seems to be an extension of MojoKDP, whereby the author is at a loss to explain this
behavior other than Apple’s explicit support for the signal’s intelligence community.</p>

<h2 id="leveraged-kernel-extensions">Leveraged Kernel Extensions</h2>

<h3 id="comappledriverairportbrcm4360-mfg">com.apple.driver.AirPort.Brcm4360-MFG</h3>

<h3 id="comappledriverairportbrcmnic-mfg">com.apple.driver.AirPort.BrcmNIC-MFG</h3>

<p>Broadcom - perhaps these are the original manufacturer versions?  Implies that there are differs
but not enough data yet.</p>

<h3 id="comappledriverappleastrisgpioprobe">com.apple.driver.AppleAstrisGpioProbe</h3>

<p>Astris is a debug system for iDevices, partially documented elsewhere.  Just assume used to
do evil things to a iDevice restored on the computer.  GPIO implies general purpose IO pins.
This may provide a probed devices PMGR/<code class="language-plaintext highlighter-rouge">force_dfu</code> pins for iDevice restore avoidance or
re-infection.</p>

<h3 id="comappledriverapplebsdkextstartervpn">com.apple.driver.AppleBSDKextStarterVPN</h3>

<p>Based on description, some form of VPN that lives in kernel mode and operates at boot?</p>

<h3 id="comappledriverapplehwaccess">com.apple.driver.AppleHWAccess</h3>

<p>Provides a user mode <code class="language-plaintext highlighter-rouge">AppleHWAccessUserClient</code> IOKit service that allows for direct access to physical memory</p>

<h3 id="comappledriverappleintelcpupowermanagementdriver">com.apple.driver.AppleIntelCPUPowerManagementDriver</h3>

<h3 id="comappledriverapplenvmepassthrough">com.apple.driver.AppleNVMePassThrough</h3>

<p>Provides a IOKit user mode service <code class="language-plaintext highlighter-rouge">AppleNVMePassThroughUC</code> to pass through commands directly to the
NVMe controller.</p>

<p>Dangerous on Apple products as NVMe uses namespaces to store / read things like bridgeOS root filesystem
bridgeOS firmware, SysCfg, NVRAM, etc.  (oh and whatever AppleEAN is?)</p>

<h3 id="comappledriverappleinteltglgraphicsframebuffer">com.apple.driver.AppleIntelTGLGraphicsFramebuffer</h3>

<h3 id="comappledriverusbappleusbrecoveryhost">com.apple.driver.usb.AppleUSBRecoveryHost</h3>

<p>Originally designed to support restoring a macOS install on the T2 from <code class="language-plaintext highlighter-rouge">UniversalMac</code> which for some reason never
saw completion.  Probably too disruptive to existing SI investments.</p>

<p>For the Intel design, internet recovery suffers from a yet unsolved downgrade/upgrade problem.  Internet recovery will
accept any valid signed <code class="language-plaintext highlighter-rouge">BaseSystem.dmg</code> without rollback or timestamped signatures, making anyone in the IP path
capable of pushing any build they like, including internal ones containing <code class="language-plaintext highlighter-rouge">MojoKDP.kext</code>.  This, with the <code class="language-plaintext highlighter-rouge">MOJO</code>
SMC key set, allows for an attacker to enable an unauthenticated kernel debug port whereby full control of the device
is possible using <code class="language-plaintext highlighter-rouge">lldb</code>.</p>

<h3 id="comappledriverapplersm--comappledriverusbappleusbvhcirsm">com.apple.driver.AppleRSM / com.apple.driver.usb.AppleUSBVHCIRSM</h3>

<p><code class="language-plaintext highlighter-rouge">USBVHCI</code> is the T2’s virtual USB over PCIe controller.</p>

<h3 id="comappledriverdrizzleplatformsupport">com.apple.driver.DrizzlePlatformSupport</h3>

<p>Some god awful mashup of the SMC, bluetooth and 8254X ethernet…</p>

<p>Wonder if it can be tripped explicitly based on conditions even if intended to be used
via VMware to give a legit use case.</p>

<h3 id="comappledriverdrizzlesmc">com.apple.driver.DrizzleSMC</h3>

<h3 id="comappledriverkernelrelaytesterhost">com.apple.driver.KernelRelayTesterHost</h3>

<p>Seems paired with <code class="language-plaintext highlighter-rouge">com.apple.driver.KernelRelayHost</code>.  Allows for a user mode application to open
the IOKit class <code class="language-plaintext highlighter-rouge">KernelRelayTesterUC</code> to be able to call the following:</p>

<h4 id="exttestfunction">extTestFunction</h4>

<p>Demangled Symbol: <code class="language-plaintext highlighter-rouge">int64_t KernelRelayTesterUC::extTestFunction(KernelRelayTesterUC *__hidden this, KernelRelayTesterUC *, void *, IOExternalMethodArguments *)</code></p>

<h4 id="extsenddata">extSendData</h4>

<p>Demangled Symbol: <code class="language-plaintext highlighter-rouge">int64_t KernelRelayTesterUC::extSendData(KernelRelayTesterUC *__hidden this, KernelRelayTesterUC *, void *, IOExternalMethodArguments *)</code></p>

<h4 id="externalmethod">externalMethod</h4>

<p>Demangled Symbol: <code class="language-plaintext highlighter-rouge">int64_t KernelRelayTesterUC::externalMethod(KernelRelayTesterUC *__hidden this, unsigned int, IOExternalMethodArguments *, IOExternalMethodDispatch *, OSObject *, void *)</code></p>

<h3 id="comappledriverluahardwareaccess">com.apple.driver.LuaHardwareAccess</h3>

<p><a href="https://en.wikipedia.org/wiki/Lua_(programming_language)">Lua</a> is a language often leveraged for lightweight
extension scripts (nginx for example does this).  For reasons beyond me, Apple created a Lua engine for kernel
mode and signed it…</p>

<p>A user mode program can evaluate code in the kernel by using <code class="language-plaintext highlighter-rouge">LuaHardwareAccessUserClient</code> and passing Lua code
to it.</p>

<h3 id="comappledrivermedetect">com.apple.driver.MEDetect</h3>

<p>This appears to be a tool to detect and correct “neuter” Intel management engines.  This process is
acomplised one of two ways, by setting an undocumented “HAP” or high assurance profile bit that
disables the bulk of the ME functionality, crippling the boot code causing the ME to hang, or both.
This should only be applicable for T1 and prior as the MacEFI binary comes from the T2 later on.
The Intel ME is not generally used in the macOS platform, so (warning conjecture) this seems
to be primarily to ensure the device’s ME / AMT / CSME is enabled for SigInt.</p>

<p>It is detection only as only the Intel ME can update its code, therefore it cannot be repaired
barring some non-standard method.  See also <code class="language-plaintext highlighter-rouge">eficheck</code>.</p>

<p>Boot Arguments:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">no_medetect</code></li>
  <li><code class="language-plaintext highlighter-rouge">medetect_panic</code></li>
</ul>

<h3 id="comappledriverkisapplekis">com.apple.driver.kis.AppleKIS</h3>

<p>Second hand knowledge says this is related to the Kanzi internal debug cable.  This would be needed
for demoting a device during restore.  I’m strongly starting to wonder if USB-C cables plumb through
pins that could be used for this purpose, or if it is used with a form of remote USB to tunnel over
other transits.</p>

<h3 id="comappledriverusbappleusbkdp">com.apple.driver.usb.AppleUSBKDP</h3>

<p>USB base kernel debug port.  Combine with below to bad effect.  Only documented kernel debuggers are ethernet,
and legacy Firewire serial.  This seems to allow for USB mode debug.  See also: MojoKDP</p>

<p>Boot Arguments:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">kdp_match_name</code> with values <code class="language-plaintext highlighter-rouge">usb</code>, <code class="language-plaintext highlighter-rouge">XHC</code></li>
  <li><code class="language-plaintext highlighter-rouge">AppleUSBKDP-debug</code></li>
  <li><code class="language-plaintext highlighter-rouge">AppleUSBDebugControllerPCI-debug</code></li>
  <li><code class="language-plaintext highlighter-rouge">AppleUSBXHCIDebugController-debug</code></li>
</ul>

<h3 id="comappleiokitrusbhostfamily">com.apple.iokit.RUSBHostFamily</h3>

<p>Allow for USB devices to appear as though they are local when they are in fact not.  Has a user client
IOKit class, so logical that the device comes from user-mode on the system (which obviously depending
the user mode binary could be from anywhere, synthetic, network, etc)</p>

<p>Boot Arguments:</p>

<ul>
  <li>RUSBHostPort-debug</li>
  <li>RUSBHostController-debug</li>
  <li>RUSBHostDevice-debug</li>
</ul>

<h3 id="comappleiokitfipscavs-kext-tool">com.apple.iokit.fipscavs-kext-tool</h3>

<p>Wanna just break crypto? <a href="https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Module-Validation-Program/documents/fips140-2/FIPS1402DTR.pdf">https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Module-Validation-Program/documents/fips140-2/FIPS1402DTR.pdf</a></p>

<p>Seems you can just new up a <code class="language-plaintext highlighter-rouge">IOFIPSCipherUserClient</code></p>

<h3 id="comapplekextmojokdp">com.apple.kext.MojoKDP</h3>

<p>A debug protocol with two versions (mojo1, mojo2).  Original find form 2017 via Parallels memory capture
and the professional edition ability to inject kernel debug.  In this year I had my logic board replaced
multiple times due to graphics issues, each time booting in recovery when the device was new would result
in no entry for <code class="language-plaintext highlighter-rouge">MojoKDP</code> in <code class="language-plaintext highlighter-rouge">ioreg</code> but seemingly after leaving my computer in my apartment alone this
node would appear, but only in recovery mode.</p>

<h3 id="comapplepaedriverapplequaibridgepcie">com.apple.pae.driver.AppleQuaibridgePCIE</h3>

<p>From my best guess seems to be direct access to the PCIe bus?</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Backstory Found this years ago while being stalked in SF mojo_thor. Recently I've found more kernel extensions beyond just MojoKDP that are involved. MojoKDP was originally found by running a VM, then capturing the memory state providing a core dump. (see other repo) Overall Theory Two Possibilities: * Apple signs…]]></summary></entry><entry><title type="html">The Security Weakness of the M1</title><link href="https://rickmark.me/blog/the-security-weakness-of-the-m1/" rel="alternate" type="text/html" title="The Security Weakness of the M1" /><published>2022-07-30T01:15:54+00:00</published><updated>2022-07-30T01:15:54+00:00</updated><id>https://rickmark.me/blog/the-security-weakness-of-the-m1</id><content type="html" xml:base="https://rickmark.me/blog/the-security-weakness-of-the-m1/"><![CDATA[<h1 id="tldr">tl;dr</h1>

<p>The M1 and iBoot was overall a massive step forward in boot integrity for our devices, but the use of an encrypted
boot-loader (as opposed to EFI which was not encrypted) makes it’s security guarantees impossible to verify.  In
addition, other regressions are outlined.</p>

<h2 id="static-and-dynamic-analysis-of-the-boot-loader">Static and Dynamic Analysis of the Boot-loader</h2>

<p>The security industry routinely performs analysis of security critical code components (the linux kernel, uBoot,
TianoCore) or in cases where the source code is not available, by reverse engineering binary components (iBoot).  This
allows the “many eyes make bugs shallow” theory to improve the overall security of our devices.  Early boot components
get the most scrutiny due to the “secure-boot-chain” or that a device is only as secure as all the element in the
chain that precede it.  <code class="language-plaintext highlighter-rouge">checkm8</code> is a massive issue largely because the chain was broken permanently at the earliest
stage of the boot process, where it is fixed in ROM.</p>

<p>It is this authors belief that iBoot, had it been open source, would have had this bug discovered and corrected much
sooner than the span between the 5s (2013) and the X (2017) with the addition of the T2 (shipping today in 2022
devices).  Nothing in the iBoot loader is particularly trade secret (as evidenced as Apple left it in the clear in
the shipping of the M1 <code class="language-plaintext highlighter-rouge">applevm2</code> stack).  This allows us to examine a nearly complete M1 boot process, but leaves
out the possibility of full verification, save NDAs with Apple or illegally obtained source material.  Given how wide
spread the iBoot source disclosure was, I believe if Apple want’s to maintain its market position of “secure
devices” that is a cornerstone of the App Store debate, it should make this fully open to external review.</p>

<h2 id="lack-of-ability-to-create-measurements-externally">Lack of ability to create measurements externally</h2>

<p>Yes, again.  The only way to assure an iBoot based device is to restore it, which is potentially expensive in
time.  A high assurance path to performing a measurement (hashes of regions, reading APTicket) would allow a
device to be attested without restore.</p>

<h2 id="relocation-of-securerom-to-volatile-memory">Relocation of SecureROM to volatile memory</h2>

<p>The initial stages of SecureROM copy the executable region to mutable SRAM (static ram).  This provides no benefit, as
only the data region need be in mutable memory.  Cache shadowing of ROM is sufficient to ensure that performance is
acceptable.  By existing in DRAM, any coprocessor released from reset with DMA path, or any incomplete clearing of
SRAM (the detection of ROM vs SRAM run is via a <code class="language-plaintext highlighter-rouge">&lt;</code> operator, which means it could be possible to execute SecureROM
code at neither ROM nor SRAM by being further into the address space) would potentially compromise the SecureROM
guarantees.  Given that the PMP is also an ARM core, and manages power state machine changes, this may indicate a
flaw in that core may cause errant PMGR sequences that may violate the secure boot chain “cold” boot state.</p>

<h2 id="security-dependence-on-hydrausb-c-ace-etc">Security dependence on Hydra/USB-C (ACE) etc</h2>

<p>The ACE (USB-C port controller) was able to be used to push a device to DFU without user interaction.  This flow
should require a physical key be depressed while the command is received to prevent misuse.  All port controllers
must operate safely from ROM until SecureROM has exited as well and co-processor verification can take place.</p>

<h2 id="the-pmp-and-pmgr">The PMP and PMGR</h2>

<p>A malicious PMP firmware can prevent the DFU flow as it is the processor handling the DFU chord.  Apple should
return to a ROM based DFU entry method.</p>

<h2 id="lack-of-documentation-of-escapes-to-secure-boot-flow">Lack of documentation of escapes to secure boot flow</h2>

<p>The usage of “dev build on production hardware” allows anyone with privileged access at Apple to create blue pill
operating systems that are nearly impossible to detect.  Other operating systems solve this with “big scary warning”
when a device is running a non-production / secure code path.</p>

<h2 id="bonus-section">Bonus Section</h2>

<h3 id="xnu-kernels-failure-to-prevent-dlopen-of-mh_executable-objects">XNU Kernel’s Failure to prevent <code class="language-plaintext highlighter-rouge">dlopen</code> of <code class="language-plaintext highlighter-rouge">MH_EXECUTABLE</code> objects</h3>

<p>Every modern operating system guarantees that only dynamic libraries may be loaded by the dynamic symbol
system (<code class="language-plaintext highlighter-rouge">dlopen</code> in POSIX, <code class="language-plaintext highlighter-rouge">LoadLibrary</code> on Windows) and not executables.  The ‘quirk’ that macOS picked up by
allowing executables compiled as PIC (position independent code) as all code now is to support user mode ASLR,
violates the security axiom of “principal of least surprise”.  Apple should immediately prevent the loading
of <code class="language-plaintext highlighter-rouge">MH_EXECUTABLE</code> objects via <code class="language-plaintext highlighter-rouge">dlopen</code>.</p>

<h3 id="implement-trust-zone-like-secure-and-non-secure-user-task-modes">Implement trust-zone like secure and non-secure user task modes</h3>

<p>Security of processes could be improved by allowing the dynamic linker to run in usermode in a similar way to how
trust-zone has two worlds.  This would allow the linker to stay in user mode but to only be able to bind from
secure mode - making the pages read only to normal user-task mode and rw to the privileged mode.  This prevents
malicious code from rebinding symbols.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[tl;dr The M1 and iBoot was overall a massive step forward in boot integrity for our devices, but the use of an encrypted boot-loader (as opposed to EFI which was not encrypted) makes it’s security guarantees impossible to verify. In addition, other regressions are outlined. Static and Dynamic…]]></summary></entry><entry><title type="html">Dissection of the Apple Internet Recovery protocol and Security Analysis</title><link href="https://rickmark.me/blog/dissection-of-the-apple-internet-recovery-protocol-and-security-analysis/" rel="alternate" type="text/html" title="Dissection of the Apple Internet Recovery protocol and Security Analysis" /><published>2022-07-30T01:15:00+00:00</published><updated>2022-07-30T01:15:00+00:00</updated><id>https://rickmark.me/blog/dissection-of-the-apple-internet-recovery-protocol-and-security-analysis</id><content type="html" xml:base="https://rickmark.me/blog/dissection-of-the-apple-internet-recovery-protocol-and-security-analysis/"><![CDATA[<p>#</p>

<p>NOTE: The authors’ machine always downgrades from 10.15.3 to 10.13.0 via
internet recovery, therefore some experiments may not be working the same
due to a network issue with an attacker at a position of privilege on the
network.</p>

<h2 id="verification-of-basesystemdmg-and-osdinstalldmg">Verification of BaseSystem.dmg and OSDInstall.dmg</h2>

<p>See <code class="language-plaintext highlighter-rouge">doc/chunklist_v1.md</code> and <a href="https://github.com/t8012/cnklverify">https://github.com/t8012/cnklverify</a></p>

<h2 id="request--response-of-internet-recovery-image-location">Request / Response of Internet Recovery image location</h2>

<p>PAW and ruby code</p>

<p><code class="language-plaintext highlighter-rouge">doc/Apple Internet Recovery.paw</code>
<code class="language-plaintext highlighter-rouge">lib/request_recovery.rb</code></p>

<p>It seems that it is impossible to fake a response from the Apple Internet
recovery server, but since the forgery token isn’t included with the signed
response, it opens up the case where a man-in-the-middle attack on the request
may occur.  This leads to the potential to downgrade an operating system.</p>

<p>This may be in part due to the age of the IR protocol and lack of stronger
PKI based crypto in older (read Lion 10.9) versions of IR.</p>

<h3 id="request-format">Request Format</h3>

<p>A session cookie is requested from <a href="http://osrecovery.apple.com/">http://osrecovery.apple.com/</a> then
A request is made to <a href="http://osrecovery.apple.com/InstallationPayload/RecoveryImage">http://osrecovery.apple.com/InstallationPayload/RecoveryImage</a></p>

<p>A request is in the form of:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    cid=A64F96125D28533D
    sn=C079442000SJRWLAX
    bid=Mac-7BA5B2DFE22DDD8C
    k=CF4EF754A68299485E52179B73382421FDBE38BAA06C7CE518A9A4BA91E3C96D
    os=latest
    bv=17.16.11081.0.0,0
    fg=9ECA302EC3E25279AA80C088EF82A821DAD22197B8516F2E9966CC462B524393
</code></pre></div></div>

<p>An analysis of variables comes to these assumed names</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">cid</code> - The T2 ECID</li>
  <li><code class="language-plaintext highlighter-rouge">sn</code> - Motherboard Serial number</li>
  <li><code class="language-plaintext highlighter-rouge">bid</code> - Board ID (BDID)</li>
  <li><code class="language-plaintext highlighter-rouge">k</code> - Key or some form of challenge (unknown, server accepts any value)</li>
  <li><code class="language-plaintext highlighter-rouge">os</code> - The requested OS</li>
  <li><code class="language-plaintext highlighter-rouge">bv</code> - Version of bridgeOS</li>
  <li><code class="language-plaintext highlighter-rouge">fg</code> - Anti forgery challenge (unknown, server accepts any value)</li>
</ul>

<h3 id="response-format">Response Format</h3>

<p>A response is in the form of</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    AP: 041-76812
    AU: http://oscdn.apple.com/content/downloads/22/29/041-76812a/2liqsakq9ocpldao5gxogpqqkg3666itc6/RecoveryImage/BaseSystem.dmg
    AH: 0DD88446D924DC180B25085F53BEA4A2B148024F69EA93E265AEC2F1102E4CB4
    AT: expires=1585251286~access=/content/downloads/22/29/041-76812a/2liqsakq9ocpldao5gxogpqqkg3666itc6/RecoveryImage/BaseSystem.dmg~md5=aade63d0bf105b660880b522ee16276f
    CU: http://oscdn.apple.com/content/downloads/22/29/041-76812a/2liqsakq9ocpldao5gxogpqqkg3666itc6/RecoveryImage/BaseSystem.chunklist
    CH: 791BD581006AD8147F988138B434A2CB792D87F4C2187BD992CC06B64234CA4A
    CT: expires=1585251286~access=/content/downloads/22/29/041-76812a/2liqsakq9ocpldao5gxogpqqkg3666itc6/RecoveryImage/BaseSystem.chunklist~md5=7b7ae5fd362c4ff1b216016121f6cb87
</code></pre></div></div>

<p>An analysis shows the following values</p>

<ul>
  <li>AP - Apple’s update ID for the package, from the software update catalog</li>
  <li>AU - base system URL to download from (dmg)</li>
  <li>AH - Some form of hash for the base system URL / content</li>
  <li>AT - BaseSystem URL token cookie (Passed in the next request as a cookie header)</li>
  <li>CU - chunklist URL (this becomes dangerous if downgrade attacked to v1)</li>
  <li>CH - Chunklist URL hash / content</li>
  <li>CT - Chunklist URL token cookie (Passed in the next request as a cookie header)</li>
</ul>

<h2 id="credit">Credit</h2>

<p>Research by Rick Mark and moved from <code class="language-plaintext highlighter-rouge">rickmark/apple_net_recovery</code></p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[NOTE: The authors' machine always downgrades from 10.15.3 to 10.13.0 via internet recovery, therefore some experiments may not be working the same due to a network issue with an attacker at a position of privilege on the network. Verification of BaseSystem.dmg and OSDInstall.dmg See…]]></summary></entry><entry><title type="html">Qualcomm Baseband Research</title><link href="https://rickmark.me/blog/qualcomm-baseband-research/" rel="alternate" type="text/html" title="Qualcomm Baseband Research" /><published>2022-07-30T01:14:11+00:00</published><updated>2022-07-30T01:14:11+00:00</updated><id>https://rickmark.me/blog/qualcomm-baseband-research</id><content type="html" xml:base="https://rickmark.me/blog/qualcomm-baseband-research/"><![CDATA[<h1 id="bbfw"><code class="language-plaintext highlighter-rouge">bbfw</code></h1>

<p>Zip package containing:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">sbl1.mbn</code> - Secondary Bootloader (after ROM PBL)</li>
  <li><code class="language-plaintext highlighter-rouge">Info.plist</code> - Apple update information</li>
  <li><code class="language-plaintext highlighter-rouge">Options.plist</code> - Zero? Seems in error? (Even empty plists have length)</li>
  <li><code class="language-plaintext highlighter-rouge">qdsp6sw.mbn</code> - Qualcomm Hexagon Digital Signal Processor (non-ARM core)</li>
  <li><code class="language-plaintext highlighter-rouge">tz.mbn</code> - Qualcomm TrustZone Implementation - QSEE</li>
  <li><code class="language-plaintext highlighter-rouge">hyp.mbn</code> - Qualcomm Hypervisor Execution Environment - QHEE - EL2</li>
  <li><code class="language-plaintext highlighter-rouge">xbl_cfg.mbn</code> - For XBL (eXtensible Boot Loader) or EFI based SPL signed static data</li>
  <li><code class="language-plaintext highlighter-rouge">restoresbl1.mbn</code> - Secondary program loader (bootloader) for baseband recovery</li>
  <li><code class="language-plaintext highlighter-rouge">acdb.mbn</code> - Accessory Calibration Database (seems to be initial)</li>
  <li><code class="language-plaintext highlighter-rouge">apps.mbn</code> - Userland baseband applications</li>
  <li><code class="language-plaintext highlighter-rouge">rpm.mbn</code> - Rollback prevention manager</li>
  <li><code class="language-plaintext highlighter-rouge">wdt.mbn</code> - Watchdog Timer</li>
  <li><code class="language-plaintext highlighter-rouge">mba.mbn</code> - QURT - Qualcomm Realtime OS Kernel image</li>
  <li><code class="language-plaintext highlighter-rouge">dsp3.mbn</code></li>
</ul>

<h2 id="mbn-signature-format">MBN Signature Format</h2>

<p>Contains a C struct styled header, followed by hashes, a signature and a certificate chain.</p>

<p>MBNs are ill-designed because the ELF header contains the offset to the signature region, which signs the ELF header
creating a circular dependency.</p>

<h3 id="header-region">Header Region</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Likely depends on hash type - samples found stated PK algorithm scep384r1 having a signature size of 384 - deterministic noncing?</span>
<span class="c1">// does this lead to a potential leak of private key with double nonce values?</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">hash</span><span class="p">[</span><span class="n">HASH_TYPE_SIZE</span><span class="p">];</span> <span class="c1">// Unfortuantly they used all zeros to encode an empty region instead of hash of zeros...</span>
                              <span class="c1">// This seems to always be true of the signature area (b01) but also of other regions?</span>
<span class="p">}</span> <span class="n">mbn_hash_row_t</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
  <span class="n">kSHA2_384</span> <span class="o">=</span> <span class="mh">0x06</span><span class="p">;</span>
<span class="p">}</span> <span class="n">mbn_hash_type_t</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">uint32_t</span> <span class="n">hash_rows</span><span class="p">;</span>         <span class="c1">// Number of hash rows - samples with 0 have hashes but no signature... and 0xFFFFFFFF for</span>
                              <span class="c1">// pk_hash.  It also has hash rows, perhaps its a problem via multiple verification paths?</span>
  <span class="n">mbn_hash_type_t</span> <span class="n">hash_type</span><span class="p">;</span>  <span class="c1">// 6 - SHA2-384?</span>
  <span class="kt">uint32_t</span> <span class="o">=</span> <span class="mi">0</span>
  <span class="kt">uint32_t</span> <span class="o">=</span> <span class="mi">0</span>
  <span class="kt">uint32_t</span> <span class="n">hash_and_signature_size</span><span class="p">;</span> <span class="c1">// Little endian - data following header and extra</span>
  <span class="kt">uint32_t</span> <span class="n">hash_size</span><span class="p">;</span> <span class="c1">// size in bytes of hash type row size * rows - signature follows</span>
  <span class="kt">uint32_t</span> <span class="n">pk_hash_one</span><span class="o">?</span> <span class="o">=</span> <span class="mh">0xFFFFFFFF</span> <span class="o">/</span> <span class="mh">0xA803708F</span>
  <span class="kt">uint32_t</span> <span class="n">signature_size</span><span class="p">;</span> <span class="c1">// Size of ASN.1 signature following hash list</span>
  <span class="kt">uint32_t</span> <span class="n">pk_hash_two</span><span class="o">?</span> <span class="o">=</span> <span class="mh">0xFFFFFFFF</span> <span class="o">/</span> <span class="mh">0xA803708F</span> <span class="c1">// Usually matches pk_hash_one</span>
  <span class="kt">uint32_t</span> <span class="n">some_size</span><span class="p">;</span>  <span class="c1">// Some header item size or possibly align value?</span>
  <span class="kt">uint32_t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">uint32_t</span> <span class="n">extra_size</span><span class="p">;</span> <span class="c1">// Seems to be 0x78 bytes long... 64bit extension?</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">extra</span><span class="p">[</span><span class="n">extra_size</span><span class="p">];</span>
  <span class="n">mbn_hash_row_t</span> <span class="n">hashes</span><span class="p">[</span><span class="n">hash_rows</span><span class="p">];</span>
<span class="p">}</span> <span class="n">mbn_header_t</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</code></pre></div></div>

<h4 id="examples-of-headers">Examples of headers</h4>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>restoresbl1.b01
00000000 06000000 00000000 00000000 A8120000 40020000 FFFFFFFF 68000000 FFFFFFFF 00100000 00000000 78000000
00000000 00000000 00000000 E1401400 00000000 00000000 00000000 04000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 B7EB6FD8 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qdsp06sw.b01
0C000000 06000000 00000000 00000000 40050000 40050000 A803708F 00000000 A803708F 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>multi_image.b01
00000000 06000000 00000000 00000000 F8100000 90000000 FFFFFFFF 68000000 FFFFFFFF 00100000 00000000 78000000
00000000 00000000 22000000 E1401400 00000000 00000000 00000000 04000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 B7EB6FD8 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hyp.b01
00000000 06000000 00000000 00000000 C0000000 C0000000 FFFFFFFF 00000000 FFFFFFFF 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>devcfg.b01
00000000 06000000 00000000 00000000 C0000000 C0000000 FFFFFFFF 00000000 FFFFFFFF 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apps.b01
04000000 06000000 00000000 00000000 70020000 70020000 C821F980 00000000 C821F980 00000000 00000000 00000000
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aop.b01
00000000 06000000 00000000 00000000 F0000000 F0000000 C880E08F 00000000 C880E08F 00000000 00000000 00000000
</code></pre></div></div>

<h3 id="asn1-encoded-signature">ASN.1 Encoded Signature</h3>

<h4 id="ecdsa-scep384r1">ECDSA scep384r1</h4>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9062 // ASN1 string header

// SHA2-384 of the data to sign
BCD8BE0C F9D0C2FD 4B19F174 CCEB6387 C3B05F17 1BAFA3D1 3DD12AC1 067E2B17 4424C5B4 9DC318C5 5E45C5F9 9E703066

02 // Type?
31 // Length
00 // Compression of point? (possible non-standard 0/1 instead of 03/04)
C0BA9832 B6F45BA2 AB8D411E E1C719F6 42342B86 2D4D3623 C7252D13 507339D7 C7EDAF53 5C84C3FA 1D14ABE4 BA1048A4

02 // Type?
31 // Length
00 // Compression of point?
8A8598AD B921E977 1276DACC 6FCEAA7A DEA4E971 EABAFEEB 61FF5F55 11AAB378 48C91884 8C6CE7E4 BABC4907 05F1E36F
</code></pre></div></div>

<h3 id="asn1-encoded-certificate-chain">ASN.1 Encoded Certificate Chain</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SEQUENCE (3 elem)
  SEQUENCE (8 elem)
    [0] (1 elem)
      INTEGER 2
    INTEGER (63 bit) 5102134721289033247
    SEQUENCE (1 elem)
      OBJECT IDENTIFIER 1.2.840.10045.4.3.3 ecdsaWithSHA384 (ANSI X9.62 ECDSA algorithm with SHA384)
    SEQUENCE (3 elem)
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
          UTF8String Test Eureka SOC Root CA 35
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.10 organizationName (X.520 DN component)
          UTF8String Apple Inc.
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.8 stateOrProvinceName (X.520 DN component)
          UTF8String California
    SEQUENCE (2 elem)
      UTCTime 2018-05-15 22:12:28 UTC
      UTCTime 2018-05-16 22:12:28 UTC
    SEQUENCE (2 elem)
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
          UTF8String Test Eureka SOC Root CA 35 Leaf
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.10 organizationName (X.520 DN component)
          UTF8String Apple Inc.
    SEQUENCE (2 elem)
      SEQUENCE (2 elem)
        OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
        OBJECT IDENTIFIER 1.3.132.0.34 secp384r1 (SECG (Certicom) named elliptic curve)
      BIT STRING (776 bit) 0000010011101011000011110010001100011110100010100110000000100001100000…
    [3] (1 elem)
      SEQUENCE (4 elem)
        SEQUENCE (3 elem)
          OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
          BOOLEAN true
          OCTET STRING (2 byte) 3000
            SEQUENCE (0 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.29.35 authorityKeyIdentifier (X.509 extension)
          OCTET STRING (24 byte) 301680140C64EDABDEA076FCCBB4F49FBDB75D46F597AF32
            SEQUENCE (1 elem)
              [0] (20 byte) 0C64EDABDEA076FCCBB4F49FBDB75D46F597AF32
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension)
          OCTET STRING (22 byte) 0414DD5C0F80952FB597AB60DD9282EA70B80EEA0E7A
            OCTET STRING (20 byte) DD5C0F80952FB597AB60DD9282EA70B80EEA0E7A
        SEQUENCE (3 elem)
          OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension)
          BOOLEAN true
          OCTET STRING (4 byte) 03020780
            BIT STRING (1 bit) 1
  SEQUENCE (1 elem)
    OBJECT IDENTIFIER 1.2.840.10045.4.3.3 ecdsaWithSHA384 (ANSI X9.62 ECDSA algorithm with SHA384)
  BIT STRING (816 bit) 0011000001100100000000100011000000110100111101101000100011111010111100…
    SEQUENCE (2 elem)
      INTEGER (382 bit) 8151756030331056487823161874997707277988121415666908648513990112722474…
      INTEGER (383 bit) 1281400542485460847206440091939968328867920960916542938903846231152859…
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SEQUENCE (3 elem)
  SEQUENCE (8 elem)
    [0] (1 elem)
      INTEGER 2
    INTEGER (61 bit) 1625249655888498160
    SEQUENCE (1 elem)
      OBJECT IDENTIFIER 1.2.840.10045.4.3.3 ecdsaWithSHA384 (ANSI X9.62 ECDSA algorithm with SHA384)
    SEQUENCE (3 elem)
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
          UTF8String Test Eureka SOC Root CA 35
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.10 organizationName (X.520 DN component)
          UTF8String Apple Inc.
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.8 stateOrProvinceName (X.520 DN component)
          UTF8String California
    SEQUENCE (2 elem)
      UTCTime 2018-05-15 21:55:08 UTC
      UTCTime 2038-05-10 21:55:08 UTC
    SEQUENCE (3 elem)
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
          UTF8String Test Eureka SOC Root CA 35
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.10 organizationName (X.520 DN component)
          UTF8String Apple Inc.
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.8 stateOrProvinceName (X.520 DN component)
          UTF8String California
    SEQUENCE (2 elem)
      SEQUENCE (2 elem)
        OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
        OBJECT IDENTIFIER 1.3.132.0.34 secp384r1 (SECG (Certicom) named elliptic curve)
      BIT STRING (776 bit) 0000010001111010111101000100010110101111010000000101100101000010110101…
    [3] (1 elem)
      SEQUENCE (3 elem)
        SEQUENCE (3 elem)
          OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
          BOOLEAN true
          OCTET STRING (8 byte) 30060101FF020100
            SEQUENCE (2 elem)
              BOOLEAN true
              INTEGER 0
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension)
          OCTET STRING (22 byte) 04140C64EDABDEA076FCCBB4F49FBDB75D46F597AF32
            OCTET STRING (20 byte) 0C64EDABDEA076FCCBB4F49FBDB75D46F597AF32
        SEQUENCE (3 elem)
          OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension)
          BOOLEAN true
          OCTET STRING (4 byte) 03020204
            BIT STRING (6 bit) 000001
  SEQUENCE (1 elem)
    OBJECT IDENTIFIER 1.2.840.10045.4.3.3 ecdsaWithSHA384 (ANSI X9.62 ECDSA algorithm with SHA384)
  BIT STRING (832 bit) 0011000001100110000000100011000100000000111101001001010000001111111011…
    SEQUENCE (2 elem)
      INTEGER (384 bit) 3764405614543861553181393903194413274471521338802557327047703229534942…
      INTEGER (384 bit) 2942036852031372040337745727030783615133201264286154596397242159682249…
</code></pre></div></div>

<h2 id="sahara-protocol">Sahara Protocol</h2>

<p>Based on a public gitlab copy of msm8974 headers</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Sahara command IDs */</span>
<span class="k">enum</span> <span class="n">boot_sahara_cmd_id</span>
<span class="p">{</span>
  <span class="n">SAHARA_NO_CMD_ID</span>          <span class="o">=</span> <span class="mh">0x00</span><span class="p">,</span>
  <span class="n">SAHARA_HELLO_ID</span>           <span class="o">=</span> <span class="mh">0x01</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_HELLO_RESP_ID</span>      <span class="o">=</span> <span class="mh">0x02</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_READ_DATA_ID</span>       <span class="o">=</span> <span class="mh">0x03</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_END_IMAGE_TX_ID</span>    <span class="o">=</span> <span class="mh">0x04</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_DONE_ID</span>            <span class="o">=</span> <span class="mh">0x05</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_DONE_RESP_ID</span>       <span class="o">=</span> <span class="mh">0x06</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_RESET_ID</span>           <span class="o">=</span> <span class="mh">0x07</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_RESET_RESP_ID</span>      <span class="o">=</span> <span class="mh">0x08</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_MEMORY_DEBUG_ID</span>    <span class="o">=</span> <span class="mh">0x09</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_MEMORY_READ_ID</span>     <span class="o">=</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_CMD_READY_ID</span>       <span class="o">=</span> <span class="mh">0x0B</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_CMD_SWITCH_MODE_ID</span> <span class="o">=</span> <span class="mh">0x0C</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_CMD_EXEC_ID</span>        <span class="o">=</span> <span class="mh">0x0D</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>
  <span class="n">SAHARA_CMD_EXEC_RESP_ID</span>   <span class="o">=</span> <span class="mh">0x0E</span><span class="p">,</span> <span class="cm">/* sent from target to host */</span>
  <span class="n">SAHARA_CMD_EXEC_DATA_ID</span>   <span class="o">=</span> <span class="mh">0x0F</span><span class="p">,</span> <span class="cm">/* sent from host to target */</span>

  <span class="cm">/* place all new commands above this */</span>
  <span class="n">SAHARA_LAST_CMD_ID</span><span class="p">,</span>
  <span class="n">SAHARA_MAX_CMD_ID</span>             <span class="o">=</span> <span class="mh">0x7FFFFFFF</span> <span class="cm">/* To ensure 32-bits wide */</span>
<span class="p">};</span>
</code></pre></div></div>

<h2 id="baseband-config">Baseband Config</h2>

<p><code class="language-plaintext highlighter-rouge">bbcfg</code> files are a 48 byte header:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">magic</span> <span class="o">=</span> <span class="err">'\</span><span class="mi">0</span><span class="n">GFC</span><span class="err">'</span><span class="p">;</span> <span class="c1">// LE 'CFG\0'</span>
    <span class="kt">uint32_t</span> <span class="n">header_size</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// Offset to next magic?</span>
    <span class="kt">uint32_t</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="kt">uint32_t</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span> <span class="n">bbcfg_header_t</span><span class="p">;</span>

<span class="n">typdef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint64_t</span> <span class="n">magic</span> <span class="o">=</span> <span class="mh">0xDAEF3003DAEF3003</span><span class="p">;</span> <span class="c1">// Magic</span>
    <span class="kt">uint64_t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// Guess: offset following header?</span>
    <span class="kt">uint64_t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// Guess: size, 0 being to EoF</span>
    <span class="kt">uint8_t</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="n">name</span><span class="p">;</span> <span class="c1">// 'BBCFGMBN'</span>
<span class="p">}</span> <span class="n">bbcfg_mbn_header_t</span><span class="p">;</span>
</code></pre></div></div>

<p>The remaining data is ASN1 - DER encoded:</p>

<ul>
  <li>Tag 0 - String: Build Type (<code class="language-plaintext highlighter-rouge">Mav21_Official</code>)</li>
  <li>Tag 1 - String: Build Number (Seems in Apple <code class="language-plaintext highlighter-rouge">\d+[A-Z]\d+</code> format)</li>
  <li>Tag 2 - String: Build Host</li>
  <li>Tag 3 - String: Build User</li>
  <li>Tag 4 - String: Build Host IP Address</li>
  <li>Tag 5 - String: 6 byte short commit hash?</li>
  <li>Tag 6 - String: Build Timestamp</li>
  <li>Tag 7 - String: Branch</li>
  <li>Tag 8 - Sequence of Tag 16:</li>
  <li>Tag 200 -</li>
  <li>Tag 201</li>
  <li>Tag 202</li>
  <li>Tag 203</li>
  <li>Tag 204</li>
  <li>Tag 9 - Sequence, Patch Files?</li>
  <li>Tag 100 - String: SHA1 Hash</li>
  <li>Tag 101 - String: Binary Data</li>
</ul>

<h2 id="blobs">Blobs</h2>

<h3 id="asn-coded-files">ASN Coded Files</h3>

<ul>
  <li>Sequence containing nodes</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">600</code> - A series of patches into non-volatile</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">400</code> - Offset</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">401</code> - Unknown (Usually 0, guess - pad char?)</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">402</code> - Unknown (guess - length?)</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">403</code> - Content</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">404</code></li>
  <li>Tag <code class="language-plaintext highlighter-rouge">601</code> - A sequence of files</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">500</code> - File Name</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">501</code> - Guess: Permission? Offset?</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">502</code> - Content</li>
  <li>Tag <code class="language-plaintext highlighter-rouge">503</code></li>
  <li>Tag <code class="language-plaintext highlighter-rouge">504</code></li>
</ul>

<h3 id="stx2vg">STX2VG</h3>

<h3 id="mavz">MAVZ</h3>

<p>A compressed stream with the following header followed by <code class="language-plaintext highlighter-rouge">zlib</code> compressed data</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">uint32_t</span> <span class="n">magic</span> <span class="o">=</span> <span class="err">'</span><span class="n">MAVZ</span><span class="err">'</span><span class="p">;</span> <span class="c1">// Magic</span>
  <span class="kt">uint16_t</span> <span class="n">unknown1</span><span class="p">;</span> <span class="c1">// DE76</span>
  <span class="kt">uint16_t</span> <span class="n">unknown2</span><span class="p">;</span> <span class="c1">// 0000</span>
<span class="p">}</span> <span class="n">mavz_file_heaeder_t</span>
</code></pre></div></div>

<h2 id="xbl_cfg">xbl_cfg</h2>

<p>Signed ELF (MBN) file with a CFGL header and payloads for each entry.</p>

<p>Example files from manifest:</p>

<ul>
  <li>/6013_0100_0_dcb.bin</li>
  <li>/6013_0100_1_dcb.bin</li>
  <li>/6013_0200_1_dcb.bin</li>
</ul>

<p>Each of which appear to be machine code as evidenced by the constant string areas:</p>

<p>File contains a number of unicode (wide char) 8 byte full caps magic values:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0000</code></li>
  <li><code class="language-plaintext highlighter-rouge">DEFG</code></li>
  <li><code class="language-plaintext highlighter-rouge">ABVW</code></li>
  <li><code class="language-plaintext highlighter-rouge">HIJK</code></li>
</ul>

<h3 id="cfgl">CFGL</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">uint32_t</span> <span class="n">magic</span> <span class="o">=</span> <span class="err">'</span><span class="n">CFGL</span><span class="err">'</span><span class="p">;</span>
  <span class="kt">uint32_t</span>
  <span class="kt">uint32_t</span> <span class="n">size</span><span class="p">;</span>
<span class="p">}</span> <span class="n">cfgl_header_t</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="kt">uint32_t</span> <span class="n">unknown1</span><span class="p">;</span> <span class="c1">// 0</span>
  <span class="kt">uint32_t</span> <span class="n">file_offset</span><span class="p">;</span>
  <span class="kt">uint32_t</span> <span class="n">unknown2</span><span class="p">;</span> <span class="c1">// 04340000</span>
  <span class="kt">uint32_t</span> <span class="n">file_name_length</span><span class="p">;</span> <span class="c1">// In examples 0x14</span>
  <span class="kt">char</span><span class="p">[</span><span class="n">file_name_length</span><span class="p">]</span> <span class="o">=</span> <span class="s">"/6013_0100_0_dcb.bin"</span><span class="p">;</span>
  <span class="kt">uint32_t</span> <span class="n">unknown3</span><span class="p">;</span>
<span class="p">}</span> <span class="n">cfgl_row_t</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="qhee">QHEE</h2>

<h3 id="devices-in-hypmbn">Devices in <code class="language-plaintext highlighter-rouge">hyp.mbn</code></h3>

<p>Suspicion - <code class="language-plaintext highlighter-rouge">$</code> are serviced by the TrustZone</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">IORT</code></li>
  <li><code class="language-plaintext highlighter-rouge">QCOM</code></li>
  <li><code class="language-plaintext highlighter-rouge">2KDEMOCQ</code></li>
  <li><code class="language-plaintext highlighter-rouge">MOCQ</code></li>
  <li><code class="language-plaintext highlighter-rouge">$AOSS</code></li>
  <li><code class="language-plaintext highlighter-rouge">$BLSP</code></li>
  <li><code class="language-plaintext highlighter-rouge">$CRYPTO</code></li>
  <li><code class="language-plaintext highlighter-rouge">$DAP</code></li>
  <li><code class="language-plaintext highlighter-rouge">$DCC</code></li>
  <li><code class="language-plaintext highlighter-rouge">$ECATS_TEST</code></li>
  <li><code class="language-plaintext highlighter-rouge">$IPA</code></li>
  <li><code class="language-plaintext highlighter-rouge">$LPASS</code></li>
  <li><code class="language-plaintext highlighter-rouge">$PCIE0</code></li>
  <li><code class="language-plaintext highlighter-rouge">$QPIC</code></li>
  <li><code class="language-plaintext highlighter-rouge">$SDC2</code></li>
  <li><code class="language-plaintext highlighter-rouge">$SPDM</code></li>
  <li><code class="language-plaintext highlighter-rouge">$SPMI</code></li>
  <li><code class="language-plaintext highlighter-rouge">$TIC</code></li>
  <li><code class="language-plaintext highlighter-rouge">$USB0</code></li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[bbfw Zip package containing: * sbl1.mbn - Secondary Bootloader (after ROM PBL) * Info.plist - Apple update information * Options.plist - Zero? Seems in error? (Even empty plists have length) * qdsp6sw.mbn - Qualcomm Hexagon Digital Signal Processor (non-ARM core) * tz.mbn - Qualcomm TrustZone Implementation - QSEE * hyp.mbn…]]></summary></entry><entry><title type="html">Plug’nPwn - Connect to Jailbreak</title><link href="https://rickmark.me/blog/plugnpwn-connect-to-jailbreak/" rel="alternate" type="text/html" title="Plug’nPwn - Connect to Jailbreak" /><published>2022-07-30T01:13:49+00:00</published><updated>2022-07-30T01:13:49+00:00</updated><id>https://rickmark.me/blog/plugnpwn-connect-to-jailbreak</id><content type="html" xml:base="https://rickmark.me/blog/plugnpwn-connect-to-jailbreak/"><![CDATA[<hr />

<p>Authors</p>

<ul>
  <li>Rick Mark</li>
  <li>mrarm</li>
  <li>Aun-Ali Zaidi</li>
  <li>h0m3us3r
published: Oct 12, 2020</li>
</ul>

<hr />

<h1 id="plugnpwn---connect-to-jailbreak">Plug’nPwn - Connect to Jailbreak</h1>

<h2 id="state-of-the-world-checkm8-checkra1n-and-the-t2">State of the World: checkm8, checkra1n and the T2</h2>

<p>For those just joining us, news broke last week about the jailbreaking of Apple’s T2 security processor in
recent Macs. If you haven’t read it yet, you can catch up on the story here, and try this out yourself at home
using the latest build of checkra1n. So far we’ve stated that you must put the computer into DFU before you can
run checkra1n to jailbreak the T2 and that remains true, however today we are introducing a demo of replacing a
target Mac’s EFI and releasing details on the T2 debug interface.</p>

<h2 id="a-monkey-by-any-other-name">A Monkey by any Other Name</h2>

<p>In order to build their products unlike app developers Apple has to debug the core operating system. This is how
firmware, the kernel and the debugger itself are built and debugged. From the earliest days of the iPod, Apple has
built specialized debug probes for building their products. These devices are leaked from Apple headquarters and their
factories and have traditionally had monkey related names such as the “Kong”, “Kanzi” and “Chimp”. They work by allowing
access to special debug pins of the CPU, (which for ARM devices is called Serial Wire Debug or SWD), as well as other
chips via JTAG and UART. JTAG is a powerful protocol allowing direct access to the components of a device and access
generally provides the ability to circumvent most security measures. Apple has even spoken about their debug capabilities
in a BlackHat talk describing the security measures in effect. Apple has even deployed versions of these to their retail
locations allowing for repair of their iPads and Macs.</p>

<h2 id="the-bonobo-in-the-myst">The Bonobo in the Myst</h2>

<p>Another hardware hacker and security researcher Ramtin Amin did work last year to create an effective clone of the
Kanzi cable. This combined with the checkm8 vulnerability from axi0mX allows iPhones 5s - X to be debugged.</p>

<h2 id="the-usb-port-on-the-mac">The USB port on the Mac</h2>

<p>One of the interesting questions is how does the Macs share a USB port with both the Intel CPU (macOS) and the
T2 (bridgeOS) for DFU.  These are essentially separate computers inside of the case sharing the same pins.  Schematics
of the MacBook leaked from Apple’s vendors (a quick search with a part number and “schematic”), and analysis of the
USB-C firmware update payload show that there is a component on each port which is tasked with both multiplexing
(allowing the port to be shared) as well as terminating USB power delivery (USB-PD) for the charging of the MacBook or
connected devices.  Further analysis shows that this port is shared between the following:</p>

<ul>
  <li>The Thunderbolt controller which allows the port to be used by macOS as Thunderbolt, USB3 or DisplayPort</li>
  <li>The T2 USB host for DFU recovery</li>
  <li>Various UART serial lines</li>
  <li>The debug pins of the T2</li>
  <li>The debug pins of the Intel CPU for debugging EFI and the kernel of macOS</li>
</ul>

<p>Like the above documentation related to the iPhone, the debug lanes of a Mac are only available if enabled via the
T2.  Prior to the checkm8 bug this required a specially signed payload from Apple, meaning that Apple has a skeleton
key to debug any device including production machines.  Thanks to checkm8, any T2 can be demoted, and the debug
functionality can be enabled.  Unfortunately Intel has placed large amounts of information about the Thunderbolt
controllers and protocol under NDA, meaning that it has not been properly researched leading to a string of
vulnerabilities over the years.</p>

<h2 id="the-usb-c-plug-and-usb-pd">The USB-C Plug and USB-PD</h2>

<p>Given that the USB-C port on the Mac does many things, it is necessary to indicate to the multiplexer what device
inside the Mac you’d like to connect too.  The USB-C port specification provides pins for this exact purpose (CC1/CC2)
as well as detecting the orientation of the cable allowing for it to be reversible.  On top of the CC pins runs another
low speed protocol called USB-PD or USB power delivery.  It is primarily used to negotiate power requirements between
chargers(sources) and devices (sinks).  USB-PD also allows for arbitrary packets of information in what are called
“Vendor Defined Messages” or VDMs.</p>

<h2 id="apples-usb-pd-extensions">Apple’s USB-PD Extensions</h2>

<p>The VDM allows Apple to trigger actions and specify the target of a USB-C connection.  We have discovered USB-PD payloads
that cause the T2 to be rebooted and for the T2 to be held into a DFU state.  Putting these two actions together, we can
cause the T2 to restart ready to be jailbroken by checkra1n without any user interaction.  While we haven’t tested a Apple
Serial Number Reader, we suspect it works in a similar fashion, allowing the devices ECID and Serial Number to be read from
the T2’s DFU reliably.  The Mac also speaks USB-PD to other devices, such as when an iPad Pro is connected in DFU mode.</p>

<p>Apple needs to document the entire set of VDM messages used in their products so that consumers can understand the security
risks.  The set of commands we issue are unauthenticated, and even if they were they were undocumented and thus
un-reviewed.  Apple could have prevented this scenario by requiring that some physical attestation occurs during these VDMs
such as holding down the power button at the same time.</p>

<h2 id="putting-it-together">Putting it Together</h2>

<p>Taking all this information into account, we can string it together to reflect a real world attack.  By creating a specialized
device about the size of a power charger, we can place a T2 into DFU mode, run checkra1n, replace the EFI and upload a key
logger to capture all keys.  This is possible even though macOS is un-altered (the logo at boot is for effect but need
not be done).  This is because in Mac portables the keyboard is directly connected to the T2 and passed through to macOS.</p>

<h2 id="video-demo">VIDEO DEMO</h2>

<h3 id="plugnpwn-automatic-jailbreak">PlugN’Pwn Automatic Jailbreak</h3>

<p>PlugNPwn is the entry into DFU directly from connecting a cable to the DFU port</p>

<p><img src="https://img.youtube.com/vi/LRoTr0HQP1U/0.jpg" alt="PlugNPwn" /></p>

<h3 id="replacing-the-t2-macefi-with-secureboot-enabled">Replacing the T2 MacEFI with SecureBoot Enabled</h3>

<p>In the next video we use checkra1n to modify the MacEFI payload for the Intel processor</p>

<p><img src="https://img.youtube.com/vi/uDSPlpEP-T0/0.jpg" alt="PlugNPwn" /></p>

<h2 id="usb-c-debug-probe">USB-C Debug Probe</h2>

<p>In order to facilitate further research on the topic of USB-PD security, and to allow users at home to perform
similar experiments we are pleased to announce pre-ordereing of our USB-PD screamer.  It allows a computer to directly
“speak” USB-PD to a target device.  Get more info here:</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Authors * Rick Mark * mrarm * Aun-Ali Zaidi * h0m3us3r published: Oct 12, 2020 Plug'nPwn - Connect to Jailbreak State of the World: checkm8, checkra1n and the T2 For those just joining us, news broke last week about the jailbreaking of Apple’s T2 security processor in recent Macs. If you haven't read…]]></summary></entry><entry><title type="html">ACE Controller Secrets</title><link href="https://rickmark.me/blog/ace-controller-secrets/" rel="alternate" type="text/html" title="ACE Controller Secrets" /><published>2022-07-30T01:12:36+00:00</published><updated>2022-07-30T01:12:36+00:00</updated><id>https://rickmark.me/blog/ace-controller-secrets</id><content type="html" xml:base="https://rickmark.me/blog/ace-controller-secrets/"><![CDATA[<p>NOTE: This was originally published on <code class="language-plaintext highlighter-rouge">blog.t8012.dev</code> in conjunction with h0meus3r, mrarm, and aunali1</p>

<h3 id="introduction">Introduction</h3>

<p><img src="/assets/images/ace-controller-secrets/s-l400-2.jpg" alt="s-l400-2" /></p>

<p>After our team successfully ported the checkm8 exploit to the AppleSilicon T2 chip, we began exploring methods for
closed-case hardware debugging, or CCD, as found on other iDevices. On such devices, the Serial Wire Debug protocol
can be muxed out across the Lightning connector, which we presumed was replicable across the USB Type-C connector.
With some assistance from easily obtainable schematics for our MacBook models, we have determined that muxing
is handled by an Apple/TI co-designed USB Type-C Port Controller, colloquially known as “ACE”. The following details
our findings and the vendor defined protocol, termed AppleVDM, Apple has implemented over the USB Power Delivery
standard for muxing out various internal peripherals.</p>

<p>A member of our team, @h0m3us3r has dumped the ACE firmware by attaching a SWD probe onto exposed test points on
the logic board of a MacBook Pro. Thanks to this we were able to obtain both the ROM and the firmware payload patch
applied over it and discover that the ACE chip contains a Cortex-M0 r0p1 ARM core. Most of the static analysis was
later conducted by @mrarm.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connecting to target via SWD
Found SW-DP with ID 0x0BC11477
DPIDR: 0x0BC11477
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x04770031)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x410CC601. Implementer code: 0x41 (ARM)
Found Cortex-M0 r0p1, Little endian.
FPUnit: 4 code (BP) slots and 0 literal slots
CoreSight components:
ROMTbl[0] @ E00FF000
ROMTbl[0][0]: E000E000, CID: B105E00D, PID: 000BB008 SCS
ROMTbl[0][1]: E0001000, CID: B105E00D, PID: 000BB00A DWT
ROMTbl[0][2]: E0002000, CID: B105E00D, PID: 000BB00B FPB
Cortex-M0 identified.
</code></pre></div></div>

<h2 id="ace-overview">ACE Overview</h2>

<p>To better understand the inner-workings of ACE, we began looking for identifying information within the dumped
firmware. We found the string <code class="language-plaintext highlighter-rouge">CD3217   HW0022 FW002.032.00 ZACE2-J213</code> and upon searching CD3217 online resulted
in the similar <a href="https://www.ti.com/lit/ds/symlink/tps65986.pdf">TI TPS65986</a>. Based on how similar the functional
description of the aforementioned TI USB Type-C Controller is to ACE, and considering that TI co-designed ACE
with Apple, it was reasonable to assume most of the technical information applies to ACE.</p>

<p>TI’s USB Type-C Controllers expose an I²C interface for host management, for which we found the excellent Host
<a href="https://www.ti.com/lit/ug/slvuan1a/slvuan1a.pdf">Interface Technical Reference Manual</a>, documenting a multitude
of public I²C registers and commands.</p>

<p><img src="/assets/images/ace-controller-secrets/TPS65986_block.png" alt="TPS65986 Functional Block Diagram" /></p>

<p>The primary component of focus based on the above block diagram is the digital core, which communicates directly
with the host and runs the firmware we dumped previously. As mentioned, the core is based on a Cortex-M0 r0p1.
Unfortunately, we were unable to create a complete memory map with peripherals as TI does not release public
information on the core itself. Regardless, we have the basic memory layout as follows:</p>

<p>Since we weren’t sure whether the code for muxing out things lives in the ACE or somewhere else (there are
registers for receiving vendor messages and processing them on another chip), we also investigated the firmware
of chips that can directly communicate with the ACE, the SMC, part of T2 SoC, and the Thunderbolt controller. While
we obtained and analyzed the I2C usages in the SMC firmware and found no suspicious code whatsoever, we had issues
with analyzing the Thunderbolt controller firmware and decided to only reverse engineer it as a last resort. We
initially thought that the only way that we could talk with the ACE from Mac OS (Intel) was by modifying the SMC
firmware to relay commands to the ACE. While we have successfully managed to edit the SMC firmware and talk with
the ACE, it turned out that this effort wasn’t needed. Later we stumbled upon the following project:
<a href="https://github.com/osy/ThunderboltPatcher">osy/ThunderboltPatcher</a>, which uses the AppleHPM kext in order
to communicate with the ACE.</p>

<p>The <code class="language-plaintext highlighter-rouge">AppleHPM</code> KEXT allows a user space program running as root to read and write ACE registers. It also has
several interesting methods that seem to be intended for reading and writing registers on ACEs connected using
a USB Type-C cable to the DUT. Unfortunately, while we tried invoking them, we didn’t manage to get these
methods working, suggesting that either they have been disabled on production hardware or need some more preparation
work in order to work. We also discovered that there exists an EFI mode firmware updater for the ACE called
<code class="language-plaintext highlighter-rouge">HPMUtil.efi</code>, which we also partially reverse engineered. There seems to be several methods of updating the
ACEs depending on the hardware revision; the EFI program also seems to have an argument that makes it update
externally connected ACEs, however at least for recent ACEs it seems to be broken; the only update route that
would work on the firmware dump we obtained from our Mac (based on available commands) seems to be hardcoded in
a few places to run commands on the local ACE.</p>

<p>There are at least 3 known revisions of the ACE chip. Based on hardware available to us, the first variant,
ACE1, is known to be used in 2018 and older T2 models, the second, ACE2, in 2019 and newer T2 models, and
the third in 2020 M1 enabled laptops. The software update method differs significantly between ACE1 and ACE2.
At the time of writing the article, we have only successfully dumped a single ACE firmware (ACE2) and all the
analysis here is based on that version.</p>

<h2 id="usb-pd">USB PD</h2>

<p>The logical channel for telling the Mac to mux out something other than USB from the chip would be USB PD, since
ACE’s main communication vector with external devices is USB PD and because controlling data lines using USB PD
is a widespread practice (see: MIPI debug interface as well as this article on getting UART off an Samsung
phone: <a href="https://ntnuopen.ntnu.no/ntnu-xmlui/bitstream/handle/11250/2632162/bookchapter.pdf">https://ntnuopen.ntnu.no/ntnu-xmlui/bitstream/handle/11250/2632162/bookchapter.pdf</a>). This TI-derived
controller can be configured to support some variant of MIPI debug mode by default (and the MIPI debug ID is
present in the Apple ACE firmware as well), however as we discovered later it is disabled in Apple’s configuration
and can not be used. As such, we decided to look for other Vendor Defined Messages that the ACE understands.</p>

<p>In the USB PD protocol, entering a vendor mode begins by sending a SVID (Standard ID or Vendor ID, usually
the vendor’s USB VID) and object position (think of it as a sub mode that the vendor can define). By analyzing the
ACE firmware we found at least 3 possible object positions under the Apple SVID, however their availability is
dynamic and by default only a single SVID and object position is available. This primary mode is, for example,
used when the Apple’s charger is connected. We are not sure when the other modes are activated and plan to do
further work related to figuring out what the purpose of these other modes is.</p>

<p>Since it would be logical if there was a reply for the command for entering a mode and also because reverse
ngineering an embedded firmware with no context whatsoever is hard, we decided to look into the VDMs command,
which can be used to send a VDM PD message. This allowed us to gather important information about the firmware’s
inner workings and also to find a few functions that sent a message with Apple’s vendor ID. We investigated
several of these, some of them were indeed related to the protocol used with the charger (which we aren’t sure
what the purpose of is; however from what it seems it can be only used to read some memory sections from the
external device), but we also found another procedure that had three cases, two of which replied with 16-bit
values (created from information from a particular memory area) in a similar way to the Discover SVIDs VDM,
and one of them was complex and handled additional logic. We investigated it further and eventually managed to
use it to mux things out of the controller.</p>

<p>Another possible use of the VDMs command can be found in the <code class="language-plaintext highlighter-rouge">AppleHPM</code> KEXT and the <code class="language-plaintext highlighter-rouge">HPLUtil.efi</code> program,
which is reading registers from externally connected devices. Since we haven’t given much attention to it
as it was not our goal and our experiments were a failure, we are not going to describe it in this article.</p>

<p>Note that since SWD can also be muxed from the ACE, further reverse engineering ACE modes is not that
interesting; you should be able to use the ACE’s SWD to trigger any mux choice of your choosing and directly
talk to all peripherals ACE has access to.</p>

<h2 id="dive-into-the-code">Dive into the code</h2>

<p>With @h0m3us3r’s dump of ROM and RAM memory, we started by loading the ACE firmware in IDA. The reset handler
address is present at <code class="language-plaintext highlighter-rouge">0x00000004</code> and can be used to get the address of the entrypoint.</p>

<p>The command table can be trivially found by looking for the 4 character codes. Register table requires a bit
more effort but is also not hard to find (since there is a register that is a string, you can find what
references it). In comparison to the public TI documentation, there are substantially more commands and
registers available, some of which are Apple-specific additions. Since the firmware has barely any strings
or debug information, the command list has been very helpful.</p>

<p>After initially exploring the firmware we quickly stumbled upon cursed looking trampolines such as the following:</p>

<pre><code class="language-assembly">ROM:000266C2 _Command_HRST                           ; DATA XREF: ROM:commandsâ†“o
ROM:000266C2
ROM:000266C2
ROM:000266C2                 PUSH            {R4-R6,LR}
ROM:000266C4                 MOV             R4, R1
ROM:000266C6                 MOV             R5, R0
ROM:000266C8                 BL              sub_E4
ROM:000266CC                 LDR             R0, =dword_20041040
ROM:000266CE                 MOV             R1, R4
ROM:000266D0                 ADDS            R0, #0x40 ; '@'
ROM:000266D2                 LDR             R2, [R0]
ROM:000266D4                 MOV             R0, R5
ROM:000266D6                 BLX             R2
ROM:000266D8                 MOV             R4, R0
ROM:000266DA                 BL              sub_E8
ROM:000266DE                 MOV             R0, R4
ROM:000266E0                 B               loc_260E2
ROM:000266E0 ; End of function _Command_HRST
</code></pre>

<p>Since IDA seems not to handle them nicely, we wrote a simple script to comment the BLX call. Unfortunately,
this does not play nicely with the IDA decompiler but was enough for further firmware research. The purpose
of these trampolines is to allow selective patching of functions in the firmware, since the main firmware
seems to reside in ROM.</p>

<p>After analyzing the VDMs (VDM send) command handler, we quickly found the function responsible for sending
arbitrary PD messages. From here, we looked at the list functions referencing it, finding a few interesting
possible investigation candidates, one of which turned out to be the one we were looking for. In addition,
it was called by a function that checked whether the <code class="language-plaintext highlighter-rouge">SOP</code> it originated from is <code class="language-plaintext highlighter-rouge">SOP'DBG</code> or <code class="language-plaintext highlighter-rouge">SOP''DBG</code>.</p>

<p><img src="/assets/images/ace-controller-secrets/HandleAppleVDM.png" alt="Handle Apple VDM" /></p>

<p>The function named <code class="language-plaintext highlighter-rouge">AppleVDM_0x12</code> in this image is in particular interesting as it is also referenced by
DVEn command. Unfortunately, with only 4 characters we were unable to derive the function from the name
alone. We decided to analyze all of these function called by this function starting from 0x10.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">AppleVDM_0x10_StartNo</span><span class="p">,</span> <span class="n">AppleVDM_0x10_NextStartNo</span><span class="p">,</span> <span class="n">AppleVDM_0x10_IterA</span><span class="p">,</span> <span class="n">AppleVDM_0x10_IterB</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">AppleVDM_Data</span><span class="p">[];</span>
<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">AppleVDM_Type1_0x10_Values</span><span class="p">[];</span>

<span class="kt">void</span> <span class="kr">__fastcall</span> <span class="nf">AppleVDM_0x10</span><span class="p">(</span><span class="kt">int</span> <span class="n">sop</span><span class="p">)</span>
<span class="p">{</span>
  <span class="c1">// Prepare the reply VDM</span>
  <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x50</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">AppleVDM_0x10_StartNo</span> <span class="p">)</span>
    <span class="n">AppleVDM_0x10_StartIter</span><span class="p">();</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">AppleVDM_0x10_StartNo</span><span class="p">;</span>
  <span class="n">bool</span> <span class="n">even</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">7</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="n">AppleVDM_0x10_GetValue</span><span class="p">(</span><span class="n">j</span><span class="p">);</span>
    <span class="n">AppleVDM_0x10_NextIter</span><span class="p">(</span><span class="o">&amp;</span><span class="n">j</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">even</span> <span class="p">)</span>
      <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">value</span> <span class="o">&amp;&amp;</span> <span class="p">(</span> <span class="o">!</span><span class="n">AppleVDM_0x10_IterA</span> <span class="o">||</span> <span class="n">AppleVDM_0x10_IterB</span> <span class="o">==</span> <span class="mi">8</span> <span class="p">)</span> <span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">value</span> <span class="o">&amp;&amp;</span> <span class="n">AppleVDM_0x10_IterB</span> <span class="o">&lt;</span> <span class="mi">8</span> <span class="p">)</span>
      <span class="k">continue</span><span class="p">;</span>

    <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">|=</span> <span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="p">(</span> <span class="n">even</span> <span class="o">?</span> <span class="mi">16</span> <span class="o">:</span> <span class="mi">0</span> <span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">even</span> <span class="p">)</span>
      <span class="o">++</span><span class="n">i</span><span class="p">;</span>
    <span class="n">even</span> <span class="o">=</span> <span class="o">!</span><span class="n">even</span><span class="p">;</span>
    <span class="n">AppleVDM_0x10_NextStartNo</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">7</span> <span class="p">)</span> <span class="p">{</span>
    <span class="n">AppleVDM_0x10_NextStartNo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">AppleVDM_0x10_StartIter</span><span class="p">();</span>
    <span class="o">++</span><span class="n">i</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">AppleVDM_0x10_ReplyMsgId</span> <span class="o">=</span> <span class="n">NextSendMessageId</span><span class="p">[</span><span class="n">sop</span><span class="p">];</span>
  <span class="n">SendMessage</span><span class="p">(</span><span class="n">sop</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">AppleVDM_0x10_StartIter</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">AppleVDM_0x10_IterA</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">AppleVDM_0x10_IterB</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">bool</span> <span class="nf">AppleVDM_0x10_NextIter</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="n">i</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">while</span> <span class="p">(</span> <span class="o">*</span><span class="n">i</span> <span class="o">&lt;</span> <span class="mh">0x40</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="c1">// the d variable is composed of two parts - the end position (bits 0:5) and the entry type (bits 6:7)</span>
    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">d</span> <span class="o">=</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="o">*</span><span class="n">i</span><span class="p">];</span>
    <span class="k">if</span> <span class="p">(</span> <span class="p">(</span> <span class="n">d</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span> <span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">AppleVDM_0x10_IterB</span> <span class="o">&lt;</span> <span class="mi">8</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="o">++</span><span class="n">AppleVDM_0x10_IterB</span><span class="p">;</span>
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// endpos is the position where this data entry ends (relative to the start of the AppleVDM_Data blob)</span>
    <span class="kt">int</span> <span class="n">endpos</span> <span class="o">=</span> <span class="n">d</span> <span class="o">&amp;</span> <span class="mh">0x3F</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">endpos</span> <span class="o">||</span> <span class="n">endpos</span> <span class="o">==</span> <span class="mh">0x3F</span> <span class="p">)</span>
      <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="o">*</span><span class="n">i</span> <span class="o">=</span> <span class="n">endpos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>

    <span class="c1">// if the type is not zero, return this index, otherwise skip</span>
    <span class="k">if</span> <span class="p">(</span> <span class="p">(</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="o">*</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span> <span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">)</span>
      <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">AppleVDM_0x10_GetValue</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">4</span> <span class="o">&gt;=</span> <span class="mh">0x40</span> <span class="p">)</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>

  <span class="kt">int</span> <span class="n">type</span> <span class="o">=</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span><span class="p">;</span>
  <span class="k">switch</span> <span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
    <span class="n">AppleVDM_0x10_IterA</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="n">AppleVDM_0x10_IterB</span> <span class="o">||</span> <span class="o">!</span><span class="n">sub_27B30</span><span class="p">())</span> <span class="o">&amp;&amp;</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">AppleVDM_0x10_IterB</span><span class="p">)</span> <span class="p">)</span>
      <span class="k">return</span> <span class="n">AppleVDM_Type1_0x10_Values</span><span class="p">[</span><span class="n">AppleVDM_0x10_IterB</span><span class="p">];</span>
  <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
    <span class="k">return</span> <span class="mh">0x100</span> <span class="o">+</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
  <span class="k">case</span> <span class="mi">3</span><span class="p">:</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">|</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This AppleVDM_0x10 function handles the 0x10 message. This function iterates over a list of possible
Actions, and presents them in a format similar to the one in Discover SVIDs (shorts followed by a 0
terminator).</p>

<p>This function wasn’t perhaps particularly interesting on it’s own but it was pretty easy to get a
rough idea of most of what is happening in general and was pretty stand-alone (other than the type
perhaps which was cross validated later).</p>

<p>Continuing to <code class="language-plaintext highlighter-rouge">0x11</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">AppleVDM_0x11_StartNo</span><span class="p">,</span> <span class="n">AppleVDM_0x11_NextStartNo</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">AppleVDM_0x11_LastArgVal</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">Apple_0x11_ArgValIdx</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">AppleVDM_Type1_0x11_Values</span><span class="p">[];</span>

<span class="kt">void</span> <span class="kr">__fastcall</span> <span class="nf">AppleVDM_0x11</span><span class="p">(</span><span class="kt">int</span> <span class="n">sop</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">argVal</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mh">0xffff</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">argVal</span> <span class="o">!=</span> <span class="n">AppleVDM_0x11_LastArgVal</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">AppleVDM_0x11_LastArgVal</span> <span class="o">=</span> <span class="n">argVal</span><span class="p">;</span>
    <span class="n">AppleVDM_0x11_StartNo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">AppleVDM_0x11_NextStartNo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">AppleVDM_0x10_StartIter</span><span class="p">();</span>
  <span class="n">Apple_0x11_ArgValIdx</span> <span class="o">=</span> <span class="n">AppleVDM_0x10_FindValue</span><span class="p">(</span><span class="n">argVal</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">Apple_0x11_ArgValIdx</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x91</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
    <span class="n">SendMessage</span><span class="p">(</span><span class="n">sop</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x51</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kr">__int8</span><span class="p">)</span><span class="n">AppleVDM_0x11_StartNo</span><span class="p">;</span>
  <span class="n">bool</span> <span class="n">even</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">7</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">even</span> <span class="p">)</span>
      <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">data</span> <span class="o">=</span> <span class="n">AppleVDM_0x11_GetReplyData</span><span class="p">(</span><span class="n">Apple_0x11_ArgValIdx</span><span class="p">,</span> <span class="n">j</span><span class="o">++</span><span class="p">);</span>
    <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">|=</span> <span class="n">data</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">even</span> <span class="o">?</span> <span class="mh">0x10</span> <span class="o">:</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">AppleVDM_0x11_NextStartNo</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">even</span> <span class="p">)</span>
      <span class="o">++</span><span class="n">i</span><span class="p">;</span>
    <span class="n">even</span> <span class="o">=</span> <span class="o">!</span><span class="n">even</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">data</span> <span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">7</span> <span class="p">)</span> <span class="p">{</span>
    <span class="n">AppleVDM_0x11_NextStartNo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">AppleVDM_0x10_StartIter</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">j</span> <span class="o">&amp;</span> <span class="mi">1</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="o">++</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">AppleVDM_0x11_ReplyMsgId</span> <span class="o">=</span> <span class="n">NextSendMessageId</span><span class="p">[</span><span class="n">sop</span><span class="p">];</span>
  <span class="n">SendMessage</span><span class="p">(</span><span class="n">sop</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="kr">__fastcall</span> <span class="nf">AppleVDM_0x11_GetReplyData</span><span class="p">(</span><span class="kt">int</span> <span class="n">argIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">argIndex</span> <span class="o">==</span> <span class="o">-</span><span class="mi">2</span> <span class="p">)</span>
    <span class="k">return</span> <span class="n">AppleVDM_0x11_GetReplyData_Type1</span><span class="p">(</span><span class="n">argIndex</span><span class="p">,</span> <span class="n">num</span><span class="p">);</span>

  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">endposAndType</span> <span class="o">=</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">argIndex</span><span class="p">];</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">endpos</span> <span class="o">=</span> <span class="n">endposAndType</span> <span class="o">&amp;</span> <span class="mh">0x3F</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">endpos</span> <span class="p">)</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">type</span> <span class="o">=</span> <span class="n">endposAndType</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">argIndex</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">j</span> <span class="o">&gt;</span> <span class="n">endpos</span> <span class="p">)</span>
      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">num</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span> <span class="n">j</span> <span class="o">&gt;</span> <span class="n">endpos</span> <span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
      <span class="n">j</span> <span class="o">+=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">|</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="kt">int</span> <span class="n">idx_b5_6</span><span class="p">,</span> <span class="n">idx_remaining</span><span class="p">,</span> <span class="n">idx_b1</span><span class="p">,</span> <span class="n">idx_221</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="o">~</span><span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">3</span><span class="p">];</span>
    <span class="n">AppleVDM_0x11_GetReplyIndexes_Type3</span><span class="p">(((</span><span class="n">t</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="p">((</span><span class="n">t</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">idx_b5_6</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">idx_remaining</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">idx_b1</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">idx_221</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">idx_b1</span> <span class="o">==</span> <span class="n">num</span> <span class="p">)</span>
      <span class="k">return</span> <span class="mh">0x100</span> <span class="o">+</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">4</span><span class="p">];</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">idx_221</span> <span class="o">==</span> <span class="n">num</span> <span class="p">)</span>
      <span class="k">return</span> <span class="mh">0x221</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">num</span> <span class="o">==</span> <span class="n">idx_b5_6</span> <span class="o">?</span> <span class="p">(</span><span class="n">argIndex</span> <span class="o">+</span> <span class="mi">5</span><span class="p">)</span> <span class="o">:</span> <span class="p">(</span><span class="n">argIndex</span> <span class="o">+</span> <span class="mi">7</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="n">num</span> <span class="o">-</span> <span class="n">idx_remaining</span><span class="p">));</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;=</span> <span class="n">endpos</span><span class="p">)</span>
      <span class="k">return</span> <span class="p">(</span><span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">|</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">AppleVDM_0x11_GetReplyData_Type1</span><span class="p">(</span><span class="kt">int</span> <span class="n">argIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">a2</span> <span class="o">&lt;</span> <span class="mi">8</span> <span class="p">)</span>
  <span class="n">result</span> <span class="o">=</span> <span class="n">AppleVDM_Type1_0x11_Values</span><span class="p">[</span><span class="mi">8</span> <span class="o">*</span> <span class="n">AppleVDM_0x10_IterB</span> <span class="o">+</span> <span class="n">num</span><span class="p">];</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">AppleVDM_0x11_GetReplyIndexes_Type3</span><span class="p">(</span><span class="kt">int</span> <span class="n">a1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a2</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">idx_b5_6</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">idx_remaining</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">idx_b1</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">idx_221</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">a1</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="o">*</span><span class="n">idx_b5_6</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="o">*</span><span class="n">idx_b1</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">a2</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="o">*</span><span class="n">idx_221</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
      <span class="o">*</span><span class="n">idx_remaining</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="o">*</span><span class="n">idx_remaining</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="o">*</span><span class="n">idx_221</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span>
  <span class="p">{</span>
    <span class="o">*</span><span class="n">idx_b1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">a2</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="o">*</span><span class="n">idx_221</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">*</span><span class="n">idx_b5_6</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
      <span class="o">*</span><span class="n">idx_remaining</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="o">*</span><span class="n">idx_b5_6</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="o">*</span><span class="n">idx_remaining</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="o">*</span><span class="n">idx_221</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">AppleVDM_0x10_FindValue</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="n">AppleVDM_0x10_StartIter</span><span class="p">();</span>
  <span class="k">while</span> <span class="p">(</span> <span class="n">AppleVDM_0x10_GetValue</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">!=</span> <span class="n">value</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">AppleVDM_0x10_NextIter</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">)</span> <span class="p">)</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">AppleVDM_0x10_IterA</span> <span class="p">)</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">2</span><span class="p">;</span>
  <span class="k">else</span>
    <span class="k">return</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This seems to list some additional information for each argument (list of these can be obtained
from the 0x10 VDM). Right now there is nothing we can say about these but for Type 2 the
information will become clear once we analyze some basic information about 0x12. Note that due
to the complexity, 0x12 was not fully analyzed and some aspects of it were skipped and instead
experimented with.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bool</span> <span class="kr">__fastcall</span> <span class="nf">AppleVDM_0x12</span><span class="p">(</span><span class="kt">int</span> <span class="n">sop</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">dataCount</span><span class="p">,</span> <span class="kt">int</span> <span class="n">internalNonVDM</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">int</span> <span class="n">replyVdoCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">internalNonVDM</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x52</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
    <span class="n">replyVdoCount</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">argVal</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mh">0xffff</span><span class="p">;</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">argLines</span> <span class="o">=</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x7F</span><span class="p">;</span>
  <span class="n">bool</span> <span class="n">argTryToExitPrevious</span> <span class="o">=</span> <span class="p">((</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="mi">16</span> <span class="o">+</span> <span class="mi">7</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">bool</span> <span class="n">argPersistThroughReset</span> <span class="o">=</span> <span class="p">((</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">24</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">bool</span> <span class="n">argExit</span> <span class="o">=</span> <span class="p">((</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">24</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">2</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">argVal</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">argTryToExitPrevious</span> <span class="p">)</span>
      <span class="n">DisableConflictingMuxModes</span><span class="p">(</span><span class="n">argLines</span><span class="p">);</span>
    <span class="k">goto</span> <span class="n">succcess</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">bool</span> <span class="n">hasNoCollidingModes</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">7</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">argLines</span> <span class="o">&amp;&amp;</span> <span class="n">LineModeInfo</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">type</span> <span class="o">&gt;=</span> <span class="mi">2u</span> <span class="p">)</span>
    <span class="n">hasNoCollidingModes</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// has active colliding mode we should exit first</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">hasNoCollidingModes</span> <span class="o">&amp;&amp;</span> <span class="n">argTryToExitPrevious</span> <span class="p">)</span> <span class="p">{</span>
    <span class="c1">// note: this method sends a reply if it fails - 0x5AC80D2 if it exits an altmode</span>
    <span class="c1">// and you need to wait or 0x5AC8092 if it fails</span>
    <span class="n">TryToExitCollidingModes</span><span class="p">(</span><span class="n">sop</span><span class="p">,</span> <span class="n">argLines</span><span class="p">,</span> <span class="n">replyVdoCount</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hasNoCollidingModes</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">hasNoCollidingModes</span> <span class="o">&amp;&amp;</span> <span class="n">argTryToExitPrevious</span> <span class="p">)</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">argTryToExitPrevious</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">hasNoCollidingModes</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">internalNonVDM</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x92</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
      <span class="n">SendMessage</span><span class="p">(</span><span class="n">sop_</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="n">replyVdoCount</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">args</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
  <span class="n">memset</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">20</span><span class="p">);</span>
  <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">dataCount</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">args</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">;</span>
    <span class="n">args</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">AppleVDM_0x12_Perform</span><span class="p">(</span><span class="n">argValue</span><span class="p">,</span> <span class="o">!</span><span class="n">argExit</span><span class="p">,</span> <span class="n">argLines</span><span class="p">,</span> <span class="n">argPersistThroughReset</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">internalNonVDM</span> <span class="p">)</span>
    <span class="p">{</span>
      <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x92</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
      <span class="n">SendMessage</span><span class="p">(</span><span class="n">sop_</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="n">replyVdoCount</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
  <span class="p">}</span>

<span class="nl">succcess:</span>
  <span class="n">AppleVDM_0x12_CollectStateForReply</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="o">&amp;</span><span class="n">AppleVDM_0x12_CurrentStateForReply</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">internalNonVDM</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="n">AppleVDM_0x12_SOPForReply</span> <span class="o">=</span> <span class="n">sop</span><span class="p">;</span>
    <span class="n">ScheduleWork</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">52</span><span class="p">,</span> <span class="n">AppleVDM_0x12_SendSuccessWithCurrentState</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">sub_25B66</span><span class="p">(</span><span class="mi">56</span><span class="p">);</span>
  <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="kr">__fastcall</span> <span class="nf">AppleVDM_0x12_CollectStateForReply</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">unsigned</span> <span class="kt">short</span> <span class="o">*</span><span class="n">sdata</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">short</span> <span class="o">*</span><span class="p">)</span> <span class="n">data</span><span class="p">;</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">3</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">4</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
  <span class="n">sdata</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetCurrentActiveModeInfo</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">type</span><span class="p">[</span><span class="mi">6</span><span class="p">]);</span>

  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">connState</span> <span class="o">=</span> <span class="n">SystemStatus</span><span class="p">.</span><span class="n">ConnState</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">connState</span> <span class="o">==</span> <span class="mi">2</span> <span class="o">||</span> <span class="n">connState</span> <span class="o">==</span> <span class="mi">3</span> <span class="p">)</span> <span class="c1">// Audio connection (Ra/Ra), Debug connection (Rd/Rd)</span>
  <span class="p">{</span>
    <span class="n">v4</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span> <span class="n">connState</span> <span class="o">==</span> <span class="mi">6</span> <span class="o">||</span> <span class="n">connState</span> <span class="o">==</span> <span class="mi">7</span> <span class="p">)</span> <span class="c1">// Connection present</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">IsPlugUpsideUp</span><span class="p">()</span> <span class="p">)</span>
      <span class="n">v4</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">else</span>
      <span class="n">v4</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="c1">// No connection</span>
  <span class="p">{</span>
    <span class="n">v4</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">|=</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">18</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">20</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">22</span><span class="p">)</span> <span class="o">|</span>
             <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">24</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">26</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">type</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="mi">28</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">v4</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">AppleVDM_0x12_SendSuccessWithCurrentState</span><span class="p">()</span>
<span class="p">{</span>
  <span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="n">byte_20044394</span> <span class="o">&lt;&lt;</span> <span class="mi">13</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x52</span><span class="p">)</span> <span class="o">|</span> <span class="mh">0x5AC8000</span><span class="p">;</span>
  <span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">SendMessageDataAfterHeader</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">AppleVDM_0x12_CurrentStateForReply</span><span class="p">,</span> <span class="mi">16</span><span class="p">);</span>
  <span class="n">SendMessage</span><span class="p">(</span><span class="n">AppleVDM_0x12_SOPForReply</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">bool</span> <span class="nf">AppleVDM_0x12_Perform</span><span class="p">(</span><span class="kt">int</span> <span class="n">argValue</span><span class="p">,</span> <span class="n">bool</span> <span class="n">activate</span><span class="p">,</span> <span class="kt">int</span> <span class="n">targetLines</span><span class="p">,</span> <span class="n">bool</span> <span class="n">persistThroughReset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">short</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">int</span> <span class="n">argIndex</span> <span class="o">=</span> <span class="n">AppleVDM_0x10_FindValue</span><span class="p">(</span><span class="n">argValue</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">argIndex</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="p">)</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">type</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">argIndex</span> <span class="o">==</span> <span class="o">-</span><span class="mi">2</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">AppleVDM_0x10_IterB</span> <span class="o">&gt;=</span> <span class="mi">7u</span> <span class="p">)</span>
      <span class="n">type</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">else</span>
      <span class="n">type</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span>
  <span class="p">{</span>
    <span class="n">type</span> <span class="o">=</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">argIndex</span><span class="p">]</span> <span class="o">&gt;&gt;</span> <span class="mi">6</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">type</span> <span class="o">==</span> <span class="mi">2</span> <span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="n">args</span> <span class="p">)</span>
      <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>

    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">extraVal</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="n">AppleVDM_0x12_Find_Type2_ExtraValue</span><span class="p">(</span><span class="n">valNo</span><span class="p">,</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">extraVal</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">result</span> <span class="p">)</span>
      <span class="n">result</span> <span class="o">=</span> <span class="n">AppleVDM_0x12_Perform_Type2</span><span class="p">(</span><span class="n">extraVal</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">valNo</span> <span class="o">==</span> <span class="o">-</span><span class="mi">2</span> <span class="p">)</span>
      <span class="n">v10</span> <span class="o">=</span> <span class="n">AppleVDM_Type1_0x12_Values</span><span class="p">[</span><span class="n">AppleVDM_0x10_IterB</span><span class="p">];</span>
    <span class="k">else</span>
      <span class="n">v10</span> <span class="o">=</span> <span class="n">AppleVDM_Data</span><span class="p">[</span><span class="n">argIndex</span> <span class="o">+</span> <span class="mi">3</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mh">0x1F</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">AppleVDM_0x12_Perform_Type3</span><span class="p">(</span><span class="n">v10</span><span class="p">,</span> <span class="n">targetLines</span><span class="p">,</span> <span class="n">activate</span><span class="p">,</span> <span class="n">argValue</span><span class="p">,</span> <span class="n">flag1</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">AppleVDM_0x12_Perform_Type2</span><span class="p">(</span><span class="kt">int</span> <span class="n">internalId</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">internalId</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">)</span>
    <span class="n">Command_GAID_Gaid</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">internalId</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="n">internalId</span> <span class="o">==</span> <span class="mi">2</span> <span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span> <span class="n">internalId</span> <span class="o">==</span> <span class="mi">2</span> <span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span> <span class="n">FindGPIOBit</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">!=</span> <span class="mh">0xFF</span> <span class="p">)</span>
        <span class="n">GPIOAction</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
      <span class="n">MEMORY</span><span class="p">[</span><span class="mh">0x4009004C</span><span class="p">]</span> <span class="o">&amp;=</span> <span class="mh">0xFEFFFFFF</span><span class="p">;</span>
      <span class="k">if</span> <span class="p">(</span> <span class="n">RegAppleVIDConfig</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mh">0x20</span> <span class="p">)</span>
        <span class="n">sub_28B22</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="n">GPIOAction</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="n">GPIOAction</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">7</span><span class="p">);</span>
    <span class="n">byte_200424F2</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">ScheduleWork</span><span class="p">(</span><span class="mi">35</span><span class="p">,</span> <span class="n">dword_200406A0</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">sub_289EE</span><span class="p">);</span> <span class="c1">// resets the GPIO</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span> <span class="n">internalId</span> <span class="o">==</span> <span class="mi">3</span> <span class="p">)</span> <span class="p">{</span>
      <span class="n">GPIOAction</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">byte_20042FC8</span> <span class="o">|=</span> <span class="mh">0x10u</span><span class="p">;</span>
    <span class="n">sub_25B66</span><span class="p">(</span><span class="mh">0x3A</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">AppleVDM_0x12_Perform_Type3</span><span class="p">(</span><span class="kt">int</span> <span class="n">internalId</span><span class="p">,</span> <span class="kt">int</span> <span class="n">targetLines</span><span class="p">,</span> <span class="n">bool</span> <span class="n">activate</span><span class="p">,</span> <span class="kt">int</span> <span class="n">argValue</span><span class="p">,</span>
                                <span class="n">bool</span> <span class="n">persistThroughReset</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">short</span> <span class="o">*</span><span class="n">params</span><span class="p">);</span>
</code></pre></div></div>

<p>The first thing we figured out from analyzing and trying to use the <code class="language-plaintext highlighter-rouge">0x12</code> handler is that Type 2 is used to reset the chip
and pulse GPIO pins. Type 2, Action 0 resets the ACE, Action 1 seems to reset the whole device, Action 2 asserts force DFU
and resets the device. We are not sure what Action 3 does as it does not seem to be exposed on our ACE.</p>

<p>For Type 1 actions, the <code class="language-plaintext highlighter-rouge">AppleVDM_0x10_FindValue</code> function returns <code class="language-plaintext highlighter-rouge">-2</code>, and as such Type 1 actions are translated to either
Type 1 or Type 2 (the last one will be Type 2).</p>

<p>For Type 3, things are more interesting and we haven’t managed to fully reverse engineer all the involved code. However,
by making some assumptions, we found code resetting the modes which allowed us to guess the meanings of <code class="language-plaintext highlighter-rouge">argTryToExitPrevious</code>,
<code class="language-plaintext highlighter-rouge">argPersistThroughReset</code> and argExit bits. In general, the params parameter seems to be only saved and not used, except
for internal action id <code class="language-plaintext highlighter-rouge">0x15</code> (external id <code class="language-plaintext highlighter-rouge">0x303</code>?), where it picks the first of one of the following parameters: <code class="language-plaintext highlighter-rouge">0x306</code>,
<code class="language-plaintext highlighter-rouge">0x30C</code>, <code class="language-plaintext highlighter-rouge">0x809E</code> and changes an IO register write based on it.</p>

<p>Decoding the <code class="language-plaintext highlighter-rouge">0x10</code> values on ACE2
Afterwards, we proceeded to decode the actions available in our firmware based on the decompiled code. This is helpful if
one wanted to analyze the firmware further.</p>

<h3 id="action-types">Action Types</h3>

<h4 id="type-1">Type 1</h4>

<p>From our ACE firmware dump the following Type 1 actions are possible (if they were actually enabled but they aren’t). It
is possible that this list may vary depending on the ACE firmware and variant pair.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0] 0x203 - internal ID 0x5
[1] 0x303 - internal ID 0x15
[2] 0x803 - internal ID 0xB
[3] 0x809 - internal ID 0xC
(4-6) are not defined
[7] 0x103 - Resolves to a General Action with an internal id of 0.
</code></pre></div></div>

<p>Note that in the case of the firmware we analyzed this exact action is available as a native Type 2 action and this
Type 1 Action is not enabled.</p>

<h4 id="type-2">Type 2</h4>

<p>On our firmware dump the following General Actions with the given VDO argument map to the following internal General
Action IDs:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0x106</code> with arg = <code class="language-plaintext highlighter-rouge">0x8001</code> maps to ID 2 (PMU reset + DFU hold)</li>
  <li><code class="language-plaintext highlighter-rouge">0x105</code> with arg = <code class="language-plaintext highlighter-rouge">0x8000</code> maps to ID 1 (PMU reset)</li>
  <li><code class="language-plaintext highlighter-rouge">0x103</code> with arg = <code class="language-plaintext highlighter-rouge">0x8000</code> maps to ID 0 (ACE GAID reset)</li>
</ul>

<p>Sending other arguments to known actions should have no effect.</p>

<h4 id="type-3">Type 3</h4>

<p>Mapping to internal IDs, again from ACE2:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0x606</code> - internal ID 2</li>
  <li><code class="language-plaintext highlighter-rouge">0x206</code> - internal ID 8</li>
  <li><code class="language-plaintext highlighter-rouge">0x304</code> - internal ID 9</li>
  <li><code class="language-plaintext highlighter-rouge">0x203</code> - internal ID 5</li>
</ul>

<p>Dumping the raw table on your device</p>

<p>It is possible to dump the AppleVDM table on any ACE and use the code above to decode it manually. This can be done by
reading the <code class="language-plaintext highlighter-rouge">0x57</code> register.</p>

<h2 id="protocol-summary">Protocol Summary</h2>

<p>With the code above available, it is possible to finally sum up how this protocol works. All messages must come
from <code class="language-plaintext highlighter-rouge">SOP'DBG</code> or <code class="language-plaintext highlighter-rouge">SOP''DBG</code>.</p>

<h3 id="applevdm-0x10-get-action-list">AppleVDM 0x10: Get Action List</h3>

<p>Input: { 0x5AC8010 }
Reply: Shorts encoded using VDM (first short in high 16 bytes, second in low 16 bytes). Zero terminated.</p>

<p>Example reply VDOs: <code class="language-plaintext highlighter-rouge">05020702 06060206 01060105 02030103 00000000</code></p>

<h3 id="applevdm-0x11-get-action-info">AppleVDM 0x11: Get Action Info</h3>

<p>Parameters:</p>

<ul>
  <li>uint16_t ActionId - specifies the action, taken from 0x10 reply
Input: { <code class="language-plaintext highlighter-rouge">0x5AC8011</code>, ActionId }
Reply: Shorts encoded using VDM (first short in high 16 bytes, second in low 16 bytes). Zero terminated.
Example reply VDOs: <code class="language-plaintext highlighter-rouge">05010103 04090305 00000000</code></li>
</ul>

<h3 id="applevdm-0x12-perform-action">AppleVDM <code class="language-plaintext highlighter-rouge">0x12</code>: Perform Action</h3>

<p>Parameters:</p>

<ul>
  <li>uint16_t ActionId- specifies the action, taken from 0x10 reply</li>
  <li>uint8_t Lines - bit mask of the lines on which the action should be muxed</li>
  <li>bool TryToExitPrevious - the ACE will try to exit any conflicting modes</li>
  <li>bool PersistSoftReset - the ACE will try to keep this mode active over a soft reset</li>
  <li>bool Exit - instead of entering this mode, let’s exit it</li>
  <li>Input:</li>
  <li>0x5AC8012</li>
  <li><code class="language-plaintext highlighter-rouge">(Exit &lt;&lt; 25) | (PersistSoftReset &lt;&lt; 24) | (TryToExitPrevious &lt;&lt; 23) | ((Lines &amp; 0x7F) &lt;&lt; 16) | ActionId }</code></li>
  <li>Output: Status of the currently active lines, encoded using 8 16-bit shorts (first short in high 16 bytes,
second in low 16 bytes): first a packed value (ConnectionState « 14) | (LineState[i] « (2 * i)) for i
between 0 and 7, exclusive), followed by 7 shorts which specify what action id is being muxed on the given line.
ConnectionState can be 0 for disconnected, 1 or 2 for a standard connected device depending on the orientation and 3
for audio and debug connections. LineState is a 2 bit value, which significance is not well known at the moment.</li>
</ul>

<h2 id="concluding-remarks">Concluding Remarks</h2>

<p>We have detailed the inner-workings of Apple’s proprietary USB Type-C Controller, termed ACE, and exposed the Vendor
Defined Messages that are used to externally control these controllers over the USB-PD protocol, termed AppleVDM. We
believe that further research in this area is crucial in exposing the hardware security mechanisms present on modern
Apple devices.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[NOTE: This was originally published on blog.t8012.dev in conjunction with h0meus3r, mrarm, and aunali1 Introduction After our team successfully ported the checkm8 exploit to the AppleSilicon T2 chip, we began exploring methods for closed-case hardware debugging, or CCD, as found on other iDevices. On such devices, the Serial…]]></summary></entry><entry><title type="html">Security Critical Kernel Object Confidentiality and Integrity</title><link href="https://rickmark.me/blog/security-critical-kernel-object-confidentiality-and-integrity/" rel="alternate" type="text/html" title="Security Critical Kernel Object Confidentiality and Integrity" /><published>2022-07-30T01:03:30+00:00</published><updated>2022-07-30T01:03:30+00:00</updated><id>https://rickmark.me/blog/security-critical-kernel-object-confidentiality-and-integrity</id><content type="html" xml:base="https://rickmark.me/blog/security-critical-kernel-object-confidentiality-and-integrity/"><![CDATA[<h1 id="license">License</h1>

<p>This work is licensed under a <a href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.</p>

<h2 id="from-the-author">From the Author</h2>

<p>Furthermore I make no intellectual property claims, other then attribution of work.  Therefore, from myself it can be used for both research as well as commercial works.  This paper draws on the ARM public reference documentation, and to the best of my knowledge does not contain any rights protected patents or any other protected materials.  This does not act as a guarantee of non-infringement as I have not made the effort to ensure non-infringement myself.  I urge commercial implementer to verify non-infringement prior to implementing, with simple credit to myself as an author.</p>

<h1 id="primer-work-in-linux-kernel-protection">Primer (Work In Linux Kernel Protection)</h1>

<p><a href="https://www.kernel.org/doc/html/latest/security/self-protection.html">https://www.kernel.org/doc/html/latest/security/self-protection.html</a></p>

<h1 id="introduction">Introduction</h1>

<p>Today many advanced operating systems have mitigation around the kinds of security bugs that they were susceptible tojust years ago.  No execute brought about an era where data in RAM could not hold executable machine code that could be modified, stack canaries sought to prevent stack smashing.  Some of the most advanced techniques such as iOS’s KTRR (Kernel Text Read-only Region) use higher privileged processor levels to prevent the kernel from disabling these protections.  All of these in total have narrowed attackers to very few possible routes whereby gaining control of the system can occur.  Broadly there are a few paths left:</p>

<ol>
  <li>From the bottom up by using EoP from un-trusted user mode bug to some modification of the kernel state that allows for privileged execution.</li>
  <li>For example, changing a process effective UID to 0</li>
  <li>Inserting libraries into other processes to provide “rootkit like” abilities</li>
  <li>From the top down by re-writing some part of the secure boot chain, allowing the attacker to control the operating system before it loads</li>
  <li>a defect in secure boot</li>
  <li>overwriting “Boot ROM” (shockingly usually not ROM but locked flash regions)</li>
  <li>blue pill like virtualization, where a malicious hyper-visor can control a guest OS that does not know it’s not running on bare metal</li>
  <li>From the side using other system elements such as the baseband processor in cell phones to modify regions of data</li>
  <li>can allow for an “over the air” attack from a LTE or WiFi chip</li>
  <li>can be used by a low privilege segment of code to modify regions of memory that would gain access to high privilege levels of the main processing element.</li>
</ol>

<p>In cases of #1 and #3, code that is in fact valid and booted using a secure boot chain has been modified into executing down code paths that are not as expected by the designers of the kernel.The common pattern in #1 and #3 compromises is that they take advantage of the fact that the kernel trusts its own mutable data structures.  Since data structures in the kernel are used to make security decisions, they are fundamentally required.  The problem in all of these situations described is that they assume that the data is valid and as was last written by the kernel.  As there are numerous ways to affect the values from outside the expected and legitimate paths, this may not be true.  Mutations can occur by use of a Read/Write gadget that allows for arbitrary read and write to kernel space.  It can also occur when DMA allows other processing elements to directly modify kernel memory.
In these cases, the code reading and making a security decision is generally undisturbed and is operating properly, albeit with incorrect data.  The failure was code that was not intended to mutate the kernel state in such a way having been executed prior to the read.  I therefore propose a new technique known as security critical kernel object confidentiality and integrity.
Errors of the #2 category are explicitly out of scope as modification of the secure boot chain would prevent sign and validate operations to occur, and can best be accomplished by other means, although hardening of the running kernel may provide some protection for the update mechanism preventing some #2 type attacks.+The basis is simple, mutations to kernel state should come only from known code paths, and therefore can create a cryptographic signature at time of mutation that can prove it was modified by an approved method.  Other parts of the kernel can then validate this hash to prove that no unauthorized modifications of state have occurred.  For the purposes of this example I base a theoretical implementation on iOS with KTRR on ARM hardware supporting TrustZone and ARMv8.3 pointer signing.
KTRR executes in the ARM TrustZone (EL3 - the secure monitor) and gives us good assurance that any code executed in the processing element at kernel privilege is part of the kernel text region, and that MMU protections have not been modified or disabled.  This also means we have some “secure world” OS we can extend.
The kernel would compile a new data structure that includes the types of kernel objects that have security properties (likethe XNU process, known as a task).  It would also include a series of valid functions in the kernel which can “sign” such objects.  For the sake of simplicity let’s ignore non-secure mutations of such objects, and assume the kernel could split task into the signed object and the non-security related mutable state.
On startup the secure world creates random tweak values for each object type to ensure one signing gadget cannot be used for different types, and stores it in secure memory.  It also generates a root key per boot stored in secure memory.  Think of this as a form of object ASLR.
Upon entering a function in the kernel such as task_create, a call to the “secure world” notifying that it is entering a task mutation function.  The secure world uses the read only structures to verify this entry point is a valid location to begin a task sign operation.  The secure world notes this state for the processor that is handling this operation, adds in validation data such as a random nonce, the stack pointer, and returns a cookie.  The function continues and either enters a commit or an abort phase.  Commit calls the secure world back with the address of the new struct and the cookie.  If the cookie is valid and we haven’t unwound the kernel stack past when the cookie was created, we use a tweaked per object type and random key in the secure world to sign the task.  If abort is called, we verify that we are in a valid sign state, and then clean up the sign operation state.  If we are invalid somehow, we panic.
We use this enter and commit/fail method to ensure that a kernel which an attacker has control of  the instruction pointer does not jump to some point within the task_create function turning it into a signing gadget.  Also, to prevent race conditions, the struct should exist in processor local memory until signed.
To ensure that the kernel maintains integrity, upon every user / kernel mode transition we tensure that the signing state does not exist and panic if it does, as it should always be committed or aborted in a single kernel operation.  Since the cookie can exist outside of the secure memory, this should not require a transition across the TrustZone barrier.
Later when the kernel needs to read the kernel object, it calls a secure world operation with the address of the kernel object.  The secure world verifies the signature and if valid copies into processor local storage.  The processor is then free to read the object and make security decisions.  The processor local cache must be reset on every kernel mode transition.</p>

<h2 id="this-scheme-can-be-further-enhanced-in-the-following-ways">This scheme can be further enhanced in the following ways:</h2>

<p><strong>Confidentiality</strong>: Encryption can be added to these operations to prevent reading sensitive values from non-approved code paths.<strong>List and tree operations</strong>: The secure world can provide append and remove operations for lists allowing an entire list of items to be validated.<strong>Tweak values passed to children</strong>:  A thread value may be able to use a tweak value from the task that it is part of to ensure that it is not moved between tasks.  Provides Merkle tree like function.<strong>Rollback prevention</strong>: By using a central monotonically increasing counter rollbacks to prior valid signed states can be avoided.<strong>Hardware acceleration</strong>:  With the ARM extension process, hardware support to increase the speed and security of this scheme can be developed.</p>

<h2 id="hardware-mitigations---the-secure-von-neumann-architecture">Hardware Mitigations - The Secure Von Neumann Architecture</h2>

<h1 id="reference-implementation">Reference Implementation</h1>

<h2 id="arm-and-the-cryptographic-extensions">ARM and The Cryptographic Extensions</h2>

<p>Because the signer and the validation key are both protected inside of the ARM TrustZone SMEM, there is no need for public / private cryptographic signing in this scene.  Further the ARMv8.2 cryptographic extensions provide hardware based acceleration of the SHA256 algorithm, which to our benefit also allows for hashing of a non-contiguous region.  This in sum total means that the HMAC Sign / Verify operations are hardware optimized and much like ARMv8.3 pointer signing may not lead to an odious burden on the operating system to sign and verify.</p>

<h2 id="op-tee-and-linaro">OP-TEE and Linaro</h2>

<p>OP-TEE () is an open source trusted execution environment which has mainline support in the linux kernel, and can be run in a QEMU AArch32/AArch64 emulated environment.  This provides the required substrate to implement a reference implementation.  In this solution we will be building an early load OP-TEE TA (trusted application) that will run inside the TrustZone of an ARM processor.
Technical Implementation</p>

<ul>
  <li>Kernel jumps to EL3 and call site is retained in ELR_EL3</li>
</ul>

<p>Experimental Tree Manifest:<a href="https://github.com/rickmark/manifest/blob/master/qemu_v8.xml">https://github.com/rickmark/manifest/blob/master/qemu_v8.xml</a></p>

<h2 id="interface">Interface</h2>

<ul>
  <li>Initialize</li>
  <li>Creates per-object tweak values and stores configuration</li>
  <li>While for the purposes of this example we will take a dynamic configuration from the REE kernel, this would not be done in practice as it would allow reconfiguration or disabling the protections set out here.  This configuration would likely be compiled directly into the TA, and immutable as the TA and the kernel are paired.</li>
  <li>The cookie could be a tweaked, random prefixed copy of the stack pointer to ensure we have returned to the same stack where the cookie was issued.</li>
  <li>Enter</li>
  <li>This notifies the TEE that a client function has been entered.  The TA verifies the instruction pointer of the processor before the secure call, and creates a cookie to mark the beginning of the transaction.</li>
  <li>Protect</li>
  <li>Pass enter cookie, sign object with object type tweak value and return signed blob, possibly encrypted</li>
  <li>Abort</li>
  <li>Clear a signing cookie state, called when a function has a gracefully handled error.</li>
  <li>Clear</li>
  <li>Called during entry to kernel mode transitions to ensure that no cookie state was leaked.  Can cause a panic if state is found.  This depends on the CPU time required for this check.</li>
  <li>Verify</li>
  <li>Verifies signature and copies to processor local cache</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[License This work is licensed under a Creative Commons Attribution 4.0 International License. From the Author Furthermore I make no intellectual property claims, other then attribution of work. Therefore, from myself it can be used for both research as well as commercial works. This paper draws on the ARM…]]></summary></entry><entry><title type="html">Design: Hybrid PROM / SPI Flash</title><link href="https://rickmark.me/blog/design-hybrid-prom-spi-flash/" rel="alternate" type="text/html" title="Design: Hybrid PROM / SPI Flash" /><published>2022-07-30T01:03:02+00:00</published><updated>2022-07-30T01:03:02+00:00</updated><id>https://rickmark.me/blog/design-hybrid-prom-spi-flash</id><content type="html" xml:base="https://rickmark.me/blog/design-hybrid-prom-spi-flash/"><![CDATA[<h1 id="todays-problem">Todays Problem:</h1>

<p>Nearly every device makes use of SPI flash for early load boot-loader as well as recovery environments.  These devices are Non-Volatile storage areas that provide the foundation of security in modern computing.  Due to a rash of boot-kits, many manufacturers now make use of PKI based verification of the SPI flash from mask ROM (Intel BootGuard for example).  While this does assist in reducing the likely-hood of arbitrary code execution, it doesn’t solve several problems:</p>

<ul>
  <li>It doesn’t allow for per-device configuration such as license data, MAC addresses, Serial Numbers, SKUs etc</li>
  <li>“Valid Signed Code” can include malware if the manufacturer looses control of their private key or ever signs a malicious payload, or a development payload/vulnerable payload that can load an arbitrary payload</li>
  <li>May still require complex SPI programmer hardware to read / write in the case of recovery</li>
  <li>Is not clear or understandable to the end user of what it’s guarantees are.  “restore” implies restore to a known good secure configuration like the device was shipped with, while signed boot-loaders just guarantee signed payloads.  Plenty of opportunity exists for other mutable configuration to break those security models (NVRAM for example)</li>
</ul>

<h2 id="what-consumers-really-want">What consumers really want:</h2>

<p>With the physical presence they want the ability to 100% of time get a device back to health.  We will go ahead and make the assumption physical presence may be either trivial or non-trivial.  Trivial may include holding the power button for an extended period, a specialized “reset” button, or the like.  Non-trivial would include opening the case of a computer and removal of a jumper.  Both of these should be hardened processes that make use of the PMU directly to ensure the device is pulled though hard reset, all memory is flushed, all other hardware is pulled into power down and they cannot be accessed via software control.
By using this it can be put into true “factory restore” as in exactly what the device originally came with.  This prevents the use of a valid signed configuration / payload to prevent the user from reclaiming hardware where an attacker had unmitigated physical access for a moment in time.  While this does in fact downgrade the firmware by design, an old, physically attested firmware is a better choice than an inability to get to a valid state (examples include PKI changes, or AMT enablement on Intel hardware, changing anti-rollback tokens to higher then available values).
<strong>Apple implemented this largely with their SecureROM concept but fell short in a number of ways:</strong></p>

<ul>
  <li>Firmware for various other controller come up that can interfere with this process, such as the Power Manager, and the USB-C / Thunderbolt controllers</li>
  <li>The restore process for an iDevice is non-atomic and complex.</li>
  <li>A lack of visual indication of this mode or the restore process means that malicious restore devices can choose to spin cycles then exit restore maintaining presence.</li>
  <li>SysCfg is conserved between restores, making it a target for long term persistence.  Any configuration such as this should be:</li>
  <li>Non-confidential and measurable from the restoring machine</li>
  <li>Signed by a valid signature to ensure only hardware OEM approved mutations occur</li>
</ul>

<p><strong>Intel Implemented this on various firmware restore processes such as the Visual BIOS but failed in other ways:</strong></p>

<ul>
  <li>The Intel ME contains large amounts of MFS data partition that cannot be reset and can affect the security of the device (CVE ish_bup)</li>
  <li>Measurements of the BIOS and OEM keys are not displayed, allowing key-swaps</li>
  <li>Clearing the NVRAM operation doesn’t seem to be respected</li>
</ul>

<p><strong>Google implemented this in the fastboot flashing protocol but failed in yet other ways:</strong></p>

<ul>
  <li>The Titan-M is consulted for root-of-trust and therefore its own SPI flash is at risk</li>
  <li>It’s not clear that it is possible to pull the device entirely though reset, analysis of the PMIC would be needed</li>
  <li>The EDL mode of the Qualcomm chip can circumvent this</li>
  <li>Portions of the flash area are not restored by this process, such as the radio GM, the FDT/CDT areas (devicespecific) etc.</li>
  <li>The surface area has been expanded by QSEE / QHEE before aboot is run</li>
</ul>

<p><strong>Amazon/Annapurna Labs Alpine v2 has yet other issues (common to headless devices, like those that use U-Boot):</strong></p>

<ul>
  <li>Re-use of signing keys allowing for developer builds to be flashed to production hardware</li>
  <li>An expectation that recovery comes from later boot components (Serial not exposed, and therefore large HTTP stacks have to be brought up with a full kernel later)</li>
</ul>

<h2 id="implementation-choices">Implementation Choices</h2>

<p><strong>High Scale Devices - Mask ROM and eFuses and Signed Configuration</strong>The reason that high scale devices like the iPhone are not entirely from ROM for this are multi-faceted.  Most center around a device and the ability to be refurbished and production-like verification testing.  By making everything ROM it makes it impossible for the device (barring solder reworking) to ever be re-configured for a new consumer.  This is why Apple approached the problem with a SecureROM and SysCfg.  This is overall the most restorable device I’ve encountered, and should the device be taken to an Apple store, and restored on a secure machine is generally highly effective.  The only additions I would add would be PKI based signing of SysCfg (may have to be checked by a later stage) and “breaking” the boot-chain once in recovery, so that a failed restore doesn’t just re-enter a bad state as there is very little visual indication.  (basically, wipe APTicket and iBoot and restore them last, don’t boot if the Baseband isn’t successfully restored etc.).  In addition careful care to ensuring other devices such as PMP cannot avoid restart / DFU with debounce on the volume keys, and the USB-C port controller firmware are the remaining threat vectors.
In addition, Apple and Google like to have “production like” devices.  These are usually gated by some form of eFuse or other tech that selects the SKU version, but a PVT/EVT is not obvious, especially when a tech can move a board between cases.
Google and Android suffer from being subject to multiple masters.  This means more of the restore process lives in Flash than an Apple device where they have tight ecosystem control.  Still, the use of Mask ROM for the Titan-M, signing of device specific config like the FDT/CDT/Radio GM, and the like would improve the Android restore of higher end devices.
<strong>Moderate Scale - Hybrid chips with write once flash regions</strong>These devices would still clearly need to make use of PKI verification of SPI as de-soldering and re-chipping a device would otherwise allow unbounded access.  In this case the SPI chip might support 3 region types.  RW/WP/RO.  RW is of course the read write portion.  WP is the traditionally “read-only” (in this case clearly a misnomer as in the case of the Chromebook EC/Titan-M) as this is really an area that is “locked down” early in the boot process and becomes non-RW.  And a third PROM version by blowing a PROM fuse.  This may require doubling the size of the SPI flash chip in these cases, but I find for the several hundred dollar devices in scope that cost is offset by support costs easily.
<strong>Small Scale Devices - Make Firmware Measurable</strong>In these devices just being able to pull the firmware and verify the version / if the device is running a particular hash would be an improvement.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Todays Problem: Nearly every device makes use of SPI flash for early load boot-loader as well as recovery environments. These devices are Non-Volatile storage areas that provide the foundation of security in modern computing. Due to a rash of boot-kits, many manufacturers now make use of PKI based verification of…]]></summary></entry><entry><title type="html">How Minimalism Hurts Security</title><link href="https://rickmark.me/blog/how-minimalism-hurts-security/" rel="alternate" type="text/html" title="How Minimalism Hurts Security" /><published>2022-07-30T01:02:50+00:00</published><updated>2022-07-30T01:02:50+00:00</updated><id>https://rickmark.me/blog/how-minimalism-hurts-security</id><content type="html" xml:base="https://rickmark.me/blog/how-minimalism-hurts-security/"><![CDATA[<h1 id="apple-device-boot-process">Apple Device Boot Process</h1>

<p>Apple has for many years valued ease of use and consumer friendliness over actual security.  This is totally clear when you consider that an Apple laptop can have its security features disabled without any clear visual indicator of this lowered security state.  (Android and Chromebooks place a large loud warning when booting in anything other then the most secure state).</p>

<h1 id="online-accounts">Online Accounts</h1>

<p>Apple does not provide historical data about your account.  This means that if an attacker gains access to your email, you are unable to create an audit trail of the events that have occurred.  An attacker can quite simply restore your backup, delete the email of the device, and then remove it from the Apple ID screen.  Microsoft has a dated but still better log of events for login to a Microsoft account, but this is still often lacking (what the account was actually logged into, or what is called the “relying party”) but still an improvement.  Clearly Microsoft provides much better visibility into the use of company owned Microsoft Accounts known as “OrgID”, but this is restricted to paying corporate customers, not consumers who, ya know, bank on outlook.com.  The best implementation of audit trail I’ve seen is GitHub.com which, although knowingly designed for a engineer class, provides a full trail of every security related event from login, to second factor modification.  Other companies, especially ones that we rely on like Google, Apple and Microsoft should provide at least that level of detail if requested.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Apple Device Boot Process Apple has for many years valued ease of use and consumer friendliness over actual security. This is totally clear when you consider that an Apple laptop can have its security features disabled without any clear visual indicator of this lowered security state. (Android and Chromebooks place…]]></summary></entry><entry><title type="html">How Apple Gets Security Wrong</title><link href="https://rickmark.me/blog/how-apple-gets-security-wrong/" rel="alternate" type="text/html" title="How Apple Gets Security Wrong" /><published>2022-07-30T01:02:10+00:00</published><updated>2022-07-30T01:02:10+00:00</updated><id>https://rickmark.me/blog/how-apple-gets-security-wrong</id><content type="html" xml:base="https://rickmark.me/blog/how-apple-gets-security-wrong/"><![CDATA[<p>NOTE: Much of this is older analysis and some is addressed by Developer Mode and Lockdown mode in iOS 16</p>

<ul>
  <li>Undocumented protocols (USB-PD, lightning, UTDM, usbmux, IPSW, etc)</li>
  <li>Use of MFi to prevent research and disclosure</li>
  <li>Lack of Physical Attestation for privileged operations</li>
  <li>Hold a key to enable auto-DFU</li>
  <li>DFU on modern iPad / iPhone cumbersome and unreliable</li>
  <li>No audit of SecureBoot source code</li>
  <li>This should be open source</li>
  <li>Lack of critical security indicators (SecureBoot off, upgrade vs erase)</li>
  <li>ChromeBook in insecure mode graphic</li>
  <li>No indicator of a restore vs a upgrade / revive</li>
  <li>Can cary forward malware on the mutable data partition</li>
  <li>Lack of adequate settings (disable BootCamp, Microsoft keys)</li>
  <li>By allowing BootCamp in full all Microsoft bugs are also Apple bugs</li>
  <li>Disable magic-pairing</li>
  <li>Debug protocols in production products</li>
  <li>Bonobo cable</li>
  <li>T2 SWD + Intel DCI</li>
  <li>No system in place to detect modifications (Configurator Verify mode)</li>
  <li>Assume that security will not be circumvented</li>
  <li>No indicator of pairing records in macOS / iOS</li>
  <li>Extracting non-user data isn’t a privacy concern</li>
  <li>Extracting user data with permission (PIN etc) is not a concern</li>
  <li>Forensic boot image</li>
  <li>No audit trail for online accounts</li>
  <li>Device removed / added to FindMy</li>
  <li>Logins</li>
  <li>Active sessions</li>
  <li>Device restored</li>
  <li>2Fa requests and approvals</li>
  <li>iMessage activations</li>
  <li>SIM card swaps / eSIM operations</li>
  <li>ApplePay enroll / disenrollment</li>
  <li>Pairing records</li>
  <li>iCloud restores</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[NOTE: Much of this is older analysis and some is addressed by Developer Mode and Lockdown mode in iOS 16 * Undocumented protocols (USB-PD, lightning, UTDM, usbmux, IPSW, etc) * Use of MFi to prevent research and disclosure * Lack of Physical Attestation for privileged operations * Hold a key to enable auto-DFU * DFU…]]></summary></entry><entry><title type="html">Design: Surface Area Reduction of the CS/ME by Using Bogus Public Keys</title><link href="https://rickmark.me/blog/design-surface-area-reduction-of-the-cs-me-by-using-bogus-public-keys/" rel="alternate" type="text/html" title="Design: Surface Area Reduction of the CS/ME by Using Bogus Public Keys" /><published>2022-07-30T01:01:08+00:00</published><updated>2022-07-30T01:01:08+00:00</updated><id>https://rickmark.me/blog/design-surface-area-reduction-of-the-cs-me-by-using-bogus-public-keys</id><content type="html" xml:base="https://rickmark.me/blog/design-surface-area-reduction-of-the-cs-me-by-using-bogus-public-keys/"><![CDATA[<h1 id="the-csme-is-scary">The CS/ME is Scary…</h1>

<p>Because the CS/ME is run before the CPU comes up, and it has complete access to a system and is even designed for remote management (see Intel AMT) perhaps our classic approach isn’t working.  Classic “High Assurance” of the Intel ME has centered around the undocumented “High Assurance Profile” bit and “nuttering” by crashing the ME after the bup or “bring up” module.  System integrators like System76 have used a slim profile for the ME where it cannot be eliminated, as it is antithetical to the FOSS nature of the systems they build.</p>

<h2 id="perhaps-using-bogus-public-keys-using-verifiably-random-data-to-lock-down-features-not-shipped">Perhaps using bogus public keys (using verifiably random data) to lock down features not shipped.</h2>

<p>The CS/ME uses the MFS for data storage.  It’s clear that it is possible to integrate signed modules not intended for a SKU into a device that isn’t supposed to have them as the manifest of shipping modules is not device specific and an entire module policy seems to have the ability to influence the SKU of the PCH/CPU.  Where features like the AMT exist, perhaps the best approach is to set the configuration even though the module isn’t enabled to ensure that if the mctpmodule is loaded, it is cut off at the pass by reading a useless management key.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[The CS/ME is Scary… Because the CS/ME is run before the CPU comes up, and it has complete access to a system and is even designed for remote management (see Intel AMT) perhaps our classic approach isn’t working. Classic “High Assurance” of the Intel ME has centered…]]></summary></entry><entry><title type="html">DataMigration iOS Mitigations</title><link href="https://rickmark.me/blog/datamigration-ios-mitigations/" rel="alternate" type="text/html" title="DataMigration iOS Mitigations" /><published>2022-07-30T01:00:07+00:00</published><updated>2022-07-30T01:00:07+00:00</updated><id>https://rickmark.me/blog/datamigration-ios-mitigations</id><content type="html" xml:base="https://rickmark.me/blog/datamigration-ios-mitigations/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>While iOS continues to advance security controls on code with signing and entitlements, key aspects of the OS are lacking in security hardening.  This paper proposes two features that could be included in iOS to increase the security of subsystems that handle untrusted data and uses the DataMigration framework as an example place for implementation.
This is compounded by the fact that DataMigration can be force triggered even when no OS upgrade has occurred</p>

<h1 id="datamigration-and-dynamic-plugins">DataMigration and Dynamic Plugins</h1>

<p>The data restore and upgrade of iOS is known as DataMigration.framework and its associated XPC workers.  During a restore or upgrade, various plugins are allowed to process data to convert it to the current OS data formats (such as upgrading SMS databases etc).  I’ve identified two issues with this system:</p>

<ol>
  <li>There is a generic very entitled plugin host process.  It holds entitlements that is a strict superset of the entitlements needed by all of the supported plugins.  This means many plugins are running in a process with higher entitlements than needed for their work.  This could be resolved by introducing a method whereby a process starts with the entitlements embedded in the process, but code can opt to drop specific entitlements or all but a set of entitlements.  Similar functionality has existed in linux for the capability model for some time.</li>
  <li>Entitlements are generally a function of the process binary.  Since the plugin host loads dynamic code, it would be beneficial if the shared object could embed an entitlement such as com.apple.datamigration.plugin that could would then allow the plugin host to choose to dlopen (without running dyld at that phase), ensure it has the proper entitlement, declare that it must be signed via the trust cache, then permit the remainder of dlopen to proceed.</li>
</ol>

<p>To further strengthen sandbox profiles, a code check that the XPC connection is occurring from an entitled process as a belt and suspenders approach to XPC communication can further improve this system.</p>

<h1 id="the-over-entitled-process">The Over Entitled Process</h1>

<p>Because the entitlements are processed at the process level, processes are over entitled.  This means that any migration plugin that has an error allowing for ACE (which, given they are processing untrusted user input is a likely source of such things) it may be able to pivot to a part of the system that is unrelated.  Let’s use a concrete example:</p>

<ul>
  <li>The migration system begins migrating contacts</li>
  <li>A plugin host process is started and the contact plugin is loaded</li>
  <li>A malformed contact is able to gain code execute in the plugin process</li>
  <li>Because the plugin has entitlements to mange keychain and profiles these can be used to pivot to a higher level of privilege even though profiles are unrelated to contacts</li>
</ul>

<h1 id="trust-cache-and-abusing-apple-libraries">Trust Cache and Abusing Apple Libraries</h1>

<p>Because there is no mechanism being used to to ensure that the code loaded in the migration plugin host was intended for that host, and the plugin host is a simple Objective-C proxy, this may mean that a process that is able to connect to the migration system can load either a Apple signed library that is unrelated to migration, or possibly depending on profile / other factors enterprise signed code into a privileged helper.
Since dlopen is an atomic operation, and doesn’t have a method to declare more information about how that loaded object is to be used, this leads to a potential EoP.  Ideally a module could be “loaded” in a pending state where the pages are mapped R and not X.  The hosting process could then check that the module meets requirements such as being Apple platform code (CDHash is part of the loaded Trust Cache), and that it is a data migration plugin.  Once those are satisfied, the dlopen could be “finalized” where the pages are given their pending X, and the normal dyld process and module init occur.
There is already a system for “preflight” and this model could be extended to include the use case outlined in the previous paragraph.  Preflight lacks the ability to perform the interrogation detailed above and more importantly doesn’t have a model that accounts for ToCToU, therefore the mapping of R → RX is key to the success of this system.</p>

<h1 id="compounding-factors">Compounding Factors</h1>

<h2 id="inadequate-protection-for-mobiledevice-framework-and-kext">Inadequate Protection for MobileDevice Framework and Kext</h2>

<p>Because these must be updated out of band of the operating system, they are able to be modified on the Data partition of a macOS system.  This allows for downgrading of the MobileDevice system without requiring it to be a entitled process.  SIP should only allow write access to /Library/Apple by installer and only by Apple signed installers that contain a right to that area of disk.A computer was observed with mds downgrading MobileDevice after using Xcode’s upgrade pkgs (only the latest supports ARM macs).  The computer would briefly show configurator working, then the device would revert to an unknown device class when the older version of the framework and kext were loaded.</p>

<h2 id="loading-a-trust-cache-for-a-different-architecture-type">Loading a Trust Cache for a Different Architecture Type</h2>

<p>TrustCaches are img4 signed objects.  Is it possible to extend an arm64e system by loading the TrustCache for arm64 into the kernel to allow pointer signing bypass?  The processes that can extend the TrustCache are:<a href="http://newosxbook.com/ent.jl?osVer=iOS13&amp;exec=MobileStorageMounter">MobileStorageMounter</a><a href="http://newosxbook.com/ent.jl?osVer=iOS13&amp;exec=softwareupdated">softwareupdated</a>Do both of these processes ensure that they do not allow an iPhone 11 does not load the trust cache for the iPhone X(therefore allowing PAC-less binaries to be loaded).  This may result in the following part of the backtrace on an iPhone 11 (which does not contain a slice for arm64 in this binary):<code class="language-plaintext highlighter-rouge">Powerstats for:   SpringBoard</code><code class="language-plaintext highlighter-rouge">UUID:             E0BBCB0B-1570-367A-9F55-910F7DE374E0</code><code class="language-plaintext highlighter-rouge">Beta Identifier:  CE46DF2B-7C46-45C7-9A97-FF949B633991</code><code class="language-plaintext highlighter-rouge">App Version:      1.0</code><code class="language-plaintext highlighter-rouge">Build Version:    50</code><code class="language-plaintext highlighter-rouge">Path:             /System/Library/CoreServices/SpringBoard.app/SpringBoard</code><code class="language-plaintext highlighter-rouge">Architecture:     arm64</code></p>

<h2 id="execve-reload-keeping-open-descriptors">execve Reload Keeping Open Descriptors</h2>

<p>It may be possible that a process with entitlements opens resources (and has the connecting process entitlements checked at that time) which remain open after execve replaces the process.  This may allow executing a new binary inside of the data migration plugin where connections have been opened and entitlements have been checked but using those connections by the replacing image.  A solution would be for a process to mark the connection as “does not survive execve” from the other end before performing the entitlements checks.  This may be the source of this part of the backtrace: <code class="language-plaintext highlighter-rouge">Binary Images:</code> <code class="language-plaintext highlighter-rouge">0x1000f8000 -                ???  ???                      &lt;39964180-42A5-3A59-8AD1-6B72E7F9B51A&gt;</code> <code class="language-plaintext highlighter-rouge">0x100940000 -                ???  ???                      &lt;B95DE91A-D8DA-3B8A-A387-86A7B978A756&gt;</code></p>

<h2 id="softlinkingframework-and-hid">SoftLinking.framework and HID</h2>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Introduction While iOS continues to advance security controls on code with signing and entitlements, key aspects of the OS are lacking in security hardening. This paper proposes two features that could be included in iOS to increase the security of subsystems that handle untrusted data and uses the DataMigration framework…]]></summary></entry><entry><title type="html">The SIM Swap Revisited</title><link href="https://rickmark.me/blog/the-sim-swap-revisited/" rel="alternate" type="text/html" title="The SIM Swap Revisited" /><published>2022-07-30T00:56:34+00:00</published><updated>2022-07-30T00:56:34+00:00</updated><id>https://rickmark.me/blog/the-sim-swap-revisited</id><content type="html" xml:base="https://rickmark.me/blog/the-sim-swap-revisited/"><![CDATA[<h2 id="terms">Terms</h2>

<p><strong>IMSI</strong> - The identifier for a particular line of service on the cellular network.  Fixed for the lifetime of the line (pending some unknown rotation scheme)</p>

<p><strong>IMEI</strong> - A unique device on the GSM network.  iPhones contain two IMEIs so that they can participate in Dual SIM (today DSS - Dual SIM Standby) because should both SIMs be from the same carrier the base station needs to be able to identify both lines separately in the core network.</p>

<p><strong>MEID</strong> - An older identifier from the CDMA specification (which did not use SIMs and instead kept this ID as the device identifier) - Modern MEIDs are the first IMEI without the check digit</p>

<p><strong>EID</strong> - An identifier for the eSIM to allow it to be identified in the eSIM provisioning process.  This identifier is used to allow a new eSIM profile (with a generated ICCID) to be sent to the device where it then works as a normal SIM application.  The iPhone eSIM can contain 10 such profiles.</p>

<p><strong>ICCID</strong> - The identifier of the SIM itself</p>

<p><strong>Ki</strong> - The key in the SIM used to prove the SIM card is held by the mobile device requesting cellular service</p>

<p><strong>AP</strong> - Application processor.  The ARM core which the Android or iOS kernel runs</p>

<p><strong>Modem</strong> - The ASIC that is tasked with driving the cellular radio</p>

<p><strong>Baseband</strong> - A general purpose processing element that manages the SIM/Modem and radios.  Connected to the AP to provide access to the cellular network</p>

<p><strong>APN</strong> - Access point name. A particular data service on the cellular network</p>

<h2 id="cellular-registration---an-overview">Cellular Registration - An Overview</h2>

<p>When a phone is powered on, brought out of airplane mode or a SIM is inserted, the device then attempts to register with the cellular network.  Roughly, the phone provides it’s IMEI, IMSI to the cellular network and uses the ability to perform a HMAC using the Ki value to prove it’s IMSI to the network.  If these operations succeed, the MS (mobile station) is allowed to use cellular resources as the subscriber.  This process generally operates entirely in the baseband as it is a real-time operating system designed for this purpose.</p>

<h2 id="malware-in-the-baseband">Malware in the Baseband</h2>

<p>The baseband is generally opaque to both the mobile operator as well as the mobile operating system and it’s AP.  Majority of the information presented to the user about a phone and its service are queries passed to the baseband (using rather antiquated AT* modem commands).  The baseband when operating normally uses the SIM or eSIM to get the IMSI and to HMAC Ki to perform the registration.  If an attacker has code execution on the baseband, it does not have to do this.  A malicious baseband can:</p>

<ul>
  <li>Use some other IMSI and Ki for registration not from the SIM or eSIM</li>
  <li>Can filter or modify voice, SMS and data traffic</li>
  <li>Can directly perform network service requests, such as enabling call forwarding without interaction</li>
  <li>Can perform a Ki HMAC and pass the resulting value to the attacker allowing them to impersonate the subscriber on the network.  This value can be either passed via cellular data or another radio (wifi for instance)</li>
  <li>Since the baseband manages IMEI, two colluding devices can “swap IMEIs” so that the cellular provider sees no change to the device being used</li>
</ul>

<h2 id="ways-to-attack-the-baseband">Ways to Attack the Baseband</h2>

<ul>
  <li>Modify the separate non-volatile storage where the baseband code and data are stored</li>
  <li>Take advantage of errors in baseband code parsing network data such as signaling data, SMS, eSIM/SIM provisioning or other traffic types</li>
  <li>From the AP interface</li>
  <li>From other baseband managed radios (bluetooth / wifi)</li>
</ul>

<h2 id="ways-to-improve">Ways to Improve</h2>

<ul>
  <li>Baseband fuzzing</li>
  <li>Baseband secure boot verification</li>
  <li>Identify and verify mutable storage of the baseband</li>
  <li>Implement SDR based attack detection</li>
  <li>IMEI public keys to provide strong device identity (instead of solely relying on the SIM as a proof of identity)</li>
  <li>Allowing the AP to verify the integrity of the baseband, and pull it through a hard reset</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Terms IMSI - The identifier for a particular line of service on the cellular network. Fixed for the lifetime of the line (pending some unknown rotation scheme) IMEI - A unique device on the GSM network. iPhones contain two IMEIs so that they can participate in Dual SIM (today DSS…]]></summary></entry><entry><title type="html">Intel Goa’uld</title><link href="https://rickmark.me/blog/intel-goauld-dark-symbiote/" rel="alternate" type="text/html" title="Intel Goa’uld" /><published>2022-07-30T00:56:19+00:00</published><updated>2022-07-30T00:56:19+00:00</updated><id>https://rickmark.me/blog/intel-goauld-dark-symbiote</id><content type="html" xml:base="https://rickmark.me/blog/intel-goauld-dark-symbiote/"><![CDATA[<h1 id="about-the-name">About the name…</h1>

<p>Look… Lots of Stargate SG1 was playing while I slept, waking up to realize why the Intel ME layout was like it was (twocopies of the Boot partition sharing pages making it impossible for it to be for reasons of resiliency).  Because it includes an Intel AMT/ME/CSME host and “guest” as well as a UEFI host/guest division, and it’s an evil force that takes advantage of its host, can hide in plain sight….  Also SymBIOSis makes ma laugh, and it has similarities to other ACPI dark-wake attacks…
Also when you’re looking at maestro, vermanus loader, arben, hotham, snowball, sigma you have to be a little punchy too.  (Not saying every word of that is kit specific).  It’s also highly likely that I’m observing an in-the-wild usage of this CVE: <a href="https://www.zdnet.com/article/intel-csme-bug-is-worse-than-previously-thought/">https://www.zdnet.com/article/intel-csme-bug-is-worse-than-previously-thought/</a> trying to detangle undocumented components vs malicious ones.</p>

<h1 id="play-at-home-with-the-capture">Play at home with the capture…</h1>

<p><a href="https://www.dropbox.com/sh/6gcgbeor709hqig/AAC5InYhG_uRFf3QOCcBiNIxa?dl=0%3Fdl%3D0">https://www.dropbox.com/sh/6gcgbeor709hqig/AAC5InYhG_uRFf3QOCcBiNIxa?dl=0?dl=0</a>
<a href="https://www.dropbox.com/sh/6gcgbeor709hqig/AAC5InYhG_uRFf3QOCcBiNIxa?dl=0">https://www.dropbox.com/sh/6gcgbeor709hqig/AAC5InYhG_uRFf3QOCcBiNIxa?dl=0</a></p>

<h1 id="apriori">Apriori:</h1>

<p><a href="https://paper.dropbox.com/doc/6uFseu7zXJg6v1gjLs1mq">+Intel x64 Hierarchy of Privilege</a> <a href="https://blog.t8012.dev/">https://blog.t8012.dev</a><a href="https://paper.dropbox.com/doc/lnawIcJBvIpbZj1zPSbxf">+Abusing EFI Variables and the AMT</a> <a href="https://www.intel.com/content/dam/www/public/us/en/security-advisory/documents/intel-csme-security-white-paper.pdf">https://www.intel.com/content/dam/www/public/us/en/security-advisory/documents/intel-csme-security-white-paper.pdf</a><a href="https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/secure_boot_chain_in_uefi/intel_boot_guard">https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/secure_boot_chain_in_uefi/intel_boot_guard</a><a href="https://www.intel.com/content/www/us/en/architecture-and-technology/intel-active-management-technology.html">https://www.intel.com/content/www/us/en/architecture-and-technology/intel-active-management-technology.html</a>
<a href="https://www.intel.com/content/www/us/en/support/articles/000007452/intel-nuc.html">https://www.intel.com/content/www/us/en/support/articles/000007452/intel-nuc.html</a></p>

<h1 id="current-working-hypothesis">Current Working Hypothesis</h1>

<h2 id="the-core-ish_bup-the-amt-and-a-csme-kit">The Core, ish_bup, The AMT and a CSME kit</h2>

<ul>
  <li>ME runs old Intel ME 11 with ish_bup CVE (this chipset lacks ROM rollback prevention) from one ME partition.  (CSE Main containing bup, kernel, syslib, icc, dal_ivm, tcb, sigma)</li>
  <li>ME runs hybrid CSME 11/12 with custom AMT OEM key + Boot Guard and rbe as well as essential features such as power management, snowball, and the Java VM</li>
  <li>The MFS data partition is shared amongst both personalities, easily done as the Main is lightweight</li>
  <li>These two personalities are stored in two Boot tables that share pages:</li>
</ul>

<p><img src="/assets/images/intel-goauld-dark-symbiote/6258a16601-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631377672887_image.png" alt="" /></p>

<ul>
  <li>Intel ME makes use of SR-IOV to share the Intel Gigabit Ethernet hardware</li>
</ul>

<h2 id="the-uefi-hosting-environment">The UEFI Hosting Environment</h2>

<ul>
  <li>rbe decompresses 8MB SPI flash into 16.8MB runtime area</li>
  <li>UEFI Boots AMI Text BIOS (NB)</li>
  <li>Loads early DXEs causing the dual driver issue later</li>
  <li>Contains custom PK/KEK/db/dbx</li>
  <li>Delta compression also explains the dual NVRAM areas which are largely or wholey duplicate (loaded at base address 0x800078 and 0x830078)</li>
  <li>Intel VT-d is leveraged to control hardware during the OS runtime phase</li>
</ul>

<h2 id="the-uefi-guest-environment">The UEFI Guest Environment</h2>

<ul>
  <li>Runs Intel Visual BIOS payload as a secure boot UEFI Capsule under AMI BIOS (SB)</li>
  <li>Update / Restore Code copies out only the “Intel Visual BIOS” EFI App - maintaining persistence, as any UEFI Protocols would maintain backward compatibility</li>
  <li>Causes reloading of core UEFI modules (double driver problem)</li>
  <li>By now it is too late to access the root UEFI</li>
  <li>By the time the Gig Ethernet adapter is brought up in UEFI Shell it is ID 0x6 - making it a highly virtualized device, likely to facilitate loopback AMT / iSCSI / PXE (it also seems to like to use the MAC address 888888888788 for these purposes:</li>
</ul>

<p><img src="/assets/images/intel-goauld-dark-symbiote/d8fa42f353-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631377277923_image.png" alt="" /></p>

<ul>
  <li>The Gig Ethernet adapter comes up under the “Managed Network Profile” and is immediately attempting to reach back over IPv4/IPv6 to a IPSec host via IKE (port 500)</li>
</ul>

<h2 id="restore--update-persistence">Restore / Update Persistence</h2>

<ul>
  <li>By using RomLegacyLayout DXE and a Faked JDEC part (parseIntelImage: SPI flash with unknown JEDEC ID 207018 found in VSCC table, decoding to STMicro as a manufacturer part ID 0x701B), a firmware update capsule can be “applied” and then delta compressed against the working payload, with blacklist DXEs removed.  A new runtime capsule is generated and stored</li>
  <li>A capsule is just a verified, UEFI executable, so the payload and the loadable code areas are separate and parseable</li>
  <li>The capsule then drops permissions to be able to write to real SPI</li>
  <li>Explains the usage of NVRAM to store the version of the UEFI payload and lack of variation on some components across updates</li>
  <li>FirmwareIdGuid stored in NVRAM as example</li>
</ul>

<p><img src="/assets/images/intel-goauld-dark-symbiote/939526316f-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631377440962_image.png" alt="" /></p>

<ul>
  <li>Avoid SVN increments by being 0xFF</li>
</ul>

<hr />

<h2 id="efi-variable-offset--0x0">EFI Variable (offset = 0x0):</h2>

<ul>
  <li>Name : SinitSvn</li>
  <li>Guid : ee5edcac-1490-a44d-820f-d43b78010ec3</li>
  <li>Attributes: 0x3 ( NV+BS )</li>
  <li>Data:</li>
  <li>
    <table>
      <tbody>
        <tr>
          <td>FF</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="tricking-the-runtime-with-nv-vars-shadowing-bs--rt-vars">Tricking the Runtime with NV vars shadowing BS / RT vars</h2>

<h2 id="storage--hiding-of-data-in-raw-areas-and-invalid-vars">Storage / Hiding of data in RAW areas and “Invalid” vars</h2>

<h2 id="analysis-nothing-novel--new-cve---but-a-real-world-kit-ware-and-ttps">Analysis: Nothing Novel / new-CVE - But a Real World Kit-Ware and TTPs</h2>

<ul>
  <li>Usage of AMT maliciously isn’t new (has happened to me in the past San Francisco circa 2017)</li>
  <li>ish_bup flaw plus a ME rollback seems plausible</li>
  <li>Dual-personality of CSME via ish_bup seems new, they share a MFS</li>
  <li>Usage of BootGuard to keep into a malicious UEFI</li>
  <li>Usage of SecureBoot to keep locked into a UEFI BIOS as a Capsule / App is new</li>
  <li>Ramdisk / iSCSI / ACPI injection into next HLOS is new / advanced</li>
  <li>Abuse of Intel Silicon Debug MSR80, especially from an OS seems novel</li>
  <li>CSME Java VM / loader is interesting</li>
  <li>Long term persistence via snowball and DRM of code via PAVP is novel</li>
</ul>

<h1 id="delta-in-the-me-file-system-mfs-is-stored-generationally">Delta in the ME File-System (MFS is stored generationally):</h1>

<p>The “OEM” configuration: <a href="https://www.dropbox.com/home/Public/Dark%20Symbiote/unpacked_ime/MFS%200000%20%5B0x006000%5D/007%20OEM%20Configuration?preview=home_records.txt">https://www.dropbox.com/home/Public/Dark%20Symbiote/unpacked_ime/MFS%200000%20%5B0x006000%5D/007%20OEM%20Configuration?preview=home_records.txt</a>My custom configuration (with a new defaults section with prior values): <a href="https://www.dropbox.com/home/Public/Dark%20Symbiote/unpacked_ime/MFS%200000%20%5B0x006000%5D/008%20Home%20Directory?preview=home_records.txt">https://www.dropbox.com/home/Public/Dark%20Symbiote/unpacked_ime/MFS%200000%20%5B0x006000%5D/008%20Home%20Directory?preview=home_records.txt</a></p>

<h1 id="the-two-personalities-of-the-csme">The Two Personalities of the CSME:</h1>

<p>Note: Not at all mad at them (it’s not in their scope of control), but this is from a System76 version of the Intel NUC known as the meer4, these devices did not and never have had the AMT as an option.  It appears there is a file in the MFS that is called cse_part which mediates which CSE boot profile is used.  (Note one is CSE Main while the other is another variant of the CSE with rbe defined as the CS/ME injected ROM Boot Extension - typically for implementation of BootGuard)</p>

<p><img src="/assets/images/intel-goauld-dark-symbiote/75e77adc7c-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631202638038_image.png" alt="" /></p>

<p>Both boot partitions reuse the same pages for code modules and share one MFS, one is more advanced than the other and includes a non-fully intel chain of signing.  The latter “CSE Main” includes the AMT portion (mctp) including the Java VM (dal_*) and the OEM signed Intel Sensor Hub bring-up ish_bup, while the other contains a full BootGuard stack(rbe) - coresponding to RB in UEFI, power manager, and custom signing elements.  In order to get a better view it might be required to patch UEFITool NE to be more forgiving of clever use of the partition tables in this way…</p>

<p><img src="/assets/images/intel-goauld-dark-symbiote/ccb32403b7-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631202897319_image.png" alt="" /></p>

<h2 id="living-through-s5-without-a-battery">Living through S5 without a battery…</h2>

<p>Enter snowball - a module that takes advantage of NVMe to save and persist host state even when power is fully removed.  This allows for a much larger kit to live through power removal than would exist if only NVRAM / SPI Flash were in use.  It’s preferred method seems to be NVMe namespace or encrypted swap.  The CSME was already able to persist small portions of data using susram (aprox 3kb) but snowball is intended for a much larger hibernate like persistance of data.  References to bioscomm, svimgboot and imagesrc in susram imply that the CSME is able to push the x64 cores into restore from suspend to disk at any time.</p>

<h2 id="the-converged-security--manageability-engine-csme-brought-to-you-mostly-by-intel">The Converged Security / Manageability Engine (CS/ME), brought to you <em>MOSTLY</em> by Intel…</h2>

<p>The Intel Sensor Hub allows OEMs to sign ish_bup which puts them in the critical path for security of the CSME.  What if you brought up the CSME as a sensor of itself?  Add to this the OEMP which allows the OEM key to be included into the CSME portion of SPI, this with rot.key seem to allow arbitrary change of the trust anchors that Intel spends doc after doc convincing us it has a valid chain of trust for…. The PMC is signed and included in one of the two personalities.  Finally a signed RBEP / rbe module is included in one personality but not the other.  (Those are the portions of this system that seem to be signed via valid chains, meaning other components are either valid or signed by those keys).</p>

<h2 id="how-to-weaponize-the-intel-sensor-hub">How to weaponize the Intel Sensor Hub…</h2>

<p>It appears to me that someone somewhere created an ISH based on a x86 core, just like the one running the ME 12 on the PCH.  This has the unfortunate effect of making it possible for the PCH to become a sensor hub unto itself.  Combine that with the custom signing of ish_bup and a little IPC (inter-process communication) magic and you can run the Intel ME as a guest of itself.  There’s even a module known as ish_srv that is intended to serve the boot image from the CSME to the sensor hub for boot (assuming it has no mutable storage of its own).
<strong>Taking control of the dTPM and giving clients the fTPM…</strong>By integrating fpf the TPM can be used to replace the dTPM on a board.  The dTPM can then be used by the kit for its on purposes.  This includes the Secure Boot policy system.
<strong>Leveraging the Power Manager</strong></p>

<h2 id="living-off-the-land-java-vm-amt-hdcpdrm">Living off the land… Java VM, AMT, HDCP/DRM…</h2>

<p>One thing I’ve observed is if it isn’t broke, don’t fix it applies.  Instead of inventing new network protocols, use mctp, protect your code and data with pavp (protected Audio/Video path) or the default DRM / HDCP component… Even have the guest CSME re-use the standard ish_svr (and /home/ish_srv/INTC_pdt and /home/ish_srv/trace_config) to send itself its CSME image.  The AMT / ME has grown to such a large closed source and undocumented size that any kit only need glue valid signed modules (and the Java runtime + the dynamic loader is wonderful glue…) together to be able to exist.  Combine this with a lack of the ability to test for the presence of these modules until far after they are loaded…. Mine were stored in a signed module called NFTP that included many core AMT technologies in the second ME personality.  The generic loader module is configured for the non Intel signed code regions that make use of dynamic loading capabilities.  (It is configured in the MFS data portion, mine had configuration for arben, audio, ish, iunit and iup_upd as well as svns).</p>

<h2 id="the-amt-has-always-been-able-to-control-boot-flow">The AMT has always been able to control boot flow…</h2>

<p>Because one is using the AMT in the stack, we have signed modules that can influence a valid signed UEFI boot process.</p>

<h2 id="usb-heci---usb-host-controller-interface">USB HECI - USB Host Controller Interface</h2>

<h2 id="did-we-really-need-nested-virtualization">Did we really need nested virtualization???</h2>

<p>Still looking but I suspect HVMP is part of the bringup of a hypervisor that is UEFI capable.</p>

<h2 id="inter-process-communication-on-the-csme">Inter-process communication on the CSME…</h2>

<p><img src="/assets/images/intel-goauld-dark-symbiote/03bdee2847-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631274322464_image.png" alt="" /></p>

<h2 id="the-policy-module-and-the-mfs">The policy module and the MFS</h2>

<p>Recall that the data portion of the Intel ME is far more malleable than code.  This is by design, as for instance we want to set our AMT configurations, but not by definition allow the AMT to run arbitrary code in the CSME.  The policy module makes use of data found in the MFS but can configure greatly powerful things like gating the debug policy of the silicon as well as enable vPro or the AMT stack.  One bad write to the SPI flash and your Intel ME can become much larger in scope due to this.  (The area is not signed).</p>

<h2 id="the-intel-power-manager">The Intel Power Manager</h2>

<p>Looks to be a custom signed OEM module built on ARCCore (the same ISA of previous Intel ME versions).  Lives in its own PMCP that includes the PMCC000 code section and an ERTABLE as well (verify but likely the config run on the CSME side).  This would have to be customized for /snowball to work correctly and to transition through power states such as firmware flashing.</p>

<h2 id="abusing-intel-bootguard-to-inject-early-efi-code">Abusing Intel BootGuard to inject early EFI code…</h2>

<p>Now that we can demonstrate that the root of trust can be broken by ish_bup it’s not surprising that we can affect lower levels of privilege such as the UEFI region.  Typically the CSME does BootGuard by booting to an authenticated boot area which then verifies the SPI flash before continuing.  Our evil host can do the same by modifying IVBP as well (SeeIntegrity Check-Value and Integrity Check Private Key).
<strong>A cooperative host EFI payload…</strong>The UEFI partition has a DXE called MePlatformReset which may be the point which switches from the AMT version to the lowered version locking away the services behind SMBios.  My hosting EFI payload was a AMI UEFI from 2018 while the “guest” was the Intel Visual BIOS from 2021, strangely the version name was stored in NVRAM, implying that the evil host wants to allow arbitrary “guest” UEFI upgrades without disturbing the host.
Other interesting portions included DXEs being loaded without an identifiable backing FFV.  This must mean they are coming from another source such as directly being placed into DRAM via DMA.
<strong>iunit and Serving OS Boot over iSCSI</strong>The same references to DUMMY ATA devices occurred in the iunit module, making me fairly sure the intent is to support iSCSI virtual LUN boot redirection (more advanced then IDEr which isn’t approprate for IDE’less systems and is more compatible with the sg or SCSI generic  / bsg block SCSI generic driver surface area)</p>

<h2 id="once-in-efi">Once in EFI…</h2>

<p>It’s not too hard to hand a faked HOB to a “guest” BDS, use and modify the result to leverage iSCSI and PXE to boot from a faked image on the other side of the ME personality (persisted thanks to snowball).  This lets a large adaptive kit run to inject itself intelligently into hypervisors, para,-virtualized kernels, boot-loaders, etc.
It seems this partitions the UEFI into a SB (Secure Boot) and a NB (Native Boot?) area mediated by SBRun.  This is a clever use of the Secure Boot system locking our user into a specific UEFI workload, the UEFI bios of our expected system itself (in my case Visual BIOS).  The Secure Boot policy of the native UEFI (AMT Text BIOS in my image) is held in the dTPM, while a new fTPM is presented to the guest image for its use.  Because of the use of copy on write or other non-reset technique, this has the unfortunate effect of causing DXEs to be loaded from both portions.  I noticed NTFS and iSCSI and a large part of iPXE being loaded a second time.  UEFITool also found two FIT tables in the payload, where the host appears to be a 2018 copy of AMI text BIOS and the guest is a 2021 copy of the Intel Visual BIOS.  Two copies of the uCode also exist at the two points in time as well.</p>

<p><img src="/assets/images/intel-goauld-dark-symbiote/ab903f5eda-s_3995126A312D89C3B54B9B9EE6A9EC443D492BAA5111D7A8A2B8B0DEC8C639AB_1631200068986_image.png" alt="" /></p>

<h2 id="handing-uefi-updates">Handing UEFI Updates…</h2>

<p>A specialized DXE providing access to the ROM layout allows a synthetic SPI flash to be created, accept an update then have the firmware layout pulled apart to a point where it can be persisted for run from SBRun.  This is because UEFI updates come often in the form of “UEFI Capsules” which are signed payloads that can be executed from high privilege levels where SPI is unlocked.  It’s a combination of the update code as well as the payload, therefore the easiest way to be adaptive is to let the code run and to inspect the results from a virtual backing store.  This explanation validates why the Intel NUC suddenly no longer wises to accept updates from the recovery mode of having the security jumper removed.</p>

<h2 id="downstream-effects">Downstream effects…</h2>

<p><strong>Warning: don’t put too much stock in this section…. By now things are sufficiently hosed up (DUBIOUS AT BEST analysis)</strong>
Overall the theme here is I kinda refuse to believe that the OS that requires me to manually configure loading of lvm2 and device mapper would automatically bring up a NFSv4 server, a static key for brltty generate and activate sshd and GPGkeys…. But I could be wrong…
I found that snowball preferred my NVMe drive, as the concept of NVMe namespaces already exist and allow it to“carve” a portion of storage for itself.  For AHCI / SATA drives, it seems that dummy ATA devices are the method.  (Thedevice is unplugged once it’s been used).  My NMVe device had a wwn or iSCSI world-wide name associated with it across a mac address that cannot exist.  The initrd of my Arch install also made use of a ieee1394 device for serial(assuming this is used for SOL / KGDB when KGDBoE isn’t possible).  During kernel load a number of PAT table mappings overlapped.  The initrd also created a number of units such as remote-fs.target that were cleaned-up on transition, also units that dynamiclly generate initrd on every shutdown, including the early load kernel event that stores uCode in initrd save_microcode_in_initrd.  The first protocols to come up included NetLink and CALIPSOv4(remoteproc_init, ras_init, nvmem_init, devlink_init and nexthop_init) all before initrd is unpacked.  brltty and “bluetooth meshing” were then included.  The batman  network protocol also is brought into scope.  The remote FS also made use of cyrpto as well.  Arch ZKOs were signed by a dynamic generated key rather then the true Arch x509 and iwlan sforshee: 00b28ddf47aef9cea7 key.  The ethernet adapter complained bitterly about being brought up the third time in the device with the same DMTF WMI GUID.  TTYs on the system were backed by the driver Serial: 8250/16550 driver, 32 ports, IRQ sharing enabled.  The “agp arbiter” came up as well in a strange way as well as many many calls to the fjes module as well.  A number of generated initrd units are later “cleaned up” which only leave the trace that they executed, without the ability to inspect the unit file.  They are symbolic links in initrd to hash file names that do not exist.  The system also seems to invalidate the entire GPG keyring from arch and creates its own.
Generated systemd units (may well be legitimate but easy to trigger incorrectly - like nfs-server):<code class="language-plaintext highlighter-rouge">[   76.029865] systemd-hibernate-resume-generator[293]: Not running in an initrd, quitting.[   76.033309] systemd-fstab-generator[290]: Parsing /etc/fstab...[   76.037654] systemd-bless-boot-generator[287]: Skipping generator, not booted with boot counting in effect.[   76.039296] systemd-gpt-auto-generator[292]: Reading EFI variable /sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f.[   76.040289] systemd[281]: /usr/lib/systemd/system-generators/systemd-bless-boot-generator succeeded.[   76.043949] systemd-gpt-auto-generator[292]: open("/sys/firmware/efi/efivars/LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f") failed: No such file or directory[   76.052434] systemd-gpt-auto-generator[292]: EFI loader partition unknown, exiting.[   76.056795] systemd-gpt-auto-generator[292]: (The boot loader did not set EFI variable LoaderDevicePartUUID.)[   76.061329] systemd-gpt-auto-generator[292]: Neither root nor /usr file system are on a (single) block device.[   76.085134] systemd[281]: /usr/lib/systemd/system-generators/systemd-cryptsetup-generator succeeded.[   76.087600] systemd[281]: /usr/lib/systemd/system-generators/systemd-gpt-auto-generator succeeded.[   76.089842] systemd[281]: /usr/lib/systemd/system-generators/rpc-pipefs-generator succeeded.[   76.092091] systemd[281]: /usr/lib/systemd/system-generators/systemd-veritysetup-generator succeeded.[   76.203831] x86/PAT: Overlap at 0x7a9a4000-0x7a9a5000[   76.206008] x86/PAT: memtype_reserve added [mem 0x7a9a4000-0x7a9a4fff], track write-back, req write-back, ret write-back[   76.208324] x86/PAT: memtype_free request [mem 0x7a9a4000-0x7a9a4fff][   76.987132] systemd[281]: /usr/lib/systemd/system-generators/cloud-init-generator succeeded.[   76.989545] systemd[281]: /usr/lib/systemd/system-generators/systemd-system-update-generator succeeded.[   76.991947] systemd[281]: /usr/lib/systemd/system-generators/nfs-server-generator succeeded.[   76.994410] systemd[281]: /usr/lib/systemd/system-generators/systemd-debug-generator succeeded.[   76.996842] systemd[281]: /usr/lib/systemd/system-generators/systemd-hibernate-resume-generator succeeded.[   76.999296] systemd[281]: /usr/lib/systemd/system-generators/netplan succeeded.[   77.001764] systemd[281]: /usr/lib/systemd/system-generators/systemd-fstab-generator succeeded.[   77.004239] systemd[281]: /usr/lib/systemd/system-generators/systemd-run-generator succeeded.[   77.006733] systemd[281]: /usr/lib/systemd/system-generators/systemd-getty-generator succeeded.[   77.009227] systemd[281]: /usr/lib/systemd/system-generators/lvm2-activation-generator succeeded.</code></p>

<ul>
  <li>Netplan uses Open Virtual Switch to setup a network between elements of the system (LAN, BT PAN, WiFi)</li>
  <li>Hibernate resume generator seems to be handling the creating of initrd re-generation logic.</li>
</ul>

<p>Strange Targets:</p>

<ul>
  <li>brltty-device - useful as a bluetooth based tty into the system</li>
  <li>darkhttpd.service - great for becoming one’s own pacman mirror</li>
  <li>initrd-switch-root.service under /usr - for a second root-fs switch away from the network mounted version to the “real” root.</li>
  <li>machine.slice - a part of the namespace control group tree that cannot be seen in cgtop</li>
  <li>mkinitcpio-generate-shutdown-ramfs.service - initrd is normally only regenerated on shutdown when updates are applied, this one seemed unconditional</li>
  <li>nfsv4-exportd.service</li>
  <li>nbd.service</li>
</ul>

<h2 id="terms---made-up-mostly">Terms - Made up mostly</h2>

<p>/snowball/sbbistres - secure/secondary boot BIST (built in self test) response/home/mca/3LVLSCD.dat - 3rd level SCD (reminds me of SLAT)/fpf/intel/SbAcmSvn/fpf/intel/SbBsmmSvn - secondary boot B? System Management Mode - Security version number/fpf/intel/SbKmSvn <strong>Storage Mechanisms for fTPM</strong>/fpf/intel/Emmc/fpf/intel/Ufs/fpf/intel/Spi</p>

<h1 id="whats-the-point">Whats the point?</h1>

<p>Year after year we add additional phases of security and boot integrity.  Hypervisors here, secure elements there… but in reality what we have done is ensure a failure of any of these systems is non-observable.  By focusing on confidentiality, we truly have lost integrity in our computing environments (</p>

<p><img src="/assets/images/intel-goauld-dark-symbiote/bb1db919ab-1f440.png" alt="eyes" title="eyes" /></p>

<p>TCG).  Why “restore from ROM” and “createmeasurements using ROM” and “export code from ROM” are not things that more IoT and devices implement might(grabs tin-foil hat) be motivated by state actors who want control of environments without it being possible to observe (</p>

<p><img src="/assets/images/intel-goauld-dark-symbiote/bb1db919ab-1f440.png" alt="eyes" title="eyes" /></p>

<p>NSA).  Sadly they missed one important point, any such engineered design flaw will quickly be reverse engineered, and re-weaponized.  The TCG should re-focus on publishing known good configuration, making specifications and code for early load boot security FOSS, and creating high integrity read-only out of band measurement (remove jumper, boot from ROM and have OEM hash displayed on the screen without executing any non-Intel code) a higher priority.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[About the name… Look… Lots of Stargate SG1 was playing while I slept, waking up to realize why the Intel ME layout was like it was (twocopies of the Boot partition sharing pages making it impossible for it to be for reasons of resiliency). Because it includes an Intel AMT/…]]></summary></entry><entry><title type="html">Apple USB Target Disk Mode</title><link href="https://rickmark.me/blog/apple-usb-target-disk-mode/" rel="alternate" type="text/html" title="Apple USB Target Disk Mode" /><published>2022-07-30T00:56:08+00:00</published><updated>2022-07-30T00:56:08+00:00</updated><id>https://rickmark.me/blog/apple-usb-target-disk-mode</id><content type="html" xml:base="https://rickmark.me/blog/apple-usb-target-disk-mode/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>In earlier generations of Apple MacBook computers, TDM or Target Disk Mode was a boot mode that made all internal drives appear to an external FireWire capable system to be LUNs which could be consumed by another endpoint (Thisusually included the internal Hard Drive and CD/DVD-ROMs).  Because of the peer-to-peer nature of FireWire and the standard SCSI command set, implementing a consumer in linux for this protocol was relatively straight forward.  Modern USB and Thunderbolt based target disk mode requires a machine that is ordinarily a USB host to become a slave.  Moreover, Apple’s security features such as encryption and effaceable storage complicate the implementation.  What follows is an analysis of the USB based target disk mode protocol, and also a revelation that the FileVault2 key may be extractable (albeit in wrapped form) from a machine without the OS booted.  This paper will be extended in the future to cover the slight differences when using Thunderbolt to replace USB mass-storage as an underlying transport.</p>

<h2 id="usb-bulk-only-transport-by-any-other-name">USB Bulk-Only-Transport by any other name…</h2>

<p>The first layer of the TDM onion is a simple obfuscation.  When an Apple laptop is booted into TDM and a USB 3.0 cable is attached (it should be noted that the USB-C cable needs all USB3.0 pins connected, UTDM does not work with 1.0, 1.1 or 2.0 cables or controllers), it declares itself to be a Apple, PID_1800, implementing a Diagnostic Class (0xDC) device with subclass 0x02 and protocol 0x01.
This provides two 1024 byte bulk endpoints that communicate with the device in what is called USB MSD BOT (USBmass-storage device, bulk only transport - see <a href="https://usb.org/sites/default/files/usbmassbulk_10.pdf">https://usb.org/sites/default/files/usbmassbulk_10.pdf</a>).  This provides basic framing/length, checksum, direction, logical targets, etc.  Think of this level as TCP with a set number of pipes.  These pipes end up translating into LUNs at the next level up the stack.  Beyond this everything appears to be a superset of the standard SCSI command set.</p>

<h2 id="a-little-scsi-here-and-there">A little SCSI here and there…</h2>

<p>Next up the stack is the SCSI transport.  It should be noted that this is not UASP or USB attached SCSI protocol, but instead SCSI over the mass-storage BOT.  This is a simpler protocol to implement as it doesn’t permit more eccentric things like native command queueing.  A device in UTDM has 4 addresses or in SCSI language LUNs (logical unit numbers).  SCSI sits on top of the BOT layer and provides basic commands, Apple extensions and LUN addressing.</p>

<ul>
  <li>The Apple proprietary  LUN0 - CONTROL endpoint, for managing power, device information, read/write protect and a few other things</li>
  <li>The Apple proprietary LUN1 - AppleKeyStore endpoint.  This is for accessing a T2’s AppleKeyStore service to unwrap FileVault2 keys with a password.  (see <a href="https://github.com/nabla-c0d3/iphone-dataprotection/blob/master/ramdisk_tools/AppleKeyStore.h">https://github.com/nabla-c0d3/iphone-dataprotection/blob/master/ramdisk_tools/AppleKeyStore.h</a>)</li>
  <li>The Apple proprietary LUN2 - AppleEffaceableStorage endpoint.  This is to wipe the device key that is used in the wrapping process, stored in special NOR memory (the NVMe is NAND).  Wiping this key should provide protection for the entire disk, because without it the volume data cannot be decrypted.</li>
  <li>The “standard” LUN3 - DISK endpoint with a little non-standard opcode magic.  This is a generally compliant SCSI disk.</li>
</ul>

<h2 id="the-control-endpoint">The Control Endpoint</h2>

<p>TODO: More analysis of how the Kext operations match up to non-standard SCSI command IDs</p>

<ul>
  <li>Query ReadOnly/ReadWrite</li>
  <li>Query Device Information</li>
  <li>Query Battery Level</li>
  <li>Configure USB power distribution</li>
</ul>

<p>Perform page 0 inquiry, length 6 - response 1F 00 05 02 E0 00 - somewhere is full lengthThis seems standard - see specificaiton
Perform Inquiry with “Enable Vital Product Data = true” and page code = 0
Response - uint32 length (number of page codes)
Perform Inquiry with “Enable Vital Product Data = true” and page code = 0 and length
Response - uint32 length, byte[] page_codes</p>

<h2 id="reading-the-key-bag-from-effaceable-storage">Reading the Key Bag from Effaceable Storage</h2>

<p>Effaceable storage is a special storage region designed to be effaceable or wipeable at any time.  This is part of Apple’s wrapped key system allowing for instant device wipe.
Open Question: Can the key be read and written back with different geometry?
Keys from iOS - Likely not used on Disk Storage.  (These seem to be sequentially ordered)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define LOCKER_DKEY 0x446B6579
#define LOCKER_EMF  0x454D4621
#define LOCKER_BAG1 0x42414731
#define LOCKER_LWVM 0x4C77564d
</code></pre></div></div>

<p>Commands</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 : getCapacity - get full capacity of effaceable storage
1 : getBytes (kernel debug)
2 : setBytes (kernel debug)
3 : isFormatted - if the NOR has geometry table configured
4 : format - create geometry housekeeping records
5 : getLocker - get value for bag id
6 : setLocker - get value for bag id
7 : effaceLocker - erase operation for locker_id
8 : lockerSpace - get size of bag?
</code></pre></div></div>

<p>Performs Apple extension SCSI command 0xF4, data in</p>

<ul>
  <li>Get Effaceable Geometry - Number and size of wipeable regions.  This appears to allow for different regions to be encrypted with different keys.</li>
  <li>Read Bytes</li>
  <li>AppleTDMEffaceableNORDriver::DoEffaceableRead(IOMemoryDescriptor* data, unsigned int region, unsigned long long start, unsigned long long length)</li>
  <li>Write Bytes</li>
  <li>AppleTDMEffaceableNORDriver::DoEffaceableWrite(IOMemoryDescriptor* data, unsigned int region, unsigned long long start, unsigned long long length)</li>
  <li>Erase</li>
  <li>AppleTDMEffaceableNORDriver::DoEffaceableErase(unsigned int region, unsigned long long start, unsigned long long length)</li>
  <li>ReadWriteBytes (atomic transaction)</li>
</ul>

<h2 id="unwrapping-the-key-with-applekeystore">Unwrapping the key with AppleKeyStore</h2>

<p>iOS / Apple ARM processor devices have a key wrapping and unwrapping service.  You may have heard of GID and UID keys burned into Apple processors, and this is in part what is being referred too.  Since the UID key can never leave the T2 processor, Apple had to expose an endpoint that allow unwrapping the disk key stored in effaceable storage to unlock the APFS Macintosh HD - Data volume.
Open question: Does this endpoint allow for wrapping / unwrapping of arbitrary keys other then the disk key that may be used on the T2 itself?
Send message / Get response protocolSCSI Opcode 0xF7
AppleTDMAKSDriver::SendMessage(unsigned short target, unsigned long long command)AppleTDMAKSDriver::DoSendMessage(void* request, unsigned long long requestBufferLength, void* response, unsigned long long responseBufferLength)AppleTDMAKSDriver::GetResponse(unsigned long long target, unsigned long long*)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 : initUserClient scalarOutSize=1
 1 : unknown, possibly obsoleted
 2 : AppleKeyStoreKeyBagCreate
 3 : AppleKeyStoreKeyBagCopyData inscalars=id structOutSize=0x8000
 4 : keybagrelease inscalars":[0]}
 5 : AppleKeyStoreKeyBagSetSystem
 6 : AppleKeyStoreKeyBagCreateWithData
 7 : getlockstate "inscalars":[0], "scalarOutSize":1}
 8 : AppleKeyStoreLockDevice
 9 : AppleKeyStoreUnlockDevice instruct
 10: AppleKeyStoreKeyWrap
 11: AppleKeyStoreKeyUnwrap - used with effaceable NOR
 12: AppleKeyStoreKeyBagUnlock - used to provide password
 13: AppleKeyStoreKeyBagLock
 14: AppleKeyStoreKeyBagGetSystem scalarOutSize=1
 15: AppleKeyStoreKeyBagChangeSecret
 17: AppleKeyStoreGetDeviceLockState scalarOutSize=1
 18: AppleKeyStoreRecoverWithEscrowBag - recovery key?
 19: AppleKeyStoreOblitClassD
</code></pre></div></div>

<h2 id="setting-up-for-disk-reading">Setting up for Disk Reading</h2>

<p>Apple Extended Request Sense Key 0x05, response non-standard as it is 1 byte and not a full 4 bytes, which is minimum for a mode-sense response.
Responses from mode sense include, 0x0A, 0xFC
Apple SCSI command `0x</p>

<h2 id="reading-blocks-from-the-disk-with-aes-xts">Reading Blocks from the Disk with AES-XTS</h2>

<p>While it appears that raw blocks can be read off the disk using a relatively straightforward SCSI command set, if decryption of the block using the wrapped key is requested, additional SCSI commands are needed to support AES-XTS.
Reading the GPT both primary and backup seems to occur in the clear, without use of any cryptographic operation.
Apple Command 0xF6 with direction outApple Command 0xF2 with direction in
There are “two keys” being passed, header is 0x1F in length, some crypto material of 0x30 in length (128 bit block and 256 bit key) and a 0x20 footer</p>

<h2 id="unwrapping-the-disk-key">Unwrapping the Disk Key</h2>

<p>Generally to access a FileVault2 encrypted volume, you need the AppleKeyStore for access to the UID key, the DKey in effaceable storage and a password for a user of the system.  By passing these two values to AKS, you are able to access the key material that protects the APFS volume.
TODO: SCSI opcode 0xF6?  Submitted with each block read, with 104 bytes of data.  Perhaps this is AES-XTS.  (AppleTDMType00::SendCryptoDataToTarget(unsigned char*, unsigned short, unsigned long long, unsigned long long, unsigned long long, unsigned char))</p>

<h2 id="mounting-the-apfs-volume">Mounting the APFS volume</h2>

<p><a href="https://github.com/sgan81/apfs-fuse">https://github.com/sgan81/apfs-fuse</a></p>

<h2 id="potential-linux-driver">Potential Linux Driver</h2>

<h2 id="fuzzing-analysis-on-the-stack---hackers-look-here">Fuzzing Analysis on the Stack - Hackers Look Here!</h2>

<ul>
  <li>USB MSD BOT error modes</li>
  <li>SCSI command / length / invalid state</li>
  <li>Command / AKS / AES endpoints are non-standard and were likely not meant to be exposed outside the kernel</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Introduction In earlier generations of Apple MacBook computers, TDM or Target Disk Mode was a boot mode that made all internal drives appear to an external FireWire capable system to be LUNs which could be consumed by another endpoint (Thisusually included the internal Hard Drive and CD/DVD-ROMs). Because of…]]></summary></entry><entry><title type="html">Abusing EFI Variables and the AMT</title><link href="https://rickmark.me/blog/abusing-efi-variables-and-the-amt/" rel="alternate" type="text/html" title="Abusing EFI Variables and the AMT" /><published>2022-07-30T00:55:47+00:00</published><updated>2022-07-30T00:55:47+00:00</updated><id>https://rickmark.me/blog/abusing-efi-variables-and-the-amt</id><content type="html" xml:base="https://rickmark.me/blog/abusing-efi-variables-and-the-amt/"><![CDATA[<h2 id="speculation-on-how-efi-was-modified">Speculation on How EFI was Modified:</h2>

<p>By simply having Ring 0 (kernel mode) one can place EFI variables into NVRAM via EFI runtime services.  If one of these variables is scanned as a valid FFV, that gives execute at level of Ring -1, from there modifying the SPI contents of the flash chip to re-write the Intel ME / Intel Gigabit Ethernet is possible.  By flashing an old version of the Intel ME (orbetter the Intel AMT) one can take advantage of known CVEs in the Intel ME giving Ring -3.  From here one can inject any SMBios of their choosing and maintain Ring -2 every boot.  This allows for a evil actor to run their own stack during any OS load or reinstall.  By using AMT ramdisks, EFI drivers, and modifying the ACPI tables they can then live in Ring 0 cooperatively with any OS that is installed.</p>

<h1 id="booting-into-a-decent-shell">Booting Into a Decent Shell</h1>

<p>After some working around various issues I finally got into a decent EFI v2.2 shell.  The first five entries in the handle table were what are known as “FFV” or flash-firmware-volume entries.  This implies that the lion share of this is happening one of two ways: the flash chip has been somehow updated to a version of EFI that it should not contain, or two that something is persisting to disk and performing a restore in a way that it is not possible to reset with only pulling the power cable out of the device.  It is clearly running vPro and the AMT stack, and has created an entry of a ramdisk entry (shows in the table) as well as loading a number of drivers and Dxe’s that are to say the least, unexpected.
From a running linux view the following EFI vars were observed, not matching in any way what was pulled from the shell: <a href="https://gist.githubusercontent.com/rickmark/21059379ab65c11bfcb2f3b339bdbea1/raw/7a0d2a60f38cdc1bf7887df1e7e461474dced25c/refi_var_list.txt">https://gist.githubusercontent.com/rickmark/21059379ab65c11bfcb2f3b339bdbea1/raw/7a0d2a60f38cdc1bf7887df1e7e461474dced25c/refi_var_list.txt</a></p>

<ul>
  <li>PlatformLangCodes = en-US;x-UQI</li>
  <li>ItkModifiedSetup = 0</li>
  <li>MeInfoSetup</li>
  <li>SIO_DEV_STATUS_VAR</li>
  <li>VV_SIO_LD0</li>
  <li>DriverHlthEnable</li>
  <li>TpmServFlatgs</li>
  <li>OptaneState</li>
  <li>FPDT_Volatile</li>
  <li>NBPlatformData</li>
  <li>E770BB69-BCB4-4D09-9E97-23FF9456FEAC:SystemAccess = 0</li>
  <li>BootDebugPolicyApplied</li>
  <li>CurrentPolicy</li>
  <li>CurrentActivePolicy</li>
  <li>1C697A091199_IAIDPXE</li>
  <li>Ip6Config:16697A091199</li>
  <li>IPv4Config2:1C697A091199</li>
  <li>
    <p>SetupCpuFetures</p>
  </li>
  <li>StandardGUID 8BE4DF61-93CA-11D2-AA0D-00E098032B9C</li>
  <li>ACA9F304-21E1-4852-9875-7FF488AD67A5</li>
  <li>PCI_COMMON</li>
  <li>7B59104A-C00D-4158-87FF-F03D6396A915</li>
  <li>SecureBootSetup</li>
  <li>EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9</li>
  <li>SdioDevConfiguration</li>
  <li>64192DCA-D034-49D2-A6DE-65A829EB4C74</li>
  <li>`IccAdvancedSetupDataVar</li>
  <li>5432122D-D034-29D2-A6DE-65A829EB4C74</li>
  <li>MeSetupStorage</li>
  <li>90D93E09-4E91-4B3D-8C77-C82FF10E3C81</li>
  <li>CpuSmm</li>
  <li>05A798EA-39EE-40FC-92C5-622582FA634B</li>
</ul>

<p>Asking the device for the listing of devices shows</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Seg:Bus:Dev:Func</td>
      <td>Ven:Dev</td>
      <td>Description</td>
    </tr>
    <tr>
      <td>00:00:00:00</td>
      <td>8086:3ED0</td>
      <td>Bridge Device - Host/PCI bridge</td>
    </tr>
    <tr>
      <td>00:00:02:00</td>
      <td>8086:3EA5</td>
      <td>Display Controller - VGA/8514</td>
    </tr>
    <tr>
      <td>00:00:08:00</td>
      <td>8086:1911</td>
      <td>Other System Peripheral (Gaussian Mixture Model?)</td>
    </tr>
    <tr>
      <td>00:00:12:00</td>
      <td>8086:9DF9</td>
      <td>Other DAQ &amp; SP controllers</td>
    </tr>
    <tr>
      <td>00:00:14:00</td>
      <td>8086:9DED</td>
      <td>USB Controller</td>
    </tr>
    <tr>
      <td>00:00:14:02</td>
      <td>8086:9DED</td>
      <td>RAM Memory Controller (Interface 30)</td>
    </tr>
    <tr>
      <td>00:00:16:00</td>
      <td>8086:9DE0</td>
      <td>Simple Communications Controller</td>
    </tr>
    <tr>
      <td>00:00:17:00</td>
      <td>8086:9DD3</td>
      <td>Mass Storage SATA (interface 1)</td>
    </tr>
    <tr>
      <td>00:00:1D:00</td>
      <td>8086:9DB0</td>
      <td>Bridge Device PCI/PCI</td>
    </tr>
    <tr>
      <td>00:00:1F:00</td>
      <td>8086:9D84</td>
      <td>Bridge Device PCI/ISA bridge</td>
    </tr>
    <tr>
      <td>00:00:1F:04</td>
      <td>8086:9DA3</td>
      <td>SMBus Controller</td>
    </tr>
    <tr>
      <td>00:00:1F:05</td>
      <td>8086:9DA4</td>
      <td>Serial Bus Controllers</td>
    </tr>
    <tr>
      <td>00:00:1F:06</td>
      <td>8086:15BE</td>
      <td>Network Controller</td>
    </tr>
    <tr>
      <td>00:01:00:00</td>
      <td>144D:A808</td>
      <td>Mass Storage Controller - NV memory subsystem</td>
    </tr>
  </tbody>
</table>

<p>The following does skip some entries as there’s no good way to copy and paste this, and UDIDs are hard…</p>

<ul>
  <li>LoadedImage DxeCore</li>
  <li>5CB5C776-</li>
  <li>Decompress</li>
  <li>FirmwareVolume2 -B9A42172CE53</li>
  <li>FirmwareVolume2 -EC40C23C5916</li>
  <li>FirmwareVolume2 -DC1671C10F36</li>
  <li>FirmwareVolume2 -E48809A7ACE3</li>
  <li>FirmwareVolume2 -2A4FF6CA6FE5</li>
  <li>EE4E5898-</li>
  <li>LoadedImage StatusCodeDxe</li>
  <li>36232936-</li>
  <li>SmartCardReader RscHandler</li>
  <li>LoadedImage PcdDxe</li>
  <li>GetPcdInfo GetPcdInfoProtocol Pcd Pcd</li>
  <li>LoadedImage CpuIo2Dxe</li>
  <li>CpuIo2</li>
  <li>LoadedImage FlashDriver</li>
  <li>755B6596-</li>
  <li>LoadedImage NvramDxe</li>
  <li>VariableWriteArch VariableArch</li>
  <li>MonotonicCounterArch</li>
  <li>LoadedImage CrbDxe</li>
  <li>LoadedImage FastBootRuntime</li>
  <li>LoadedImage DxeBoardConfigInit</li>
  <li>LoadedImage WdtDxe</li>
  <li>LoadedImage CmosDxe</li>
  <li>9851740C-</li>
  <li>LoadedImage RomLayoutDxe</li>
  <li>HiiPackageList LoadedImage Bds</li>
  <li>BdsArch</li>
  <li>LoadedImage DataHubDxe</li>
  <li>AE80D021-</li>
  <li>LoadedImage DevicePathDxe</li>
  <li>DevicePathFromText DevicePathToText DevicePathUtilities</li>
  <li>DebugSupport EBCInterpreter LoadedImage EbcDxe</li>
  <li>LoadedImage HiiDatabase</li>
  <li>HIIImage ConfigKeywordHandler HIIConfigRouting HIIDatabase HIIString HIIFont</li>
  <li>LoadedImage SecurityStubDxe</li>
  <li>SecurityArch Security2Arch</li>
  <li>LoadedImage TimestampDxe</li>
  <li>Timestamp</li>
  <li>LoadedImage CpuDxe</li>
  <li>LoadedImage CpuIoDxe</li>
  <li>B0732526-</li>
  <li>LoadedImage AmiCpuFeaturesDxe</li>
  <li>LoadedImage AmiPciPlatform</li>
  <li>PciPlatform</li>
  <li>DebugPort LoadedImage GopDebugDxe</li>
  <li>LoadedImage WdtAppDxe</li>
  <li>LoadedImage PlatformInfoDxe</li>
  <li>LoadedImage PolicyInitDxe</li>
  <li>LoadedImage AmiSyncSetupData</li>
  <li>LoadedImage CpuInitDxe</li>
  <li>E223CF65-</li>
  <li>LoadedImage SmmAccess</li>
  <li>SmmAccess2</li>
  <li>LoadedImage LegacyInterrupt</li>
  <li>31CE593d-</li>
  <li>LoadedImage PchSmbusDxe</li>
  <li>SmbusHc</li>
  <li>LoadedImage FspWrapperNotifyDxe</li>
  <li>LoadedImage Aint31</li>
  <li>LoadedImage Acoustic</li>
  <li>10E9D800-</li>
  <li>LoadedImage S3SaveStateDxe</li>
  <li>S3SaveState</li>
  <li>LoadedImage SioDxeInit</li>
  <li>9D36F7EF-</li>
  <li>LoadedImage IdeBusBoard</li>
  <li>LoadedImage PciDxeInit</li>
  <li>EC63428D-</li>
  <li>LoadedImage RdspPlus</li>
  <li>ComponentName2 DriverBinding LoadedImage Uhcd</li>
  <li>2AD8E2D2-</li>
  <li>ComponentName2 DriverBinding</li>
  <li>ComponentName2 DriverBinding</li>
  <li>LoadedImage DpcDxe</li>
  <li>480F8AE9-</li>
  <li>LoadedImage AmiBoardInfo2</li>
  <li>4FC0733F-</li>
  <li>LoadedImage FanDxe</li>
  <li>LoadedImage HddSecurity</li>
  <li>CE6F86BB-</li>
  <li>LoadedImage EsrtDxe</li>
  <li>A340C064-</li>
  <li>LoadedImage OpalSecurity</li>
  <li>59AF16B0-</li>
  <li>LoadedImage RngDxe</li>
  <li>Rng</li>
  <li>LoadedImage AmiRedFishApi</li>
  <li>B5E7C7AF-</li>
  <li>LoadedImage AmiDeviceGuardApi</li>
  <li>DAEEAFC8-</li>
  <li>LoadedImage TpmSmbiosDxe</li>
  <li>LoadedImage TpmNvmeSupport</li>
  <li>LoadedImage TcgStorageSecurity</li>
  <li>734AA01D-</li>
  <li>LoadedImage UpdateDriverProtocol</li>
  <li>LoadedImage CpuDxe</li>
  <li>CpuArch</li>
  <li>MpService</li>
  <li>LoadedImage DxeSignBiosAuthenticate</li>
  <li>24400798-</li>
  <li>LoadedImage EventLog</li>
  <li>DAED23EC-</li>
  <li>LoadedImage IntelVBios2</li>
  <li>HIIFormBrowser2</li>
  <li>49374A18-</li>
  <li>HIIFormBrowser2</li>
  <li>1F73B18D-</li>
  <li>348C4D62-</li>
  <li>BEBF428C-</li>
  <li>LoadedImage FsDxe</li>
  <li>LoadedImage DnsrDxe</li>
  <li>ComponentName2 DriverBinding LoadedImage NTFS</li>
  <li>LoadedImage CapsuleRuntimeDxe</li>
  <li>CapsuleArch</li>
  <li>LoadedImage RuntimeDxe</li>
  <li>RuntimeArch</li>
  <li>MetronomeArch LoadedImage SbRun</li>
  <li>RealTimeClockArch</li>
  <li>SmmControl2 LoadedImage SmmControl</li>
  <li>LoadedImage MePlatformReset</li>
  <li>ResetArch</li>
  <li>LoadedImage CryptoDXE</li>
  <li>ComponentName2 DriverBinding LoadedImage NTFS</li>
  <li>DriverBinding LoadedImage MouseDriver</li>
  <li>LoadedImage StdDefaultsUpdate</li>
  <li>LoadedImage Achi</li>
  <li>83: CompnentName2 DriverBinding</li>
  <li>LoadedImage HttpUtilitiesDxe</li>
  <li>HttpUtilities</li>
  <li>LoadedImage Nvme</li>
  <li>ComponentName2 DriverBinding</li>
  <li>LoadedImage SecureBootDXE</li>
  <li>LoadedImage TcgPlatformSetupPolicy</li>
  <li>LoadedImage ITK50</li>
  <li>LoadedImage CISDWdtDxe</li>
  <li>LoadedImage OCDxe</li>
  <li>LoadedImage OemGop</li>
  <li>LoadedImage NbDxe</li>
  <li>LoadedImage AmiTxtDxe</li>
  <li>LoadedImage HstiIhvDxe</li>
  <li>LoadedImage TxtDxe</li>
  <li>LoadedImage PciHostBridgeDxe</li>
  <li>PciHostBridgeResourceAllocation</li>
  <li>PCIRootBridgeIO DevicePath(PciRoot(0x0))</li>
  <li>LoadedImage AmiUpdateCspResources</li>
  <li>27CFAC87-</li>
  <li>LoadedImage PchSpiRuntime</li>
  <li>00C7D289-</li>
  <li>LoadedImage SiInitDxe</li>
  <li>IncompatiblePciDeviceSupport</li>
  <li>LoadedImage HpetTimerDxe</li>
  <li>TimerArch</li>
  <li>HiiPackageList LoadedImage AmiHsti</li>
  <li>AdapterInfo(AdapterInfo)</li>
  <li>LoadedImage ACPI</li>
  <li>AcpiSdt AcpiTable</li>
  <li>01FA319E-</li>
  <li>LoadedImage AcpiS3SaveDxe</li>
  <li>HiiPackageList LoadedImage PciOutOfResourcesSetupPage</li>
  <li>LoadedImage UsbRtDxe</li>
  <li>HiiPackageList LoadedImage HddSmart</li>
  <li>9401BD4F-</li>
  <li>HiiPackageList LoadedImage PauseKey</li>
  <li>LoadedImage SmbiosBoard</li>
  <li>HiiPackageList LoadedImage Tpm20PlatformDxe</li>
  <li>LoadedImage CpuS3DataDxe</li>
  <li>LoadedImage PlatformConfigDxe</li>
  <li>C298B206-</li>
  <li>23F2D944-</li>
  <li>HiiPackageList ICBDTSEPopupMenu</li>
  <li>HiiPackageList LoadedImage HkUpdate</li>
  <li>E2E6CF23-</li>
  <li>HiiPackageList LoadedImage PlatformIdPage</li>
  <li>HIIConfigAccess</li>
  <li>LoadedImage OemBoardDxe</li>
  <li>BA8D58AB-</li>
  <li>LoadedImage PiSmmIpl</li>
  <li>LoadedImage PiSmmCore</li>
  <li>SmmCommunication SmmBase2</li>
  <li>LoadedImage Tcg2Dxe</li>
  <li>LoadedImage StatusCodeDxe</li>
  <li>LoadedImage FlashDriverSmm</li>
  <li>ECB867AB-</li>
  <li>LoadedImage CpuIo2Smm</li>
  <li>LoadedImage SmmLockBox</li>
  <li>BD445d79-</li>
  <li>LoadedImage PchSmbusSmm</li>
  <li>LoadedImage SraSmmStub</li>
  <li>LoadedImage AhciSmm</li>
  <li>LoadedImage CryptoCMM</li>
  <li>91ABC830-</li>
  <li>LoadedImage SmmS3SaveState</li>
  <li>LoadedImage RuntimeSmm</li>
  <li>395C33FE-</li>
  <li>LoadedImage PiSmmCpuDxeSmm</li>
  <li>SmmConfig</li>
  <li>LoadedImage NvramSmm</li>
  <li>CD3D0A05-</li>
  <li>LoadedImage PchSpiSmm</li>
  <li>LoadedImage SmmPcieSataController</li>
  <li>LoadedImage SbDxe</li>
  <li>WatchdogTimerArch</li>
  <li>17706D27-</li>
  <li>PciHotPlugInit</li>
  <li>377E6D6B-</li>
  <li>LoadedImage CnvUefiVariables</li>
  <li>C77AE557-</li>
  <li>LoadedImage Dptf</li>
  <li>LoadedImage HstiResultDxe</li>
  <li>LoadedImage TbtDxe</li>
  <li>4D6A54D1-</li>
  <li>LoadedImage PlatoformVTdSampleDxe</li>
  <li>3D17E448-</li>
  <li>LoadedImage PlatformSetup</li>
  <li>D5E1268B- D4D2F201-</li>
  <li>LoadedImage PowerMgmtDxe</li>
  <li>D71DB106-</li>
  <li>LoadedImage BdatAccessHandler</li>
  <li>LoadedImage PchInitDxe</li>
  <li>LoadedImage SraDxe</li>
  <li>7AE12E27-</li>
  <li>LoadedImage HeciInit</li>
  <li>EC7BC880-</li>
  <li>1498D127-</li>
  <li>LoadedImage BootScriptExecutorDxe</li>
  <li>LoadedImage HardwareSignatureEntry</li>
  <li>43169678-</li>
  <li>ComponentName DriverBinding LoadedImage RtkSdCardDxe</li>
  <li>LoadedImage Smbios</li>
  <li>LoadedImage OEMActivation</li>
  <li>LoadedImage OemUsbPort</li>
  <li>LoadedImage OemEventDxe</li>
  <li>LoadedImage SaInitDxe</li>
  <li>LegacyRegion2</li>
  <li>9E67AECF-</li>
  <li>603DF7CA-</li>
  <li>LoadedImage AcpiPlatform</li>
  <li>C77AE556-</li>
  <li>LoadedImage AcpiDebugDxe</li>
  <li>LoadedImage RamDiskDxe</li>
  <li>HIIConfigAccess DevicePath -BB1A4F94081E</li>
  <li>HIIConfigAccess DevicePath -2B769AAA30C5</li>
  <li>F7: 28A03FF4- RamDisk</li>
  <li>LoadedImage ItkSmmVarsDxe</li>
  <li>LoadedImage ItkSmmVarsDxe</li>
  <li>LoadedImage PchSmiDispatcher</li>
  <li>LoadedImage CpuSpSMI</li>
  <li>LoadedImage NbSmi</li>
  <li>LoadedImage PowerButton</li>
  <li>LoadedImage SbRunSmm</li>
  <li>LoadedImage SleepSmi</li>
  <li>FF: LoadedImage PeriodicSmiControl</li>
  <li>LoadedImage TcoSmi</li>
  <li>LoadedImage AcpiModeEnable</li>
  <li>LoadedImage PepBccdSmm</li>
  <li>LoadedImage TbtSmm</li>
  <li>LoadedImage OverClockSmiHandler</li>
  <li>LoadedImage PowerMgmtSmm</li>
  <li>LoadedImage SaLateInitSmm</li>
  <li>0D66A1CF- LoadedImage PchInitSmm</li>
  <li>LoadedImage UsbRtSmm</li>
  <li>LoadedImage CmosSmm</li>
  <li>LoadedImage SmmHddSecurity</li>
  <li>LoadedImage NvmeSmm</li>
  <li>LoadedImage SdioSmm</li>
  <li>LoadedImage TpmClearOnRollbackSmm</li>
  <li>LoadedImage SmmTcgStorageSec</li>
  <li>LoadedImage CrbSmi</li>
  <li>LoadedImage PiSmmCommunicationSmm</li>
  <li>LoadedImage RtcWakeup</li>
  <li>LoadedImage ItkSmmVars</li>
  <li>LoadedImage OemBoardSmi</li>
  <li>LoadedImage SmmPlatoform</li>
  <li>ImageDevicePath -AB74D2C1A600 LoadedImage EnglishDxe</li>
  <li>UnicodeCollation2 UnicodeCollation</li>
  <li>LoadedImage SmbiosUpdateData</li>
  <li>LoadedImage AmiMemoryInfoConfig</li>
  <li>LoadedImage MeSmbiosDxe</li>
  <li>ComponentName2 ComponentName DriverBinding ImageDevicePath -CD92CFB7D362 LoadedImage SataController</li>
  <li>LoadedImage PlatofrmInitDxe</li>
  <li>LoadedImage VtioDxe</li>
  <li>LoadedImage DxeOverClock</li>
  <li>LoadedImage MeFwDowngrade</li>
  <li>3EA824D1-</li>
  <li>LoadedImage ConSplitter</li>
  <li>ComponentName2 DriverBinding</li>
  <li>ComponentName2 DriverBinding</li>
  <li>AbsolutePointer SimplePointer SimpleTextInEx SimpleTextIn SimpleTextOut</li>
  <li>LoadedImage GraphicsConsole</li>
  <li>ComponentName2 DriverBinding</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage DiskIoDxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage PartitionDxe</li>
  <li>LoadedImage RstOneClickEnable</li>
  <li>LoadedImage RstuefiDriverSupport</li>
  <li>5B10CDC8-</li>
  <li>SupportedEfiSpecVersion(0x0002001E) ComponentName2 ComponentnName DriverBinding LoadedImage IntegratedTouch</li>
  <li>LoadedImage GenericSio</li>
  <li>7576CC89- ComponentName2 DriverBinding</li>
  <li>LoadedImage IdeBusSrc</li>
  <li>132: ComponentName2 DriverBinding</li>
  <li>LoadedImage PciBus</li>
  <li>ComponentName2 DriverBinding</li>
  <li>LoadedImage Ps2Main</li>
  <li>ComponentName2 DriverBindding</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage SnpDxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage MnpDxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage ArpDxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage IpSecDxe</li>
  <li>IpSec2 IpSecConfig</li>
  <li>ComponentName2 ComponentName DriverBinding</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage TcpDxe</li>
  <li>ComponentName2 ComponentName DriverBinding</li>
  <li>13F:</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage UefiPxeBcDxe</li>
  <li>ComponentName2 ComponentName DriverBinding</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage DnsDxe</li>
  <li>ComponentName2 ComponentName DriverBinding</li>
  <li>LoadedImage TlsDxe</li>
  <li>TlsServiceBinding</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Dhcp4Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Ip4Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Mtftp4Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Udp4Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Ip6Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Udp6Dxe</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Mtftp6Dxe</li>
  <li>LoadedImage AtaPassThru</li>
  <li>C6734411-</li>
  <li>LoadedImage AudioPlayback</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage Fat</li>
  <li>AuthenticationInfo iSCSIInitiatorName ComponentName2 ComponentName DriverBinding LoadedImage IScsiDxe</li>
  <li>ComponentName2 ComponentName DriverBinding</li>
  <li>HIIConfigAccess DevicePath(-CCAD2E0F4CF9)</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage ScsiBus</li>
  <li>ComponentName2 ComponentName DriverBinding LoadedImage ScsiDisk</li>
  <li>LoadedImage PcieSataController</li>
  <li>ComponentName2 DriverBinding</li>
  <li>ComponentName2 DriverBinding</li>
  <li>ComponentName2 DriverBinding LoadedImage SdioDriver</li>
  <li>LoadedImage AcpiPlatformFeatures</li>
  <li>LoadedImage CustomSMBIOS</li>
  <li>HiiPackageList LoadedImage AMITSE</li>
  <li>HiiPopup</li>
  <li>160: LoadedImage SmmGenericSio</li>
  <li>LoadedImage UpdateMemoryRecord</li>
  <li>EDIDOverride</li>
  <li>PciEnumerationComplete</li>
  <li>30249499- C7D4703B-</li>
  <li>651B7EBD- DBCB2FCD- ComponentName2 DriverBinding ImageDevicePath((0x3,0x75F5A018,0x75F6BA98)) LoadedImage MemoryMapped</li>
  <li>3279A703-</li>
  <li>AD77AE29- 1FD29BE6- AtaPassThru</li>
  <li>1FD29BE6- AD77AE29</li>
  <li>FA20568B-</li>
  <li>6DE538E4-</li>
  <li>A33319B5-</li>
  <li>A33319B5-</li>
  <li>DevicePath LoadFile</li>
  <li>ImageDevicePath LoadedImage SmbiosMisc</li>
  <li>ImageDevicePath LoadedImage FileExplorerLite</li>
  <li>088C3203-</li>
  <li>HiiPackageList ImageDevicePath LoadedImage DpsdSetup</li>
  <li>HIIConfigAccess DevicePtah</li>
  <li>BootManagerPolicy</li>
  <li>A68D1FDE-</li>
  <li>4622F942-</li>
  <li>HIIConfigAccess DevicePath</li>
  <li>3A3300AB-</li>
  <li>F8DD3A9D-</li>
  <li>F31FCBB5-</li>
  <li>348C4D62-</li>
  <li>18F: 348C4D62-</li>
  <li>348C4D62-</li>
  <li>AdapterInfo(AdapterInfo)</li>
  <li>0F500BE6-</li>
  <li>8D9B3387-</li>
  <li>Shell ShellParameters SimpleTextOut ImageDevicePath LoadedImage()</li>
  <li>PciEnumerationComplete F42A009D-</li>
  <li>USBHostController2 USBHostController 3279A703- DevicePath(PciRoot(0x0)/Pci(0x14,0x0)) PCIIO</li>
  <li>0ADFB62D- SimpleTextInEx SimpleTextIn 1FEDE521- DevicePath(..)/Pci(0x14,0x0)/USB(0x0,0x0)) USBIO</li>
  <li>198: SimplePointer 1FEDE521- DevicePath(..)/Pci(0x14,0x0)/USB(0x0,0x1)) USBIO</li>
  <li>DevicePath(..)/Pci(0x014,0x0)/USB(0x0,0x2)) USBIO</li>
  <li>30249499- C7D3703B- LoadFile2 BusSpecificDriverOverride DevicePath(PciRoot(0x0)/Pci(0x2,0x0)) PCIIO</li>
  <li>E1E4A857- SimpleTextOut EDIDActive(EDIDActive GraphicsOutput(GraphicsOutput) EDIDDiscovered(EDIDDiscovered) 39487C79- DevicePath(..0x2,0x0)/AcpiAdr(0x80013310))</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x0,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x8,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x12,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x14,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x16,0x0)) PCIIO</li>
  <li>FDB29BE6- AD77AE29- AtaPassThru B2FA4764- IdeControllerInit DevicePath(PciRoot(0x0)/Pci(0x17,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x1D,0x0)) PCIIO</li>
  <li>4B235191- 1FD29BE6- AD77AE29- F4F63529- NvmExpressPassThru AFA4CF3F-DevicePath(..)/Pci(0x1D,0x0)/Pci(0x0,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x1F,0x0)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x1F,0x4)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x1F,0x5)) PCIIO</li>
  <li>DevicePath(PciRoot(0x0)/Pci(0x1F,0x6)) PCIIO</li>
  <li>DiskIO F4F63529- BlockIO DickInfo DevicePath(..17,0x0)/Sata(0x2,0xFFFF,0x0))</li>
  <li>1A1: DickIO E6D6D379- PartitionInfo BlockIO DevicePath(..49E6173E12,0x800,0x7470658F))</li>
  <li>DiskIO BlockIO DiskInfo DevicePath(..0x1,8D-73-B0-91-55-38-26-00)) StorageSecurityCommand</li>
  <li>SimpleFileSystem DiskIO EFISystemPartition PartitionInfo BlockIO DevicePath(..-FFC0339F3A57,0x800,0xEE000))</li>
  <li>DiskIO 0FC63DAF- PartitionInfo BlockIO DevicePath(..78C7D5369,0xEE800,0x12A0800))</li>
  <li>1A7: DiskIO E6D6D379- PartitionInfo BlockIo DevicePath(.. 18EF8D,0x138F000,0x38FF6800))</li>
</ul>

<h1 id="open-questions">Open Questions:</h1>

<ul>
  <li>How does the EFI Runtime Services pointer get passed from EFI boot-loaders to the kernel?  Or does it re-scan ACPI to pick it up?</li>
  <li>Why does the kernel have an option for performing an ACPI SSDT overlay from an EFI variable?</li>
  <li>Will a EFI variable containing a EFI FFV (flash firmware volume) or FFS (flash file system) be picked up as part of the EFI payload?  Would this allow for early injection of additional DXE’s into the runtime environment before exiting EFI to the boot-loader?</li>
  <li>For what possible reason did someone think it was a good idea to have an NVMe over TCP and other fabric protocol?  This seems to be in use as the device also showed up with a wwn or “World Wide Name” ala iSCSI.</li>
  <li>What is required to enable AMT on a device that was not intended for it?</li>
  <li>For what reason would a firewire and cdrom kernel module get injected into initrd?</li>
  <li>Why would there be a script in initrd that creates systemd units that are later deleted?</li>
  <li>Why would a network controller be brought up 3 times with the name WMI identity when virtualization of the adapter is not in use</li>
  <li>Why would network address families be brought up so early in the process if not to access the root filesystem across a synthetic network fabric?</li>
  <li>Why would seccomp be creating eBPF LSM executables without any other audit record?</li>
  <li>Why would one override the ACPI tables for Intel WiFi compliance if not to use frequency bands from other countries in the US to evade detection?</li>
  <li>Why would a bluetooth based braile TTY attempt to come up if not a side channel for access to the machine?</li>
  <li>Why would kernel objects on a clean Arch install (*.zko) files be signed with an ephemeral key if not tampered with?</li>
  <li>Why is there a “bluetooth meshing” driver</li>
  <li>Why is the EC able to perform interrupt pausing and resumption - during normal operation of the Intel ME it doesn’t interfere with normal OS operations in this way.</li>
  <li>Why would there be two tpm objects if not a root and a synthetic device?  Or perhaps a dTPM while the system has also enabled a fTPM (both occur at path ACPI LNXSYSTM:00-LNXSYBUS:00-MSFT0101:00 which makes reference to the Microsoft ACPI table</li>
  <li>Can dleyna be used as a form of remote desktop?</li>
  <li>What is slsh?</li>
  <li>Why does the SATA device occur at ata3-host2-target2 - and why is ata1/2 “DUMMY”</li>
  <li>Why does the network device occur at address PCI 0000:00-0000:00:1f.6 and not .0?  Are these IO-SRV virtual functions?</li>
  <li>Why are the TTYs platform-serial8250 which is a hardware backed device rather then a psudo terminal</li>
  <li>Why did a /var/lib/machines mount come up and later die?</li>
  <li>Why is there a binfmt_misc that gets brought up with the system</li>
  <li>Why are there kernel trace file system mounts?</li>
  <li>What is systemd-ask-password-console.path and systemd-ask-password-wall.path</li>
  <li>Why would there be an on shutdown service mkinitcpio-generate-shutdown-ramfs.service as this should only happen upon kernel updates via pacman.  It runs with TMPDIR=/run and /usr/bin/mkinitcpio -A sd-shutdown -k none -c /dev/null -d /run/initramfs</li>
  <li>What is shaddow.service and why does it have to run to change or verify passwd and shaddow - both of which have clearly been edited as they contain a vi trailing “-” pair.  Seems to execute <code class="language-plaintext highlighter-rouge">/usr/binpwck -r || r=1; /usr/bin/grpck -r</code></li>
  <li>What systemd-boot-system-token.service do?</li>
  <li>What are the getty-pre.target doing?</li>
  <li>Why is remote-fs.target a thing, it also includes verity and cryptsetup</li>
  <li>Somehow “RealtimeKit” is a name collision on linux and apple ecosystems?  Also what happened to remoteprocfor the Intel EC</li>
  <li>Why is udisks2 being used as a fuse helper for most things</li>
  <li>Why does my initrd have a /usr mount (initrd-usr-fs.target) - clearly this is being loaded across some other busbecause I have no /usr but do have a /usr/local in my fstab</li>
  <li>What is request-key.conf and why does it have to many defined values for debug and dns_resolver, it also seems to make special consideration o debug:loop:*</li>
  <li>What is “Rygel Remote UI Server”</li>
  <li>Secure TTY config makes reference to hvc0 - probably some hypervisor based channel</li>
  <li>it also allows the tty[1-6], ttyS0 and console</li>
</ul>

<h1 id="useful-non-network-control-channels">Useful non-Network Control Channels</h1>

<p>Using accessibility systems like brltty over bluetooth can give terminal access without need of a reliable network (WiFior ethernet).</p>

<h1 id="early-injection-using-firewire-serial">Early Injection using Firewire Serial</h1>

<h1 id="messing-with-the-acpi-tables">Messing with the ACPI Tables</h1>

<p>People often forget that operating systems will happily collect data from ACPI including AML code.  This is usually executed during power events like suspend and resume and has been abused in the past in the form of “dark wake” attacks.</p>

<h1 id="hiding-from-root-using-the-linux-bfp-lsm">Hiding from Root Using the Linux BFP LSM</h1>

<p>One of the more recent advancements in the Linux tree is reusing eBPF (yes of note because it has been used for network firewalls for many years) to become a policy agent.  eBPF was selected because it is a Turing complete language that we already compile and execute in-kernel by way of ip_tables/x_tables and the like.
When auditing is enabled, loading and unloading of these BPF programs will become part of the kernel debug output so they can be observed.  You can actually “mount” this to see the BPF entries by executing mount bpffs /mnt/bpffs/ -t bpf which will provide maps.debug and progs.debug.  Another useful tool to get more information about this is bpftool prog show</p>

<h1 id="xen-para-virtualization-is-still-a-thing">Xen Para-virtualization is Still a Thing</h1>

<p>Even without using Intel’s VT, it is still very possible for an attacker to kexec into a Xen based kernel providing themselves a way to control non-virtual ring-0 even while still letting an arbitrary linux guest OS execute thinking it is the kernel of the system.  Even without kexec one can do about exactly the same thing using kgdb after transferring an image to memory.</p>

<h2 id="tampering-during-compile">Tampering During Compile</h2>

<ul>
  <li>sync_regs()</li>
  <li>mce_setup()</li>
  <li>do_machine_check()</li>
  <li>rcu_nmi_enter()</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Speculation on How EFI was Modified: By simply having Ring 0 (kernel mode) one can place EFI variables into NVRAM via EFI runtime services. If one of these variables is scanned as a valid FFV, that gives execute at level of Ring -1, from there modifying the SPI contents of…]]></summary></entry><entry><title type="html">How To: Bypass T-Mobile SIM block, steal all their money, and leave no trace…</title><link href="https://rickmark.me/blog/how-to-bypass-t-mobile-sim-block-steal-all-their-money-and-leave-no-trace/" rel="alternate" type="text/html" title="How To: Bypass T-Mobile SIM block, steal all their money, and leave no trace…" /><published>2021-12-13T00:01:51+00:00</published><updated>2021-12-13T00:01:51+00:00</updated><id>https://rickmark.me/blog/how-to-bypass-t-mobile-sim-block-steal-all-their-money-and-leave-no-trace</id><content type="html" xml:base="https://rickmark.me/blog/how-to-bypass-t-mobile-sim-block-steal-all-their-money-and-leave-no-trace/"><![CDATA[<h1 id="disclaimer">Disclaimer</h1>

<p>This is a tutorial to do something illegal to demonstrate how bad the vendor is, despite multiple complaints from me.  If you do this, you will likely be caught and go to prison.  I do not condone these actions and the experiments that prove their validity took place against my own accounts and did not require criminal behavior.</p>

<h1 id="the-t-mobile-sim-lock">The T-Mobile SIM Lock</h1>

<p>By asking T-Mobile nicely they can put up additional barriers to having the SIM card replaced.  This means that retail locations and the phone services have to go through additional hoops to swap your SIM card.</p>

<h2 id="trivial-bypass">Trivial Bypass</h2>

<p>Buy a new iPhone linked to the phone number / carrier.  Upon receipt of the device you will be asked for the last four of the SSN, and the billing zip code.  Upon entry of these, even though the account holder is set to SIM lock, the new device will activate and receive calls and messages.  In my experience in about 15-20 minutes the SIM reverts to the previous value leaving the new device inactive.  Most importantly, there is no record at customer service that the new device was activated or that it was reverted (though these records do exist in back end systems, the customer would require escalation to retrieve them)</p>

<h1 id="whats-wrong-here">What’s wrong here…</h1>

<h2 id="that-the-sim-lock-doesnt-do-its-job">That the SIM lock doesn’t do it’s job…</h2>

<p>Apple’s back end activation services were able to bypass the SIM lock, and that begs the question if the SIM lock is a“front end” customer service block, how many other back end systems can directly modify the AUC (AuthenticationCenter) and HLR (Home Location Register).  Metro by T-Mobile and all the MVNOs that target T-Mobile as the PLMN registrar are potential vectors.  Because it didn’t block Apple’s modification, it almost surely doesn’t block others…</p>

<h2 id="there-was-no-audit-record-of-the-change">There was no audit record of the change…</h2>

<p>Because the SIM was modified outside the T-Mobile customer care system, there was no obvious record of the change that I the customer was able to retrieve at a corporate store.  Every change to the SIM regardless of the back end system of origin should be customer visible.  Also they tell you to reach out to fraud when this happens, but again - with what phone or compromised email?  A catch-22 of security.</p>

<h2 id="bonus-awful-sim-lock-emails-your-the-imsi">Bonus Awful: SIM lock emails your the IMSI…</h2>

<p>When you do have the SIM lock feature enabled, and it eventually does go through, it breaks rule one of cellular, do not reveal the IMSI (international mobile subscriber identifier).  This is why there’s the entire concept of the TMSI(temporary mobile subscriber identifier) exists.  The IMSI is considered confidential and there is NO REASON to email it to the customer where it could be exposed to an attacker.  Careless…</p>

<h2 id="bonus-awful-2-totp-uses-a-fixed-secret">Bonus Awful 2: TOTP uses a fixed secret…</h2>

<p>T-Mobile’s “Google Authenticator” which means TOTP has an absolutely awful implementation.  By removing authenticator and re-adding it the “secret” value doesn’t change.  Which means that once an attacker gets the TOTP they have it for the length of the account.  This is a simple fix of making sure the secret rotates between enrollments.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Disclaimer This is a tutorial to do something illegal to demonstrate how bad the vendor is, despite multiple complaints from me. If you do this, you will likely be caught and go to prison. I do not condone these actions and the experiments that prove their validity took place against…]]></summary></entry><entry><title type="html">On Warren’s Plan to Break Up Facebook</title><link href="https://rickmark.me/blog/on-warrens-plan-to-break-up-facebook/" rel="alternate" type="text/html" title="On Warren’s Plan to Break Up Facebook" /><published>2021-12-13T00:00:22+00:00</published><updated>2021-12-13T00:00:22+00:00</updated><id>https://rickmark.me/blog/on-warrens-plan-to-break-up-facebook</id><content type="html" xml:base="https://rickmark.me/blog/on-warrens-plan-to-break-up-facebook/"><![CDATA[<h1 id="the-difficulty-with-ubiquious-services">The Difficulty with Ubiquious Services</h1>

<p>The reason that the utility of Facebook is what it is, is primarily its de-facto status as the ubiquitous system of record.  Before Facebook conversations in real life were a binary search tree of what system’s you shared in common (IRC, AIM, ICQ, LinkedIn, Friendster, MySpace…).  Facebook years ago started to bring “common carrier” interoperability to the world via social login and the Graph API.  Combine that with the several orders of magnitude increase in complexity of SIP, Voice / Video, Data Taxonomy, and Data Interchange over the Bell System, and the AT&amp;T breakup (which one should note has resulted in almost all of the baby bell’s re-merging by 2021) is not an appropriate template.</p>

<h1 id="proposed-solutions">Proposed Solutions</h1>

<h2 id="user-data-sovereignty">User Data Sovereignty</h2>

<p>From the perspective of content / social networks like Facebook, they see themselves as “owning” the content and data posted to them.  As a potent example of this: a politician who creates a “public page” on the Facebook platform posts their upcoming event schedule.  While anyone on the internet can go to this page from a Google search result, Facebook requires App developers to have a business entity and get approval from the platform in the form of “<a href="https://developers.facebook.com/docs/features-reference/page-public-content-access/">Public</a> <a href="https://developers.facebook.com/docs/features-reference/page-public-content-access/">Page Content Access</a>” to be able to read the same data in a machine form.  The public page wants this data to be discovered, but Facebook forces a set of consumers into a relationship with Facebook via the developer programs where they can then exert undue influence and control of data that should be owned by the page owner.</p>

<p><strong>Resolution:</strong></p>

<ul>
  <li>Apps on the internet should at the least be able to view public content at with the same ease as a user in a browser.</li>
  <li>Facebook has used “protecting user privacy” to push out other consumers of their data.  At this stage it is clear that this is increasing Facebook influence, and is decided in an arbitrary way.  We need a better solution to protecting against data harvesting other than having Facebook be the keeper of this walled garden.</li>
</ul>

<h2 id="classifying-facebook-graph--messenger--portal-video-chat-as-a-utility">Classifying Facebook Graph / Messenger / Portal (Video Chat) as a “Utility”</h2>

<p>We have existing common carrier definitions of “utility”.  We need to update this to better support the year 2021.  By forcing companies that provide solutions like this to have carrier peering agreements (this is handled by the back end system used by such systems known as “XMPP” or “Jabber”) as well as requiring documentation of the protocols so that one can use a client other then the one provided by the service (for instance bringing Facebook messenger to other operating systems which lack corporate support like Linux) we can increase competition.  A classical example of this was a messaging app from 15-20 years ago named “<a href="https://en.wikipedia.org/wiki/Trillian_(software)">Trillian</a>”.</p>

<p><strong>Resolution:</strong></p>

<ul>
  <li>Forced documentation of protocols, similar to the requirements placed on Microsoft after the IE4 anti-trust case(<a href="https://docs.microsoft.com/en-us/openspecs/protocols/ms-protocolslp/9a3ae8a2-02e5-4d05-874a-b3551405d8f9">https://docs.microsoft.com/en-us/openspecs/protocols/ms-protocolslp/9a3ae8a2-02e5-4d05-874a-b3551405d8f9</a>)</li>
  <li>“Fair Use” rules regarding interoperability</li>
</ul>

<h2 id="forced-discoverability-of-other-platforms-meta-contacts">Forced Discoverability of Other Platforms (Meta-contacts)</h2>

<p>Platforms that provide social context need a simple method whereby users are able to link their presence across platforms.  As a user I should be able to see that a contact and myself both have FaceTime and could use this instead if we prefer.  This prevents the lock in to ecosystem.  We built a scheme for this a long time ago in the form of URLs and URIs.  By simply having my Facebook profile have a URI of facebook.com:profile:penwellr and it linking to linkedin.com:profile:penwellr we could discover across platforms.  This type of linkage should be forced to be supported by these systems but of corse their disclosure should be in the control of a user in the form of privacy options.</p>

<p><strong>Resolution:</strong></p>

<ul>
  <li>Create a standard for cross-platform linkage allowing transitions to other platforms where users decide they wish too</li>
</ul>

<h2 id="examination-of-incentive-models">Examination of “incentive models”</h2>

<p>Reddit is a much better design of engagement for social media.  The content is shown as a result of “up” and “down”voting rather than algorithms designed for engagement.  On top of this moderation is provided as a teem of volunteers that are experts in their particular sub-reddit.  This makes the ecosystem police themselves.  Facebook’s hiring an army of content moderators with little impact should show that you cannot police a system where you profit from it being lawless.  Furthermore, Facebook’s unique position of being able to access all data sets and then deciding what and how to publish should be examined as well.  Qualified academics should be able to work with raw data sets to produce the kind of evidence about platform and sociological behavior.
<strong>Resolution:</strong></p>

<ul>
  <li>Thoughtfully consider where the profit model takes away from “social good”</li>
  <li>Break up the monopoly of expertise that exists in house on data analysis</li>
</ul>

<h2 id="identity-verification--kyc-requirements">Identity Verification / KYC requirements</h2>

<p>Many of the worst abuses of social media come in the form of COPPA violations as well as bot/non-human actors manipulating human interaction.  Our banks require KYC (know your customer) requirements so that financial crimes can be tracked and prosecuted.  Identity verification documents are not a high bar of proof of a human accountable for a particular account / content.</p>

<p><strong>Resolution:</strong></p>

<ul>
  <li>Require documentation for any account / profile publishing “public” or “discoverable” information (outside of accepted “friends”)</li>
</ul>

<h2 id="transparency-reports-should-be-prepared-with-outside-experts">Transparency Reports Should Be Prepared with Outside Experts</h2>

<p>We trust the “transparency reports” from tech companies which are prepared by in house data scientists which often hold stock in their company.  We should build better, academic style, peer-reviewed methods for gathering and verifying key metrics about platform abuse.</p>

<p><strong>Resolution:</strong></p>

<ul>
  <li>Require data interchange with accredited higher learning institutions</li>
</ul>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[The Difficulty with Ubiquious Services The reason that the utility of Facebook is what it is, is primarily its de-facto status as the ubiquitous system of record. Before Facebook conversations in real life were a binary search tree of what system’s you shared in common (IRC, AIM, ICQ, LinkedIn…]]></summary></entry><entry><title type="html">Puppeteer with ChromeOS</title><link href="https://rickmark.me/blog/puppeteer-with-chromeos/" rel="alternate" type="text/html" title="Puppeteer with ChromeOS" /><published>2020-10-23T04:11:59+00:00</published><updated>2020-10-23T04:11:59+00:00</updated><id>https://rickmark.me/blog/puppeteer-with-chromeos</id><content type="html" xml:base="https://rickmark.me/blog/puppeteer-with-chromeos/"><![CDATA[<h1 id="headed-chrome-testing">“Headed” Chrome Testing</h1>

<p>Recently I’ve been working on using Chrome and WebUSB to communicate with Apple iPhone/iPads which implement the <code class="language-plaintext highlighter-rouge">usbmuxd</code> protocol.  As I was working with this, developer ergonomics and testing became very important, and unlike a regular website “headless” testing was infeasible because of the reliance on WebUSB which is a full browser feature.  Moreover I really wanted to target WebUSB from a Chromebook as an ideal test case.  I settled on using <code class="language-plaintext highlighter-rouge">jsdom</code> and <code class="language-plaintext highlighter-rouge">webusb</code> from NPM for lightweight local testing, and the following to remotely drive tests via the Chrome DevTools protocol to a Pixelbook Slate.</p>

<h2 id="big-scary---much-danger">Big Scary - Much Danger</h2>

<p>Because this guide is showing you how to disable security protections in ChromeOS, and that it will make the browser remotely (albeit with a generally safe SSH configuration) accessible, <strong>I do not recommend logging into this Chrome device with your actual Google account</strong> or using it as anything other then a test device.  Restore the ChromeOS configuration to the non-Developer version before re-using the device for any other purpose.  You have been warned.</p>

<h2 id="entering-developer-mode-and-debugging-features">Entering Developer Mode and Debugging Features</h2>

<p>Chrome devices can be put into “<strong>Developer Mode</strong>” which is a configuration which allows running the operating system that has been modified in such a way that it is no longer in the most secure configuration.  The instructions for this vary by device and I find it is just easier to refer you to Google / Chromiums instructions (here <a href="https://chromium.googlesource.com/chromiumos/docs/+/master/developer_mode.md#dev-mode">https://chromium.googlesource.com/chromiumos/docs/+/master/developer_mode.md#dev-mode</a>).  After entering developer mode, select “<strong>Enable debugging features</strong>” on the first screen of the setup process and set a password (<a href="https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/debugging-features">https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/debugging-features</a>).    I’ve also noticed that updates sometimes break R/W filesystem and reset the <code class="language-plaintext highlighter-rouge">root</code> / <code class="language-plaintext highlighter-rouge">chronos</code> password.  You can always try the default of <code class="language-plaintext highlighter-rouge">test0000</code> and if that doesn’t work, powerwash and re-enable debugging features.</p>

<h2 id="configuring-a-secure-ssh-connection">Configuring a Secure SSH Connection</h2>

<p>Now that the device is effectively “rooted” as in an Android device would be (you have a working root account and mutable filesystem), it’s time to setup the remote SSH server.  A device with Developer Mode and Debugging Features will already be running this sshd by default, but it uses password authentication.  If you are OK with password based auth because the network is relatively private, you can skip this step.
You can perform the following steps from a SSH connection to the device, a local <code class="language-plaintext highlighter-rouge">VT-2</code> terminal (<code class="language-plaintext highlighter-rouge">[ Ctrl ] [ Alt ] [ → ]</code>) or from a crosh shell prompt (<code class="language-plaintext highlighter-rouge">[ Ctrl ] [ Alt ] [ T ]</code>).
The example below just downloads my SSH public keys from my GitHub account, but you could also have downloaded your public key in the browser or moved it to the device via a flash-drive.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Enable Pubkey authentication</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">PubkeyAuthentication yes"</span> <span class="o">&gt;&gt;</span> /etc/ssh/sshd_config

<span class="c"># Disable Challenge-Response authentication</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">ChallengeResponseAuthentication no"</span> <span class="o">&gt;&gt;</span> /etc/ssh/sshd_config

<span class="c"># The following is an example of downloading all SSH keys for a GitHub user, replace `rickmark` with your username.</span>
<span class="nv">$ </span>curl https://github.com/rickmark.keys <span class="o">&gt;</span> /root/.ssh/authorized_keys

<span class="c"># The folowing is an example of copying a SSH key downloaded in the browser with the file name `id_rsa.pub`</span>
<span class="nv">$ </span><span class="nb">cp</span> /home/chronos/user/Downloads/id_rsa.pub /root/.ssh/authorized_keys

<span class="c"># Next we set the ownership and mode of authorized_keys</span>
<span class="nv">$ </span><span class="nb">chown </span>root:root /root/.ssh/authorized_keys
<span class="nv">$ </span><span class="nb">chmod </span>600 /root/.ssh/authorized_keys

<span class="c"># Restart the SSH server to apply</span>
<span class="nv">$ </span>initctl stop openssh-server &amp; initctl start openssh-server
</code></pre></div></div>

<h2 id="enabling-chrome-devtools-remote">Enabling Chrome DevTools Remote</h2>

<p>Now that we have a configured SSH to the device, the remaining steps can be completed over SSH.  In this step we add an additional flag to the chrome process start command.  Because on a ChromeOS device the browser <em>is</em> the shell, we are effectively changing the configuration of  the OS’s equivalent of KDM / GDM</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Append the parameter to the chrome process arguments</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"--remote-debugging-port=1337"</span> <span class="o">&gt;&gt;</span> /etc/chrome_dev.conf

<span class="c"># Restart the device for the settings to take effect</span>
<span class="nv">$ </span>shutdown <span class="nt">-r</span> now
</code></pre></div></div>

<h2 id="running-a-tunnel-to-chrome">Running a Tunnel to Chrome</h2>

<p>Now that the ChromeOS device is configured, run the following to use SSH to create an encrypted tunnel from the Puppeteer machine to the ChromeOS device.  This command must remain running while Puppeteer is in use, and you will start it every time you want to use the ChromeOS device with Puppeteer.  Remember to replace *<chromedevice>* with the IP address or domain name of the Chrome device as well.</chromedevice></p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh <span class="nt">-L</span> 1337:localhost:1337 root@&lt;chromedevice&gt;
</code></pre></div></div>

<h2 id="connecting-from-puppeteer-core">Connecting from Puppeteer Core</h2>

<p>The following is a simple test using <code class="language-plaintext highlighter-rouge">puppeteer-core</code> on the remote Chrome machine.  Ensure you have installed <code class="language-plaintext highlighter-rouge">puppeteer-core</code> via <code class="language-plaintext highlighter-rouge">yarn</code> or <code class="language-plaintext highlighter-rouge">npm</code> before running.  We use puppeteer core because it does not download a copy of Chrome with the module but either should work just as well.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="o">*</span> <span class="nx">as</span> <span class="nx">puppeteer</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">puppeteer-core</span><span class="dl">'</span>

<span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nf">connect</span><span class="p">({</span><span class="na">browserURL</span><span class="p">:</span> <span class="dl">'</span><span class="s1">http://localhost:1337</span><span class="dl">'</span><span class="p">})</span>

<span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nf">newPage</span><span class="p">()</span>

<span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nf">goto</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://google.com</span><span class="dl">'</span><span class="p">)</span>

<span class="c1">// If you do the following, the entire shell restarts (remember the browser is the OS)</span>
<span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre></div></div>

<h2 id="bonus-how-to-webusb-with-an-apple-mobile-device-on-chromeos">BONUS: How to WebUSB with an Apple Mobile Device on ChromeOS</h2>

<p>Recent versions of ChromeOS have included copies of <code class="language-plaintext highlighter-rouge">mtpd</code> or the media transfer protocol agent to allow a ChromeOS device to copy photos, and since the iPhone implements this protocol, it can happen that the background agent refuses to give up the device leading to “Access Denied” errors when trying to drive the device via WebUSB in the browser.  Also the linux kernel itself can attempt to claim the device as a iPhone tether device as well.  I’ve filed a bug to allow for UI to let the use “eject” the MTP device from the file browser, but for now follow the following steps to disable these on a ChromeOS device you’ve already enabled debugging features on to be able to use the device without ChromeOS getting in the way:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Blacklist the "iPhone Ethernet" linux kernel module</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"blacklist ipheth"</span> <span class="o">&gt;&gt;</span> /etc/modprobe.d/blacklist.conf

<span class="c"># Move the 'mtpd' service to the home folder so it wont be started with the operating system.  Move it back to restore</span>
<span class="nv">$ </span><span class="nb">mv</span> /etc/init/mtpd.conf ~/

<span class="c"># Restart to apply changes</span>
<span class="nv">$ </span>shutdown <span class="nt">-r</span> now
</code></pre></div></div>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[“Headed” Chrome Testing Recently I’ve been working on using Chrome and WebUSB to communicate with Apple iPhone/iPads which implement the usbmuxd protocol. As I was working with this, developer ergonomics and testing became very important, and unlike a regular website “headless” testing was infeasible because of the reliance…]]></summary></entry><entry><title type="html">checkra1n and the T2</title><link href="https://rickmark.me/blog/checkra1n-and-the-t2/" rel="alternate" type="text/html" title="checkra1n and the T2" /><published>2020-10-06T04:56:43+00:00</published><updated>2020-10-06T04:56:43+00:00</updated><id>https://rickmark.me/blog/checkra1n-and-the-t2</id><content type="html" xml:base="https://rickmark.me/blog/checkra1n-and-the-t2/"><![CDATA[<p>Given the interest in the industry I’ve decided to make some quick notes from earlier this year available, I plan to expland on this later:</p>

<h2 id="what-can-i-do-with-ssh-to-the-t2-anyway">What can I do with SSH to the T2 anyway?</h2>

<p>Initially, look around and perform additional research.  Once executing on the T2 core, the security of the T2 can be evaluated.  In this environment you are both root and have full kernel execute (because the kernel is rewritten before execute).</p>

<h2 id="what-is-pongoos-and-what-does-it-have-to-do-with-this">What is pongoOS and what does it have to do with this?</h2>

<p><a href="https://github.com/checkra1n/pongoOS">pongoOS</a> runs after the iBoot loader and loads the XNU kernel with patches.  This allows it to modify the XNU kernel on the T2 to disable various security features and is how we shim the dropbear SSH server into the T2.  While checkra1n uses this to enable the end user to access the T2, a malicious actor could use it to tamper with the T2.  With great power comes great responsibility.</p>

<h2 id="when-will-there-be-a-patch">When will there be a patch?</h2>

<p>Apple uses SecureROM in the early stages of boot.  ROM cannot be altered after fabrication and is done so to prevent modifications.  This usually prevents an attacker from placing malware at the beginning of the boot chain, but in this case also prevents Apple from fixing the SecureROM.  The net effect is Apple cannot fix this problem without replacing the T2 chip, but as long as a machine is bootable into DFU, it can be “repaired” by a trustworthy second machine.</p>

<h2 id="i-want-to-recover-my-t2-to-its-factory-configuration">I want to recover my T2 to it’s factory configuration.</h2>

<p>You have two choices, but either one requires a computer that you trust.  Remember just like where you download a jailbreak utility (which should always be from the official <a href="https://checkra.in/">https://checkra.in</a>) the security of the device being restored is only as secure as the device doing the restore.  This process might wipe disk encryption keys, so be careful!  If you’re using a Mac to restore the T2, Apple’s Configurator can be used by following their guidance here.  Linux and Windows machines can use the open-source <a href="https://github.com/libimobiledevice">libimobiledevice</a> tools.</p>

<h2 id="is-it-safe-to-jailbreak-the-t2-can-it-harm-my-device--wipe-my-data">Is it safe to jailbreak the T2? Can it harm my device / wipe my data?</h2>

<p>At this phase, yes it is absolutely possible to overwrite encryption keys (read AppleEffacableStorage) and loose your data.  Trust us, a few of the gang have already done this!  Do not use on any machine you love or care about.  While we cannot speak to if this violates Apple Care, we suspect it may.  That being said, anyone can run checkra1n on anyone’s machine so Apple will need to sort out the warranty issue themselves.</p>

<h2 id="how-can-i-tell-if-my-t2-has-been-tampered-with">How can I tell if my T2 has been tampered with?</h2>

<p>Currently it is difficult to do so.  Any process of booting into DFU will loose the RAM of the processor.  Ensuring that you’ve truly reached DFU may require disconnecting system power, which is somewhat difficult in Apple portables.</p>

<h2 id="will-i-be-able-to-repair-my-own-mac">Will I be able to repair my own Mac?</h2>

<p>Many of the internal Apple tools used to perform hard drive swaps, serial number changes etc use Apple signed code that is run on the T2.  Since this is an ACE circumvents Apple code execution policies and has full access to NVMe, most modifications that were perviously only available to Apple would be possible.</p>

<h2 id="what-about-encrypted-disks-are-they-safe">What about encrypted disks, are they safe?</h2>

<p>If you have FileVault2, arbitrary code execute on the T2 does not by itself allow decrypting of documents.  Unfortunately the simplest thing for an attacker to do is to place a shim into the operating system that reports the encryption key after the machine boots and you’re password is entered.</p>

<h2 id="will-a-firmware-password-mitigate-this">Will a firmware password mitigate this?</h2>

<p>Because the firmware password is handled by the Intel processor and EFI, no a firmware password is evaluated later in the boot than the T2.  The EFI password requires the keyboard and display to be online to operate.</p>

<h2 id="but-i-have-secure-boot-on-in-full-mode-what-gives">But I have secure boot on in full mode, what gives?</h2>

<p>Like the answer about firmware passwords, secure boot is a function of the T2 verifying boot components later in the boot chain then DFU.  Since we have arbitrary code execution at such an early stage, secure boot can be completely circumvented, disabled, and alternate operating systems placed on the unencrypted portion of disk.</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[Given the interest in the industry I've decided to make some quick notes from earlier this year available, I plan to expland on this later: What can I do with SSH to the T2 anyway? Initially, look around and perform additional research. Once executing on the T2 core, the security…]]></summary></entry><entry><title type="html">The Execution of the Warrant</title><link href="https://rickmark.me/blog/the-execution-of-the-warrant/" rel="alternate" type="text/html" title="The Execution of the Warrant" /><published>2020-04-16T06:01:33+00:00</published><updated>2020-04-16T06:01:33+00:00</updated><id>https://rickmark.me/blog/the-execution-of-the-warrant</id><content type="html" xml:base="https://rickmark.me/blog/the-execution-of-the-warrant/"><![CDATA[<p>In 2002 the country looked on as the offices of Arthur Anderson LLP had box after box of records carted out of the Houston office. It is through both photographs and court documents that the accounting firm’s practices were displayed and all very publicly. That was almost 20 years ago, and the majority of documents material to a criminal investigation are now created and stored in digital form. Unlike collecting reams of paperwork from an office building, warrants for this form of information lack the grandeur and spectacle of federal agents cataloging and transporting physical files.</p>

<p>As though by some predictable ebb and flow of attention to our privacy, we are yet again considering vast, sweeping legislation to kneecap the use of end-to-end encryption (a technology that allows only the participants to read the contents even if a third party is relaying the data). Reincarnated in the form of the EARN IT Act, yet it is a familiar argument we’ve had before. The pros profess that Government needs ever-increasing access to be able to perform crucial law enforcement and public safety functions. Those against asserting government overreach and the death of privacy as personal liberty. Consider instead, that the last vestige of our warrant system is that it should be costly to invade someone’s privacy.</p>

<p>By cost, I don’t mean just in dollars and cents. The company whose documents pillaged would have been aware of what had transpired, should the order have been unlawful. In this case, the warrants exposed the Government to public scrutiny. Had the target been wronged, it would have been possible to seek reparations. The prosecuting attorney would have been embarrassed, rebuked, and wasted precious manpower—an awkward annual performance review to be sure.</p>

<p>Luckily end-to-end encryption is not unbreakable encryption. A well funded and motivated attacker (Government, large corporation, or otherwise) can break keys with enough time and computational effort. An ability now within reach of both the good and the bad through the vastness of the cloud. Should that fail, accessing the data by compromising the devices at either end of the communication remains a viable alternative.  Copying data in this century is inexpensive and straightforward, so it is the cost of decrypting communications that stands in the way of unlimited access. It is because of these conditions that I see that expansion of surveillance on the public at large is not only a possibility but instead an eventuality.</p>

<p>Only performing traffic analysis, oft referred to as “metadata” as is legal and commonplace today, provides substantial value. Knowing who an actor is talking to when the communications occur how often and the verbosity is precisely the kind of information frequently cited in obtaining a lawful warrant.</p>

<p>Permitting any government unmitigated access to encryption keys erodes both jurisprudence and the traditional warrant system. The cost of invading another person’s privacy would be amortized over a mass collection, making it irresistible to review as much data as possible.  All likely to be conducted under the FISA court system operating without transparency. The ever-expanding abilities of AI, big data, and machine prediction may prove too sweet a temptation for us to resist.</p>

<p>Understandably, the Government is rightfully interested in crime prevention and prosecution. Still, we must temper that interest with the constitutional rights to due process granted to the innocent as well as the guilty.  Even darker yet, there is no evidence that the agents operating such collection systems are any more pious than their private sector counterparts. Regular reports of the invasion of privacy by employees at high-tech firms with access do occur. Do we honestly think that the Government would be substantially more effective at self-regulating and reporting such abuses?</p>

<p>Finally, and most importantly, cryptographically-strong end-to-end encryption is and would remain widely available in countries that maintain no restrictions on its use.  It is highly unlikely that the criminals we are aiming to stop would even notice such a law.</p>

<p>We are, therefore, once again called to action, to voice opposition to the expansion of the surveillance state and re-assert our fundamental right to privacy. When the Government has real cause to obtain full access to our private information, it should come at a cost. An authentic and apparent price to pay for the liberty lost. Do you think we will grant the warrant a stay of execution again?  If so, for how long?</p>]]></content><author><name>Rick Mark-Penwell</name></author><summary type="html"><![CDATA[In 2002 the country looked on as the offices of Arthur Anderson LLP had box after box of records carted out of the Houston office. It is through both photographs and court documents that the accounting firm's practices were displayed and all very publicly. That was almost 20 years ago…]]></summary></entry></feed>