macos-iso-to-usb.md (12727B)
1 --- 2 title: "macOS-ISO-to-USB" 3 description: "shasum -a 256 ~/Downloads/some.iso" 4 category: linux-it 5 tags: ["linux-it", "hashing"] 6 tools: ["Ligolo-ng"] 7 difficulty: intermediate 8 updated: "2026-08-10" 9 source: "vault:macOS-ISO-to-USB-Cheatsheet.md" 10 --- 11 # πΏ Burning ISOs to USB on macOS (CLI) 12 13 > [!info] TL;DR 14 > - **Linux / BSD / macOS / most ISOs** β `dd` just works. 15 > - **Windows 10/11 ISOs** β `dd` **does not work**. `install.wim` is usually >4 GB, `diskutil eraseDisk` can't do FAT32, and the Windows boot chain needs a UEFI-visible FAT32 partition. Use the **mount + rsync + wimlib-split** method. 16 > - **Erasing / wiping** β see the [diskutil erase section](#-diskutil--erasing--secure-erasing-drives). Secure-erase passes are for spinning HDDs; flash/SSDs need encryption-based wipes. 17 > - Always `diskutil list` **twice** before writing. `of=` to the wrong disk destroys your Mac in seconds. 18 19 --- 20 21 ## β οΈ Before You Start 22 23 - **Identify your USB drive**: `diskutil list` β look for size, name, `external, physical`. 24 - **Never** write to `/dev/disk0` (internal SSD) or the disk containing `/System/Volumes/Data`. 25 - Use the **raw** device (`/dev/rdiskN`) for `dd` β it's ~10Γ faster than `/dev/diskN`. 26 - Apple Silicon caveat: a Windows **x64** USB will **not boot an ARM Mac**. You're making this for a PC or an ARM Windows VM. 27 28 --- 29 30 ## π§ͺ Step 0 β Verify the ISO (always do this) 31 32 ```bash 33 # SHA-256 β compare against the vendor's published hash 34 shasum -a 256 ~/Downloads/some.iso 35 36 # Or if the vendor published SHA-512 37 shasum -a 512 ~/Downloads/some.iso 38 ``` 39 40 --- 41 42 ## π§ General Method β Linux / BSD / macOS / Kali / Ubuntu / etc. 43 44 Works for **any hybrid ISO** (isohybrid / modern Linux / Kali / Ubuntu / FreeBSD / macOS recovery). This is the `dd` path. 45 46 ```bash 47 # 1. List disks, find your USB 48 diskutil list 49 50 # 2. Unmount the whole disk (not `eject`, not a partition) 51 diskutil unmountDisk /dev/disk4 52 53 # 3. Write the ISO β note `rdisk`, not `disk` 54 sudo dd if=~/Downloads/kali-linux-2025.iso of=/dev/rdisk4 bs=4m status=progress 55 56 # 4. Eject when done 57 diskutil eject /dev/disk4 58 ``` 59 60 > [!tip] Speed & progress 61 > - `bs=4m` is a sane block size on macOS (lowercase `m`, not `M`). 62 > - `status=progress` works on recent macOS; if not, hit **Ctrl+T** during `dd` to print SIGINFO progress. 63 64 > [!warning] "Resource busy" 65 > If `dd` refuses with `Resource busy`, you forgot `diskutil unmountDisk`. Do **not** reformat the drive to fix this. 66 67 --- 68 69 ## πͺ Windows 10/11 ISO β The Method That Actually Works 70 71 > [!danger] Why `dd` fails for Windows 72 > Windows ISOs since ~2017 ship `sources/install.wim` larger than 4 GB. A `dd` copy preserves the ISO's internal filesystem (UDF/ISO9660), which most PC firmwares won't boot as a Windows installer. The canonical fix: format USB as **FAT32 + MBR**, copy files, and **split `install.wim`** with `wimlib` so it fits FAT32's 4 GB per-file limit. Windows Setup transparently reassembles split `.swm` files. 73 74 ### Prereqs 75 76 ```bash 77 # Install wimlib (provides wimlib-imagex) 78 brew install wimlib 79 ``` 80 81 ### Full procedure 82 83 ```bash 84 # 1. Find the USB 85 diskutil list 86 # Assume it's /dev/disk4 β a 16 GB+ stick 87 88 # 2. Format: MS-DOS (FAT32) + MBR, label WIN11 89 sudo diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4 90 91 # 3. Mount the Windows ISO 92 hdiutil mount ~/Downloads/Win11_English_x64.iso 93 # Note the mount point β usually /Volumes/CCCOMA_X64FRE_EN-US_DV9 94 # (name varies by build/language) 95 96 # 4. Set variables for clarity 97 ISO_MOUNT="/Volumes/CCCOMA_X64FRE_EN-US_DV9" 98 USB_MOUNT="/Volumes/WIN11" 99 100 # 5. Copy everything EXCEPT install.wim (too big for FAT32) 101 rsync -avh --progress --exclude='sources/install.wim' "$ISO_MOUNT/" "$USB_MOUNT/" 102 103 # 6. Split install.wim into <4 GB chunks directly onto the USB 104 wimlib-imagex split "$ISO_MOUNT/sources/install.wim" \ 105 "$USB_MOUNT/sources/install.swm" 3800 106 107 # 7. Unmount cleanly (flush buffers β this takes a minute, be patient) 108 hdiutil unmount "$ISO_MOUNT" 109 diskutil eject /dev/disk4 110 ``` 111 112 > [!note] Why `3800` MB? 113 > FAT32's per-file cap is 4 GiB = 4096 MB. `3800` leaves headroom; Microsoft docs suggest splitting below the limit. 114 115 > [!tip] If the target PC won't boot the USB 116 > - Some modern PCs want **GPT**, not MBR. Re-run step 2 with `GPT` instead of `MBR` and try again. 117 > - In BIOS/UEFI, disable **CSM/Legacy** and ensure **Secure Boot** is off for installation. 118 > - For **Windows 7** (legacy), `dd` actually works fine β the `.wim` bloat is a modern Windows problem. 119 120 ### Windows ARM ISO (for Apple Silicon VMs) 121 122 Same procedure, but `install.wim` is often **under** 4 GB β try a straight `rsync` first with no split: 123 124 ```bash 125 rsync -avh --progress "$ISO_MOUNT/" "$USB_MOUNT/" 126 # If it fails on install.wim, fall back to the wimlib-split step above. 127 ``` 128 129 --- 130 131 ## π§Ή `diskutil` β Erasing & Secure-Erasing Drives 132 133 > [!danger] Read this first 134 > Every `diskutil erase*` verb is **destructive and immediate** β no confirmation prompt, no undo. Always run `diskutil list` twice and target the correct `/dev/diskN`. Hitting `disk0` wipes your Mac's internal SSD. 135 136 ### Verb cheat sheet 137 138 | Verb | What it does | Scope | 139 |---|---|---| 140 | `eraseDisk` | Wipe entire disk, lay down new partition scheme + one volume | Whole drive | 141 | `eraseVolume` | Wipe a single mounted volume, keep the disk's partition scheme | One partition | 142 | `partitionDisk` | Wipe disk and create multiple partitions in one shot | Whole drive | 143 | `zeroDisk` | Fill entire disk with zeros (single pass) | Whole drive | 144 | `randomDisk <passes>` | Fill entire disk with random data, N passes | Whole drive | 145 | `secureErase <level>` | Multi-pass overwrite wipe of a whole disk | Whole drive | 146 | `secureErase freespace <level>` | Overwrite only the unused space on a mounted volume | Free space only | 147 148 ### Formats you'll actually use 149 150 | Format string | Real filesystem | Typical use | 151 |---|---|---| 152 | `APFS` | APFS | Modern macOS-only volumes | 153 | `JHFS+` | Mac OS Extended (Journaled) | macOS legacy / Time Machine on HDD | 154 | `MS-DOS` or `MS-DOS FAT32` | FAT32 | Windows installers, UEFI boot, BIOS flash | 155 | `ExFAT` | exFAT | Large files + cross-OS (no 4 GB limit) | 156 | `Free Space` | unformatted | Create a blank slot for later | 157 158 ### Partition schemes 159 160 | String | When to use | 161 |---|---| 162 | `MBR` / `MBRFormat` | Windows installer USB (FAT32 + MBR), legacy BIOS | 163 | `GPT` / `GPTFormat` | Modern UEFI systems, anything >2 TB, most 2020+ PCs | 164 | `APM` / `APMFormat` | PowerPC-era Macs β don't use unless you need to | 165 166 ### Common erase patterns 167 168 ```bash 169 # Plain reformat a USB as exFAT + GPT (cross-OS daily-driver stick) 170 sudo diskutil eraseDisk ExFAT "DATA" GPT /dev/disk4 171 172 # FAT32 + MBR for a Windows installer USB 173 sudo diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4 174 175 # APFS + GPT for a macOS-only stick 176 sudo diskutil eraseDisk APFS "MACSTICK" GPT /dev/disk4 177 178 # Wipe a single mounted volume, keep the scheme intact 179 sudo diskutil eraseVolume JHFS+ "Scratch" /Volumes/Scratch 180 181 # Partition a disk into two volumes in one go (exFAT + APFS, GPT) 182 sudo diskutil partitionDisk /dev/disk4 2 GPT \ 183 ExFAT "SHARED" 50% \ 184 APFS "MACONLY" 0b 185 ``` 186 187 ### Secure erase β `diskutil secureErase` 188 189 > [!warning] Secure erase on SSDs / USB flash is largely theatre 190 > Apple removed the GUI option because **overwriting doesn't reliably wipe flash**. Wear-levelling, over-provisioning, and TRIM mean the controller may silently keep copies of "erased" blocks. Use it on **spinning HDDs** where it actually works. For SSDs/flash, prefer **FileVault / encryption with a discarded key**, or the drive's own ATA Secure Erase / NVMe Sanitize (usually only accessible from Linux via `hdparm` / `nvme-cli`). 191 192 **Syntax:** 193 194 ```bash 195 sudo diskutil secureErase <level> /dev/diskN 196 sudo diskutil secureErase freespace <level> /Volumes/VolumeName 197 ``` 198 199 **Levels** (yes, the numbering is bizarre): 200 201 | Level | Passes | Standard | Notes | 202 |---|---|---|---| 203 | `0` | 1 | Single-pass zero | Fast. Fine for HDDs. | 204 | `1` | 1 | Single-pass random | Slightly better than zeros on HDD | 205 | `2` | **7** | DoE 3-pass (historic: DoD 5220.22-M 7-pass) | Overkill for modern HDDs | 206 | `3` | **35** | Gutmann | Almost never justified; hoursβdays | 207 | `4` | **3** | US DoD 5220.22-M (3-pass) | The "sensible paranoid" option | 208 209 **Examples:** 210 211 ```bash 212 # Single zero-pass wipe of a whole USB (HDD-era fast option) 213 sudo diskutil secureErase 0 /dev/disk4 214 215 # DoD 3-pass wipe of a USB stick (for pentest engagement hygiene) 216 sudo diskutil secureErase 4 /dev/disk4 217 218 # Scrub only the free space on a mounted volume β leaves files intact, 219 # tries to kill recoverable remnants of already-deleted files 220 sudo diskutil secureErase freespace 1 /Volumes/DATA 221 222 # Equivalent "lite" path: single-pass zero-fill of whole disk 223 sudo diskutil zeroDisk /dev/disk4 224 225 # Random-fill, 3 passes 226 sudo diskutil randomDisk 3 /dev/disk4 227 ``` 228 229 > [!tip] Ctrl+T for progress 230 > `secureErase`, `zeroDisk`, and `randomDisk` are quiet. Press **Ctrl+T** in the terminal to send SIGINFO and get a one-line progress update. 231 232 ### Pentest-engagement hygiene recipe 233 234 For reusable installer/tooling USBs between clients (bearing in mind flash-memory caveats above): 235 236 ```bash 237 # 1. Identify 238 diskutil list external physical 239 240 # 2. Unmount (just in case) 241 diskutil unmountDisk /dev/disk4 242 243 # 3. Single random-pass (good enough for flash; don't waste cycles on 7/35) 244 sudo diskutil randomDisk 1 /dev/disk4 245 246 # 4. Reformat ready for the next client 247 sudo diskutil eraseDisk ExFAT "ENGAGEMENT" GPT /dev/disk4 248 ``` 249 250 For genuinely sensitive data on flash, **encrypt from day one** (APFS encrypted volume or LUKS from Linux) and destroy the passphrase at end-of-life β that's the only reliable "secure erase" for modern flash. 251 252 --- 253 254 ## π Quick Reference Table 255 256 | Scenario | Tool | Target filesystem | Partition | Notes | 257 | ----------------------------- | ------------------ | ----------------- | --------- | ----------------------------- | 258 | Kali / Ubuntu / Linux live | `dd` | (raw write) | n/a | `bs=4m`, use `rdiskN` | 259 | FreeBSD / OpenBSD | `dd` | (raw write) | n/a | Same as above | 260 | macOS installer (DMGβISO) | `createinstallmedia` | HFS+ | GPT | Apple's own tool, not `dd` | 261 | Windows 7 | `dd` | (raw write) | n/a | Legacy β works | 262 | **Windows 10 / 11 (x64)** | `rsync` + `wimlib` | FAT32 | MBR (GPT fallback) | **Do not use `dd`** | 263 | Windows 11 ARM | `rsync` (+ wimlib if >4GB) | FAT32 | MBR/GPT | Check `install.wim` size first | 264 265 --- 266 267 ## π§° Handy One-Liners 268 269 ```bash 270 # Identify only external physical disks (less scary than plain `diskutil list`) 271 diskutil list external physical 272 273 # Check install.wim size before deciding split vs direct copy 274 ls -lh /Volumes/CCCOMA_*/sources/install.wim 275 276 # Watch dd progress without status=progress (send SIGINFO) 277 # During dd, press Ctrl+T 278 279 # Unmount every partition of a disk at once 280 diskutil unmountDisk force /dev/disk4 281 282 # Verify what's actually on the stick after burning 283 diskutil info /dev/disk4 284 ``` 285 286 --- 287 288 ## π§― Troubleshooting 289 290 | Symptom | Fix | 291 |---|---| 292 | `dd: /dev/rdisk4: Resource busy` | `diskutil unmountDisk /dev/disk4` first | 293 | `dd: Permission denied` | Prefix with `sudo`; on Sonoma+ grant Terminal **Full Disk Access** in System Settings β Privacy | 294 | Windows USB not listed in PC boot menu | Likely booted ISO raw with `dd` β redo with the rsync+wimlib method | 295 | `rsync: failed: Read-only file system` | macOS mounted the FAT32 stick read-only (seen on some Sonoma builds). Re-plug, or erase again with `diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4` | 296 | Windows installer says "can't find drivers" mid-install | Try a **USB 2.0 port** β some Win10 media lacks USB 3.x xHCI drivers | 297 | `hdiutil: mount failed` | ISO may be corrupt β re-verify the SHA-256 | 298 | Secure Boot rejects the USB | Disable Secure Boot during install, re-enable after | 299 300 --- 301 302 ## π Security-Adjacent Notes (relevant for pentest lab work) 303 304 - **Always verify ISO hashes** β pre-poisoned ISOs (e.g. backdoored Kali mirrors) have happened. Cross-check against multiple sources for release signing keys. 305 - For a clean **evidence-grade write**, follow `dd` with `sync; sync` and a hash of the source ISO vs `dd if=/dev/rdisk4 bs=4m count=<iso_blocks> | shasum -a 256` (read back and compare). 306 - Throwaway installer sticks for engagements: consider `shred` / `diskutil secureErase` between clients to avoid cross-contamination of tooling. 307 308 --- 309 310 ## π Related 311 312 - ligolo-ng Cheatsheet 313 - Kali on Parallels M1 Setup 314 - NetHydra VM Provisioning