Skip to content

thatdogmachine/cat-privy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cat-privy

Because the obvious .com wasn't available.

Cat privy is starting as an experiment in reaction to this case reporting a social engineering attack leveraging time pressure & false sense of security to trick people into downloading a malicious payload from a online-meeting.


Technical Solution: Kernel-Level Identity Isolation

A Hard Boundary sandbox for Google Chrome on macOS that prevents data exfiltration (reading sensitive files) even if the browser process is fully compromised (Remote Code Execution), while maintaining full hardware acceleration (GPU/Camera/Mic).

The Architecture: "Identity Injection"

Instead of relying on the macOS App Sandbox (which breaks Chrome) or Enterprise Policies (which are soft blocks), we manipulate the Unix Process Identity.

We offer two security modes:

  1. Selective Block (Default): Chrome runs as you but is explicitly DENIED access to specific folders (Documents, Desktop, .ssh).
  2. Default Deny: Chrome is denied access to everything in your Home directory by default and is only allowed to see specific "Whitelisted" folders (Downloads, Chrome Sandbox).

Technical Note: Listing vs. Searching (Traversal)

In the Default Deny configuration, we use a specific combination of ACLs on your Home directory:

  • Deny list: Prevents Chrome from seeing the names of files and folders in your home directory (e.g., ls ~ fails).
  • Allow search: Allows Chrome to "traverse" through your home directory to reach folders it is explicitly allowed to see (like ~/Downloads).

Setup Instructions

Tip

Clean Slate: To safely remove all isolation rules, handling both "ACL Exhaustion" (Memory Error) and "Ghost Inheritance":

