
Kit de acoplamiento de secciones de binarios ELF para la entrega de payloads sin etapa, permitiendo la fijación de payloads en el campo, evasión de firmas y resistencia a la carga estática/dinámica mediante la manipulación personalizada de secciones ELF.
.data.payload.h:
const data[3432] = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23
};
Se logra manualmente o con herramientas como bin2c o xxd -i payload.bin > payload.h con inclusión de encabezado adicional.
Almacenar cargas útiles en .text y .data de manera genérica también es una mala idea debido a la facilidad de rastreo de carga y la introspección de la semántica de comportamiento de la carga de datos para su ejecución.
__attribute__. Esto es un poco mejor pero aún bien trazable debido a cómo se crea y carga ELF.char stack[10000] __attribute__ ((section ("binstack"))) = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23 };
int init_data __attribute__ ((section ("bindata"))) = 0;
main()
{
/* Inicializar puntero de pila */
init_sp (stack + sizeof (stack));
/* Inicializar datos inicializados */
memcpy (&init_data, &data, &edata - &data);
}
Una directiva similar a .incbin dependiente del ensamblador puede crear una sección e incrustar una carga útil.
Ej: 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 su posterior recuperación en el cargador como:
int main(void) {
extern uint8_t payload_start;
uint8_t *ptrPayload = &payload_start;
...
}
Nota: Podemos incluir un ELF completamente funcional en payload.bin, lo cual es importante cuando se trata de crear binarios "gordos", que contienen elementos de varios kits de herramientas.
Nota: Existen herramientas más ergonómicas para realizar la tarea, como INCBIN de @graphitemaster [enlace]
Una variación del tema es ASM en línea como la siguiente:
/* Datos de imagen sin procesar para todas las imágenes incrustadas */
#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
/* Estructuras de imagen para todas las imágenes incrustadas */
#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: Observa PROGBITS en la definición de una sección, será importante.
La inclusión binaria de cargas útiles mediante compilador/enlazador no es ideal
Hay compensaciones:

El tipo de sección y los indicadores establecidos en la nueva sección que contiene determinan si el cargador del sistema operativo la carga en memoria al lanzar el ejecutable. Algunas secciones se cargan automáticamente por defecto, otras no (por ejemplo, .symtab, .strtab)
Desde el punto ofensivo, ¿qué eficiencias podemos obtener de eso?
Podemos evitar establecer indicadores en secciones que asumen la carga por defecto en memoria.
Podemos usar un tipo diferente de sección que no se cargue en memoria.
Un vendedor o ingeniero de sistemas podría necesitar marcar un archivo objeto con información especial que otros programas puedan verificar para determinar conformidad o compatibilidad. Las secciones de tipo
SHT_NOTEy los elementos de encabezado de programa de tipoPT_NOTEse pueden usar para este propósito.
En este último caso, podemos ver el uso de este tipo de sección en binarios del sistema:
$ readelf --sections /bin/tar | grep NOTE
[ 2] .note.gnu.bu[...] NOTE 00000000000002c4 000002c4
[ 3] .note.ABI-tag NOTE 00000000000002e8 000002e8
Y podemos inspeccionar su contenido:
$ readelf -p .note.ABI-tag /bin/tar
String dump of section '.note.ABI-tag':
[ c] GNU
El resultado final de crear una sección SHT_NOTE se verá así en el ELF:

Bonus: SHT_NOTE nos proporciona estructura si la necesitamos (y la usaremos más adelante):

Hasta ahora hemos podido crear una sección y evitar que el cargador del sistema operativo la cargue en memoria. La sección está efectivamente inactiva en la imagen ELF por el momento. Discutiremos cómo cargarla un poco más tarde. Sin embargo, una pregunta más apremiante es el hecho de que todavía estamos operando a nivel de compilador y enlazador, y la sección es un objeto que se entreteje en la estructura del ELF final, creando relaciones y direcciones de memoria desde el código del cargador que hace referencia a su contenido.