Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
xspawn — Avvia programmi macOS tramite l'interfaccia XPC privata di launchd senza eseguirli tramite exec, facendo sì che l'EDR registri launchd come processo padre. Supporta job one-shot, KeepAlive e basati su plist. | Kitploit
Strumenti/GitHubGitHub/cenobyte-vincit/xspawn
Meccanismi di PersistenzaEvasione IDS/IPSPost-ExploitRed TeamingAttacco Avversario
GitHubcenobyte-vincit/xspawn

xspawn

Avvia programmi macOS tramite l'interfaccia XPC privata di launchd senza eseguirli tramite exec, facendo sì che l'EDR registri launchd come processo padre. Supporta job one-shot, KeepAlive e basati su plist.

Vedi Repository
2123 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

xspawn

xspawn avvia un programma su macOS tramite launchd e non esegue mai quel programma direttamente. L'obiettivo è che un EDR registri launchd come processo padre, non questo strumento o la shell chiamante.

di cenobyte [email protected] 2026

https://github.com/cenobyte-vincit/xspawn

Riepilogo

xspawn apre xpc_pipe_create_from_port(bootstrap_port) e avvia l'esecuzione di un programma tramite _xpc_pipe_interface_routine, la stessa pipe XPC privata usata da launchctl, e non esegue mai il programma stesso.

  • Root viene rifiutato. Non esiste una modalità per altri UID.
  • Una singola invocazione invia o rimuove un job.
  • Il client non esegue mai /bin/launchctl.

Requisiti

Host di runtime

  • macOS (Darwin) con una sessione gui/<uid>

Host di build

  • macOS (Darwin) con Xcode Command Line Tools o Xcode
  • compilatore C17 (cc)
  • make
  • cppcheck per lo sviluppo (brew install cppcheck)

Compilazione

root@kitploit:~
make

Utilizzo

root@kitploit:~
xspawn oneshot -l <label> [-o <stdout>] [-e <stderr>] [--] <program> [args...]
xspawn submit  -l <label> [-o <stdout>] [-e <stderr>] [--] <program> [args...]
xspawn remove  -l <label>
xspawn load    -p <plist>
SottocomandoCiclo di vita
oneshotOne-shot (RunAtLoad + LaunchOnlyOnce)
submitKeepAlive
loadplist di proprietà del chiamante così com'è scritta
removeRimozione tramite etichetta

One-shot (RunAtLoad + LaunchOnlyOnce; 0 significa nessuna attesa):

root@kitploit:~
./xspawn oneshot -l com.example.once -- /tmp/helloworld 0

Gli argomenti dopo -- sono ProgramArguments. Questo include codice inline (python3 -c, perl -e). CrowdStrike Falcon per macOS registra l'intera CommandLine, quindi usa il codice inline con gli interpreti con parsimonia.

root@kitploit:~
./xspawn oneshot -l com.example.py -o /tmp/py.out -- \
	/usr/bin/python3 -c "print('hello world')"

Job KeepAlive, con lo stesso ciclo di vita di launchctl submit. Attesa 60 così CrowdStrike Falcon per macOS e launchctl print vedono ancora il processo:

root@kitploit:~
./xspawn submit -l com.example.svc \
	-o /tmp/out.log -e /tmp/err.log -- /tmp/helloworld 60

Ispeziona con launchctl print (solo come riferimento; questo client non lo invoca):

root@kitploit:~
launchctl print gui/$(id -u)/com.example.svc

In caso di successo viene mostrato type = LaunchAgent (non Submitted), program come percorso assoluto e state = running o brevemente xpcproxy. Submitted significa che il job non ha seguito il percorso di bootstrap.

Rimuovi un job di test:

root@kitploit:~
./xspawn remove -l com.example.svc

Carica una plist di proprietà del chiamante (non eliminata dopo la risposta):

root@kitploit:~
./xspawn load -p /tmp/job.plist

<program> deve essere un percorso assoluto. launchd non cerca in $PATH.

load -p richiede un percorso assoluto che termina con .plist.

-o / -e possono essere relativi. Vengono risolti rispetto alla directory di lavoro corrente prima di essere scritti nella plist. Se -o e -e sono omessi, il valore è /dev/null.

oneshot e submit verificano l'etichetta in gui e user (descrittore 708) prima di scrivere la plist temporanea. Un'etichetta già occupata termina con label already loaded e nessun output su stdout. Questo controllo esiste per evitare che un 800 destinato a fallire scriva $TMPDIR/XXXXXX/XXXXXX.plist (un artefatto DFIR; CrowdStrike Falcon conserva il percorso in ASEPFilePath) o stampi la copia XML del dizionario del job. Con un'etichetta libera viene stampato il percorso temporaneo, poi quell'XML e quindi viene inviato 800. load -p esegue lo stesso controllo di occupazione sulla Label del file, poi stampa il percorso del chiamante e l'XML. La directory temporanea viene rimossa a ogni uscita. remove opera per etichetta.

Codici di uscita

CodiceSignificato
0Bootstrap o bootout XPC riuscito
1Errore di utilizzo, etichetta non valida, root, o rifiuto da launchd/XPC