for group in tdm-deny-all-chrome tdm-allow-selective-chrome tdm-deny-selective-chrome; do
  # Pass 1: Pressure Valve (Pure Removal from Home)
  # Solves "Cannot allocate memory" by freeing space first
  while idx=$(/bin/ls -le -d ~ | grep "group:$group" | head -n 1 | awk -F: '{print $1}' | xargs) && [ -n "$idx" ]; do
    /bin/chmod -a# "$idx" ~
  done

  # Pass 2: Ghost Flush
  # Re-link and remove to force-clear inherited entries on children
  /bin/chmod +a "group:$group allow search,file_inherit,directory_inherit" ~ 2>/dev/null
  while idx=$(/bin/ls -le -d ~ | grep "group:$group" | head -n 1 | awk -F: '{print $1}' | xargs) && [ -n "$idx" ]; do
    /bin/chmod -a# "$idx" ~
  done

  # Pass 3: Final Sub-file Sweep
  /usr/bin/find ~ -maxdepth 4 -acl -print0 2>/dev/null | xargs -0 -n1 bash -c "
    while idx=\$(/bin/ls -le -d \"\$1\" | grep \"group:$group\" | grep -v \"inherited\" | head -n 1 | awk -F: '{print \$1}' | xargs) && [ -n \"\$idx\" ]; do
      /bin/chmod -a# \"\$idx\" \"\$1\" 2>/dev/null || break
    done
  " --
done

Verify with:

/usr/bin/find ~ -maxdepth 2 -exec /bin/ls -le -d {} + 2>/dev/null | grep -B 1 "group:tdm-"

1. Create the Isolation Groups

# Selective Block Group (GID 9999)
sudo dseditgroup -o create -i 9999 tdm-deny-selective-chrome

# Default Deny Groups (GID 9998, 9997)
sudo dseditgroup -o create -i 9998 tdm-deny-all-chrome
sudo dseditgroup -o create -i 9997 tdm-allow-selective-chrome

2. Build the "Walls" (ACLs)

For Selective Block:

# Documents, Desktop, SSH
for folder in Documents Desktop .ssh; do
  target="$HOME/$folder"
  rule="group:tdm-deny-selective-chrome deny read,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"
  
  # 1. Remove ALL existing instances of this rule (Idempotent)
  while /bin/chmod -a "$rule" "$target" 2>/dev/null; do :; done
  
  # 2. Apply the rule once
  /bin/chmod +a "$rule" "$target"
done

For Default Deny:

# 1. Clear existing Home ACLs (Ensures Clean Slate for Home)
/bin/chmod -N ~

# 2. Block Chrome from LISTING files in Home, but allow traversing through it
/bin/chmod "+a#" 0 "group:tdm-deny-all-chrome deny list" ~
/bin/chmod "+a#" 0 "group:tdm-deny-all-chrome allow search,readattr" ~
/bin/chmod "+a#" 0 "group:tdm-allow-selective-chrome allow search,readattr" ~

# 3. Block Chrome from READING/WRITING any individual FILE in Home (Inheritable)
/bin/chmod "+a#" 0 "group:tdm-deny-all-chrome deny read,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,only_inherit,file_inherit" ~

# 3b. Seal ALL Existing Top-Level Folders (True Default Deny)
# We must explicitly lock existing folders because inheritance doesn't propagate to them automatically.
for folder in ~/*; do
  folder_name=$(basename "$folder")
  # Skip Whitelisted Folders (Add others here if needed, e.g. "Public")
  if [[ "$folder_name" == "Downloads" || "$folder_name" == "chrome_sandbox" ]]; then
    continue
  fi
  
  # Skip items we don't own (prevents "Operation not permitted" on system files)
  if [[ ! -O "$folder" ]]; then continue; fi
  
  rule="group:tdm-deny-all-chrome deny read,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"
  while /bin/chmod -a "$rule" "$folder" 2>/dev/null; do :; done
  /bin/chmod +a "$rule" "$folder"
done

# 4. Whitelist Downloads & Sandbox Profile
mkdir -p ~/chrome_sandbox
for target in ~/chrome_sandbox ~/Downloads; do
  # Define rules
  allow_sel="group:tdm-allow-selective-chrome allow read,list,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"
  allow_deny="group:tdm-deny-all-chrome allow read,list,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"

  # 1. Loop-remove ALL existing instances
  while /bin/chmod -a "$allow_sel" "$target" 2>/dev/null; do :; done
  while /bin/chmod -a "$allow_deny" "$target" 2>/dev/null; do :; done

  # 2. Apply rules once (at the top, index 0)
  /bin/chmod "+a#" 0 "$allow_sel" "$target"
  /bin/chmod "+a#" 0 "$allow_deny" "$target"
done

# 4b. Whitelist System Keychain (Enable Passwords/Login)
# 1. Allow traversing ~/Library (Insert at TOP to override Deny)
/bin/chmod "+a#" 0 "group:tdm-deny-all-chrome allow search" ~/Library

# 2. Whitelist Keychains folder
target=~/Library/Keychains
allow_keychain="group:tdm-deny-all-chrome allow read,list,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"
if [ -d "$target" ]; then
    while /bin/chmod -R -a "$allow_keychain" "$target" 2>/dev/null; do :; done
    /bin/chmod -R "+a#" 0 "$allow_keychain" "$target"
fi

# 5. Explicitly block .ssh (Security Requirement)
rule_ssh="group:tdm-deny-all-chrome deny read,write,execute,delete,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit"
while /bin/chmod -a "$rule_ssh" ~/.ssh 2>/dev/null; do :; done
/bin/chmod +a "$rule_ssh" ~/.ssh

3. Compile the Wrapper

The wrapper (cat-privy.c) must be compiled and given setuid root permissions.

# Compile
clang -O3 \
-fstack-protector-all \
-D_FORTIFY_SOURCE=2 \
-Wl,-pie \
-ftrivial-auto-var-init=pattern \
-o cat-privy cat-privy.c

# apply entitlements
codesign --entitlements entitlements.plist -s - --force ./cat-privy


# Set Ownership & Permissions
sudo chown root:wheel cat-privy
sudo /bin/chmod 4755 cat-privy

4. Launch

# Selective Mode (Default)
./chrome-privy.sh selective

# Default Deny Mode
./chrome-privy.sh default-deny

Verification & Diagnosis

1. Automatic Verification

Check the terminal output for the dropped identity:

  • Selective: Final UID: 501, GID: 9999
  • Default Deny: Final UID: 501, GID: 9998 (with 9997 in supplementary)

2. Manual Probe (privy-ls)

The privy-ls tool allows you to simulate the permissions of the Chrome process. Since it modifies process identity, it requires root privileges via sudo.

# Test Selective Block
sudo ./privy-ls 9999 ~/Documents

# Test Default Deny Block
sudo ./privy-ls 9998,9997 ~/Documents

# Test Default Deny Whitelist
sudo ./privy-ls 9998,9997 ~/Downloads

3. ACL Inspection

Verify that the ACLs are actually applied to your home directory:

/usr/bin/find ~ -maxdepth 2 -exec /bin/ls -le -d {} + 2>/dev/null | grep -B 1 "group:tdm-"

4. Browser Test

In Chrome, try to upload a file from ~/Documents to a website. The upload will fail (0 bytes or error).

FAQ

  • Why can I still see files in the "Open File" dialog? The dialog is drawn by the macOS System (Trusted), not Chrome. It shows you the files you have access to. However, when you select a file and click "Open", Chrome (Untrusted) receives the file path but cannot read it because the Kernel enforces the GID 9999 block.
  • How do I upload files? Move the file to a "Transfer" folder (like ~/Downloads or ~/Public) that does not have the Deny ACL. This mimics an "Air-Gap" transfer workflow.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published