
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.