Verifica

Host di build (make e l'albero dei test; spesso nella stessa macchina di una sessione gui). Questi controlli non sono una prova di esecuzione pulita:

root@kitploit:~
make
make test
make test-unit
make test-functional
root@kitploit:~
./xspawn oneshot -l com.example.once -- /tmp/helloworld 0

Limitazioni

  • Solo gui/<uid> dello stesso utente. Root viene rifiutato. Nessuna modalità per altri UID.
  • Effimero: non persistente tra riavvii o logout.
  • Le costanti XPC private di load e bootout sono ancorate a macOS 26.6.1 build 25G76. Riancorare se sw_vers -buildVersion cambia (vedi ARCHITECTURE.md).
  • La plist temporanea è $TMPDIR/XXXXXX/XXXXXX.plist ($TMPDIR deve essere assoluto, altrimenti /tmp). La directory viene rimossa a ogni uscita. Un'etichetta già occupata non crea mai quel file.
  • CrowdStrike Falcon per macOS registra il percorso della plist temporanea nel campo Auto-Start Extensibility Point (ASEPFilePath) nell'evento ProcessRollup2. Il processo padre rimane launchd.
  • Un'esecuzione standalone di xspawn è visibile come questo client: cronologia della shell e un evento di processo EDR per questo binario. CrowdStrike Falcon per macOS registra l'intera CommandLine, che include il percorso del programma e i suoi argomenti. Compila il client all'interno di altri strumenti quando quell'immagine e argv sarebbero distintivi. L'incorporamento non rimuove ASEPFilePath né la riga di bootstrap in launchd.log (vedi ARCHITECTURE.md, Parentage).
  • launchd registra anche lo spawn in /private/var/log/com.apple.xpc.launchd/launchd.log (vedi ARCHITECTURE.md, Parentage).
  • Non inserire una chiave XPCService in una plist scritta a mano: xpcproxy quindi fa fork e CrowdStrike Falcon per macOS registra xpcproxy come padre.

Protocollo XPC privato

launchd è un server bootstrap Mach. Questo client non usa la XPC pubblica (xpc_connection_create). Apre una pipe libxpc privata sul bootstrap_port ereditato con xpc_pipe_create_from_port(bootstrap_port, 4), quindi invia _xpc_pipe_interface_routine. Questi simboli si trovano in libxpc e non sono negli header dell'SDK.

L'ID della routine è l'argomento descrittore, non una chiave nel dizionario della richiesta. Su macOS 26.6.1 build 25G76, load è il descrittore 800 e bootout è 801. I flag di interfaccia sono 6. È richiesta una sessione gui/<uid>: la porta ereditata è il dominio launchd gui solo all'interno di una sessione di login Aqua, e questo client invia solo type 8 con handle = uid.

Load (800) è un dizionario XPC. La definizione del job non è nel corpo del messaggio.

root@kitploit:~
handle   uid (uint64)
type     8 (gui)
paths    [absolute .plist]
by-cli   true

launchd esegue stat sul percorso, analizza la plist, poi esegue posix_spawn di xpcproxy. xpcproxy esegue exec del programma nello stesso PID. Il successo corrisponde a ritorno della pipe 0, nessun xpc-fault, error 0, bootstrap-error 0.

Bootout (801) avviene per etichetta: handle, type 8, name, no-einprogress, wait. Nessuna plist.

Il canale è un precedente noto. Jonathan Levin (launjctl, 2015; Mac OS X and iOS Internals Vol. 1) ha mostrato che launchctl comunica con launchd tramite una pipe XPC privata e ha documentato xpc_pipe_create_from_port / xpc_pipe_routine con le chiavi di dizionario type, handle, subsystem, routine e name. Patrick Wardle (The Art of Mac Malware Vol. 2) ha documentato _xpc_pipe_interface_routine come successiva voce di invio. Csaba Fitzl e Brandon Dalton (OBTS) hanno mappato la stessa famiglia di dizionari e i codici di tipo di dominio (gui è 8). Snippet pubblici usavano già xpc_pipe_create_from_port(bootstrap_port, 4).

Questi scritti descrivono la classe del protocollo. Non includono le costanti live di load della 25G76. La cattura di Levin del 2015 inseriva subsystem e routine nel dizionario e usava xpc_pipe_routine. Sulla 25G76 queste chiavi sono assenti. launchctl bootstrap usa _xpc_pipe_interface_routine con l'ID della routine come argomento descrittore. L'analisi statica arm64e di launchctl assomiglia ancora al vecchio percorso a dizionario e suggerisce 703 come ID di load. Lldb live x86_64 e un client arm64 in esecuzione usano entrambi 800 / 801 con quelle chiavi assenti. Questo client mantiene quella stessa forma su entrambe le slice.

I dump dei registri, la procedura di riancoraggio lldb e le note sul campo parentage sono in ARCHITECTURE.md.

Vedi anche

  • ARCHITECTURE.md: percorso di spawn, parentela, wire live, riancoraggio
  • AGENTS.md: host di build e target
Scarica lo strumento